updated AudioRingBuffer bytes vs samples returns

This commit is contained in:
wangyix 2014-08-08 17:00:39 -07:00
parent f71e1edd30
commit 4ec84b32b0
3 changed files with 97 additions and 104 deletions

View file

@ -20,18 +20,16 @@
AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) :
_frameCapacity(numFramesCapacity),
_sampleCapacity(numFrameSamples * numFramesCapacity),
_isFull(false),
_numFrameSamples(numFrameSamples),
_randomAccessMode(randomAccessMode),
_overflowCount(0)
_frameCapacity(numFramesCapacity),
_sampleCapacity(numFrameSamples * numFramesCapacity),
_bufferLength(numFrameSamples * (numFramesCapacity + 1)),
_numFrameSamples(numFrameSamples),
_randomAccessMode(randomAccessMode),
_overflowCount(0)
{
if (numFrameSamples) {
_buffer = new int16_t[_sampleCapacity];
if (_randomAccessMode) {
memset(_buffer, 0, _sampleCapacity * sizeof(int16_t));
}
_buffer = new int16_t[_bufferLength];
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
_nextOutput = _buffer;
_endOfLastWrite = _buffer;
} else {
@ -53,28 +51,29 @@ void AudioRingBuffer::reset() {
void AudioRingBuffer::resizeForFrameSize(int numFrameSamples) {
delete[] _buffer;
_sampleCapacity = numFrameSamples * _frameCapacity;
_bufferLength = numFrameSamples * (_frameCapacity + 1);
_numFrameSamples = numFrameSamples;
_buffer = new int16_t[_sampleCapacity];
_buffer = new int16_t[_bufferLength];
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
if (_randomAccessMode) {
memset(_buffer, 0, _sampleCapacity * sizeof(int16_t));
memset(_buffer, 0, _bufferLength * sizeof(int16_t));
}
reset();
}
void AudioRingBuffer::clear() {
_isFull = false;
_endOfLastWrite = _buffer;
_nextOutput = _buffer;
}
int AudioRingBuffer::readSamples(int16_t* destination, int maxSamples) {
return readData((char*) destination, maxSamples * sizeof(int16_t));
return readData((char*)destination, maxSamples * sizeof(int16_t)) / sizeof(int16_t);
}
int AudioRingBuffer::readData(char *data, int maxSize) {
// only copy up to the number of samples we have available
int numReadSamples = std::min((int) (maxSize / sizeof(int16_t)), samplesAvailable());
int numReadSamples = std::min((int)(maxSize / sizeof(int16_t)), samplesAvailable());
// If we're in random access mode, then we consider our number of available read samples slightly
// differently. Namely, if anything has been written, we say we have as many samples as they ask for
@ -83,16 +82,16 @@ int AudioRingBuffer::readData(char *data, int maxSize) {
numReadSamples = _endOfLastWrite ? (maxSize / sizeof(int16_t)) : 0;
}
if (_nextOutput + numReadSamples > _buffer + _sampleCapacity) {
if (_nextOutput + numReadSamples > _buffer + _bufferLength) {
// we're going to need to do two reads to get this data, it wraps around the edge
// read to the end of the buffer
int numSamplesToEnd = (_buffer + _sampleCapacity) - _nextOutput;
int numSamplesToEnd = (_buffer + _bufferLength) - _nextOutput;
memcpy(data, _nextOutput, numSamplesToEnd * sizeof(int16_t));
if (_randomAccessMode) {
memset(_nextOutput, 0, numSamplesToEnd * sizeof(int16_t)); // clear it
}
// read the rest from the beginning of the buffer
memcpy(data + (numSamplesToEnd * sizeof(int16_t)), _buffer, (numReadSamples - numSamplesToEnd) * sizeof(int16_t));
if (_randomAccessMode) {
@ -108,22 +107,19 @@ int AudioRingBuffer::readData(char *data, int maxSize) {
// push the position of _nextOutput by the number of samples read
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numReadSamples);
if (numReadSamples > 0) {
_isFull = false;
}
return numReadSamples * sizeof(int16_t);
}
int AudioRingBuffer::writeSamples(const int16_t* source, int maxSamples) {
return writeData((const char*) source, maxSamples * sizeof(int16_t));
int AudioRingBuffer::writeSamples(const int16_t* source, int maxSamples) {
return writeData((const char*)source, maxSamples * sizeof(int16_t)) / sizeof(int16_t);
}
int AudioRingBuffer::writeData(const char* data, int maxSize) {
// make sure we have enough bytes left for this to be the right amount of audio
// otherwise we should not copy that data, and leave the buffer pointers where they are
int samplesToCopy = std::min((int)(maxSize / sizeof(int16_t)), _sampleCapacity);
int samplesRoomFor = _sampleCapacity - samplesAvailable();
if (samplesToCopy > samplesRoomFor) {
// there's not enough room for this write. erase old data to make room for this new data
@ -132,19 +128,16 @@ int AudioRingBuffer::writeData(const char* data, int maxSize) {
_overflowCount++;
qDebug() << "Overflowed ring buffer! Overwriting old data";
}
if (_endOfLastWrite + samplesToCopy <= _buffer + _sampleCapacity) {
if (_endOfLastWrite + samplesToCopy <= _buffer + _bufferLength) {
memcpy(_endOfLastWrite, data, samplesToCopy * sizeof(int16_t));
} else {
int numSamplesToEnd = (_buffer + _sampleCapacity) - _endOfLastWrite;
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
memcpy(_endOfLastWrite, data, numSamplesToEnd * sizeof(int16_t));
memcpy(_buffer, data + (numSamplesToEnd * sizeof(int16_t)), (samplesToCopy - numSamplesToEnd) * sizeof(int16_t));
}
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, samplesToCopy);
if (samplesToCopy > 0 && _endOfLastWrite == _nextOutput) {
_isFull = true;
}
return samplesToCopy * sizeof(int16_t);
}
@ -158,61 +151,52 @@ const int16_t& AudioRingBuffer::operator[] (const int index) const {
}
void AudioRingBuffer::shiftReadPosition(unsigned int numSamples) {
if (numSamples > 0) {
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples);
_isFull = false;
}
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples);
}
int AudioRingBuffer::samplesAvailable() const {
if (!_endOfLastWrite) {
return 0;
}
if (_isFull) {
return _sampleCapacity;
}
int sampleDifference = _endOfLastWrite - _nextOutput;
if (sampleDifference < 0) {
sampleDifference += _sampleCapacity;
sampleDifference += _bufferLength;
}
return sampleDifference;
}
int AudioRingBuffer::addSilentFrame(int numSilentSamples) {
int AudioRingBuffer::addSilentSamples(int silentSamples) {
int samplesRoomFor = _sampleCapacity - samplesAvailable();
if (numSilentSamples > samplesRoomFor) {
if (silentSamples > samplesRoomFor) {
// there's not enough room for this write. write as many silent samples as we have room for
numSilentSamples = samplesRoomFor;
silentSamples = samplesRoomFor;
qDebug() << "Dropping some silent samples to prevent ring buffer overflow";
}
// memset zeroes into the buffer, accomodate a wrap around the end
// push the _endOfLastWrite to the correct spot
if (_endOfLastWrite + numSilentSamples <= _buffer + _sampleCapacity) {
memset(_endOfLastWrite, 0, numSilentSamples * sizeof(int16_t));
if (_endOfLastWrite + silentSamples <= _buffer + _bufferLength) {
memset(_endOfLastWrite, 0, silentSamples * sizeof(int16_t));
} else {
int numSamplesToEnd = (_buffer + _sampleCapacity) - _endOfLastWrite;
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
memset(_endOfLastWrite, 0, numSamplesToEnd * sizeof(int16_t));
memset(_buffer, 0, (numSilentSamples - numSamplesToEnd) * sizeof(int16_t));
}
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numSilentSamples);
if (numSilentSamples > 0 && _nextOutput == _endOfLastWrite) {
_isFull = true;
memset(_buffer, 0, (silentSamples - numSamplesToEnd) * sizeof(int16_t));
}
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, silentSamples);
return numSilentSamples * sizeof(int16_t);
return silentSamples;
}
int16_t* AudioRingBuffer::shiftedPositionAccomodatingWrap(int16_t* position, int numSamplesShift) const {
if (numSamplesShift > 0 && position + numSamplesShift >= _buffer + _sampleCapacity) {
if (numSamplesShift > 0 && position + numSamplesShift >= _buffer + _bufferLength) {
// this shift will wrap the position around to the beginning of the ring
return position + numSamplesShift - _sampleCapacity;
return position + numSamplesShift - _bufferLength;
} else if (numSamplesShift < 0 && position + numSamplesShift < _buffer) {
// this shift will go around to the end of the ring
return position + numSamplesShift + _sampleCapacity;
return position + numSamplesShift + _bufferLength;
} else {
return position + numSamplesShift;
}
@ -221,22 +205,22 @@ int16_t* AudioRingBuffer::shiftedPositionAccomodatingWrap(int16_t* position, int
float AudioRingBuffer::getFrameLoudness(const int16_t* frameStart) const {
float loudness = 0.0f;
const int16_t* sampleAt = frameStart;
const int16_t* _bufferLastAt = _buffer + _sampleCapacity - 1;
const int16_t* _bufferLastAt = _buffer + _bufferLength - 1;
for (int i = 0; i < _numFrameSamples; ++i) {
loudness += fabsf(*sampleAt);
sampleAt = sampleAt == _bufferLastAt ? _buffer : sampleAt + 1;
}
loudness /= _numFrameSamples;
loudness /= MAX_SAMPLE_VALUE;
return loudness;
}
float AudioRingBuffer::getNextOutputFrameLoudness() const {
return getFrameLoudness(_nextOutput);
return loudness;
}
float AudioRingBuffer::getFrameLoudness(ConstIterator frameStart) const {
return getFrameLoudness(&(*frameStart));
}
float AudioRingBuffer::getNextOutputFrameLoudness() const {
return getFrameLoudness(_nextOutput);
}

View file

@ -30,7 +30,7 @@ const int NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL = 512;
const int NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL / sizeof(int16_t);
const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL
/ (float) SAMPLE_RATE) * USECS_PER_SECOND);
/ (float)SAMPLE_RATE) * USECS_PER_SECOND);
const int MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
const int MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
@ -44,33 +44,33 @@ public:
void reset();
void resizeForFrameSize(int numFrameSamples);
void clear();
int getSampleCapacity() const { return _sampleCapacity; }
int getFrameCapacity() const { return _frameCapacity; }
int readSamples(int16_t* destination, int maxSamples);
int writeSamples(const int16_t* source, int maxSamples);
int readData(char* data, int maxSize);
int writeData(const char* data, int maxSize);
int16_t& operator[](const int index);
const int16_t& operator[] (const int index) const;
void shiftReadPosition(unsigned int numSamples);
float getNextOutputFrameLoudness() const;
int samplesAvailable() const;
int framesAvailable() const { return samplesAvailable() / _numFrameSamples; }
int getNumFrameSamples() const { return _numFrameSamples; }
int getOverflowCount() const { return _overflowCount; } /// how many times has the ring buffer has overwritten old data
int addSilentFrame(int numSilentSamples);
int addSilentSamples(int samples);
private:
float getFrameLoudness(const int16_t* frameStart) const;
@ -79,12 +79,12 @@ protected:
// disallow copying of AudioRingBuffer objects
AudioRingBuffer(const AudioRingBuffer&);
AudioRingBuffer& operator= (const AudioRingBuffer&);
int16_t* shiftedPositionAccomodatingWrap(int16_t* position, int numSamplesShift) const;
int _frameCapacity;
int _sampleCapacity;
bool _isFull;
int _bufferLength; // actual length of _buffer: will be one frame larger than _sampleCapacity
int _numFrameSamples;
int16_t* _nextOutput;
int16_t* _endOfLastWrite;
@ -97,13 +97,13 @@ public:
class ConstIterator { //public std::iterator < std::forward_iterator_tag, int16_t > {
public:
ConstIterator()
: _capacity(0),
: _bufferLength(0),
_bufferFirst(NULL),
_bufferLast(NULL),
_at(NULL) {}
ConstIterator(int16_t* bufferFirst, int capacity, int16_t* at)
: _capacity(capacity),
: _bufferLength(capacity),
_bufferFirst(bufferFirst),
_bufferLast(bufferFirst + capacity - 1),
_at(at) {}
@ -113,7 +113,7 @@ public:
const int16_t& operator*() { return *_at; }
ConstIterator& operator=(const ConstIterator& rhs) {
_capacity = rhs._capacity;
_bufferLength = rhs._bufferLength;
_bufferFirst = rhs._bufferFirst;
_bufferLast = rhs._bufferLast;
_at = rhs._at;
@ -147,40 +147,50 @@ public:
}
ConstIterator operator+(int i) {
return ConstIterator(_bufferFirst, _capacity, atShiftedBy(i));
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
}
ConstIterator operator-(int i) {
return ConstIterator(_bufferFirst, _capacity, atShiftedBy(-i));
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
}
void readSamples(int16_t* dest, int numSamples) {
int16_t* at = _at;
for (int i = 0; i < numSamples; i++) {
*dest = *(*this);
*dest = *at;
++dest;
++(*this);
at = (at == _bufferLast) ? _bufferFirst : at + 1;
}
}
void readSamplesWithFade(int16_t* dest, int numSamples, float fade) {
int16_t* at = _at;
for (int i = 0; i < numSamples; i++) {
*dest = (float)*at * fade;
++dest;
at = (at == _bufferLast) ? _bufferFirst : at + 1;
}
}
private:
int16_t* atShiftedBy(int i) {
i = (_at - _bufferFirst + i) % _capacity;
i = (_at - _bufferFirst + i) % _bufferLength;
if (i < 0) {
i += _capacity;
i += _bufferLength;
}
return _bufferFirst + i;
}
private:
int _capacity;
int _bufferLength;
int16_t* _bufferFirst;
int16_t* _bufferLast;
int16_t* _at;
};
ConstIterator nextOutput() const { return ConstIterator(_buffer, _sampleCapacity, _nextOutput); }
ConstIterator nextOutput() const { return ConstIterator(_buffer, _bufferLength, _nextOutput); }
float getFrameLoudness(ConstIterator frameStart) const;
};
#endif // hifi_AudioRingBuffer_h
#endif // hifi_AudioRingBuffer_h

View file

@ -27,28 +27,28 @@ void AudioRingBufferTests::runAllTests() {
int16_t readData[10000];
int readIndexAt;
AudioRingBuffer ringBuffer(10, false, 10); // makes buffer of 100 int16_t samples
for (int T = 0; T < 300; T++) {
writeIndexAt = 0;
readIndexAt = 0;
// write 73 samples, 73 samples in buffer
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 73) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 73);
assertBufferSize(ringBuffer, 73);
// read 43 samples, 30 samples in buffer
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 43) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 43);
assertBufferSize(ringBuffer, 30);
// write 70 samples, 100 samples in buffer (full)
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 70) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 70);
assertBufferSize(ringBuffer, 100);
// read 100 samples, 0 samples in buffer (empty)
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 100) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 100);
assertBufferSize(ringBuffer, 0);
@ -65,15 +65,15 @@ void AudioRingBufferTests::runAllTests() {
readIndexAt = 0;
// write 59 samples, 59 samples in buffer
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 59) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 59);
assertBufferSize(ringBuffer, 59);
// write 99 samples, 100 samples in buffer
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 99) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 99);
assertBufferSize(ringBuffer, 100);
// read 100 samples, 0 samples in buffer
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 100) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 100);
assertBufferSize(ringBuffer, 0);
// verify 100 samples of read data
@ -88,23 +88,23 @@ void AudioRingBufferTests::runAllTests() {
readIndexAt = 0;
// write 77 samples, 77 samples in buffer
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 77) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 77);
assertBufferSize(ringBuffer, 77);
// write 24 samples, 100 samples in buffer (overwrote one sample: "0")
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 24) / sizeof(int16_t);
writeIndexAt += ringBuffer.writeSamples(&writeData[writeIndexAt], 24);
assertBufferSize(ringBuffer, 100);
// write 29 silent samples, 100 samples in buffer, make sure non were added
int samplesWritten;
if ((samplesWritten = ringBuffer.addSilentFrame(29)) != 0) {
qDebug("addSilentFrame(29) incorrect! Expected: 0 Actual: %d", samplesWritten);
if ((samplesWritten = ringBuffer.addSilentSamples(29)) != 0) {
qDebug("addSilentSamples(29) incorrect! Expected: 0 Actual: %d", samplesWritten);
return;
}
assertBufferSize(ringBuffer, 100);
// read 3 samples, 97 samples in buffer (expect to read "1", "2", "3")
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3);
for (int i = 0; i < 3; i++) {
if (readData[i] != i + 1) {
qDebug("Second readData[%d] incorrect! Expcted: %d Actual: %d", i, i + 1, readData[i]);
@ -114,14 +114,14 @@ void AudioRingBufferTests::runAllTests() {
assertBufferSize(ringBuffer, 97);
// write 4 silent samples, 100 samples in buffer
if ((samplesWritten = ringBuffer.addSilentFrame(4) / sizeof(int16_t)) != 3) {
qDebug("addSilentFrame(4) incorrect! Exptected: 3 Actual: %d", samplesWritten);
if ((samplesWritten = ringBuffer.addSilentSamples(4)) != 3) {
qDebug("addSilentSamples(4) incorrect! Exptected: 3 Actual: %d", samplesWritten);
return;
}
assertBufferSize(ringBuffer, 100);
// read back 97 samples (the non-silent samples), 3 samples in buffer (expect to read "4" thru "100")
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 97) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 97);
for (int i = 3; i < 100; i++) {
if (readData[i] != i + 1) {
qDebug("third readData[%d] incorrect! Expcted: %d Actual: %d", i, i + 1, readData[i]);
@ -131,7 +131,7 @@ void AudioRingBufferTests::runAllTests() {
assertBufferSize(ringBuffer, 3);
// read back 3 silent samples, 0 samples in buffer
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3) / sizeof(int16_t);
readIndexAt += ringBuffer.readSamples(&readData[readIndexAt], 3);
for (int i = 100; i < 103; i++) {
if (readData[i] != 0) {
qDebug("Fourth readData[%d] incorrect! Expcted: %d Actual: %d", i, 0, readData[i]);
@ -143,4 +143,3 @@ void AudioRingBufferTests::runAllTests() {
qDebug() << "PASSED";
}