mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 13:21:13 +00:00
Removed prebuffer code from Player -- let the Stream worry about that.
This commit is contained in:
parent
99f3c25a13
commit
6ec4418cfd
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user