mv localInjectorsBuffer to float-based localInjectorsStream

The localInjectorsBuffer is based on
AudioRingBuffer, which only accounts for int16_t.
Local injectors are mixed, and so they can exceed
std::numeric_limits<int16_t> before limiting.
This will allow them to remain as float until
limiting (in the device callback) - once the new
stream is implemented.
This commit is contained in:
Zach Pomerantz 2017-01-19 15:17:07 -05:00
parent c5415f9624
commit 4f7f3c2a60
2 changed files with 35 additions and 32 deletions

View file

@ -132,7 +132,7 @@ AudioClient::AudioClient() :
_loopbackAudioOutput(NULL), _loopbackAudioOutput(NULL),
_loopbackOutputDevice(NULL), _loopbackOutputDevice(NULL),
_inputRingBuffer(0), _inputRingBuffer(0),
_localInjectorsBuffer(0), _localInjectorsStream(0),
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES), _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES),
_isStereoInput(false), _isStereoInput(false),
_outputStarveDetectionStartTimeMsec(0), _outputStarveDetectionStartTimeMsec(0),
@ -154,7 +154,7 @@ AudioClient::AudioClient() :
_localAudioThread(this), _localAudioThread(this),
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT), _audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
_outgoingAvatarAudioSequenceNumber(0), _outgoingAvatarAudioSequenceNumber(0),
_audioOutputIODevice(_localInjectorsBuffer, _receivedAudioStream, this), _audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
_stats(&_receivedAudioStream), _stats(&_receivedAudioStream),
_inputGate(), _inputGate(),
_positionGetter(DEFAULT_POSITION_GETTER), _positionGetter(DEFAULT_POSITION_GETTER),
@ -1072,7 +1072,7 @@ void AudioClient::prepareLocalAudioInjectors() {
return; return;
} }
int bufferCapacity = _localInjectorsBuffer.getSampleCapacity(); int bufferCapacity = _localInjectorsStream.getSampleCapacity();
if (_localToOutputResampler) { if (_localToOutputResampler) {
// avoid overwriting the buffer // avoid overwriting the buffer
bufferCapacity -= bufferCapacity -=
@ -1086,7 +1086,7 @@ void AudioClient::prepareLocalAudioInjectors() {
// lock for every write to avoid locking out the device callback // lock for every write to avoid locking out the device callback
Lock lock(_localAudioMutex); Lock lock(_localAudioMutex);
samplesNeeded = bufferCapacity - _localInjectorsBuffer.samplesAvailable(); samplesNeeded = bufferCapacity - _localInjectorsStream.samplesAvailable();
if (samplesNeeded <= 0) { if (samplesNeeded <= 0) {
break; break;
} }
@ -1101,22 +1101,20 @@ void AudioClient::prepareLocalAudioInjectors() {
_localReverb.render(_localMixBuffer, _localMixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); _localReverb.render(_localMixBuffer, _localMixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
} }
convertToScratch(_localScratchBuffer, _localMixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
int samples; int samples;
if (_localToOutputResampler) { if (_localToOutputResampler) {
// resample to output sample rate // resample to output sample rate
int frames = _localToOutputResampler->render(_localScratchBuffer, _localOutputScratchBuffer, int frames = _localToOutputResampler->render(_localMixBuffer, _localOutputMixBuffer,
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
// write to local injectors' ring buffer // write to local injectors' ring buffer
samples = frames * AudioConstants::STEREO; samples = frames * AudioConstants::STEREO;
_localInjectorsBuffer.writeSamples(_localOutputScratchBuffer, samples); _localInjectorsStream.writeSamples(_localOutputMixBuffer, samples);
} else { } else {
// write to local injectors' ring buffer // write to local injectors' ring buffer
samples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; samples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
_localInjectorsBuffer.writeSamples(_localScratchBuffer, _localInjectorsStream.writeSamples(_localMixBuffer,
AudioConstants::NETWORK_FRAME_SAMPLES_STEREO); AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
} }
@ -1440,8 +1438,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
delete[] _outputScratchBuffer; delete[] _outputScratchBuffer;
_outputScratchBuffer = NULL; _outputScratchBuffer = NULL;
delete[] _localOutputScratchBuffer; delete[] _localOutputMixBuffer;
_localOutputScratchBuffer = NULL; _localOutputMixBuffer = NULL;
} }
if (_networkToOutputResampler) { if (_networkToOutputResampler) {
@ -1501,8 +1499,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
_outputPeriod = periodSampleSize * 2; _outputPeriod = periodSampleSize * 2;
_outputMixBuffer = new float[_outputPeriod]; _outputMixBuffer = new float[_outputPeriod];
_outputScratchBuffer = new int16_t[_outputPeriod]; _outputScratchBuffer = new int16_t[_outputPeriod];
_localOutputScratchBuffer = new int16_t[_outputPeriod]; _localOutputMixBuffer = new float[_outputPeriod];
_localInjectorsBuffer.resizeForFrameSize(_outputPeriod * 2); _localInjectorsStream.resizeForFrameSize(_outputPeriod * 2);
qCDebug(audioclient) << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / AudioConstants::SAMPLE_SIZE / (float)deviceFrameSize << qCDebug(audioclient) << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / AudioConstants::SAMPLE_SIZE / (float)deviceFrameSize <<
"requested bytes:" << requestedSize << "actual bytes:" << _audioOutput->bufferSize() << "requested bytes:" << requestedSize << "actual bytes:" << _audioOutput->bufferSize() <<
@ -1630,22 +1628,16 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
samplesRequested = networkSamplesPopped; samplesRequested = networkSamplesPopped;
} }
int injectorSamplesPopped; int injectorSamplesPopped = 0;
{ {
Lock lock(_audio->_localAudioMutex); Lock lock(_audio->_localAudioMutex);
if ((injectorSamplesPopped = _localInjectorsBuffer.readSamples(scratchBuffer, samplesRequested)) > 0) { if (_audio->_shouldEchoToServer) {
qCDebug(audiostream, "Read %d samples from injectors (%d available, %d requested)", injectorSamplesPopped, _localInjectorsBuffer.samplesAvailable(), samplesRequested); // omit local audio, it should be echoed
_localInjectorsStream.skipSamples(samplesRequested);
if (_audio->_shouldEchoToServer) { } else {
// omit local audio, it should be echoed bool append = networkSamplesPopped > 0;
injectorSamplesPopped = 0; if ((injectorSamplesPopped = _localInjectorsStream.readSamples(mixBuffer, samplesRequested, append)) > 0) {
} else if (networkSamplesPopped == 0) { qCDebug(audiostream, "Read %d samples from injectors (%d available, %d requested)", injectorSamplesPopped, _localInjectorsStream.samplesAvailable(), samplesRequested);
convertToMix(mixBuffer, scratchBuffer, injectorSamplesPopped);
} else {
// add to mix buffer (float)
for (int i = 0; i < injectorSamplesPopped; i++) {
mixBuffer[i] += (float)scratchBuffer[i] * (1 / 32768.0f);
}
} }
} }
} }

View file

@ -69,6 +69,17 @@ class QIODevice;
class Transform; class Transform;
class NLPacket; class NLPacket;
class LocalInjectorsStream {
public:
LocalInjectorsStream(int numFrameSamples);
int getSampleCapacity() { return 0; };
int samplesAvailable() { return 0; }
int writeSamples(const float*, int numSamples) { return 0; }
void resizeForFrameSize(int numFrameSamples) {}
int skipSamples(int numSamples) { return 0; }
int readSamples(float* mixBuffer, int numSamples, bool append) { return 0; }
};
class AudioInjectorsThread : public QThread { class AudioInjectorsThread : public QThread {
Q_OBJECT Q_OBJECT
@ -97,9 +108,9 @@ public:
class AudioOutputIODevice : public QIODevice { class AudioOutputIODevice : public QIODevice {
public: public:
AudioOutputIODevice(AudioRingBuffer& localInjectorsBuffer, MixedProcessedAudioStream& receivedAudioStream, AudioOutputIODevice(LocalInjectorsStream& localInjectorsStream, MixedProcessedAudioStream& receivedAudioStream,
AudioClient* audio) : AudioClient* audio) :
_localInjectorsBuffer(localInjectorsBuffer), _receivedAudioStream(receivedAudioStream), _localInjectorsStream(localInjectorsStream), _receivedAudioStream(receivedAudioStream),
_audio(audio), _unfulfilledReads(0) {} _audio(audio), _unfulfilledReads(0) {}
void start() { open(QIODevice::ReadOnly | QIODevice::Unbuffered); } void start() { open(QIODevice::ReadOnly | QIODevice::Unbuffered); }
@ -108,7 +119,7 @@ public:
qint64 writeData(const char * data, qint64 maxSize) override { return 0; } qint64 writeData(const char * data, qint64 maxSize) override { return 0; }
int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; } int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; }
private: private:
AudioRingBuffer& _localInjectorsBuffer; LocalInjectorsStream& _localInjectorsStream;
MixedProcessedAudioStream& _receivedAudioStream; MixedProcessedAudioStream& _receivedAudioStream;
AudioClient* _audio; AudioClient* _audio;
int _unfulfilledReads; int _unfulfilledReads;
@ -277,7 +288,7 @@ private:
QAudioOutput* _loopbackAudioOutput; QAudioOutput* _loopbackAudioOutput;
QIODevice* _loopbackOutputDevice; QIODevice* _loopbackOutputDevice;
AudioRingBuffer _inputRingBuffer; AudioRingBuffer _inputRingBuffer;
AudioRingBuffer _localInjectorsBuffer; LocalInjectorsStream _localInjectorsStream;
MixedProcessedAudioStream _receivedAudioStream; MixedProcessedAudioStream _receivedAudioStream;
bool _isStereoInput; bool _isStereoInput;
@ -322,7 +333,7 @@ private:
// for local audio (used by audio injectors thread) // for local audio (used by audio injectors thread)
float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC]; int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
int16_t* _localOutputScratchBuffer { NULL }; float* _localOutputMixBuffer { NULL };
AudioInjectorsThread _localAudioThread; AudioInjectorsThread _localAudioThread;
Mutex _localAudioMutex; Mutex _localAudioMutex;