/* 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 "../engine_config.h" #include "../helper/HL_Exception.h" #include "../helper/HL_Log.h" #include #include #include "Audio_Mixer.h" #define LOG_SUBSYSTEM "audio" 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) { Lock l(mMutex); for (int i = 0; i < AUDIO_MIX_CHANNEL_COUNT; i++) { Stream& c = mChannelList[i]; if (c.active() && c.context() == channel) { c.setActive(false); // stream is not active anymore c.data().clear(); // clear data mActiveCounter--; } } } void Mixer::clear(void* context, unsigned ssrc) { Lock l(mMutex); for (int i = 0; i < AUDIO_MIX_CHANNEL_COUNT; i++) { Stream& c = mChannelList[i]; if (c.active() && c.context() == context && c.ssrc() == ssrc) { c.setActive(false); c.data().clear(); mActiveCounter--; } } } Mixer::Stream* Mixer::allocateChannel(void* context, unsigned ssrc) { // Allocate new channel Lock l(mMutex); Stream* channel; for (int i = 0; i < AUDIO_MIX_CHANNEL_COUNT; i++) { channel = &mChannelList[i]; if (!channel->active()) { 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); Lock l(mMutex); int i; // Locate a channel Stream* channel = NULL; for (i = 0; i < AUDIO_MIX_CHANNEL_COUNT && !channel; i++) { Stream& c = mChannelList[i]; if (c.active() && c.context() == context && c.ssrc() == ssrc) channel = &c; } if (!channel) { channel = allocateChannel(context, ssrc); if (!channel) throw Exception(ERR_MIXER_OVERFLOW); } channel->addPcm(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); Lock l(mMutex); int i; // Locate a channel Stream* channel = NULL; for (i = 0; i < AUDIO_MIX_CHANNEL_COUNT && !channel; i++) { Stream& c = mChannelList[i]; if (c.active() && c.context() == context && c.ssrc() == ssrc) channel = &c; } if (!channel) { channel = allocateChannel(context, ssrc); if (!channel) throw Exception(ERR_MIXER_OVERFLOW); } channel->addPcm(rate, w.data(), w.filled()); // ICELogSpecial(<<"Mixer stream " << int(this) << " has " << w.filled() << " bytes"); } void Mixer::mix() { Lock l(mMutex); // 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 < AUDIO_MIX_CHANNEL_COUNT; i++) if (mChannelList[i].active()) channelList[activeCounter++] = &mChannelList[i]; // No active channels - nothing to mix - exit if (!activeCounter) { // ICELogDebug(<< "No active channel"); return; } // Optimized versions for 1& 2 active channels if (activeCounter == 1) { // Copy much samples as we have Stream& audio = *channelList[0]; // Copy the decoded data mOutput.add(audio.data().data(), audio.data().filled()); // Erase copied audio samples audio.data().erase(audio.data().filled()); // ICELogSpecial(<<"Length of mixer stream " << audio.data().filled()); } else if (activeCounter == 2) { Stream& audio1 = *channelList[0]; Stream& audio2 = *channelList[1]; int filled1 = audio1.data().filled() / 2, filled2 = audio2.data().filled() / 2; int available = filled1 > 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 < available; i++) { short sample1 = filled1 > 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 < activeCounter; i++) { Stream& audio = *channelList[i]; processed++; if (audio.data().filled() > (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 < activeCounter; i++) { Stream& audio = *channelList[i]; audio.data().erase(sampleCounter * 2); } } } int Mixer::getPcm(void* outputData, int outputLength) { Lock l(mMutex); if (mOutput.filled() < outputLength) mix(); // ICELogSpecial(<<"Mixer has " << mOutput.filled() << " available bytes"); memset(outputData, 0, outputLength); return mOutput.read(outputData, outputLength); } int Mixer::mixAndGetPcm(Audio::DataWindow& output) { Lock l(mMutex); // Mix mix(); size_t avail = mOutput.filled(); if (!avail) { output.setFilled(0); return 0; } // Make sure output has enough space (setCapacity only ever grows the window) if (output.capacity() < avail) output.setCapacity(avail); // Read mixed data to output and publish the real byte count size_t got = mOutput.read(output.mutableData(), avail); output.setFilled(got); return static_cast(got); } int Mixer::available() { return mOutput.filled(); }