[asterisk-dev] playback application sends a short frame at endof file

Paul Albrecht albrecht at glccom.com
Mon Jul 30 11:44:44 CDT 2012


On Mon, 2012-07-30 at 10:49 -0500, Kevin P. Fleming wrote:
> On 07/30/2012 10:32 AM, Paul Albrecht wrote:
> 
> > The playback application sends a short frame at the end of file if the
> > sound file isn't a multiple of the 160 of samples. Is that a bug or a
> > feature?
> 
> Neither. It is sending what it was told to send. If your endpoints are 
> particular about receiving consistently-sized frames, then you'll need 
> to pad your recording files to an appropriate size. This can be tricky, 
> though, since channels can negotiate varying frame sizes, and finding a 
> multiple that makes sense for all of them might be more work than you'd 
> care to do.
> 
> In the end, though, it should not matter: any reasonably well 
> implemented endpoint will accept variable-sized frames, as long as they 
> aren't any larger than what it has stated its maximum to be (if it did so).

Padding the file out to a packet boundary was my first thought. However,
when I looked through the asterisk code, it didn't make sense. The first
example I looked at was slinear, but I think all the fixed rate codecs
are coded essentially the same way.

Here's the code for slinear:

#define BUF_SIZE        320             /* 320 bytes, 160 samples */
#define SLIN_SAMPLES    160

static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
{
        int res;
        /* Send a frame from the file to the appropriate channel */

        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_SLINEAR;
        s->fr.mallocd = 0;
        AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
        if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
        *whennext = s->fr.samples = res/2;
        s->fr.datalen = res;
        return &s->fr;
}

As I read the code, the log message is unreachable which is probably not
what the coder intended.

A better way to detect the end of the file is to reverse the arguments
to the fread. Instead of reading buf_size objects of size byte, read one
object of buf_size. That way you know you're at end of file when you
read the short frame. Since you don't need the short frame, simply
discard it though I suppose you could pad it to packet size.

Here's the updated code:

static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
{
        int res;
        /* Send a frame from the file to the appropriate channel */

        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_SLINEAR;
        s->fr.mallocd = 0;
        AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
        if (!(res = fread(s->fr.data, s->fr.datalen, 1, s->f))) {
                return NULL;
        }
        *whennext = s->fr.samples = SLIN_SAMPLES;
        s->fr.datalen = BUF_SIZE;
        return &s->fr;
}

> 
-- 
Paul Albrecht




More information about the asterisk-dev mailing list