Question

I finally got my code to reference the ruby-alsa library, but I'm stuck again. Eventually, what I'd like to happen is have an audio file play on the server when an action is invoked from the client side. As such, I have the following code in my controller:

File.open('./public/audio/test.wav', 'r') do |f|
  ALSA::PCM::Playback.open do |playback|
    playback.write do |length|
      f.read length
    end
  end
end

By reading the RDoc for the ALSA library, I get the impression I should be using the write_in_background method from the ALSA::PCM::Playback class. Unfortunately, I can't get the syntax right for getting this method to work. To simply verify I have ALSA working properly, I attempted to use the Playback.write method (note code above). The above code is syntactically correct; however, it plays a sound only for a microsecond, then stops. My guess is the request ends so quickly, it doesn't have enough time to play anything recognizable.

As previously mentioned, my ultimate goal is to have an end-user invoke an action that plays audio back on the server. The file should not stop playing at the end of the HTTP request --it should continue until another action is invoked that stops playback. Knowing that, could somebody please help me with getting the syntax and parameters right for calling the write_in_background method? I'm afraid the ruby-alsa documentation I have at this time hasn't been helpful enough for me (as a complete newbie at Ruby).

Update: If I replace the above call to the write method with a call to the write_to_background method, I get the following runtime error: cannot add pcm handler (Function not implemented)

Update 2: I tried this with a different WAV file and the following code and it plays at warp speed.

File.open('./public/audio/sample.wav', 'r') do |f|
  ALSA::PCM::Playback.open do |playback|
    playback.write do |length|
      @temp = length
      f.read length
    end
    sleep 4
  end
end

It appears there may be a combination of things going on here. I believe the first is in reference to the sample rate (length == 44100, which is CD quality). I'll have to look into how to play back audio files at a different rate. Beyond that, however, I'm still stuck on how to get it to play in the background. While the sleep proves ALSA is working, it won't work well in a real-world scenario.

Update 3: Got the sample rate bit working even though it temporarily relies on a magic number:

File.open('./public/audio/sample.wav', 'r') do |f|
  ALSA::PCM::Playback.open "default", {:channels => 1, :sample_rate => 11025} do |playback|
    playback.write do |length|
      @temp = length
      f.read length
    end
    sleep 4
  end
end

At this point, I have my ruby code playing audio through ALSA, but I'm not sure how to make it play continuously in the background without requiring the sleep.

Was it helpful?

Solution

How about kicking it off on its own thread?

Thread.new do
  File.open('myfile.wav', 'rb') do |f|
    ALSA::PCM::Playback.open do |playback|
      playback.write do |length|
        f.read length
     end
    end
  end
end.join

Edit: OK, if that doesn't work, I'm guessing it kicks off its own thread already. How about sleeping for the duration? First try:

  File.open('myfile.wav', 'rb') do |f|
    ALSA::PCM::Playback.open do |playback|
      playback.write do |length|
        f.read length
     end
    end
  end
  sleep 4 # seconds
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top