From: Michael Kuron Date: Wed, 31 Aug 2016 17:23:09 +0000 (+0200) Subject: app_mp3: Use correct buffer size and the same sample rate as the channel X-Git-Tag: 11.24.0-rc1~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=428c9643738679ee9ae0342ee6ee48d3943fbc48;p=thirdparty%2Fasterisk.git app_mp3: Use correct buffer size and the same sample rate as the channel Previously, the buffer used for MP3 streamed from HTTP servers had a size of 1 MB. For 8 kHz mono audio at 16 bit resolution, such a buffer covers about 1 minute. Only when the buffer is full does audio start to play. For MP3 files streamed from a server, that is usually not a big deal as long as the connection to the server is fast enough to supply that much data within a second or two. For MP3 live streams however, it takes 1 minute to download 1 minute of audio, so without this change, app_mp3 wasn't really usable for MP3 live streams. This commit changes the buffer size so that it covers 6 seconds of an MP3 file streamed from a server and 0.5 seconds of an MP3 live stream. The latter is identified by the use of a .m3u file extension. app_mp3 so far only supported 8 kHz audio. Now it always runs at the sample rate of the channel. ASTERISK-26085 #close Change-Id: Id1ee274733cd804a0edecf7450329b72f1235af0 --- diff --git a/apps/app_mp3.c b/apps/app_mp3.c index 463a91906f..81ece8f2bb 100644 --- a/apps/app_mp3.c +++ b/apps/app_mp3.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/translate.h" #include "asterisk/app.h" +#include "asterisk/format.h" #define LOCAL_MPG_123 "/usr/local/bin/mpg123" #define MPG_123 "/usr/bin/mpg123" @@ -76,9 +77,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") ***/ static char *app = "MP3Player"; -static int mp3play(const char *filename, int fd) +static int mp3play(const char *filename, unsigned int sampling_rate, int fd) { int res; + char sampling_rate_str[8]; res = ast_safe_fork(0); if (res < 0) @@ -92,30 +94,44 @@ static int mp3play(const char *filename, int fd) dup2(fd, STDOUT_FILENO); ast_close_fds_above_n(STDERR_FILENO); + snprintf(sampling_rate_str, 8, "%u", sampling_rate); + /* Execute mpg123, but buffer if it's a net connection */ - if (!strncasecmp(filename, "http://", 7)) { + if (!strncasecmp(filename, "http://", 7) && strstr(filename, ".m3u")) { + char buffer_size_str[8]; + snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); // 0.5 seconds for a live stream + /* Most commonly installed in /usr/local/bin */ + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + /* But many places has it in /usr/bin */ + execl(MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + /* As a last-ditch effort, try to use PATH */ + execlp("mpg123", "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); + } + else if (!strncasecmp(filename, "http://", 7)) { + char buffer_size_str[8]; + snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); // 6 seconds for a remote MP3 file /* Most commonly installed in /usr/local/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); } else if (strstr(filename, ".m3u")) { /* Most commonly installed in /usr/local/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(MPG_123, "mpg123", "-q", "-z", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-z", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", "-@", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-z", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL); } else { /* Most commonly installed in /usr/local/bin */ - execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* But many places has it in /usr/bin */ - execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); /* As a last-ditch effort, try to use PATH */ - execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL); + execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL); } /* Can't use ast_log since FD's are closed */ fprintf(stderr, "Execute of mpg123 failed\n"); @@ -154,6 +170,9 @@ static int mp3_exec(struct ast_channel *chan, const char *data) } myf = { .f = { 0, }, }; + struct ast_format native_format; + unsigned int sampling_rate; + enum ast_format_id write_format; ast_format_clear(&owriteformat); if (ast_strlen_zero(data)) { @@ -168,14 +187,18 @@ static int mp3_exec(struct ast_channel *chan, const char *data) ast_stopstream(chan); + ast_best_codec(ast_channel_nativeformats(chan), &native_format); + sampling_rate = ast_format_rate(&native_format); + write_format = ast_format_slin_by_rate(sampling_rate); + ast_format_copy(&owriteformat, ast_channel_writeformat(chan)); - res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); + res = ast_set_write_format_by_id(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } - res = mp3play(data, fds[1]); + res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } @@ -192,7 +215,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data) res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { myf.f.frametype = AST_FRAME_VOICE; - ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); + ast_format_set(&myf.f.subclass.format, write_format, 0); myf.f.datalen = res; myf.f.samples = res / 2; myf.f.mallocd = 0; @@ -210,7 +233,7 @@ static int mp3_exec(struct ast_channel *chan, const char *data) res = 0; break; } - next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); + next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) {