bool Player::PreBuffer(){ // But not if buffer is full if(this->totalBufferSize>this->maxBufferSize){ return false; }else{ BufferPtr newBuffer = this->stream->NextBuffer(); if(newBuffer){ boost::mutex::scoped_lock lock(this->mutex); this->bufferQueue.push_back(newBuffer); this->totalBufferSize += newBuffer->Bytes(); this->waitCondition.notify_all(); } return true; } }
void Player::ThreadLoop(){ // First start the stream this->stream = Stream::Create(); if(this->stream->OpenStream(this->url)){ { boost::mutex::scoped_lock lock(this->mutex); // Set the volume in the output this->output->SetVolume(this->volume); } // If it's not started, lets precache bool keepPrecaching(true); while(this->State()==Precache && keepPrecaching){ keepPrecaching = this->PreBuffer(); boost::thread::yield(); } // Lets wait until we are not precaching anymore { boost::mutex::scoped_lock lock(this->mutex); while(this->state==Precache){ this->waitCondition.wait(lock); } } this->PlaybackStarted(this); // Player should be started or quit by now bool finished(false); while(!finished && !this->Exited()){ if(this->setPosition!=-1){ // Set a new position this->output->ClearBuffers(); this->stream->SetPosition(this->setPosition); { boost::mutex::scoped_lock lock(this->mutex); this->bufferQueue.clear(); // this->lockedBuffers.clear(); this->setPosition = -1; this->totalBufferSize = 0; } } this->output->ReleaseBuffers(); // Get a buffer, either from the bufferQueue, or from the stream BufferPtr buffer; if(!this->BufferQueueEmpty()){ boost::mutex::scoped_lock lock(this->mutex); buffer = this->bufferQueue.front(); }else{ buffer = this->stream->NextBuffer(); if(buffer){ boost::mutex::scoped_lock lock(this->mutex); this->bufferQueue.push_back(buffer); this->totalBufferSize += buffer->Bytes(); } else { } } if(buffer){ { // Add the buffer to locked buffers so the output do not have time to play and // try to release the buffer before we have to add it. boost::mutex::scoped_lock lock(this->mutex); this->lockedBuffers.push_back(buffer); } // Try to play the buffer if(!this->output->PlayBuffer(buffer.get(),this)){ { // We didn't manage to play the buffer, remove it from the locked buffer queue boost::mutex::scoped_lock lock(this->mutex); this->lockedBuffers.pop_back(); } if(!this->PreBuffer()){ #ifdef _DEBUG std::cerr << "!this->PreBuffer" << std::endl; #endif // Wait for buffersize to become smaller boost::mutex::scoped_lock lock(this->mutex); if(this->totalBufferSize>this->maxBufferSize){ this->waitCondition.wait(lock); } } }else{ // Buffer send to output boost::mutex::scoped_lock lock(this->mutex); if(!this->bufferQueue.empty()){ this->bufferQueue.pop_front(); // Set currentPosition if(this->lockedBuffers.size()==1){ this->currentPosition = buffer->Position(); } } } }else{ // We have no more to decode finished = true; } } // TODO: call a signal to notify that player is almost done if(!this->Exited()){ this->PlaybackAlmostEnded(this); } // We need to wait for all the lockedBuffers to be released bool buffersEmpty=false; do{ this->output->ReleaseBuffers(); { boost::mutex::scoped_lock lock(this->mutex); buffersEmpty = this->lockedBuffers.empty(); if(!buffersEmpty && this->state!=Player::Quit){ this->waitCondition.wait(lock); } } }while(!buffersEmpty && !this->Exited()); }else{ // Unable to open stream this->PlaybackError(this); } { boost::mutex::scoped_lock lock(this->mutex); this->state = Player::Quit; } this->PlaybackEnded(this); this->output->ReleaseBuffers(); this->output.reset(); this->stream.reset(); }