fixed bug in Audio.cpp where numSilentSamples was written to wrong place in packet

added more debug stuff, other minor changes and fixes
This commit is contained in:
wangyix 2014-06-20 14:43:18 -07:00
parent 435b5094a0
commit a5457eb86b
7 changed files with 63 additions and 32 deletions

View file

@ -119,15 +119,14 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(AABox* checkSourceZone, A
} }
void AudioMixerClientData::pushBuffersAfterFrameSend() { void AudioMixerClientData::pushBuffersAfterFrameSend() {
QList<PositionalAudioRingBuffer*>::iterator i = _ringBuffers.begin(); QList<PositionalAudioRingBuffer*>::iterator i = _ringBuffers.begin();
while (i != _ringBuffers.end()) { while (i != _ringBuffers.end()) {
// this was a used buffer, push the output pointer forwards // this was a used buffer, push the output pointer forwards
PositionalAudioRingBuffer* audioBuffer = *i; PositionalAudioRingBuffer* audioBuffer = *i;
if (audioBuffer->willBeAddedToMix()) { if (audioBuffer->willBeAddedToMix()) {
audioBuffer->shiftReadPosition(audioBuffer->isStereo() audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame());
? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
audioBuffer->setWillBeAddedToMix(false); audioBuffer->setWillBeAddedToMix(false);
} else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector } else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector
&& audioBuffer->hasStarted() && audioBuffer->isStarved()) { && audioBuffer->hasStarted() && audioBuffer->isStarved()) {

View file

@ -20,7 +20,7 @@ AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo) :
int AvatarAudioRingBuffer::parseData(const QByteArray& packet) { int AvatarAudioRingBuffer::parseData(const QByteArray& packet) {
_interframeTimeGapHistory.frameReceived(); _interframeTimeGapHistory.frameReceived();
updateDesiredJitterBufferNumSamples(); updateDesiredJitterBufferFrames();
_shouldLoopbackForNode = (packetTypeForPacket(packet) == PacketTypeMicrophoneAudioWithEcho); _shouldLoopbackForNode = (packetTypeForPacket(packet) == PacketTypeMicrophoneAudioWithEcho);
return PositionalAudioRingBuffer::parseData(packet); return PositionalAudioRingBuffer::parseData(packet);

View file

@ -461,8 +461,8 @@ void Audio::handleAudioInput() {
int16_t* inputAudioSamples = new int16_t[inputSamplesRequired]; int16_t* inputAudioSamples = new int16_t[inputSamplesRequired];
_inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired); _inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired);
int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; const int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL;
int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; const int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
// zero out the monoAudioSamples array and the locally injected audio // zero out the monoAudioSamples array and the locally injected audio
memset(networkAudioSamples, 0, numNetworkBytes); memset(networkAudioSamples, 0, numNetworkBytes);
@ -622,6 +622,7 @@ void Audio::handleAudioInput() {
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
if (audioMixer && audioMixer->getActiveSocket()) { if (audioMixer && audioMixer->getActiveSocket()) {
MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar();
glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition();
glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientationInWorldFrame(); glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientationInWorldFrame();
@ -634,12 +635,11 @@ void Audio::handleAudioInput() {
packetType = PacketTypeSilentAudioFrame; packetType = PacketTypeSilentAudioFrame;
// we need to indicate how many silent samples this is to the audio mixer // we need to indicate how many silent samples this is to the audio mixer
audioDataPacket[0] = _isStereoInput networkAudioSamples[0] = numNetworkSamples;
? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
: NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
numAudioBytes = sizeof(int16_t); numAudioBytes = sizeof(int16_t);
} else { } else {
numAudioBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; numAudioBytes = numNetworkBytes;
//_isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL;
if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) {
packetType = PacketTypeMicrophoneAudioWithEcho; packetType = PacketTypeMicrophoneAudioWithEcho;

View file

@ -158,6 +158,7 @@ const int16_t& AudioRingBuffer::operator[] (const int index) const {
void AudioRingBuffer::shiftReadPosition(unsigned int numSamples) { void AudioRingBuffer::shiftReadPosition(unsigned int numSamples) {
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples); _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples);
printf("\n mixed. %d samples remaining\n", samplesAvailable());
} }
unsigned int AudioRingBuffer::samplesAvailable() const { unsigned int AudioRingBuffer::samplesAvailable() const {

View file

@ -32,7 +32,7 @@ const uchar MAX_INJECTOR_VOLUME = 255;
int InjectedAudioRingBuffer::parseData(const QByteArray& packet) { int InjectedAudioRingBuffer::parseData(const QByteArray& packet) {
_interframeTimeGapHistory.frameReceived(); _interframeTimeGapHistory.frameReceived();
updateDesiredJitterBufferNumSamples(); updateDesiredJitterBufferFrames();
// setup a data stream to read from this packet // setup a data stream to read from this packet
QDataStream packetStream(packet); QDataStream packetStream(packet);

View file

@ -33,6 +33,10 @@ InterframeTimeGapHistory::InterframeTimeGapHistory()
} }
void InterframeTimeGapHistory::frameReceived() { void InterframeTimeGapHistory::frameReceived() {
static QQueue<quint64> gaps;
static quint64 gapsSum = 0;
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
// make sure this isn't the first time frameReceived() is called, meaning there's actually a gap to calculate. // make sure this isn't the first time frameReceived() is called, meaning there's actually a gap to calculate.
@ -87,9 +91,9 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
_shouldOutputStarveDebug(true), _shouldOutputStarveDebug(true),
_isStereo(isStereo), _isStereo(isStereo),
_listenerUnattenuatedZone(NULL), _listenerUnattenuatedZone(NULL),
_desiredJitterBufferNumSamples(getNumSamplesPerFrame()) _desiredJitterBufferFrames(1),
_currentJitterBufferFrames(0)
{ {
} }
int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
@ -114,10 +118,15 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
if (numSilentSamples > 0) { if (numSilentSamples > 0) {
addSilentFrame(numSilentSamples); addSilentFrame(numSilentSamples);
} }
printf("\nparsed silent packet of %d samples\n", numSilentSamples);
} else { } else {
// there is audio data to read // there is audio data to read
readBytes += writeData(packet.data() + readBytes, packet.size() - readBytes); int dataBytes = writeData(packet.data() + readBytes, packet.size() - readBytes);
readBytes += dataBytes;
printf("\nparsed packet of %d data bytes\n", dataBytes);
} }
printf("%d samples available\n", samplesAvailable());
return readBytes; return readBytes;
} }
@ -166,40 +175,58 @@ void PositionalAudioRingBuffer::updateNextOutputTrailingLoudness() {
bool PositionalAudioRingBuffer::shouldBeAddedToMix() { bool PositionalAudioRingBuffer::shouldBeAddedToMix() {
int samplesPerFrame = getNumSamplesPerFrame(); int samplesPerFrame = getSamplesPerFrame();
int currentJitterBufferSamples = 3 * samplesPerFrame; //_currentJitterBufferFrames * samplesPerFrame;
//printf("\nsamples available: %d frames available: %d\n", samplesAvailable(), samplesAvailable() / samplesPerFrame);
if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + currentJitterBufferSamples)) {
if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + _desiredJitterBufferNumSamples)) { //printf("\nMIXING DELAYED! waiting for jitter buffer to fill after being starved\n");
//printf("samples available: %d frames available: %d\n", samplesAvailable(), samplesAvailable() / samplesPerFrame);
// if the buffer was starved and hasn't filled back up all the way, don't mix yet
if (_shouldOutputStarveDebug) { if (_shouldOutputStarveDebug) {
_shouldOutputStarveDebug = false; _shouldOutputStarveDebug = false;
} }
return false; return false;
} else if (samplesAvailable() < samplesPerFrame) { } else if (samplesAvailable() < samplesPerFrame) {
//printf("\nMIXING DELAYED! jitter buffer is starved!!!\n");
//printf("samples available: %d frames available: %d\n", samplesAvailable(), samplesAvailable() / samplesPerFrame);
// if the buffer doesn't have a full frame of samples for mixing, it is starved
_isStarved = true; _isStarved = true;
// reset our _shouldOutputStarveDebug to true so the next is printed // reset our _shouldOutputStarveDebug to true so the next is printed
_shouldOutputStarveDebug = true; _shouldOutputStarveDebug = true;
// if buffer was starved, we've effectively increased the jitter buffer by one frame
// by "holding back" this ring buffer's contents until the next client frame is prepared.
_currentJitterBufferFrames++;
//printf("jbuffer size increased: new size: %d\n", _currentJitterBufferFrames);
return false; return false;
} else {
// good buffer, add this to the mix
_isStarved = false;
// since we've read data from ring buffer at least once - we've started
_hasStarted = true;
return true;
} }
//printf("WILL MIX\n");
return false; // good buffer, add this to the mix
_isStarved = false;
// since we've read data from ring buffer at least once - we've started
_hasStarted = true;
return true;
} }
void PositionalAudioRingBuffer::updateDesiredJitterBufferNumSamples() { void PositionalAudioRingBuffer::updateDesiredJitterBufferFrames() {
const float USECS_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * USECS_PER_SECOND / (float)SAMPLE_RATE; const float USECS_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * USECS_PER_SECOND / (float)SAMPLE_RATE;
if (_interframeTimeGapHistory.hasNewWindowMaxGapAvailable()) { if (_interframeTimeGapHistory.hasNewWindowMaxGapAvailable()) {
int desiredJitterBufferNumFrames = (int)((float)_interframeTimeGapHistory.getWindowMaxGap() / USECS_PER_FRAME + 0.5f); _desiredJitterBufferFrames = ceilf((float)_interframeTimeGapHistory.getWindowMaxGap() / USECS_PER_FRAME);
_desiredJitterBufferNumSamples = desiredJitterBufferNumFrames * getNumSamplesPerFrame(); if (_desiredJitterBufferFrames < 1) {
_desiredJitterBufferFrames = 1;
}
} }
} }

View file

@ -29,6 +29,7 @@ public:
void frameReceived(); void frameReceived();
bool hasNewWindowMaxGapAvailable() const { return _newWindowMaxGapAvailable; } bool hasNewWindowMaxGapAvailable() const { return _newWindowMaxGapAvailable; }
quint64 peekWindowMaxGap() const { return _windowMaxGap; }
quint64 getWindowMaxGap(); quint64 getWindowMaxGap();
private: private:
@ -75,14 +76,14 @@ public:
AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; } AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; }
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; } void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
int getNumSamplesPerFrame() const { return _isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; } int getSamplesPerFrame() const { return _isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; }
protected: protected:
// disallow copying of PositionalAudioRingBuffer objects // disallow copying of PositionalAudioRingBuffer objects
PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); PositionalAudioRingBuffer(const PositionalAudioRingBuffer&);
PositionalAudioRingBuffer& operator= (const PositionalAudioRingBuffer&); PositionalAudioRingBuffer& operator= (const PositionalAudioRingBuffer&);
void updateDesiredJitterBufferNumSamples(); void updateDesiredJitterBufferFrames();
PositionalAudioRingBuffer::Type _type; PositionalAudioRingBuffer::Type _type;
glm::vec3 _position; glm::vec3 _position;
@ -96,7 +97,10 @@ protected:
AABox* _listenerUnattenuatedZone; AABox* _listenerUnattenuatedZone;
InterframeTimeGapHistory _interframeTimeGapHistory; InterframeTimeGapHistory _interframeTimeGapHistory;
int _desiredJitterBufferNumSamples; int _desiredJitterBufferFrames;
int _currentJitterBufferFrames;
quint64 _lastMixTime;
}; };
#endif // hifi_PositionalAudioRingBuffer_h #endif // hifi_PositionalAudioRingBuffer_h