#include "decoder.h" #include #include #include #include #include #include #include #include #include #include "types.h" #include "log.h" #include "str.h" #include "output.h" #include "mix.h" #include "resample.h" #include "codeclib.h" #include "streambuf.h" #include "main.h" #include "packet.h" #include "tag.h" int resample_audio; decode_t *decoder_new(const char *payload_str, const char *format, int ptime, output_t *outp) { str name; char *slash = strchr(payload_str, '/'); if (!slash) { ilog(LOG_WARN, "Invalid payload format: %s", payload_str); return NULL; } str_init_len(&name, (char *) payload_str, slash - payload_str); int clockrate = atoi(slash + 1); if (clockrate <= 0) { ilog(LOG_ERR, "Invalid clock rate %i (parsed from '%.20s'/'%.20s')", clockrate, slash + 1, payload_str); return NULL; } int channels = 1; slash = strchr(slash + 1, '/'); if (slash) { channels = atoi(slash + 1); if (!channels) channels = 1; } codec_def_t *def = codec_find(&name, MT_AUDIO); if (!def) { ilog(LOG_WARN, "No decoder for payload %s", payload_str); return NULL; } if (def->supplemental || !def->support_decoding || def->media_type != MT_AUDIO) { // not a real audio codec ilog(LOG_DEBUG, "Not decoding codec %s", payload_str); return NULL; } // decoder_new_fmt already handles the clockrate_mult scaling int rtp_clockrate = clockrate; clockrate = fraction_mult(clockrate, &def->default_clockrate_fact); // we can now config our output, which determines the sample format we convert to format_t out_format = { .clockrate = clockrate, .channels = channels, .format = -1, }; if (resample_audio) out_format.clockrate = resample_audio; // mono/stereo mixing goes here: out_format.channels = ... if (outp) { // if this output has been configured already, re-use the same format if (outp->requested_format.format != -1) out_format = outp->requested_format; output_config(outp, &out_format, &out_format); } else out_format.format = AV_SAMPLE_FMT_S16; // needed for TLS-only scenarios str fmtp; str_init(&fmtp, (char *) format); decoder_t *dec = decoder_new_fmtp(def, rtp_clockrate, channels, ptime, &out_format, NULL, &fmtp, NULL); if (!dec) return NULL; decode_t *deco = g_slice_alloc0(sizeof(decode_t)); deco->dec = dec; deco->mixer_idx = (unsigned int) -1; return deco; } static int decoder_got_frame(decoder_t *dec, AVFrame *frame, void *sp, void *dp) { ssrc_t *ssrc = sp; metafile_t *metafile = ssrc->metafile; output_t *output = ssrc->output; stream_t *stream = ssrc->stream; decode_t *deco = dp; dbg("got frame pts %llu samples %u contents %02x%02x%02x%02x...", (unsigned long long) frame->pts, frame->nb_samples, (unsigned int) frame->extended_data[0][0], (unsigned int) frame->extended_data[0][1], (unsigned int) frame->extended_data[0][2], (unsigned int) frame->extended_data[0][3]); if (!metafile->recording_on) goto no_recording; // handle mix output pthread_mutex_lock(&metafile->mix_lock); if (metafile->mix_out) { dbg("adding packet from stream #%lu to mix output", stream->id); if (G_UNLIKELY(deco->mixer_idx == (unsigned int) -1)) deco->mixer_idx = mix_get_index(metafile->mix, ssrc); format_t actual_format; if (output_config(metafile->mix_out, &dec->dest_format, &actual_format)) goto no_mix_out; mix_config(metafile->mix, &actual_format); // XXX might be a second resampling to same format AVFrame *dec_frame = resample_frame(&deco->mix_resampler, frame, &actual_format); if (!dec_frame) { pthread_mutex_unlock(&metafile->mix_lock); goto err; } if (mix_add(metafile->mix, dec_frame, deco->mixer_idx, ssrc, metafile->mix_out)) ilog(LOG_ERR, "Failed to add decoded packet to mixed output"); } no_mix_out: pthread_mutex_unlock(&metafile->mix_lock); if (output) { dbg("SSRC %lx of stream #%lu has single output", ssrc->ssrc, stream->id); if (output_config(output, &dec->dest_format, NULL)) goto err; if (output_add(output, frame)) ilog(LOG_ERR, "Failed to add decoded packet to individual output"); } no_recording: if (ssrc->tls_fwd_stream) { // XXX might be a second resampling to same format dbg("SSRC %lx of stream #%lu has TLS forwarding stream", ssrc->ssrc, stream->id); AVFrame *dec_frame = resample_frame(&ssrc->tls_fwd_resampler, frame, &ssrc->tls_fwd_format); ssrc_tls_state(ssrc); if (!ssrc->sent_intro) { tag_t *tag = NULL; if (ssrc->stream) tag = tag_get(metafile, ssrc->stream->tag); if (tag && tag->metadata) { dbg("Writing tag metadata header to TLS"); streambuf_write(ssrc->tls_fwd_stream, tag->metadata, strlen(tag->metadata) + 1); } else if (metafile->metadata) { dbg("Writing call metadata header to TLS"); streambuf_write(ssrc->tls_fwd_stream, metafile->metadata, strlen(metafile->metadata) + 1); } else { ilog(LOG_WARN, "No metadata present for forwarding connection"); streambuf_write(ssrc->tls_fwd_stream, "\0", 1); } ssrc->sent_intro = 1; } ssrc_tls_fwd_silence_frames_upto(ssrc, dec_frame, dec_frame->pts); uint64_t next_pts = dec_frame->pts + dec_frame->nb_samples; if (next_pts > ssrc->tls_in_pts) ssrc->tls_in_pts = next_pts; int linesize = av_get_bytes_per_sample(dec_frame->format) * dec_frame->nb_samples; dbg("Writing %u bytes PCM to TLS", linesize); streambuf_write(ssrc->tls_fwd_stream, (char *) dec_frame->extended_data[0], linesize); av_frame_free(&dec_frame); } av_frame_free(&frame); return 0; err: av_frame_free(&frame); return -1; } int decoder_input(decode_t *deco, const str *data, unsigned long ts, ssrc_t *ssrc) { return decoder_input_data(deco->dec, data, ts, decoder_got_frame, ssrc, deco); } void decoder_free(decode_t *deco) { if (!deco) return; decoder_close(deco->dec); resample_shutdown(&deco->mix_resampler); g_slice_free1(sizeof(*deco), deco); }