# Ulaw audio over network

**URL:** <https://www.ruby-forum.com/t/ulaw-audio-over-network/103560>\
**Category:** Ruby\
**Created:** [May 7, 2007, 10:36pm UTC](https://www.ruby-forum.com/t/ulaw-audio-over-network/103560 "2007-05-07T22:36:54Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![eclubb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@eclubb](https://www.ruby-forum.com/u/eclubb)\
**Post date:** [May 7, 2007, 10:36pm UTC](https://www.ruby-forum.com/t/ulaw-audio-over-network/103560/1 "2007-05-07T22:36:54Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![eclubb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@eclubb](https://www.ruby-forum.com/u/eclubb)\
**Post date:** [May 8, 2007, 9:28am UTC](https://www.ruby-forum.com/t/ulaw-audio-over-network/103560/2 "2007-05-08T09:28:54Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![eclubb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@eclubb](https://www.ruby-forum.com/u/eclubb)\
**Post date:** [May 8, 2007, 9:57am UTC](https://www.ruby-forum.com/t/ulaw-audio-over-network/103560/3 "2007-05-08T09:57:57Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![eclubb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@eclubb](https://www.ruby-forum.com/u/eclubb)\
**Post date:** [May 8, 2007, 3:57pm UTC](https://www.ruby-forum.com/t/ulaw-audio-over-network/103560/4 "2007-05-08T15:57:37Z")

</div>

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
