diff --git a/recording-daemon/decoder.c b/recording-daemon/decoder.c index 6d5e1e3f9..38fba2db5 100644 --- a/recording-daemon/decoder.c +++ b/recording-daemon/decoder.c @@ -18,6 +18,8 @@ struct decoder_s { struct output_s { + char *filename; + int clockrate; AVCodecContext *avcctx; AVFormatContext *fmtctx; AVStream *avst; @@ -27,19 +29,23 @@ struct output_s { struct decoder_def_s { const char *name; + int clockrate_mult; int avcodec_id; }; -#define DECODER_DEF(ref, id) { \ +#define DECODER_DEF_MULT(ref, id, mult) { \ .name = #ref, \ .avcodec_id = AV_CODEC_ID_ ## id, \ + .clockrate_mult = mult, \ } +#define DECODER_DEF(ref, id) DECODER_DEF_MULT(ref, id, 1) + static const struct decoder_def_s decoders[] = { DECODER_DEF(PCMA, PCM_ALAW), DECODER_DEF(PCMU, PCM_MULAW), DECODER_DEF(G723, G723_1), - DECODER_DEF(G722, ADPCM_G722), + DECODER_DEF_MULT(G722, ADPCM_G722, 2), DECODER_DEF(QCELP, QCELP), DECODER_DEF(G729, G729), DECODER_DEF(speex, SPEEX), @@ -50,6 +56,11 @@ static const struct decoder_def_s decoders[] = { typedef struct decoder_def_s decoder_def_t; + +static void output_shutdown(output_t *output); + + + static const decoder_def_t *decoder_find(const str *name) { for (int i = 0; i < G_N_ELEMENTS(decoders); i++) { if (!str_cmp(name, decoders[i].name)) @@ -75,6 +86,7 @@ decoder_t *decoder_new(const char *payload_str) { ilog(LOG_WARN, "No decoder for payload %s", payload_str); return NULL; } + clockrate *= def->clockrate_mult; decoder_t *ret = g_slice_alloc0(sizeof(*ret)); @@ -172,6 +184,7 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o dec->frame->pts = dec->frame->pkt_pts; + output_config(output, dec->avcctx->sample_rate); output_add(output, dec->frame); return 0; @@ -180,55 +193,69 @@ int decoder_input(decoder_t *dec, const str *data, unsigned long ts, output_t *o output_t *output_new(const char *filename) { output_t *ret = g_slice_alloc0(sizeof(*ret)); + ret->filename = strdup(filename); + ret->clockrate = -1; + return ret; +} + + +int output_config(output_t *output, unsigned int clockrate) { + // anything to do? + if (output->clockrate == clockrate) + return 0; + + // XXX support reset/config change + + output->clockrate = clockrate; // XXX error reporting - ret->fmtctx = avformat_alloc_context(); - if (!ret->fmtctx) + output->fmtctx = avformat_alloc_context(); + if (!output->fmtctx) goto err; - ret->fmtctx->oformat = av_guess_format("wav", NULL, NULL); // XXX better way? - if (!ret->fmtctx->oformat) + output->fmtctx->oformat = av_guess_format("wav", NULL, NULL); // XXX better way? + if (!output->fmtctx->oformat) goto err; AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE); // XXX error handling - ret->avst = avformat_new_stream(ret->fmtctx, codec); - if (!ret->avst) + output->avst = avformat_new_stream(output->fmtctx, codec); + if (!output->avst) goto err; #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0) - ret->avcctx = avcodec_alloc_context3(codec); - if (!ret->avcctx) + output->avcctx = avcodec_alloc_context3(codec); + if (!output->avcctx) goto err; #else - ret->avcctx = ret->avst->codec; + output->avcctx = output->avst->codec; #endif - ret->avcctx->channels = 1; - ret->avcctx->sample_rate = 8000; - ret->avcctx->sample_fmt = AV_SAMPLE_FMT_S16; - ret->avcctx->time_base = (AVRational){8000,1}; - ret->avst->time_base = ret->avcctx->time_base; + output->avcctx->channels = 1; + output->avcctx->sample_rate = output->clockrate; + output->avcctx->sample_fmt = AV_SAMPLE_FMT_S16; + output->avcctx->time_base = (AVRational){output->clockrate,1}; + output->avst->time_base = output->avcctx->time_base; #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0) - avcodec_parameters_from_context(ret->avst->codecpar, ret->avcctx); + avcodec_parameters_from_context(output->avst->codecpar, output->avcctx); #endif - int i = avcodec_open2(ret->avcctx, codec, NULL); + int i = avcodec_open2(output->avcctx, codec, NULL); if (i) goto err; - i = avio_open(&ret->fmtctx->pb, filename, AVIO_FLAG_WRITE); + i = avio_open(&output->fmtctx->pb, output->filename, AVIO_FLAG_WRITE); if (i < 0) goto err; - i = avformat_write_header(ret->fmtctx, NULL); + i = avformat_write_header(output->fmtctx, NULL); if (i) goto err; - av_init_packet(&ret->avpkt); + av_init_packet(&output->avpkt); - return ret; + return 0; err: - output_close(ret); - return NULL; + output_shutdown(output); + return -1; } @@ -241,12 +268,24 @@ void decoder_close(decoder_t *dec) { } -void output_close(output_t *output) { +static void output_shutdown(output_t *output) { if (!output) return; av_write_trailer(output->fmtctx); avcodec_close(output->avcctx); avio_closep(&output->fmtctx->pb); avformat_free_context(output->fmtctx); + + output->avcctx = NULL; + output->fmtctx = NULL; + output->avst = NULL; +} + + +void output_close(output_t *output) { + if (!output) + return; + output_shutdown(output); + free(output->filename); g_slice_free1(sizeof(*output), output); } diff --git a/recording-daemon/decoder.h b/recording-daemon/decoder.h index 5c3d516a6..3627006ec 100644 --- a/recording-daemon/decoder.h +++ b/recording-daemon/decoder.h @@ -10,6 +10,7 @@ int decoder_input(decoder_t *, const str *, unsigned long ts, output_t *); void decoder_close(decoder_t *); output_t *output_new(const char *filename); +int output_config(output_t *, unsigned int clock_rate); void output_close(output_t *);