static int mp3_exec(struct ast_channel *chan, const char *data) { int res=0; int fds[2]; int ms = -1; int pid = -1; RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup); int timeout = 2000; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf = { .f = { 0, }, }; struct ast_format * native_format; unsigned int sampling_rate; struct ast_format * write_format; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } ast_stopstream(chan); native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0); sampling_rate = ast_format_get_sample_rate(native_format); write_format = ast_format_cache_get_slin_by_rate(sampling_rate); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = write_format; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; myf.f.data.ptr = myf.frdata; res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } /* Wait 1000 ms first */ next = ast_tvnow(); next.tv_sec += 1; if (res >= 0) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; if (ast_write(chan, &myf.f) < 0) { res = -1; break; } } else { ast_debug(1, "No more mp3\n"); res = 0; break; } next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } if (ms) { f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); ast_frfree(f); res = 0; break; } ast_frfree(f); } } } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); ast_frfree(&myf.f); return res; }
static int mp3_exec(struct ast_channel *chan, void *data) { int res=0; struct localuser *u; int fds[2]; int ms = -1; int pid = -1; int owriteformat; int timeout = 2000; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; } LOCAL_USER_ADD(u); if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); LOCAL_USER_REMOVE(u); return -1; } ast_stopstream(chan); owriteformat = chan->writeformat; res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); LOCAL_USER_REMOVE(u); return -1; } res = mp3play((char *)data, fds[1]); if (!strncasecmp((char *)data, "http://", 7)) { timeout = 10000; } /* Wait 1000 ms first */ next = ast_tvnow(); next.tv_sec += 1; if (res >= 0) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass = AST_FORMAT_SLINEAR; myf.f.datalen = res; myf.f.samples = res / 2; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; myf.f.data = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; break; } } else { ast_log(LOG_DEBUG, "No more mp3\n"); res = 0; break; } next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } if (ms) { f = ast_read(chan); if (!f) { ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_log(LOG_DEBUG, "User pressed a key\n"); ast_frfree(f); res = 0; break; } ast_frfree(f); } } } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); LOCAL_USER_REMOVE(u); return res; }