From 361d4681f1971178c646f5010e008610c0e472b7 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Thu, 5 Apr 2012 14:47:24 -0500 Subject: [PATCH] codec_dahdi: Block on frameout the hardware has enough samples to complete a frame. Given the following generic scenario: RTP(g729) -> codec_dahdi -> RTP(ulaw) -> chan_dahdi -> phones I received a report that if codec_dahdi was replaced with codec_g729 skipping audio was no longer observed on the phones on the far left. It appeared that there were bursts of audio that could cause frames to accumulate at the ingress to chan_dahdi and potentially the jitter buffer was interfering. Regardless, the below change, which makes codec_dahdi operate in a more synchronous fashion, like codec_g729, made the problem go away for the user. As a side effect, use the file conversion tools from the Asterisk CLI now also work. The downside is that the thread responsible for transcoding the audio may be blocked for several milliseconds while it waits for the hardware transcoder to complete, but other threads in the system are free to do work and the overall load on the system remains low. Internal-Issue-ID: DAHDI-953 Signed-off-by: Shaun Ruffell --- codecs/codec_dahdi.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index cc94a83..95d3aae 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define G723_SAMPLES 240 #define G729_SAMPLES 160 +#define ULAW_SAMPLES 160 static struct channel_usage { int total; @@ -89,6 +90,7 @@ struct codec_dahdi_pvt { unsigned int fake:2; uint16_t required_samples; uint16_t samples_in_buffer; + uint16_t samples_written_to_hardware; uint8_t ulaw_buffer[1024]; }; @@ -160,7 +162,6 @@ static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buffer, const ssize_t count) { int res; - struct pollfd p = {0}; if (!count) return; res = write(dahdip->fd, buffer, count); if (option_verbose > 10) { @@ -171,9 +172,6 @@ static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buf ast_log(LOG_ERROR, "Requested write of %zd bytes, but only wrote %d bytes.\n", count, res); } } - p.fd = dahdip->fd; - p.events = POLLOUT; - res = poll(&p, 1, 50); } static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) @@ -206,8 +204,9 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) dahdip->samples_in_buffer += f->samples; } - while (dahdip->samples_in_buffer > dahdip->required_samples) { + while (dahdip->samples_in_buffer >= dahdip->required_samples) { dahdi_write_frame(dahdip, dahdip->ulaw_buffer, dahdip->required_samples); + dahdip->samples_written_to_hardware += dahdip->required_samples; dahdip->samples_in_buffer -= dahdip->required_samples; if (dahdip->samples_in_buffer) { /* Shift any remaining bytes down. */ @@ -220,6 +219,14 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) return -1; } +static void dahdi_wait_for_packet(int fd) +{ + struct pollfd p = {0}; + p.fd = fd; + p.events = POLLIN; + poll(&p, 1, 10); +} + static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) { struct codec_dahdi_pvt *dahdip = pvt->pvt; @@ -243,6 +250,10 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) return NULL; } + if (dahdip->samples_written_to_hardware >= dahdip->required_samples) { + dahdi_wait_for_packet(dahdip->fd); + } + res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen); if (-1 == res) { if (EWOULDBLOCK == errno) { @@ -262,6 +273,10 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) pvt->f.data.ptr = pvt->outbuf.c; pvt->f.samples = ast_codec_get_samples(&pvt->f); + dahdip->samples_written_to_hardware = + (dahdip->samples_written_to_hardware >= pvt->f.samples) ? + dahdip->samples_written_to_hardware - pvt->f.samples : 0; + pvt->samples = 0; pvt->datalen = 0; return ast_frisolate(&pvt->f); @@ -288,6 +303,7 @@ static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) } } dahdi_write_frame(dahdip, f->data.ptr, f->datalen); + dahdip->samples_written_to_hardware += f->samples; pvt->samples += f->samples; pvt->datalen = 0; return -1; @@ -315,6 +331,10 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) return NULL; } + if (dahdip->samples_written_to_hardware >= ULAW_SAMPLES) { + dahdi_wait_for_packet(dahdip->fd); + } + /* Let's check to see if there is a new frame for us.... */ if (dahdip->softslin) { res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer)); @@ -346,6 +366,9 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) pvt->f.data.ptr = pvt->outbuf.c; pvt->f.samples = res; pvt->samples = 0; + dahdip->samples_written_to_hardware = + (dahdip->samples_written_to_hardware >= res) ? + dahdip->samples_written_to_hardware - res : 0; return ast_frisolate(&pvt->f); } -- 1.7.9.5