static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size) { int samples = s->packet.frame_duration; int redundancy = 0; int redundancy_size, redundancy_pos; int ret, i, consumed; int delayed_samples = s->delayed_samples; ret = opus_rc_init(&s->rc, data, size); if (ret < 0) return ret; /* decode the silk frame */ if (s->packet.mode == OPUS_MODE_SILK || s->packet.mode == OPUS_MODE_HYBRID) { if (!swr_is_initialized(s->swr)) { ret = opus_init_resample(s); if (ret < 0) return ret; } samples = ff_silk_decode_superframe(s->silk, &s->rc, s->silk_output, FFMIN(s->packet.bandwidth, OPUS_BANDWIDTH_WIDEBAND), s->packet.stereo + 1, silk_frame_duration_ms[s->packet.config]); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding a SILK frame.\n"); return samples; } samples = swr_convert(s->swr, (uint8_t**)s->out, s->packet.frame_duration, (const uint8_t**)s->silk_output, samples); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error resampling SILK data.\n"); return samples; } av_assert2((samples & 7) == 0); s->delayed_samples += s->packet.frame_duration - samples; } else ff_silk_flush(s->silk); // decode redundancy information consumed = opus_rc_tell(&s->rc); if (s->packet.mode == OPUS_MODE_HYBRID && consumed + 37 <= size * 8) redundancy = opus_rc_p2model(&s->rc, 12); else if (s->packet.mode == OPUS_MODE_SILK && consumed + 17 <= size * 8) redundancy = 1; if (redundancy) { redundancy_pos = opus_rc_p2model(&s->rc, 1); if (s->packet.mode == OPUS_MODE_HYBRID) redundancy_size = opus_rc_unimodel(&s->rc, 256) + 2; else redundancy_size = size - (consumed + 7) / 8; size -= redundancy_size; if (size < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid redundancy frame size.\n"); return AVERROR_INVALIDDATA; } if (redundancy_pos) { ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; ff_celt_flush(s->celt); } } /* decode the CELT frame */ if (s->packet.mode == OPUS_MODE_CELT || s->packet.mode == OPUS_MODE_HYBRID) { float *out_tmp[2] = { s->out[0], s->out[1] }; float **dst = (s->packet.mode == OPUS_MODE_CELT) ? out_tmp : s->celt_output; int celt_output_samples = samples; int delay_samples = av_audio_fifo_size(s->celt_delay); if (delay_samples) { if (s->packet.mode == OPUS_MODE_HYBRID) { av_audio_fifo_read(s->celt_delay, (void**)s->celt_output, delay_samples); for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, delay_samples); out_tmp[i] += delay_samples; } celt_output_samples -= delay_samples; } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); av_audio_fifo_drain(s->celt_delay, delay_samples); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } } opus_raw_init(&s->rc, data + size, size); ret = ff_celt_decode_frame(s->celt, &s->rc, dst, s->packet.stereo + 1, s->packet.frame_duration, (s->packet.mode == OPUS_MODE_HYBRID) ? 17 : 0, celt_band_end[s->packet.bandwidth]); if (ret < 0) return ret; if (s->packet.mode == OPUS_MODE_HYBRID) { int celt_delay = s->packet.frame_duration - celt_output_samples; void *delaybuf[2] = { s->celt_output[0] + celt_output_samples, s->celt_output[1] + celt_output_samples }; for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, celt_output_samples); } ret = av_audio_fifo_write(s->celt_delay, delaybuf, celt_delay); if (ret < 0) return ret; } } else ff_celt_flush(s->celt); if (s->redundancy_idx) { for (i = 0; i < s->output_channels; i++) opus_fade(s->out[i], s->out[i], s->redundancy_output[i] + 120 + s->redundancy_idx, ff_celt_window2 + s->redundancy_idx, 120 - s->redundancy_idx); s->redundancy_idx = 0; } if (redundancy) { if (!redundancy_pos) { ff_celt_flush(s->celt); ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; for (i = 0; i < s->output_channels; i++) { opus_fade(s->out[i] + samples - 120 + delayed_samples, s->out[i] + samples - 120 + delayed_samples, s->redundancy_output[i] + 120, ff_celt_window2, 120 - delayed_samples); if (delayed_samples) s->redundancy_idx = 120 - delayed_samples; } } else { for (i = 0; i < s->output_channels; i++) { memcpy(s->out[i] + delayed_samples, s->redundancy_output[i], 120 * sizeof(float)); opus_fade(s->out[i] + 120 + delayed_samples, s->redundancy_output[i] + 120, s->out[i] + 120 + delayed_samples, ff_celt_window2, 120); } } } return samples; }
int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, const uint8_t *in_arg [SWR_CH_MAX], int in_count){ AudioData * in= &s->in; AudioData *out= &s->out; if (!swr_is_initialized(s)) { av_log(s, AV_LOG_ERROR, "Context has not been initialized\n"); return AVERROR(EINVAL); } while(s->drop_output > 0){ int ret; uint8_t *tmp_arg[SWR_CH_MAX]; #define MAX_DROP_STEP 16384 if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0) return ret; reversefill_audiodata(&s->drop_temp, tmp_arg); s->drop_output *= -1; //FIXME find a less hackish solution ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesn't matter s->drop_output *= -1; in_count = 0; if(ret>0) { s->drop_output -= ret; if (!s->drop_output && !out_arg) return 0; continue; } if(s->drop_output || !out_arg) return 0; } if(!in_arg){ if(s->resample){ if (!s->flushed) s->resampler->flush(s); s->resample_in_constraint = 0; s->flushed = 1; }else if(!s->in_buffer_count){ return 0; } }else fill_audiodata(in , (void*)in_arg); fill_audiodata(out, out_arg); if(s->resample){ int ret = swr_convert_internal(s, out, out_count, in, in_count); if(ret>0 && !s->drop_output) s->outpts += ret * (int64_t)s->in_sample_rate; return ret; }else{ AudioData tmp= *in; int ret2=0; int ret, size; size = FFMIN(out_count, s->in_buffer_count); if(size){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); ret= swr_convert_internal(s, out, size, &tmp, size); if(ret<0) return ret; ret2= ret; s->in_buffer_count -= ret; s->in_buffer_index += ret; buf_set(out, out, ret); out_count -= ret; if(!s->in_buffer_count) s->in_buffer_index = 0; } if(in_count){ size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; if(in_count > out_count) { //FIXME move after swr_convert_internal if( size > s->in_buffer.count && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); copy(&s->in_buffer, &tmp, s->in_buffer_count); s->in_buffer_index=0; }else if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) return ret; } if(out_count){ size = FFMIN(in_count, out_count); ret= swr_convert_internal(s, out, size, in, size); if(ret<0) return ret; buf_set(in, in, ret); in_count -= ret; ret2 += ret; } if(in_count){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); copy(&tmp, in, in_count); s->in_buffer_count += in_count; } } if(ret2>0 && !s->drop_output) s->outpts += ret2 * (int64_t)s->in_sample_rate; return ret2; } }
static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf, int buf_size, int nb_samples) { int output_samples = 0; int flush_needed = 0; int i, j, ret; /* check if we need to flush the resampler */ if (swr_is_initialized(s->swr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->swr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } if (!buf && !flush_needed) return 0; /* use dummy output buffers if the channel is not mapped to anything */ if (!s->out[0] || (s->output_channels == 2 && !s->out[1])) { av_fast_malloc(&s->out_dummy, &s->out_dummy_allocated_size, s->out_size); if (!s->out_dummy) return AVERROR(ENOMEM); if (!s->out[0]) s->out[0] = s->out_dummy; if (!s->out[1]) s->out[1] = s->out_dummy; } /* flush the resampler if necessary */ if (flush_needed) { ret = opus_flush_resample(s, s->delayed_samples); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error flushing the resampler.\n"); return ret; } swr_close(s->swr); output_samples += s->delayed_samples; s->delayed_samples = 0; if (!buf) goto finish; } /* decode all the frames in the packet */ for (i = 0; i < s->packet.frame_count; i++) { int size = s->packet.frame_size[i]; int samples = opus_decode_frame(s, buf + s->packet.frame_offset[i], size); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding an Opus frame.\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) return samples; for (j = 0; j < s->output_channels; j++) memset(s->out[j], 0, s->packet.frame_duration * sizeof(float)); samples = s->packet.frame_duration; } output_samples += samples; for (j = 0; j < s->output_channels; j++) s->out[j] += samples; s->out_size -= samples * sizeof(float); } finish: s->out[0] = s->out[1] = NULL; s->out_size = 0; return output_samples; }
static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size) { int samples = s->packet.frame_duration; int redundancy = 0; int redundancy_size, redundancy_pos; int ret, i, consumed; int delayed_samples = s->delayed_samples; ret = opus_rc_init(&s->rc, data, size); if (ret < 0) return ret; /* decode the silk frame */ if (s->packet.mode == OPUS_MODE_SILK || s->packet.mode == OPUS_MODE_HYBRID) { #if CONFIG_SWRESAMPLE if (!swr_is_initialized(s->swr)) { #elif CONFIG_AVRESAMPLE if (!avresample_is_open(s->avr)) { #endif ret = opus_init_resample(s); if (ret < 0) return ret; } samples = ff_silk_decode_superframe(s->silk, &s->rc, s->silk_output, FFMIN(s->packet.bandwidth, OPUS_BANDWIDTH_WIDEBAND), s->packet.stereo + 1, silk_frame_duration_ms[s->packet.config]); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding a SILK frame.\n"); return samples; } #if CONFIG_SWRESAMPLE samples = swr_convert(s->swr, (uint8_t**)s->out, s->packet.frame_duration, (const uint8_t**)s->silk_output, samples); #elif CONFIG_AVRESAMPLE samples = avresample_convert(s->avr, (uint8_t**)s->out, s->out_size, s->packet.frame_duration, (uint8_t**)s->silk_output, sizeof(s->silk_buf[0]), samples); #endif if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error resampling SILK data.\n"); return samples; } av_assert2((samples & 7) == 0); s->delayed_samples += s->packet.frame_duration - samples; } else ff_silk_flush(s->silk); // decode redundancy information consumed = opus_rc_tell(&s->rc); if (s->packet.mode == OPUS_MODE_HYBRID && consumed + 37 <= size * 8) redundancy = opus_rc_p2model(&s->rc, 12); else if (s->packet.mode == OPUS_MODE_SILK && consumed + 17 <= size * 8) redundancy = 1; if (redundancy) { redundancy_pos = opus_rc_p2model(&s->rc, 1); if (s->packet.mode == OPUS_MODE_HYBRID) redundancy_size = opus_rc_unimodel(&s->rc, 256) + 2; else redundancy_size = size - (consumed + 7) / 8; size -= redundancy_size; if (size < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid redundancy frame size.\n"); return AVERROR_INVALIDDATA; } if (redundancy_pos) { ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; ff_celt_flush(s->celt); } } /* decode the CELT frame */ if (s->packet.mode == OPUS_MODE_CELT || s->packet.mode == OPUS_MODE_HYBRID) { float *out_tmp[2] = { s->out[0], s->out[1] }; float **dst = (s->packet.mode == OPUS_MODE_CELT) ? out_tmp : s->celt_output; int celt_output_samples = samples; int delay_samples = av_audio_fifo_size(s->celt_delay); if (delay_samples) { if (s->packet.mode == OPUS_MODE_HYBRID) { av_audio_fifo_read(s->celt_delay, (void**)s->celt_output, delay_samples); for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, delay_samples); out_tmp[i] += delay_samples; } celt_output_samples -= delay_samples; } else { av_log(s->avctx, AV_LOG_WARNING, "Spurious CELT delay samples present.\n"); av_audio_fifo_drain(s->celt_delay, delay_samples); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_BUG; } } opus_raw_init(&s->rc, data + size, size); ret = ff_celt_decode_frame(s->celt, &s->rc, dst, s->packet.stereo + 1, s->packet.frame_duration, (s->packet.mode == OPUS_MODE_HYBRID) ? 17 : 0, celt_band_end[s->packet.bandwidth]); if (ret < 0) return ret; if (s->packet.mode == OPUS_MODE_HYBRID) { int celt_delay = s->packet.frame_duration - celt_output_samples; void *delaybuf[2] = { s->celt_output[0] + celt_output_samples, s->celt_output[1] + celt_output_samples }; for (i = 0; i < s->output_channels; i++) { s->fdsp->vector_fmac_scalar(out_tmp[i], s->celt_output[i], 1.0, celt_output_samples); } ret = av_audio_fifo_write(s->celt_delay, delaybuf, celt_delay); if (ret < 0) return ret; } } else ff_celt_flush(s->celt); if (s->redundancy_idx) { for (i = 0; i < s->output_channels; i++) opus_fade(s->out[i], s->out[i], s->redundancy_output[i] + 120 + s->redundancy_idx, ff_celt_window2 + s->redundancy_idx, 120 - s->redundancy_idx); s->redundancy_idx = 0; } if (redundancy) { if (!redundancy_pos) { ff_celt_flush(s->celt); ret = opus_decode_redundancy(s, data + size, redundancy_size); if (ret < 0) return ret; for (i = 0; i < s->output_channels; i++) { opus_fade(s->out[i] + samples - 120 + delayed_samples, s->out[i] + samples - 120 + delayed_samples, s->redundancy_output[i] + 120, ff_celt_window2, 120 - delayed_samples); if (delayed_samples) s->redundancy_idx = 120 - delayed_samples; } } else { for (i = 0; i < s->output_channels; i++) { memcpy(s->out[i] + delayed_samples, s->redundancy_output[i], 120 * sizeof(float)); opus_fade(s->out[i] + 120 + delayed_samples, s->redundancy_output[i] + 120, s->out[i] + 120 + delayed_samples, ff_celt_window2, 120); } } } return samples; } static int opus_decode_subpacket(OpusStreamContext *s, const uint8_t *buf, int buf_size, int nb_samples) { int output_samples = 0; int flush_needed = 0; int i, j, ret; /* check if we need to flush the resampler */ #if CONFIG_SWRESAMPLE if (swr_is_initialized(s->swr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->swr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } #elif CONFIG_AVRESAMPLE if (avresample_is_open(s->avr)) { if (buf) { int64_t cur_samplerate; av_opt_get_int(s->avr, "in_sample_rate", 0, &cur_samplerate); flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate); } else { flush_needed = !!s->delayed_samples; } } #endif if (!buf && !flush_needed) return 0; /* use dummy output buffers if the channel is not mapped to anything */ if (!s->out[0] || (s->output_channels == 2 && !s->out[1])) { av_fast_malloc(&s->out_dummy, &s->out_dummy_allocated_size, s->out_size); if (!s->out_dummy) return AVERROR(ENOMEM); if (!s->out[0]) s->out[0] = s->out_dummy; if (!s->out[1]) s->out[1] = s->out_dummy; } /* flush the resampler if necessary */ if (flush_needed) { ret = opus_flush_resample(s, s->delayed_samples); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error flushing the resampler.\n"); return ret; } #if CONFIG_SWRESAMPLE swr_close(s->swr); #elif CONFIG_AVRESAMPLE avresample_close(s->avr); #endif output_samples += s->delayed_samples; s->delayed_samples = 0; if (!buf) goto finish; } /* decode all the frames in the packet */ for (i = 0; i < s->packet.frame_count; i++) { int size = s->packet.frame_size[i]; int samples = opus_decode_frame(s, buf + s->packet.frame_offset[i], size); if (samples < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error decoding an Opus frame.\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) return samples; for (j = 0; j < s->output_channels; j++) memset(s->out[j], 0, s->packet.frame_duration * sizeof(float)); samples = s->packet.frame_duration; } output_samples += samples; for (j = 0; j < s->output_channels; j++) s->out[j] += samples; s->out_size -= samples * sizeof(float); } finish: s->out[0] = s->out[1] = NULL; s->out_size = 0; return output_samples; }
int AudioSource::mixWith( struct timespec ticks, uint8_t* outSamples, int outBytes, int outBitDepth, int outNbChannels, int outFrequency, float outVolume) { if (state != SOURCE_PLAYING) return -1; if (buffer_queue.empty()) return -1; debuglog(LCF_SOUND | LCF_FRAME, "Start mixing source ", id); AudioBuffer* curBuf = buffer_queue[queue_index]; #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) /* Get the sample format */ AVSampleFormat inFormat, outFormat; switch (curBuf->format) { case SAMPLE_FMT_U8: inFormat = AV_SAMPLE_FMT_U8; break; case SAMPLE_FMT_S16: case SAMPLE_FMT_MSADPCM: inFormat = AV_SAMPLE_FMT_S16; break; case SAMPLE_FMT_S32: inFormat = AV_SAMPLE_FMT_S32; break; case SAMPLE_FMT_FLT: inFormat = AV_SAMPLE_FMT_FLT; break; case SAMPLE_FMT_DBL: inFormat = AV_SAMPLE_FMT_DBL; break; default: debuglog(LCF_SOUND | LCF_FRAME | LCF_ERROR, "Unknown sample format"); break; } if (outBitDepth == 8) outFormat = AV_SAMPLE_FMT_U8; if (outBitDepth == 16) outFormat = AV_SAMPLE_FMT_S16; /* Check if SWR context is initialized. * If not, set parameters and init it */ if (! swr_is_initialized(swr)) { /* Set channel layout */ if (curBuf->nbChannels == 1) av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_MONO, 0); if (curBuf->nbChannels == 2) av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0); if (outNbChannels == 1) av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0); if (outNbChannels == 2) av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); /* Set sample format */ av_opt_set_sample_fmt(swr, "in_sample_fmt", inFormat, 0); av_opt_set_sample_fmt(swr, "out_sample_fmt", outFormat, 0); /* Set sampling frequency */ av_opt_set_int(swr, "in_sample_rate", curBuf->frequency, 0); av_opt_set_int(swr, "out_sample_rate", outFrequency, 0); /* Open the context */ if (swr_init(swr) < 0) { debuglog(LCF_SOUND | LCF_FRAME | LCF_ERROR, "Error initializing swr context"); return 0; } } #endif /* Mixing source volume and master volume. * Taken from openAL doc: * "The implementation is free to clamp the total gain (effective gain * per-source multiplied by the listener gain) to one to prevent overflow." * * TODO: This is where we can support panning. */ float resultVolume = (volume * outVolume) > 1.0?1.0:(volume*outVolume); int lvas = (int)(resultVolume * 65536.0f); int rvas = (int)(resultVolume * 65536.0f); /* Number of samples to advance in the buffer. */ int inNbSamples = ticksToSamples(ticks, curBuf->frequency); int oldPosition = position; int newPosition = position + inNbSamples; /* Allocate the mixed audio array */ #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) int outNbSamples = outBytes / (outNbChannels * outBitDepth / 8); mixedSamples.resize(outBytes); uint8_t* begMixed = &mixedSamples[0]; #endif int convOutSamples = 0; uint8_t* begSamples; int availableSamples = curBuf->getSamples(begSamples, inNbSamples, oldPosition); if (availableSamples == inNbSamples) { /* We did not reach the end of the buffer, easy case */ position = newPosition; debuglog(LCF_SOUND | LCF_FRAME, " Buffer ", curBuf->id, " in read in range ", oldPosition, " - ", position); #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) convOutSamples = swr_convert(swr, &begMixed, outNbSamples, (const uint8_t**)&begSamples, inNbSamples); #endif } else { /* We reached the end of the buffer */ debuglog(LCF_SOUND | LCF_FRAME, " Buffer ", curBuf->id, " is read from ", oldPosition, " to its end ", curBuf->sampleSize); #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) if (availableSamples > 0) swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples); #endif int remainingSamples = inNbSamples - availableSamples; if (source == SOURCE_CALLBACK) { /* We refill our buffer using the callback function, * until we got enough bytes for this frame */ while (remainingSamples > 0) { /* Before doing the callback, we must fake that the timer has * advanced by the number of samples already read */ int64_t extraTicks = ((int64_t) 1000000000) * (-remainingSamples); extraTicks /= curBuf->frequency; detTimer.fakeAdvanceTimer({extraTicks / 1000000000, extraTicks % 1000000000}); callback(curBuf); detTimer.fakeAdvanceTimer({0, 0}); availableSamples = curBuf->getSamples(begSamples, remainingSamples, 0); #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples); #endif debuglog(LCF_SOUND | LCF_FRAME, " Buffer ", curBuf->id, " is read again from 0 to ", availableSamples); if (remainingSamples == availableSamples) position = availableSamples; remainingSamples -= availableSamples; } #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) /* Get the mixed samples */ convOutSamples = swr_convert(swr, &begMixed, outNbSamples, nullptr, 0); #endif } else { int queue_size = buffer_queue.size(); int finalIndex; int finalPos; /* Our for loop conditions are different if we are looping or not */ if (looping) { for (int i=(queue_index+1)%queue_size; remainingSamples>0; i=(i+1)%queue_size) { AudioBuffer* loopbuf = buffer_queue[i]; availableSamples = loopbuf->getSamples(begSamples, remainingSamples, 0); debuglog(LCF_SOUND | LCF_FRAME, " Buffer ", loopbuf->id, " in read in range 0 - ", availableSamples); #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples); #endif if (remainingSamples == availableSamples) { finalIndex = i; finalPos = availableSamples; } remainingSamples -= availableSamples; } } else { for (int i=queue_index+1; (remainingSamples>0) && (i<queue_size); i++) { AudioBuffer* loopbuf = buffer_queue[i]; availableSamples = loopbuf->getSamples(begSamples, remainingSamples, 0); debuglog(LCF_SOUND | LCF_FRAME, " Buffer ", loopbuf->id, " in read in range 0 - ", availableSamples); #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) swr_convert(swr, nullptr, 0, (const uint8_t**)&begSamples, availableSamples); #endif if (remainingSamples == availableSamples) { finalIndex = i; finalPos = availableSamples; } remainingSamples -= availableSamples; } } #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) /* Get the mixed samples */ convOutSamples = swr_convert(swr, &begMixed, outNbSamples, nullptr, 0); #endif if (remainingSamples > 0) { /* We reached the end of the buffer queue */ init(); state = SOURCE_STOPPED; debuglog(LCF_SOUND | LCF_FRAME, " End of the queue reached"); } else { /* Update the position in the buffer */ queue_index = finalIndex; position = finalPos; } } } #if defined(LIBTAS_ENABLE_AVDUMPING) || defined(LIBTAS_ENABLE_SOUNDPLAYBACK) #define clamptofullsignedrange(x,lo,hi) (((unsigned int)((x)-(lo))<=(unsigned int)((hi)-(lo)))?(x):(((x)<0)?(lo):(hi))) /* Add mixed source to the output buffer */ if (outBitDepth == 8) { for (int s=0; s<convOutSamples*outNbChannels; s+=outNbChannels) { int myL = ((uint8_t*)&mixedSamples[0])[s]; int otherL = ((uint8_t*)outSamples)[s]; int sumL = otherL + ((myL * lvas) >> 16) - 256; ((uint8_t*)outSamples)[s] = clamptofullsignedrange(sumL, 0, (1<<8)-1); if (outNbChannels == 2) { int myR = ((uint8_t*)&mixedSamples[0])[s+1]; int otherR = ((uint8_t*)outSamples)[s+1]; int sumR = otherR + ((myR * rvas) >> 16); ((uint8_t*)outSamples)[s+1] = clamptofullsignedrange(sumR, 0, (1<<8)-1); } } }