unoh.github.com

dRuby/Rinda/Ringでジュークボックス

2007-09-27 00:26:16 +0000

komagataです。

最近社内ではiTunes専用のPCを用意して社内BGMを流しています。

「コマンドラインから曲のリクエストを出せないかな」と思って、勉強がてらRubyを使ってジュークボックスサーバ、ジュークボックスクライアントを作ってみました。

必要な機能は、



などで、考えてみるとかなり面倒臭そうです。iTunesはDAAP(Digital Audio Access Protocol)というプロトコルで音楽をやり取りしたり、mDNS(Multicast Domain Name Service)というネームサービスを使ってサーバを見つけたりしているそうです。

今回は、dRubyを使って曲をやり取りし、RindaのTupleSpaceを使って曲の保持、クライアントとの待ち合わせをし、Ringをつかってクライアントがサーバを見つける仕組みを作りました。

スクリプトはそれぞれ下記のようになっています。



利用方法



サーバ側では音楽再生のためにコマンドラインでmp3などが再生できるmpg123が必要です。(下記はUbuntu 7.04の場合)また、サーバ、クライアント共にRubyが必要です。(Ruby 1.8.6で動作確認をしています)

sudo apt-get install mpg123 mpg123-alsa


まず、サーバ側で下記でネームサーバを立ち上げます。

ruby jukebox_ring_server.rb


同じくサーバ側でジュークボックスサーバを立ち上げます。

ruby jukebox_server.rb


あとはクライアント側で再生したいMP3ファイルをしていしてクライアントを実行します。

ruby jukebox_client.rb Heart_Of_The_Sunrise.mp3


クライアントは同じLAN内にブロードキャストしてネームサーバを見つけ、そこに登録してあるジュークボックスサービスに曲のリクエストを追加します。サーバは曲がくるまで待ちうけ、リクエストを順次再生します。

ソースを見てもらうとわかりますが、Ringのサンプルほぼそのままです。

jukebox_server.rb:

#!/usr/bin/env ruby
require 'rinda/ring'
require 'rinda/tuplespace'
require 'tmpdir'
 
class JukeboxServer
  def initialize
    @play_list = Rinda::TupleSpace.new
  end
 
  def play
    puts "waiting..."
    name, music_file = @play_list.take([:music, nil])
    puts "playing..."
    system "mpg123 #{music_file}"
    File.delete "#{Dir.tmpdir}/#{music_file}"
  end
 
  def request(file_name, music_data)
    open("#{Dir.tmpdir}/#{file_name}", "w") {|f| f.write music_data }
    @play_list.write([:music, "#{Dir.tmpdir}/#{file_name}"])
  end
end
 
jukebox_server = JukeboxServer.new
DRb.start_service(nil, jukebox_server)
 
provider = Rinda::RingProvider.new(:jukebox, DRbObject.new(jukebox_server), 'Jukebox Server')
provider.provide
 
loop { jukebox_server.play }
 
DRb.thread.join


クライアントはDRbオブジェクト経由でサーバ側のtmpディレクトリに音楽ファイルを保存し、そのパスをTubpleSpaceに保持して、サーバーが順次再生します。

こんな短いコードで分散オブジェクトやネームサービスが実現できることに驚きました。Ringに関しては複数のIPがある場合にうまくいかないところがあってまだ勉強中です。

コマンドラインから音楽のリクエストが出せて嬉しいかどうかはさておき、他に色々と面白い使いかたができそうです。

ソース: jukebox.tar.bz2