<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix"><font face="Helvetica, Arial,
sans-serif">Hi All,<br>
<br>
I've not received a response on this, and was just wondering
whether there is any hope or whether I should just give it up?<br>
<br>
Having looked again at the code in the meantime (assuming that
hold never comes into this - which will throw off the thing
anyway) I actually suspect that the logic is even more wrong
than I originally thought.<br>
<br>
outsmpl - insmpl is the number of samples read is lagging behind
write. Now if we subtract 4 x general sample size (160 for
G.729) and that ends up being <0 it actually means we're more
than 4 x 160 samples behind - so the seek will only happen if
we're "close enough" ?!<br>
<br>
Surely the code should end up doing if outsmpl - insmpl > 4 x
160 then seek?!<br>
<br>
What's the impact of call waiting / hold on this?<br>
<br>
</font>
<div class="moz-signature">Kind Regards,<br>
Jaco Kroon<br>
<img src="cid:part1.02060706.03040805@uls.co.za" usemap="#Map"
style="color:white" border="0" width="530" height="100">
<map name="Map" id="Map">
<area shape="rect" coords="441,19,460,36"
href="https://www.facebook.com/ultimatelinuxsolutions">
<area shape="rect" coords="441,39,458,57"
href="http://news.uls.co.za/">
<area shape="rect" coords="354,62,461,73"
href="http://www.uls.co.za/">
</map>
</div>
On 28/01/2014 15:41, Jaco Kroon wrote:<br>
</div>
<blockquote cite="mid:52E7B375.3010504@uls.co.za" type="cite">
<meta http-equiv="content-type" content="text/html;
charset=ISO-8859-1">
<font face="Helvetica, Arial, sans-serif">Hi All,<br>
<br>
I've got a client where I'm having some issues with CNG being
received as part of a G.729 stream. I'm using Monitor (Yes I'm
aware the recommendation is to use MixMonitor, that presents
licensing problems and max call concurrency we're trying to
avoid).<br>
<br>
I'm busy trying to write a patch for format_g729 (attached) to
better deal with CNG (and specifically I've got a scenario where
there are some phones that refuse to honor annexb=no and still
send CNG), and so far it seem to be OK'ish in that it'll ignore
CNG packets, and perform the seek to ensure that the number of
samples that asterisk core things has been written stays
accurate. However, this just caused more stuff that wasn't
itching to start. I'm attaching my patch. It'll work under the
assumption that main/channel.c will seek whenever it needs to
write to a location in the output stream that's discontinuous to
the position of the current stream, eg, if we've just written
320 (40ms) of audio to the file, then receive CNG and then at
sample offset 640 (80ms into the stream, assuming the previous
40ms was the start of the stream) receive another non-CNG frame
containing actual voice data my assumption was that
main/channel.c would SEEK_FORCECUR, +304 (it treats the two
bytes of CNG as 16 samples), so with 304 samples + 16 = 320
which is what we actually want to go forward, that would skip
the appropriate 40ms to sample location 640 (80ms, or 80 bytes
into the stream).<br>
<br>
However, looking at main/channel.c the seek seems to depend on
how many samples has gone in the opposite direction for the
channel?! This doens't really make sense for me, but I may also
be misinterpreting the code. Specifically, when sending data to
the write monitor (-out) this is the default code that applies
(I'm only going to consider one direction here, but the same
applies to both -in and -out), f is the frame we've just read
(I'm going to make comments inline, hope that's OK):<br>
</font><tt><br>
</tt><tt> if (ast_channel_monitor(chan) &&
ast_channel_monitor(chan)->read_stream ) {</tt><tt><br>
</tt><tt> /* XXX what does this do ? */ <b><-- my
question too :)</b></tt><tt><br>
</tt><tt>#ifndef MONITOR_CONSTANT_DELAY<br>
<b>This is the default case unless you edit the file
higher up, so basically if we lag by more than X number<br>
of samples in the opposite direction, apply a seek.<br>
</b></tt><tt> int jump = ast_channel_outsmpl(chan) -
ast_channel_insmpl(chan) - 4 * f->samples;</tt><tt><br>
</tt><tt> if (jump >= 0) {</tt><tt><br>
</tt><tt> jump =
calc_monitor_jump((ast_channel_outsmpl(chan) -
ast_channel_insmpl(chan)),
ast_format_rate(&f->subclass.format),
ast_format_rate(&ast_channel_monitor(chan)->read_stream->fmt->format));</tt><tt><br>
</tt><tt> if
(ast_seekstream(ast_channel_monitor(chan)->read_stream, jump,
SEEK_FORCECUR) == -1) {</tt><tt><br>
</tt><tt> ast_log(LOG_WARNING, "Failed to perform
seek in monitoring read stream, synchronization between the
files may be broken\n");</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt> ast_channel_insmpl_set(chan,
ast_channel_insmpl(chan) + (ast_channel_outsmpl(chan) -
ast_channel_insmpl(chan)) + f->samples);</tt><tt><br>
</tt><tt> } else {</tt><tt><br>
</tt><tt> ast_channel_insmpl_set(chan,
ast_channel_insmpl(chan) + f->samples);</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt>#else</tt><tt><br>
</tt><tt> int jump =
calc_monitor_jump((ast_channel_outsmpl(chan) -
ast_channel_insmpl(chan)),
ast_format_rate(f->subclass.codec),<br>
ast_format_rate(ast_channel_monitor(chan)->read_stream->fmt->format));</tt><tt><br>
</tt><tt> if (jump - MONITOR_DELAY >= 0) { <b>This will
seek if we're more than 150ms in terms of samples behind.</b></tt><tt><br>
</tt><tt> if
(ast_seekstream(ast_channel_monitor(chan)->read_stream, jump
- f->samples, SEEK_FORCECUR) == -1)</tt><tt><br>
</tt><tt> ast_log(LOG_WARNING, "Failed to perform
seek in monitoring read stream, synchronization between the
files may be broken\n");</tt><tt><br>
</tt><tt> ast_channel_insmpl(chan) +=
ast_channel_outsmpl(chan) - ast_channel_insmpl(chan);</tt><tt><br>
</tt><tt> } else</tt><tt><br>
</tt><tt> ast_channel_insmpl(chan) += f->samples;</tt><tt><br>
</tt><tt>#endif</tt><tt><br>
</tt><tt> if (ast_channel_monitor(chan)->state ==
AST_MONITOR_RUNNING) {</tt><tt><br>
</tt><tt> if
(ast_writestream(ast_channel_monitor(chan)->read_stream, f)
< 0)</tt><tt><br>
</tt><tt> ast_log(LOG_WARNING, "Failed to write
data to channel monitor read stream\n");</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><tt> }</tt><tt><br>
</tt><font face="Helvetica, Arial, sans-serif"><br>
Ok well, that's about as much as I understand of that code, and
it makes very little to no sense to me actually. As I
understand it the offset into the file should be based somehow
on the timestamp of the actual rtp, eg, when starting to send
packets from a file asterisk will use a rtp timestamp value of
(ignoring random offset) 0, then the following frame will have
ts=160, and then ts=320 (based on a G729/8000). Surely we can
utilize these timestamps to calculate the offset into the file
at which we want to be and then compare that with where we are?
Or even just store the previous timestamp + samples (assuming 1
timestamp unit implies 1 sample, which I'm not even sure of) and
then if the next timestamp we receive differs, seek in the
stream. Going back to the previous example let's say we receive
the following packets:<br>
<br>
seq=1,ts=0,len=20<br>
seq=2,ts=160,len=20<br>
seq=3,ts=320,len=2 <b>(CNG)</b><br>
seq=4,ts=640,len=20<br>
<br>
Now, according to the calculations that I've seen going on
packets 1, 2 and 4 will have samples set to 160, and seq=3 will
have samples=16, so after seq 1 we can store 0+160, on receipt
of seq=2 ts=160==160, so no seeking required, we can just write,
for seq=3, the same applies (and my patch fakes the write of two
bytes but ideally I'd actually like to let Monitor() know that I
didn't write anything so that it can know it's still at ts=320,
but for now it'll store next_expected_ts=320+16=336 since that's
where it assumes we are, and on receipt of seq=4, 640!=336, and
we seek forward 640-336=304 samples, or 38 bytes (keeping in
mind the 16 sample write has already been faked) so this will
get us to byte 80 in the file stream, at exactly the right
location.<br>
<br>
What I don't know/understand is how things like hold will affect
this, if at all?! Also, for the -out case it seems not all
values for the ast_frame is set before being written to the
stream, from my log:<br>
<br>
-- IAX2/ulsvoip-jkroon-A1-16492 is making progress passing
it to SIP/101-00000001<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=0),
frame(datalen=20,samples=160,ts=0,len=0,seqno=0)<br>
<br>
That's fine, but note that len and ts is 0.<br>
<br>
Sent RTP packet to 192.168.47.68:11784 (type 18, seq
061496, ts 000000, len 000020)<br>
<br>
And here it's actually sent (rtp debug).<br>
<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
[Jan 28 14:02:16] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=0,samples=160,ts=0,len=0,seqno=0)<br>
<br>
All of this feels wrong, ie, we're writing 160 samples, but no
actual data ?! Nor is RTP actually being sent?<br>
<br>
> 0xe374bc0 -- Probation passed - setting RTP source
address to 192.168.47.68:11784<br>
Got RTP packet from 192.168.47.68:11784 (type 18, seq
000375, ts 517557, len 000002)<br>
<br>
Receipt of RTP packet. And ts is some large (random?) number.
As I understand from this point it should increment at a rate of
8kHz.<br>
<br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:148
g729_seek:
g729_seek(/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-in,
1760, SEEK_FORCECUR), cur=0, offset=220<br>
<br>
Ok, so I've no idea what the in/outsmpl values are at this point
but I assume outsmpl=11*160=1760, which is where the seek value
comes from (insmpl=0?), and the offset to which is being seeked
is correct. My alternate suggestion may very well actually
break this come to think of it.<br>
<br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-in,pos=220),
frame(datalen=2,samples=16,ts=64694,len=2,seqno=375)<br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:104
g729_write: Probable CNG parameter update detected, this is a
bug in the sender who should not be sending CNG updates - try
and switch off Voice Activity Detected (VAD) or Silence
Suppression on the sender.<br>
<br>
And the write, and the CNG warning triggers, letting us know
that we're receiving CNG and that the peer most likely has VAD
(Silence suppression) enabled, and isn't honoring annexb=no. It
is a bug in the peer, but I'd still like to do what I can to not
bump into problems. So my patch will simply seek forward two
bytes here, incorrectly so assuming that a following seek will
attempt to seek again to get us back onto an 80-sample boundary
(10ms == 80samples, and whilst usually ptime=20 it can be other
values, including 10ms, which results in 80 samples per RTP
voice frame). After this write the write position will be 222.<br>
<br>
Got RTP packet from 192.168.47.68:11784 (type 18, seq
000376, ts 517957, len 000002)<br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-in,pos=222),
frame(datalen=2,samples=16,ts=64744,len=2,seqno=376)<br>
<br>
According to the RTP timestamp here we've moved 400 samples
ahead (or 50ms). This is not divisable by 160 as per the
original expectation from format_g729, so the patch fixes that
too. So since the previous write "wrote" 16 samples I'd expect
a seek of +384 samples, which would result in a forward seek of
48 bytes, getting to 270 offset into the file - which is where
we want to be for the next write.<br>
<br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:113
g729_write: Writing a G729A frame to the wrong offset <br>
(pos=222,ts=64744,len=2,datalen=140265041952770,writelen=0).
This is indicative of a bug, please contact <a
moz-do-not-send="true" class="moz-txt-link-abbreviated"
href="mailto:jaco@uls.co.za">jaco@uls.co.za</a> for
assistance.<br>
</font><br>
<font face="Helvetica, Arial, sans-serif"><font face="Helvetica,
Arial, sans-serif">And as a result of the seek not happening
this warning triggers.<br>
</font><br>
[Jan 28 14:02:17] WARNING[21280][C-00000001]: format_g729.c:87
g729_write:
filestream(filename=/var/spool/asterisk/monitor/2014-01-28/2014-01-28_140212-greyscale-1390910532.2-101-0845158255-out,pos=20),
frame(datalen=20,samples=160,ts=0,len=0,seqno=0)<br>
Sent RTP packet to 192.168.47.68:11784 (type 18, seq
061497, ts 004360, len 000020)<br>
<br>
And here we're still writing to output position 20, ie, in spite
of no data having been presented on the previous writes we most
likely should have seeked ahead for 160 samples for each write.
The lack of ts= and len= being filled out makes this hard to
assess.<br>
<br>
For those that's wondering, the reason for not using MixMonitor
in this case is actually primarily to avoid issues with
licensing of the G.729 codec. The cost starts adding up pretty
quickly.<br>
</font>
<div class="moz-signature">-- <br>
Kind Regards,<br>
Jaco Kroon<br>
<img src="cid:part3.01030102.09020608@uls.co.za" usemap="#Map"
style="color:white" border="0" width="530" height="100"> <map
name="Map" id="Map">
<area shape="rect" coords="441,19,460,36"
href="https://www.facebook.com/ultimatelinuxsolutions">
<area shape="rect" coords="441,39,458,57"
href="http://news.uls.co.za/">
<area shape="rect" coords="354,62,461,73"
href="http://www.uls.co.za/">
</map>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
</blockquote>
<br>
</body>
</html>