Removed prebuffer code from Player -- let the Stream worry about that.

This commit is contained in:
casey langen 2017-01-01 16:43:24 -08:00
parent 99f3c25a13
commit 6ec4418cfd
4 changed files with 62 additions and 74 deletions

View File

@ -121,7 +121,7 @@ Player::Player(
std::shared_ptr<IOutput> output,
DestroyMode destroyMode,
EventListener *listener)
: state(Player::Precache)
: state(Player::Idle)
, url(url)
, currentPosition(0)
, output(output)
@ -262,17 +262,10 @@ void musik::core::audio::playerThreadLoop(Player* player) {
l->OnPlayerPrepared(player);
}
/* precache until buffers are full */
bool keepPrecaching = true;
while (player->State() == Player::Precache && keepPrecaching) {
keepPrecaching = player->PreBuffer();
}
/* wait until we enter the Playing or Quit state; we may still
be in the Precache state. */
/* wait until we enter the Playing or Quit state */
{
std::unique_lock<std::mutex> lock(player->queueMutex);
while (player->state == Player::Precache) {
while (player->state == Player::Idle) {
player->writeToOutputCondition.wait(lock);
}
}
@ -307,26 +300,13 @@ void musik::core::audio::playerThreadLoop(Player* player) {
}
player->stream->SetPosition(position);
{
std::unique_lock<std::mutex> lock(player->queueMutex);
player->prebufferQueue.clear();
}
}
/* let's see if we can find some samples to play */
if (!buffer) {
std::unique_lock<std::mutex> lock(player->queueMutex);
/* the buffer queue may already have some available if it was prefetched. */
if (!player->prebufferQueue.empty()) {
buffer = player->prebufferQueue.front();
player->prebufferQueue.pop_front();
}
/* otherwise, we need to grab a buffer from the stream and add it to the queue */
else {
buffer = player->stream->GetNextProcessedOutputBuffer();
}
buffer = player->stream->GetNextProcessedOutputBuffer();
/* lock it down until it's processed */
if (buffer) {
@ -447,22 +427,6 @@ void Player::ReleaseAllBuffers() {
this->lockedBuffers.empty();
}
bool Player::PreBuffer() {
/* don't prebuffer if the buffer is already full */
if (this->prebufferQueue.size() < MAX_PREBUFFER_QUEUE_COUNT) {
BufferPtr newBuffer = this->stream->GetNextProcessedOutputBuffer();
if (newBuffer) {
std::unique_lock<std::mutex> lock(this->queueMutex);
this->prebufferQueue.push_back(newBuffer);
}
return true;
}
return false;
}
bool Player::Exited() {
std::unique_lock<std::mutex> lock(this->queueMutex);
return (this->state == Player::Quit);

View File

@ -115,13 +115,12 @@ namespace musik { namespace core { namespace audio {
using OutputPtr = std::shared_ptr<musik::core::sdk::IOutput>;
typedef enum {
Precache = 0,
Idle = 0,
Playing = 1,
Quit = 2
} States;
bool Exited();
bool PreBuffer();
int State();
void ReleaseAllBuffers();
ListenerList Listeners();
@ -135,7 +134,6 @@ namespace musik { namespace core { namespace audio {
MixPointList processedMixPoints;
MixPointList mixPointsHitTemp; /* so we don't have to keep alloc'ing it */
BufferList lockedBuffers;
BufferList prebufferQueue;
void UpdateNextMixPointTime();

View File

@ -60,6 +60,7 @@ Stream::Stream(int samplesPerChannel, int bufferCount, unsigned int options)
, decoderSampleRate(0)
, decoderChannels(0)
, decoderSamplePosition(0)
, done(false)
, rawBuffer(nullptr) {
if ((this->options & NoDSP) == 0) {
streams::GetDspPlugins();
@ -116,7 +117,13 @@ bool Stream::OpenStream(std::string uri) {
}
this->decoder = streams::GetDecoderForDataStream(this->dataStream);
return !!this->decoder;
if (this->decoder) {
this->RefillInternalBuffers();
return true;
}
return false;
}
void Stream::OnBufferProcessedByPlayer(BufferPtr buffer) {
@ -126,22 +133,22 @@ void Stream::OnBufferProcessedByPlayer(BufferPtr buffer) {
bool Stream::GetNextBufferFromDecoder() {
BufferPtr buffer = this->decoderBuffer;
/* get a spare buffer, then ask the decoder for some data */
/* ask the decoder for some data */
if (!this->decoder->GetBuffer(buffer.get())) {
return false;
}
/* ensure our internal state is initialized. */
if (!rawBuffer) {
if (!this->rawBuffer) {
this->decoderSampleRate = buffer->SampleRate();
this->decoderChannels = buffer->Channels();
int samplesPerBuffer = samplesPerChannel * decoderChannels;
rawBuffer = new float[bufferCount * samplesPerBuffer];
this->rawBuffer = new float[bufferCount * samplesPerBuffer];
int offset = 0;
for (int i = 0; i < bufferCount; i++) {
this->recycledBuffers.push_back(
Buffer::Create(rawBuffer + offset, samplesPerBuffer));
Buffer::Create(this->rawBuffer + offset, samplesPerBuffer));
offset += samplesPerBuffer;
}
@ -179,15 +186,46 @@ inline BufferPtr Stream::GetEmptyBuffer() {
BufferPtr Stream::GetNextProcessedOutputBuffer() {
BufferPtr currentBuffer;
/* if the buffer fill rate falls below 50%, go ahead
and refill it... */
if (!this->done && this->filledBuffers.size() < this->bufferCount / 2) {
this->RefillInternalBuffers();
}
if (this->filledBuffers.size()) {
currentBuffer = this->filledBuffers.front();
this->filledBuffers.pop_front();
this->ApplyDsp(currentBuffer);
return currentBuffer;
}
/* final remainder */
if (remainder) {
BufferPtr finalBuffer = remainder;
remainder.reset();
this->ApplyDsp(finalBuffer);
return finalBuffer;
}
/* stream is done. */
return BufferPtr();
}
void Stream::RefillInternalBuffers() {
int count = this->bufferCount - this->filledBuffers.size();
/* ensure we have at least BUFFER_COUNT buffers, and that at least a quarter
of them are filled with data! */
while ((int) this->filledBuffers.size() < (this->bufferCount / 4)) {
while (!this->done && count > 0) {
--count;
/* ask the decoder for the next buffer */
if (!GetNextBufferFromDecoder()) {
this->done = true;
break;
}
currentBuffer = this->decoderBuffer;
BufferPtr currentBuffer = this->decoderBuffer;
int floatsPerBuffer = this->samplesPerChannel * currentBuffer->Channels();
@ -212,7 +250,7 @@ BufferPtr Stream::GetNextProcessedOutputBuffer() {
}
else {
continue; /* already consumed all of the decoder buffer. go back
to the top of the loop to get some more data. */
to the top of the loop to get some more data. */
}
}
@ -234,34 +272,19 @@ BufferPtr Stream::GetNextProcessedOutputBuffer() {
COPY_BUFFER(remainder, currentBuffer, currentBuffer->Samples() - offset, offset);
}
}
}
if (this->filledBuffers.size()) {
currentBuffer = this->filledBuffers.front();
this->filledBuffers.pop_front();
void Stream::ApplyDsp(BufferPtr buffer) {
if (this->dsps.size() > 0) {
for (Dsps::iterator dsp = this->dsps.begin(); dsp != this->dsps.end(); ++dsp) {
dspBuffer->CopyFormat(buffer);
dspBuffer->SetPosition(buffer->Position());
/* let DSP plugins process the buffer */
if (this->dsps.size() > 0) {
for (Dsps::iterator dsp = this->dsps.begin(); dsp != this->dsps.end(); ++dsp) {
dspBuffer->CopyFormat(currentBuffer);
dspBuffer->SetPosition(currentBuffer->Position());
if ((*dsp)->Process(currentBuffer.get(), dspBuffer.get())) {
currentBuffer.swap(dspBuffer);
}
if ((*dsp)->Process(buffer.get(), dspBuffer.get())) {
buffer.swap(dspBuffer);
}
}
return currentBuffer;
}
/* final remainder */
if (remainder) {
BufferPtr result = remainder;
remainder.reset();
return result;
}
return BufferPtr();
}
/* marks a used buffer as recycled so it can be re-used later. */

View File

@ -75,6 +75,8 @@ namespace musik { namespace core { namespace audio {
void RecycleBuffer(BufferPtr oldBuffer);
bool GetNextBufferFromDecoder();
BufferPtr GetEmptyBuffer();
void ApplyDsp(BufferPtr buffer);
void RefillInternalBuffers();
typedef std::deque<BufferPtr> BufferList;
typedef std::shared_ptr<IDecoder> DecoderPtr;
@ -97,6 +99,7 @@ namespace musik { namespace core { namespace audio {
unsigned int options;
int samplesPerChannel;
int bufferCount;
bool done;
float* rawBuffer;