ulaw audio over network

E

Earle Clubb

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])
 
E

eden li

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
 
B

Brian Candler

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

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.
 
E

Earle Clubb

Brian said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top