static bool aucodec_equal(const struct aucodec *a, const struct aucodec *b) { if (!a || !b) return false; return get_srate(a) == get_srate(b) && a->ch == b->ch; }
static int start_player(struct aurx *rx, struct audio *a) { const struct aucodec *ac = rx->ac; uint32_t srate_dsp = get_srate(ac); int err; if (!ac) return 0; /* Optional resampler, if configured */ if (a->cfg.srate_play && a->cfg.srate_play != srate_dsp && !rx->resamp) { srate_dsp = a->cfg.srate_play; (void)re_printf("enable auplay resampler: %u --> %u Hz\n", get_srate(ac), srate_dsp); rx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); if (!rx->sampv_rs) return ENOMEM; err = auresamp_alloc(&rx->resamp, AUDIO_SAMPSZ, get_srate(ac), ac->ch, srate_dsp, ac->ch); if (err) return err; } /* Start Audio Player */ if (!rx->auplay && auplay_find(NULL)) { struct auplay_prm prm; prm.fmt = AUFMT_S16LE; prm.srate = srate_dsp; prm.ch = ac->ch; prm.frame_size = calc_nsamp(prm.srate, prm.ch, rx->ptime); if (!rx->ab) { const size_t psize = 2 * prm.frame_size; err = aubuf_alloc(&rx->ab, psize * 1, psize * 8); if (err) return err; } err = auplay_alloc(&rx->auplay, a->cfg.play_mod, &prm, a->cfg.play_dev, auplay_write_handler, rx); if (err) { DEBUG_WARNING("start_player failed (%s.%s): %m\n", a->cfg.play_mod, a->cfg.play_dev, err); return err; } } return 0; }
/* * Reference: * * https://www.avm.de/de/Extern/files/x-rtp/xrtpv32.pdf */ int audio_print_rtpstat(struct re_printf *pf, const struct audio *a) { const struct stream *s; const struct rtcp_stats *rtcp; int srate_tx = 8000; int srate_rx = 8000; int err; if (!a) return 1; s = a->strm; rtcp = &s->rtcp_stats; if (!rtcp->tx.sent) return 1; if (a->tx.ac) srate_tx = get_srate(a->tx.ac); if (a->rx.ac) srate_rx = get_srate(a->rx.ac); err = re_hprintf(pf, "EX=BareSip;" /* Reporter Identifier */ "CS=%d;" /* Call Setup in milliseconds */ "CD=%d;" /* Call Duration in seconds */ "PR=%u;PS=%u;" /* Packets RX, TX */ "PL=%d,%d;" /* Packets Lost RX, TX */ "PD=%d,%d;" /* Packets Discarded, RX, TX */ "JI=%.1f,%.1f;" /* Jitter RX, TX in timestamp units */ "IP=%J,%J" /* Local, Remote IPs */ , call_setup_duration(s->call) * 1000, call_duration(s->call), s->metric_rx.n_packets, s->metric_tx.n_packets, rtcp->rx.lost, rtcp->tx.lost, s->metric_rx.n_err, s->metric_tx.n_err, /* timestamp units (ie: 8 ts units = 1 ms @ 8KHZ) */ 1.0 * rtcp->rx.jit/1000 * (srate_rx/1000), 1.0 * rtcp->tx.jit/1000 * (srate_tx/1000), sdp_media_laddr(s->sdp), sdp_media_raddr(s->sdp) ); if (a->tx.ac) { err |= re_hprintf(pf, ";EN=%s/%d", a->tx.ac->name, srate_tx ); } if (a->rx.ac) { err |= re_hprintf(pf, ";DE=%s/%d", a->rx.ac->name, srate_rx ); } return err; }
static void aufilt_param_set(struct aufilt_prm *prm, const struct aucodec *ac, uint32_t ptime) { if (!ac) { DEBUG_WARNING("aufilt param: NO CODEC!\n"); memset(prm, 0, sizeof(*prm)); return; } prm->srate = get_srate(ac); prm->ch = ac->ch; prm->frame_size = calc_nsamp(get_srate(ac), ac->ch, ptime); }
int audio_encoder_set(struct audio *a, const struct aucodec *ac, int pt_tx, const char *params) { struct autx *tx; int err = 0; bool reset; if (!a || !ac) return EINVAL; tx = &a->tx; reset = !aucodec_equal(ac, tx->ac); if (ac != tx->ac) { (void)re_fprintf(stderr, "Set audio encoder: %s %uHz %dch\n", ac->name, get_srate(ac), ac->ch); /* Audio source must be stopped first */ if (reset) { tx->ausrc = mem_deref(tx->ausrc); } tx->is_g722 = (0 == str_casecmp(ac->name, "G722")); tx->enc = mem_deref(tx->enc); tx->ac = ac; } if (ac->encupdh) { struct auenc_param prm; prm.ptime = tx->ptime; err = ac->encupdh(&tx->enc, ac, &prm, params); if (err) { DEBUG_WARNING("alloc encoder: %m\n", err); return err; } } stream_set_srate(a->strm, get_srate(ac), get_srate(ac)); stream_update_encoder(a->strm, pt_tx); if (!tx->ausrc) { err |= audio_start(a); } return err; }
int Spectacle::init(int fftlen, int windowlen, int overlap, float srate, float maxdeltime) { if (SpectacleBase::init(fftlen, windowlen, overlap, srate) != 0) return -1; // Compute maximum delay lag and create delay lines for FFT real and // imaginary values. Remember that these delays function at the decimation // rate, not at the audio rate, so the memory footprint is not as large // as you would expect -- about 44100 samples per second at fftlen=1024, // overlap=2 and SR=44100. _maxdeltime = maxdeltime; _maxdelsamps = long(maxdeltime * get_srate() / float(_decimation) + 0.5); for (int i = 0; i < _half_fftlen; i++) { Odelay *delay = new Odelay(_maxdelsamps); if (delay == NULL) goto bad_alloc; _real_delay[i] = delay; delay = new Odelay(_maxdelsamps); if (delay == NULL) goto bad_alloc; _imag_delay[i] = delay; } _delay_bin_groups = new int [_half_fftlen]; set_delay_freqrange(0.0f, 0.0f); return 0; bad_alloc: error("%s: Not enough memory for delay lines.", instname()); return -1; }
static int aucodec_print(struct re_printf *pf, const struct aucodec *ac) { if (!ac) return 0; return re_hprintf(pf, "%s %uHz/%dch", ac->name, get_srate(ac), ac->ch); }
int audio_decoder_set(struct audio *a, const struct aucodec *ac, int pt_rx, const char *params) { struct aurx *rx; bool reset = false; int err = 0; if (!a || !ac) return EINVAL; rx = &a->rx; reset = !aucodec_equal(ac, rx->ac); if (ac != rx->ac) { (void)re_fprintf(stderr, "Set audio decoder: %s %uHz %dch\n", ac->name, get_srate(ac), ac->ch); rx->pt = pt_rx; rx->ac = ac; rx->dec = mem_deref(rx->dec); } if (ac->decupdh) { err = ac->decupdh(&rx->dec, ac, params); if (err) { DEBUG_WARNING("alloc decoder: %m\n", err); return err; } } stream_set_srate(a->strm, get_srate(ac), get_srate(ac)); if (reset) { rx->auplay = mem_deref(rx->auplay); /* Reset audio filter chain */ list_flush(&a->filtl); err |= audio_start(a); } return err; }
static inline uint32_t get_framesize(const struct aucodec *ac, uint32_t ptime) { if (!ac) return 0; return calc_nsamp(get_srate(ac), ac->ch, ptime); }
// ----------------------------------------------------------- set_maxdeltime -- // Reset delay lines to accommodate a maximum delay of <time> seconds at the // current sampling rate. Assumes that caller constrains all delay times to // fit this new maximum. void Spectacle::set_maxdeltime(float time) { _maxdeltime = time; _maxdelsamps = long(time * get_srate() / float(_decimation) + 0.5); for (int i = 0; i < _half_fftlen; i++) { _real_delay[i]->resize(_maxdelsamps); _imag_delay[i]->resize(_maxdelsamps); } }
static int add_audio_codec(struct audio *a, struct sdp_media *m, struct aucodec *ac) { if (!in_range(&a->cfg.srate, get_srate(ac))) { debug("audio: skip %uHz codec (audio range %uHz - %uHz)\n", get_srate(ac), a->cfg.srate.min, a->cfg.srate.max); return 0; } if (!in_range(&a->cfg.channels, ac->ch)) { debug("audio: skip codec with %uch (audio range %uch-%uch)\n", ac->ch, a->cfg.channels.min, a->cfg.channels.max); return 0; } return sdp_format_add(NULL, m, false, ac->pt, ac->name, ac->srate, ac->ch, ac->fmtp_ench, ac->fmtp_cmph, ac, false, "%s", ac->fmtp); }
static void aufilt_param_set(struct aufilt_prm *prm, const struct aucodec *ac, uint32_t ptime) { if (!ac) { memset(prm, 0, sizeof(*prm)); return; } prm->srate = get_srate(ac); prm->ch = ac->ch; prm->ptime = ptime; }
static int ml26124_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec); int i = get_coeff(priv->mclk, params_rate(hw_params)); int srate; if (i < 0) return i; priv->substream = substream; priv->rate = params_rate(hw_params); if (priv->clk_in) { switch (priv->mclk / params_rate(hw_params)) { case 256: snd_soc_update_bits(codec, ML26124_CLK_CTL, BIT(0) | BIT(1), 1); break; case 512: snd_soc_update_bits(codec, ML26124_CLK_CTL, BIT(0) | BIT(1), 2); break; case 1024: snd_soc_update_bits(codec, ML26124_CLK_CTL, BIT(0) | BIT(1), 3); break; default: dev_err(codec->dev, "Unsupported MCLKI\n"); break; } } else { snd_soc_update_bits(codec, ML26124_CLK_CTL, BIT(0) | BIT(1), 0); } srate = get_srate(params_rate(hw_params)); if (srate < 0) return srate; snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, srate); snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, coeff_div[i].pllnl); snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, coeff_div[i].pllnh); snd_soc_update_bits(codec, ML26124_PLLML, 0xff, coeff_div[i].pllml); snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh); snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv); return 0; }
// ---------------------------------------------------------- modify_analysis -- void Spectacle::modify_analysis(bool reading_input) { DPRINT("modify_analysis: ....................."); #ifdef PRINT_DELTIMES static float *prevdeltimes = NULL; if (prevdeltimes == NULL) { prevdeltimes = new float [_delay_table_size]; post("\nmodify_analysis: delay times --------------------------"); for (int i = 0; i < _delay_table_size; i++) { prevdeltimes[i] = _deltimetable[i]; post("[%d] %f", i, _deltimetable[i]); } #ifdef PRINT_DELTIME_CHANGES post("\nmodify_analysis: delay time changes -------------------"); #endif } #endif const bool posteq = get_posteq(); float eq; // NB: check EQ table size, rather than table pointer, to determine whether // we should use an EQ constant. Otherwise, there's a danger we could read // a null EQ table pointer, if set_eqtable called by non-perf thread. if (_control_table_size == 0) eq = _ampdb(_eqconst); for (int i = 0; i < _half_fftlen; i++) { int index = i << 1; if (_control_table_size > 0) { // EQ uses base class bin groups array. const int bg = _bin_groups[i]; eq = _ampdb(_eqtable[bg]); } float real, imag; if (reading_input) { if (posteq) { real = _fft_buf[index]; imag = _fft_buf[index + 1]; } else { real = _fft_buf[index] * eq; imag = _fft_buf[index + 1] * eq; } } else { real = 0.0f; imag = 0.0f; } const int bg = _delay_bin_groups[i]; // NB: caller must assure that deltime is in range const float deltime = _deltimetable ? _deltimetable[bg] : _deltimeconst; #ifdef PRINT_DELTIME_CHANGES if (deltime != prevdeltimes[bg]) { post("[%d] %f", bg, deltime); prevdeltimes[bg] = deltime; } #endif if (deltime == 0.0f) { if (posteq) { _fft_buf[index] = real * eq; _fft_buf[index + 1] = imag * eq; } else { _fft_buf[index] = real; _fft_buf[index + 1] = imag; } } else { const long delsamps = long((deltime * get_srate()) + 0.5) / _decimation; const float newreal = _real_delay[i]->getsamp(delsamps); const float newimag = _imag_delay[i]->getsamp(delsamps); const float feedback = _feedbacktable ? _feedbacktable[bg] : _feedbackconst; if (feedback != 0.0) { #ifdef ANTI_DENORM float fbsig = (newreal * feedback) + _antidenorm_offset; _real_delay[i]->putsamp(real + fbsig); fbsig = (newimag * feedback) + _antidenorm_offset; _imag_delay[i]->putsamp(imag + fbsig); #else _real_delay[i]->putsamp(real + (newreal * feedback)); _imag_delay[i]->putsamp(imag + (newimag * feedback)); #endif } else { _real_delay[i]->putsamp(real); _imag_delay[i]->putsamp(imag); } if (posteq) { _fft_buf[index] = newreal * eq; _fft_buf[index + 1] = newimag * eq; } else { _fft_buf[index] = newreal; _fft_buf[index + 1] = newimag; } } } _fft_buf[1] = 0.0f; // clear Nyquist real value #ifdef ANTI_DENORM _antidenorm_offset = -_antidenorm_offset; #endif }
static int start_source(struct autx *tx, struct audio *a) { const struct aucodec *ac = tx->ac; uint32_t srate_dsp = get_srate(tx->ac); int err; if (!ac) return 0; /* Optional resampler, if configured */ if (a->cfg.srate_src && a->cfg.srate_src != srate_dsp && !tx->resamp) { srate_dsp = a->cfg.srate_src; (void)re_printf("enable ausrc resampler: %u --> %u Hz\n", get_srate(ac), srate_dsp); tx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); if (!tx->sampv_rs) return ENOMEM; err = auresamp_alloc(&tx->resamp, AUDIO_SAMPSZ, srate_dsp, ac->ch, get_srate(ac), ac->ch); if (err) return err; } /* Start Audio Source */ if (!tx->ausrc && ausrc_find(NULL)) { struct ausrc_prm prm; prm.fmt = AUFMT_S16LE; prm.srate = srate_dsp; prm.ch = ac->ch; prm.frame_size = calc_nsamp(prm.srate, prm.ch, tx->ptime); tx->psize = 2 * prm.frame_size; if (!tx->ab) { err = aubuf_alloc(&tx->ab, tx->psize * 2, tx->psize * 30); if (err) return err; } err = ausrc_alloc(&tx->ausrc, NULL, a->cfg.src_mod, &prm, a->cfg.src_dev, ausrc_read_handler, ausrc_error_handler, a); if (err) { DEBUG_WARNING("start_source failed: %m\n", err); return err; } switch (a->cfg.txmode) { #ifdef HAVE_PTHREAD case AUDIO_MODE_THREAD: case AUDIO_MODE_THREAD_REALTIME: if (!tx->u.thr.run) { tx->u.thr.run = true; err = pthread_create(&tx->u.thr.tid, NULL, tx_thread, a); if (err) { tx->u.thr.tid = false; return err; } } break; #endif case AUDIO_MODE_TMR: tmr_start(&tx->u.tmr, 1, timeout_tx, a); break; default: break; } } return 0; }
static int start_player(struct aurx *rx, struct audio *a) { const struct aucodec *ac = rx->ac; uint32_t srate_dsp = get_srate(ac); uint32_t channels_dsp; bool resamp = false; int err; if (!ac) return 0; channels_dsp = ac->ch; if (a->cfg.srate_play && a->cfg.srate_play != srate_dsp) { resamp = true; srate_dsp = a->cfg.srate_play; } if (a->cfg.channels_play && a->cfg.channels_play != channels_dsp) { resamp = true; channels_dsp = a->cfg.channels_play; } /* Optional resampler, if configured */ if (resamp && !rx->sampv_rs) { info("audio: enable auplay resampler:" " %uHz/%uch --> %uHz/%uch\n", get_srate(ac), ac->ch, srate_dsp, channels_dsp); rx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); if (!rx->sampv_rs) return ENOMEM; err = auresamp_setup(&rx->resamp, get_srate(ac), ac->ch, srate_dsp, channels_dsp); if (err) { warning("audio: could not setup auplay resampler" " (%m)\n", err); return err; } } /* Start Audio Player */ if (!rx->auplay && auplay_find(NULL)) { struct auplay_prm prm; prm.srate = srate_dsp; prm.ch = channels_dsp; prm.ptime = rx->ptime; if (!rx->aubuf) { size_t psize; psize = 2 * calc_nsamp(prm.srate, prm.ch, prm.ptime); err = aubuf_alloc(&rx->aubuf, psize * 1, psize * 8); if (err) return err; } err = auplay_alloc(&rx->auplay, a->cfg.play_mod, &prm, rx->device, auplay_write_handler, rx); if (err) { warning("audio: start_player failed (%s.%s): %m\n", a->cfg.play_mod, rx->device, err); return err; } } return 0; }
static int start_source(struct autx *tx, struct audio *a) { const struct aucodec *ac = tx->ac; uint32_t srate_dsp = get_srate(ac); uint32_t channels_dsp; bool resamp = false; int err; if (!ac) return 0; channels_dsp = ac->ch; if (a->cfg.srate_src && a->cfg.srate_src != srate_dsp) { resamp = true; srate_dsp = a->cfg.srate_src; } if (a->cfg.channels_src && a->cfg.channels_src != channels_dsp) { resamp = true; channels_dsp = a->cfg.channels_src; } /* Optional resampler, if configured */ if (resamp && !tx->sampv_rs) { info("audio: enable ausrc resampler:" " %uHz/%uch <-- %uHz/%uch\n", get_srate(ac), ac->ch, srate_dsp, channels_dsp); tx->sampv_rs = mem_zalloc(AUDIO_SAMPSZ * 2, NULL); if (!tx->sampv_rs) return ENOMEM; err = auresamp_setup(&tx->resamp, srate_dsp, channels_dsp, get_srate(ac), ac->ch); if (err) { warning("audio: could not setup ausrc resampler" " (%m)\n", err); return err; } } /* Start Audio Source */ if (!tx->ausrc && ausrc_find(NULL)) { struct ausrc_prm prm; prm.srate = srate_dsp; prm.ch = channels_dsp; prm.ptime = tx->ptime; tx->psize = 2 * calc_nsamp(prm.srate, prm.ch, prm.ptime); if (!tx->aubuf) { err = aubuf_alloc(&tx->aubuf, tx->psize * 2, tx->psize * 30); if (err) return err; } err = ausrc_alloc(&tx->ausrc, NULL, a->cfg.src_mod, &prm, tx->device, ausrc_read_handler, ausrc_error_handler, a); if (err) { warning("audio: start_source failed (%s.%s): %m\n", a->cfg.src_mod, tx->device, err); return err; } switch (a->cfg.txmode) { #ifdef HAVE_PTHREAD case AUDIO_MODE_THREAD: case AUDIO_MODE_THREAD_REALTIME: if (!tx->u.thr.run) { tx->u.thr.run = true; err = pthread_create(&tx->u.thr.tid, NULL, tx_thread, a); if (err) { tx->u.thr.tid = false; return err; } } break; #endif case AUDIO_MODE_TMR: tmr_start(&tx->u.tmr, 1, timeout_tx, a); break; default: break; } } return 0; }