diff options
Diffstat (limited to 'src/audio.c')
-rw-r--r-- | src/audio.c | 212 |
1 files changed, 166 insertions, 46 deletions
diff --git a/src/audio.c b/src/audio.c index 17eb5f6..b2b3cca 100644 --- a/src/audio.c +++ b/src/audio.c @@ -81,23 +81,24 @@ struct autx { struct auenc_state *enc; /**< Audio encoder state (optional) */ struct aubuf *aubuf; /**< Packetize outgoing stream */ size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */ - volatile bool aubuf_started; + volatile bool aubuf_started; /**< Aubuf was started flag */ struct auresamp resamp; /**< Optional resampler for DSP */ struct list filtl; /**< Audio filters in encoding order */ struct mbuf *mb; /**< Buffer for outgoing RTP packets */ char device[64]; /**< Audio source device name */ - int16_t *sampv; /**< Sample buffer */ + void *sampv; /**< Sample buffer */ int16_t *sampv_rs; /**< Sample buffer for resampler */ uint32_t ptime; /**< Packet time for sending */ uint64_t ts_ext; /**< Ext. Timestamp for outgoing RTP */ - uint32_t ts_base; + uint32_t ts_base; /**< First timestamp sent */ uint32_t ts_tel; /**< Timestamp for Telephony Events */ size_t psize; /**< Packet size for sending */ bool marker; /**< Marker bit for outgoing RTP */ bool muted; /**< Audio source is muted */ int cur_key; /**< Currently transmitted event */ - enum aufmt src_fmt; - bool need_conv; + enum aufmt src_fmt; /**< Sample format for audio source */ + enum aufmt enc_fmt; /**< Sample format for encoder */ + bool need_conv; /**< Sample format conversion needed */ struct { uint64_t aubuf_overrun; @@ -137,24 +138,25 @@ struct aurx { struct audec_state *dec; /**< Audio decoder state (optional) */ struct aubuf *aubuf; /**< Incoming audio buffer */ size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */ - volatile bool aubuf_started; + volatile bool aubuf_started; /**< Aubuf was started flag */ struct auresamp resamp; /**< Optional resampler for DSP */ struct list filtl; /**< Audio filters in decoding order */ char device[64]; /**< Audio player device name */ - int16_t *sampv; /**< Sample buffer */ + void *sampv; /**< Sample buffer */ int16_t *sampv_rs; /**< Sample buffer for resampler */ uint32_t ptime; /**< Packet time for receiving */ int pt; /**< Payload type for incoming RTP */ double level_last; bool level_set; - enum aufmt play_fmt; - bool need_conv; - struct timestamp_recv ts_recv; - uint64_t n_discard; + enum aufmt play_fmt; /**< Sample format for audio playback*/ + enum aufmt dec_fmt; /**< Sample format for decoder */ + bool need_conv; /**< Sample format conversion needed */ + struct timestamp_recv ts_recv;/**< Receive timestamp state */ struct { uint64_t aubuf_overrun; uint64_t aubuf_underrun; + uint64_t n_discard; } stats; }; @@ -309,7 +311,7 @@ static inline double calc_ptime(size_t nsamp, uint32_t srate, uint8_t channels) /** - * Get the DSP samplerate for an audio-codec (exception for G.722 and MPA) + * Get the DSP samplerate for an audio-codec */ static inline uint32_t get_srate(const struct aucodec *ac) { @@ -448,7 +450,9 @@ static void encode_rtp_send(struct audio *a, struct autx *tx, len = mbuf_get_space(tx->mb); - err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, sampv, sampc); + err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, + tx->enc_fmt, sampv, sampc); + if ((err & 0xffff0000) == 0x00010000) { /* MPA needs some special treatment here */ tx->ts_ext = err & 0xffff; @@ -514,11 +518,12 @@ static void poll_aubuf_tx(struct audio *a) /* timed read from audio-buffer */ - if (tx->src_fmt == AUFMT_S16LE) { + if (tx->src_fmt == tx->enc_fmt) { aubuf_read(tx->aubuf, (uint8_t *)tx->sampv, num_bytes); } - else { + else if (tx->enc_fmt == AUFMT_S16LE) { + /* Convert from ausrc format to 16-bit format */ void *tmp_sampv; @@ -540,11 +545,23 @@ static void poll_aubuf_tx(struct audio *a) mem_deref(tmp_sampv); } + else { + warning("audio: tx: invalid sample formats (%s -> %s)\n", + aufmt_name(tx->src_fmt), + aufmt_name(tx->enc_fmt)); + } /* optional resampler */ if (tx->resamp.resample) { size_t sampc_rs = AUDIO_SAMPSZ; + if (tx->enc_fmt != AUFMT_S16LE) { + warning("audio: skipping resampler due to" + " incompatible format (%s)\n", + aufmt_name(tx->enc_fmt)); + return; + } + err = auresamp(&tx->resamp, tx->sampv_rs, &sampc_rs, tx->sampv, sampc); @@ -555,15 +572,23 @@ static void poll_aubuf_tx(struct audio *a) sampc = sampc_rs; } - /* Process exactly one audio-frame in list order */ - for (le = tx->filtl.head; le; le = le->next) { - struct aufilt_enc_st *st = le->data; + if (tx->enc_fmt == AUFMT_S16LE) { + + /* Process exactly one audio-frame in list order */ + for (le = tx->filtl.head; le; le = le->next) { + struct aufilt_enc_st *st = le->data; - if (st->af && st->af->ench) - err |= st->af->ench(st, sampv, &sampc); + if (st->af && st->af->ench) + err |= st->af->ench(st, sampv, &sampc); + } + if (err) { + warning("audio: aufilter encode: %m\n", err); + } } - if (err) { - warning("audio: aufilter encode: %m\n", err); + else if (!list_isempty(&tx->filtl)) { + warning("audio: skipping audio-filters due to" + " incompatible format (%s)\n", + aufmt_name(tx->enc_fmt)); } /* Encode and send */ @@ -623,8 +648,10 @@ static void auplay_write_handler(void *sampv, size_t sampc, void *arg) ++rx->stats.aubuf_underrun; +#if 0 debug("audio: rx aubuf underrun (total %llu)\n", rx->stats.aubuf_underrun); +#endif } aubuf_read(rx->aubuf, sampv, num_bytes); @@ -726,7 +753,7 @@ static void handle_telev(struct audio *a, struct mbuf *mb) static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) { size_t sampc = AUDIO_SAMPSZ; - int16_t *sampv; + void *sampv; struct le *le; int err = 0; @@ -735,13 +762,16 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) return 0; if (mbuf_get_left(mb)) { - err = rx->ac->dech(rx->dec, rx->sampv, &sampc, + + err = rx->ac->dech(rx->dec, + rx->dec_fmt, rx->sampv, &sampc, mbuf_buf(mb), mbuf_get_left(mb)); + } - else if (rx->ac->plch) { + else if (rx->ac->plch && rx->dec_fmt == AUFMT_S16LE) { sampc = rx->ac->srate * rx->ac->ch * rx->ptime / 1000; - err = rx->ac->plch(rx->dec, rx->sampv, &sampc); + err = rx->ac->plch(rx->dec, rx->dec_fmt, rx->sampv, &sampc); } else { /* no PLC in the codec, might be done in filters below */ @@ -754,12 +784,19 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) goto out; } - /* Process exactly one audio-frame in reverse list order */ - for (le = rx->filtl.tail; le; le = le->prev) { - struct aufilt_dec_st *st = le->data; + if (rx->dec_fmt == AUFMT_S16LE) { + /* Process exactly one audio-frame in reverse list order */ + for (le = rx->filtl.tail; le; le = le->prev) { + struct aufilt_dec_st *st = le->data; - if (st->af && st->af->dech) - err |= st->af->dech(st, rx->sampv, &sampc); + if (st->af && st->af->dech) + err |= st->af->dech(st, rx->sampv, &sampc); + } + } + else if (!list_isempty(&rx->filtl)) { + warning("audio: skipping audio-filters due to" + " incompatible format (%s)\n", + aufmt_name(rx->dec_fmt)); } if (!rx->aubuf) @@ -771,6 +808,13 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) if (rx->resamp.resample) { size_t sampc_rs = AUDIO_SAMPSZ; + if (rx->dec_fmt != AUFMT_S16LE) { + warning("audio: skipping resampler due to" + " incompatible format (%s)\n", + aufmt_name(rx->dec_fmt)); + return ENOTSUP; + } + err = auresamp(&rx->resamp, rx->sampv_rs, &sampc_rs, rx->sampv, sampc); @@ -789,15 +833,17 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) rx->stats.aubuf_overrun); } - if (rx->play_fmt == AUFMT_S16LE) { - err = aubuf_write_samp(rx->aubuf, sampv, sampc); + if (rx->play_fmt == rx->dec_fmt) { + + size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt); + + err = aubuf_write(rx->aubuf, sampv, num_bytes); if (err) goto out; } - else { + else if (rx->dec_fmt == AUFMT_S16LE) { /* Convert from 16-bit to auplay format */ - void *tmp_sampv; size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt); @@ -822,6 +868,11 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb) if (err) goto out; } + else { + warning("audio: decode: invalid sample formats (%s -> %s)\n", + aufmt_name(rx->dec_fmt), + aufmt_name(rx->play_fmt)); + } rx->aubuf_started = true; @@ -945,7 +996,7 @@ static void stream_recv_handler(const struct rtp_header *hdr, #endif if (discard) { - ++a->rx.n_discard; + ++rx->stats.n_discard; return; } @@ -1057,6 +1108,9 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm, tx->src_fmt = cfg->audio.src_fmt; rx->play_fmt = cfg->audio.play_fmt; + tx->enc_fmt = cfg->audio.enc_fmt; + rx->dec_fmt = cfg->audio.dec_fmt; + err = stream_alloc(&a->strm, stream_prm, &cfg->avt, call, sdp_sess, "audio", label, mnat, mnat_sess, menc, menc_sess, @@ -1101,8 +1155,11 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm, } tx->mb = mbuf_alloc(STREAM_PRESZ + 4096); - tx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL); - rx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL); + tx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(tx->enc_fmt), + NULL); + + rx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(rx->dec_fmt), + NULL); if (!tx->mb || !tx->sampv || !rx->sampv) { err = ENOMEM; goto out; @@ -1480,6 +1537,10 @@ static int start_source(struct autx *tx, struct audio *a) } switch (a->cfg.txmode) { + + case AUDIO_MODE_POLL: + break; + #ifdef HAVE_PTHREAD case AUDIO_MODE_THREAD: if (!tx->u.thr.run) { @@ -1495,7 +1556,9 @@ static int start_source(struct autx *tx, struct audio *a) #endif default: - break; + warning("audio: tx mode not supported (%d)\n", + a->cfg.txmode); + return ENOTSUP; } tx->ausrc_prm = prm; @@ -1602,6 +1665,7 @@ int audio_encoder_set(struct audio *a, const struct aucodec *ac, struct auenc_param prm; prm.ptime = tx->ptime; + prm.bitrate = 0; /* auto */ err = ac->encupdh(&tx->enc, ac, &prm, params); if (err) { @@ -1891,9 +1955,10 @@ int audio_debug(struct re_printf *pf, const struct audio *a) err = re_hprintf(pf, "\n--- Audio stream ---\n"); - err |= re_hprintf(pf, " tx: %H ptime=%ums\n", + err |= re_hprintf(pf, " tx: encode: %H ptime=%ums %s\n", aucodec_print, tx->ac, - tx->ptime); + tx->ptime, + aufmt_name(tx->enc_fmt)); err |= re_hprintf(pf, " aubuf: %H" " (cur %.2fms, max %.2fms, or %llu, ur %llu)\n", aubuf_debug, tx->aubuf, @@ -1905,14 +1970,15 @@ int audio_debug(struct re_printf *pf, const struct audio *a) tx->ausrc_prm.ch), tx->stats.aubuf_overrun, tx->stats.aubuf_underrun); - + err |= re_hprintf(pf, " source: %s\n", + aufmt_name(tx->src_fmt)); err |= re_hprintf(pf, " time = %.3f sec\n", autx_calc_seconds(tx)); err |= re_hprintf(pf, - " rx: %H\n" + " rx: decode: %H %s\n" " ptime=%ums pt=%d\n", - aucodec_print, rx->ac, + aucodec_print, rx->ac, aufmt_name(rx->dec_fmt), rx->ptime, rx->pt); err |= re_hprintf(pf, " aubuf: %H" " (cur %.2fms, max %.2fms, or %llu, ur %llu)\n", @@ -1926,9 +1992,9 @@ int audio_debug(struct re_printf *pf, const struct audio *a) rx->stats.aubuf_overrun, rx->stats.aubuf_underrun ); - + err |= re_hprintf(pf, " player: %s\n", aufmt_name(rx->play_fmt)); err |= re_hprintf(pf, " n_discard:%llu\n", - rx->n_discard); + rx->stats.n_discard); if (rx->level_set) { err |= re_hprintf(pf, " level %.3f dBov\n", rx->level_last); @@ -2079,3 +2145,57 @@ int audio_print_rtpstat(struct re_printf *pf, const struct audio *a) return err; } + + +int audio_set_bitrate(struct audio *au, uint32_t bitrate) +{ + struct autx *tx; + const struct aucodec *ac; + int err; + + if (!au) + return EINVAL; + + tx = &au->tx; + + ac = tx->ac; + + info("audio: set bitrate for encoder '%s' to %u bits/s\n", + ac ? ac->name : "?", + bitrate); + + if (ac) { + + if (ac->encupdh) { + struct auenc_param prm; + + prm.ptime = tx->ptime; + prm.bitrate = bitrate; + + err = ac->encupdh(&tx->enc, ac, &prm, NULL); + if (err) { + warning("audio: encupdh error: %m\n", err); + return err; + } + } + + } + else { + info("audio: set_bitrate: no audio encoder\n"); + } + + return 0; +} + + +bool audio_rxaubuf_started(struct audio *au) +{ + struct aurx *rx; + + if (!au) + return false; + + rx = &au->rx; + + return rx->aubuf_started; +} |