[Asterisk-Users] Skips and Pops in Call Recordings - channel.c Analysis

Matt Roth mroth at imminc.com
Tue Dec 13 17:04:50 MST 2005


List users,

I've traced the writing of the leg files to two functions in channel.c:

ast_write()
ast_read()

They both contain similar code, so I'm going to limit my analysis to one 
of them. If I'm misunderstanding anything or am flat out wrong, please 
don't hesitate to correct me. Your input is what I'm looking for.

Below is a code fragment, with some extraneous stuff removed for brevity 
and some comments describing what I believe is happening. Please take a 
look at it, paying special attention to the comments I've added.

My understanding is that if the channel is locked, the function will 
wait on the ast_mutex_lock() call until it is unlocked. Once it is 
unlocked, the function attempts to compensate for any loss of leg file 
synchronization by jumping the file pointer forward by some value based 
on the number of dropped frames. This puts a gap in the leg file which 
manifests itself as a popping sound in the format we are using (PCM), 
but which probably sounds a little different in other formats.

My main concern is if this fragment is responsible for writing the frame 
to its destination via RTP. If it is, the skips and pops in the 
recordings would likely manifest themselves as dropped audio on the 
calls. Is this correct? Do problems in the recordings indicate parallel 
problems in call quality? The reports from our agents don't seem to 
support this, but looking at the code worries me.

Thank you very much,

Matthew Roth
InterMedia Marketing Solutions
Software Engineer and Systems Developer

=====================================================================

int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
    /* Lock the channel */
    ast_mutex_lock(&chan->lock);

   /*
      ... Code Omitted ...
                           */

   /* Check to see if the channel is blocking */
    CHECK_BLOCKING(chan);

   /* Switch based on frame type */
    switch(fr->frametype) {

   /*
      ... Code Omitted ...
                           */

   /* Handle voice frames */
    default:
        /* Validate a function pointer */
        if (chan->pvt->write) {
            /* Validate another function pointer */
            if (chan->pvt->writetrans) {
                f = ast_translate(chan->pvt->writetrans, fr, 0);
            } else
                f = fr;
            /* Validate the frame pointer */
            if (f) {
               /* I'm not sure what this does, so please let me know if 
you do.
                  I really hope that it's not responsible for writing 
the frame out to its destination via RTP. */
               res = chan->pvt->write(chan, f);
                /* If this channel is being monitored write the frame to 
the appropriate leg file */
                if( chan->monitor &&
                        chan->monitor->write_stream &&
                        f && ( f->frametype == AST_FRAME_VOICE ) ) {
               
               /*
                  If some frames have been missed, jump the leg file 
pointer forward to keep the leg files synchronized.

                  !!! I BELIEVE THIS IS THE SOURCE OF THE SKIPS AND POPS 
IN THE RECORDINGS !!!
                  
                                                                                                                        
*/
               
#ifndef MONITOR_CONSTANT_DELAY
                    int jump = chan->insmpl - chan->outsmpl - 2 * 
f->samples;
                    if (jump >= 0) {
                        if (ast_seekstream(chan->monitor->write_stream, 
jump + f->samples, SEEK_FORCECUR) == -1)
                            ast_log(LOG_WARNING, "Failed to perform seek 
in monitoring write stream, synchronization between the files may be 
broken\n");
                        chan->outsmpl += jump + 2 * f->samples;
                    } else
                        chan->outsmpl += f->samples;
#else
                    int jump = chan->insmpl - chan->outsmpl;
                    if (jump - MONITOR_DELAY >= 0) {
                        if (ast_seekstream(chan->monitor->write_stream, 
jump - f->samples, SEEK_FORCECUR) == -1)
                            ast_log(LOG_WARNING, "Failed to perform seek 
in monitoring write stream, synchronization between the files may be 
broken\n");
                        chan->outsmpl += jump;
                    } else
                        chan->outsmpl += f->samples;
#endif
                /* Write the frame to the leg file */
                if (ast_writestream(chan->monitor->write_stream, f) < 0)
                        ast_log(LOG_WARNING, "Failed to write data to 
channel monitor write stream\n");
                }
            } else
                res = 0;
        }
    }

   /*
      ... Code Omitted ...
                           */

   /* Set the channel as not blocking */
    chan->blocking = 0;

   /*
      ... Code Omitted ...
                           */

   /* Unlock the channel and return */
    ast_mutex_unlock(&chan->lock);
    return res;
}

=====================================================================



More information about the asterisk-users mailing list