/* Copyright(C) 2007-2018 VoIP objects (voipobjects.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "../config.h" #include "../helper/HL_Exception.h" #include "../helper/HL_Log.h" #include #include #include "Audio_Mixer.h" #define LOG_SUBSYSTEM "Mixer" using namespace Audio; Mixer::Stream::Stream() { mResampler8.start(AUDIO_CHANNELS, 8000, AUDIO_SAMPLERATE); mResampler16.start(AUDIO_CHANNELS, 16000, AUDIO_SAMPLERATE); mResampler32.start(AUDIO_CHANNELS, 32000, AUDIO_SAMPLERATE); mResampler48.start(AUDIO_CHANNELS, 48000, AUDIO_SAMPLERATE); mActive = false; mContext = nullptr; mSSRC = 0; mFadeOutCounter = 0; mData.setCapacity(AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT); } Mixer::Stream::~Stream() { } void Mixer::Stream::setSsrc(unsigned ssrc) { mSSRC = ssrc; } unsigned Mixer::Stream::ssrc() { return mSSRC; } void Mixer::Stream::setContext(void* context) { mContext = context; } void* Mixer::Stream::context() { return mContext; } DataWindow& Mixer::Stream::data() { return mData; } bool Mixer::Stream::active() { return mActive; } void Mixer::Stream::setActive(bool active) { mActive = active; } void Mixer::Stream::addPcm(int rate, const void* input, int length) { // Resample to internal sample rate size_t outputSize = size_t(0.5 + length * ((float)AUDIO_SAMPLERATE / rate)); if (mTempBuffer.size() < outputSize) mTempBuffer.resize(outputSize); Resampler* resampler = (rate == 8000) ? &mResampler8 : ((rate == 16000) ? &mResampler16 : ((rate == 32000) ? &mResampler32 : &mResampler48)); size_t inputProcessed = 0; resampler->processBuffer(input, length, inputProcessed, mTempBuffer.mutableData(), outputSize); // inputProcessed result value is ignored here - rate will be 8/16/32/48k, inputProcessed is equal to length // Queue data mData.add(mTempBuffer.data(), outputSize); } Mixer::Mixer() { mActiveCounter = 0; mOutput.setCapacity(32768); } Mixer::~Mixer() { } void Mixer::unregisterChannel(void* channel) { for (int i=0; iactive()) { channel->setSsrc(ssrc); channel->setContext(context); channel->data().clear(); mActiveCounter++; channel->setActive(true); return channel; } } return NULL; } void Mixer::addPcm(void* context, unsigned ssrc, const void* inputData, int inputLength, int inputRate, bool fadeOut) { assert(inputRate == 8000 || inputRate == 16000 || inputRate == 32000); int i; // Locate a channel Stream* channel = NULL; for (i=0; iaddPcm(inputRate, inputData, inputLength); } void Mixer::addPcm(void* context, unsigned ssrc, Audio::DataWindow& w, int rate, bool fadeOut) { assert(rate == 8000 || rate == 16000 || rate == 32000 || rate == 48000); int i; // Locate a channel Stream* channel = NULL; for (i=0; iaddPcm(rate, w.data(), w.filled()); //ICELogSpecial(<<"Mixer stream " << int(this) << " has " << w.filled() << " bytes"); } void Mixer::mix() { // Current sample int sample = 0; // Counter of processed active channels int processed = 0; // Samples & sources counters unsigned sampleCounter = 0, sourceCounter; short outputBuffer[512]; unsigned outputCounter = 0; // Build active channel map Stream* channelList[AUDIO_MIX_CHANNEL_COUNT]; int activeCounter = 0; for (int i=0; i filled2 ? filled1 : filled2; // Find how much samples can be mixed int filled = mOutput.filled() / 2; int maxsize = mOutput.capacity() / 2; if (maxsize - filled < available) available = maxsize - filled; short sample = 0; for (int i=0; i i ? audio1.data().shortAt(i) : 0; short sample2 = filled2 > i ? audio2.data().shortAt(i) : 0; sample = (abs(sample1) > abs(sample2)) ? sample1 : sample2; mOutput.add(sample); } audio1.data().erase(available*2); audio2.data().erase(available*2); } else { do { sample = 0; sourceCounter = 0; processed = 0; for (int i=0; i (int)sampleCounter * 2) { short currentSample = audio.data().shortAt(sampleCounter); if (abs(currentSample) > abs(sample)) sample = currentSample; sourceCounter++; } } if (sourceCounter) { outputBuffer[outputCounter++] = (short)sample; sampleCounter++; } // Check if time to flash output buffer if ((!sourceCounter || outputCounter == 512) && outputCounter) { mOutput.add(outputBuffer, outputCounter * 2); outputCounter = 0; } } while (sourceCounter); processed = 0; for (int i=0; i