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