Ulaw audio over network

Does anyone know of a good way to stream ulaw audio (read from a file)
over a UDP socket? I have something (mostly) working, but I can’t seem
to get the packet timing right. If I use a 10ms sleep, the packets end
up being ~12ms apart. However, if I use a lower value (say 8ms), the
packets are 8ms apart. The code I’m using is included below. Has
anyone done this or something similar?

Thanks,
Earle

Code:
require ‘socket’

@audio_socket = UDPSocket.open
@audio_socket.connect(“239.1.1.3”, 4098)

def send_audio(filename)
data = “”

File.open(filename) do |file|
while file.read(80, data)
@audio_socket.send(data, 0)
sleep 0.01
end
end
end

send_audio(ARGV[0])

It looks like this is a pure #sleep issue and has nothing to do with
sending data over a socket. If you setup a simple loop and average
the time sleep actually sleeps, you get the following:

want = 0.008, actual (averaged over 1000 attempts) =
0.00800016689300537
want = 0.01, actual (averaged over 1000 attempts) = 0.0122149839401245
want = 0.012, want (averaged over 1000 attempts) = 0.0120026016235352

Not exactly sure what’s so special about 10ms…

Here’s what I ran to produce the output above:

def try(n)
dt, dc = [0, 0]
1_000.times do
t = Time.now.to_f
sleep n
dt += Time.now.to_f - t
dc += 1
end
dt / dc
end

[0.008, 0.01, 0.012].each do |n|
puts “want = #{n}, actual (averaged over 1000 attempts) = #{try(n)}”
end

On Tue, May 08, 2007 at 04:28:37PM +0900, eden li wrote:

dt / dc
end

[0.008, 0.01, 0.012].each do |n|
puts “want = #{n}, actual (averaged over 1000 attempts) = #{try(n)}”
end

Regardless of how well Ruby’s sleep worked, this would still be
inaccurate
because of the time needed to execute the other things in the loop.

Try something like this instead:

def run
t = Time.now.to_f
1_000.times do
yield if block_given?
t += 0.01
interval = t - Time.now.to_f
sleep(interval) if interval > 0 # sleep barfs with negative values
end
end

t1 = Time.now
run { x = x }
t2 = Time.now
puts t2 - t1

Your UDP packets will have a small amount of jitter, which the far end’s
jitterbuffer will handle (and if this is going over the Internet, you’ll
get
a lot more jitter from other sources), but will be sent at an average
rate
of one every 10ms.

Brian.

Brian C. wrote:

Regardless of how well Ruby’s sleep worked, this would still be
inaccurate
because of the time needed to execute the other things in the loop.

Try something like this instead:

def run
t = Time.now.to_f
1_000.times do
yield if block_given?
t += 0.01
interval = t - Time.now.to_f
sleep(interval) if interval > 0 # sleep barfs with negative values
end
end

t1 = Time.now
run { x = x }
t2 = Time.now
puts t2 - t1

Your UDP packets will have a small amount of jitter, which the far end’s
jitterbuffer will handle (and if this is going over the Internet, you’ll
get
a lot more jitter from other sources), but will be sent at an average
rate
of one every 10ms.

Brian.

Brian,

Your solution worked perfectly. The time between packets alternates
between 8ms and 12ms, but averages out to 10ms. Thanks for your help.
Thanks also to you, Eden.

Earle

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs