mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 18:40:28 +00:00
Fixed some strange bugs and logic in Player/Stream interaction. Use the boost::condition properly to block waiting when the output device is full.
This commit is contained in:
parent
93b42c7e61
commit
27b14e762e
@ -50,7 +50,7 @@ int OggDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence) {
|
|||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
{
|
{
|
||||||
long currentPosition = ((OggDecoder*)datasource)->fileStream->Position();
|
long currentPosition = ((OggDecoder*)datasource)->fileStream->Position();
|
||||||
if(((OggDecoder*)datasource)->fileStream->SetPosition(currentPosition+(long) offset)) {
|
if(((OggDecoder*) datasource)->fileStream->SetPosition(currentPosition + (long) offset)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,23 +63,24 @@ int OggDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case SEEK_SET:
|
||||||
{
|
{
|
||||||
if(((OggDecoder*) datasource)->fileStream->SetPosition((long) offset)) {
|
if(((OggDecoder*) datasource)->fileStream->SetPosition((long) offset)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
long OggDecoder::OggTell(void *datasource) {
|
long OggDecoder::OggTell(void *datasource) {
|
||||||
return ((OggDecoder*)datasource)->fileStream->Position();
|
return ((OggDecoder*) datasource)->fileStream->Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
int OggDecoder::OggClose(void *datasource) {
|
int OggDecoder::OggClose(void *datasource) {
|
||||||
if(((OggDecoder*)datasource)->fileStream->Close()) {
|
if(((OggDecoder*) datasource)->fileStream->Close()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -115,7 +115,7 @@ bool WaveOut::Play(IBuffer *buffer, IPlayer *player) {
|
|||||||
/* if we have a different format, return false and wait for the pending
|
/* if we have a different format, return false and wait for the pending
|
||||||
buffers to be written to the output device. */
|
buffers to be written to the output device. */
|
||||||
if (bufferCount > 0) {
|
if (bufferCount > 0) {
|
||||||
bool formatChanged =
|
bool formatChanged =
|
||||||
this->currentChannels != buffer->Channels() ||
|
this->currentChannels != buffer->Channels() ||
|
||||||
this->currentSampleRate != buffer->SampleRate();
|
this->currentSampleRate != buffer->SampleRate();
|
||||||
|
|
||||||
|
@ -68,7 +68,6 @@ void WaveOutBuffer::Destroy() {
|
|||||||
this->header.dwFlags = WHDR_DONE;
|
this->header.dwFlags = WHDR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->player->Notify(); /* WaveOut should do this... whatever it is. */
|
|
||||||
this->destroyed = true;
|
this->destroyed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ Player::~Player() {
|
|||||||
void Player::Play() {
|
void Player::Play() {
|
||||||
boost::mutex::scoped_lock lock(this->mutex);
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
this->state = Player::Playing;
|
this->state = Player::Playing;
|
||||||
this->waitCondition.notify_all();
|
this->writeToOutputCondition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::Stop() {
|
void Player::Stop() {
|
||||||
@ -89,6 +89,7 @@ void Player::Stop() {
|
|||||||
boost::mutex::scoped_lock lock(this->mutex);
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
this->state = Player::Quit;
|
this->state = Player::Quit;
|
||||||
this->bufferQueue.clear();
|
this->bufferQueue.clear();
|
||||||
|
this->writeToOutputCondition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->output) {
|
if (this->output) {
|
||||||
@ -160,7 +161,7 @@ void Player::ThreadLoop() {
|
|||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(this->mutex);
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
while (this->state == Precache) {
|
while (this->state == Precache) {
|
||||||
this->waitCondition.wait(lock);
|
this->writeToOutputCondition.wait(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +169,8 @@ void Player::ThreadLoop() {
|
|||||||
|
|
||||||
/* we're ready to go.... */
|
/* we're ready to go.... */
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
|
BufferPtr buffer;
|
||||||
|
|
||||||
while(!finished && !this->Exited()) {
|
while(!finished && !this->Exited()) {
|
||||||
/* see if we've been asked to seek since the last sample was
|
/* see if we've been asked to seek since the last sample was
|
||||||
played. if we have, clear our output buffer and seek the
|
played. if we have, clear our output buffer and seek the
|
||||||
@ -184,21 +187,22 @@ void Player::ThreadLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferPtr buffer;
|
/* let's see if we can find some samples to play */
|
||||||
|
if (!buffer) {
|
||||||
/* the buffer queue may already have some buffers available if it was
|
|
||||||
prefetched. */
|
|
||||||
if (!this->BufferQueueEmpty()) {
|
|
||||||
boost::mutex::scoped_lock lock(this->mutex);
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
buffer = this->bufferQueue.front();
|
|
||||||
}
|
/* the buffer queue may already have some available if it was prefetched. */
|
||||||
/* otherwise, we need to grab a buffer from the stream and add it to the queue */
|
if (!this->bufferQueue.empty()) {
|
||||||
else {
|
buffer = this->bufferQueue.front();
|
||||||
buffer = this->stream->GetNextProcessedOutputBuffer();
|
this->bufferQueue.pop_front();
|
||||||
if (buffer) {
|
}
|
||||||
boost::mutex::scoped_lock lock(this->mutex);
|
/* otherwise, we need to grab a buffer from the stream and add it to the queue */
|
||||||
this->bufferQueue.push_back(buffer);
|
else {
|
||||||
this->totalBufferSize += buffer->Bytes();
|
buffer = this->stream->GetNextProcessedOutputBuffer();
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
this->totalBufferSize += buffer->Bytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,17 +217,17 @@ void Player::ThreadLoop() {
|
|||||||
know it's done with it. */
|
know it's done with it. */
|
||||||
this->lockedBuffers.push_back(buffer);
|
this->lockedBuffers.push_back(buffer);
|
||||||
|
|
||||||
/* TODO: don't understand this yet... seems like every time we enqueue a
|
if (this->lockedBuffers.size() == 1) {
|
||||||
new buffer to the output we remove the old one that was at the front of
|
this->currentPosition = buffer->Position();
|
||||||
*/
|
|
||||||
if (!this->bufferQueue.empty()) {
|
|
||||||
this->bufferQueue.pop_front();
|
|
||||||
|
|
||||||
// Set currentPosition
|
|
||||||
if (this->lockedBuffers.size() == 1) {
|
|
||||||
this->currentPosition = buffer->Position();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer.reset(); /* important! we're done with this one locally. */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* the output device queue is full. we should block and wait until
|
||||||
|
the output lets us know that it needs more data */
|
||||||
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
|
writeToOutputCondition.wait(this->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if we're unable to obtain a buffer, it means we're out of data and the
|
/* if we're unable to obtain a buffer, it means we're out of data and the
|
||||||
@ -268,11 +272,6 @@ void Player::ReleaseAllBuffers() {
|
|||||||
this->lockedBuffers.empty();
|
this->lockedBuffers.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Player::BufferQueueEmpty() {
|
|
||||||
boost::mutex::scoped_lock lock(this->mutex);
|
|
||||||
return this->bufferQueue.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Player::PreBuffer() {
|
bool Player::PreBuffer() {
|
||||||
/* don't prebuffer if the buffer is already full */
|
/* don't prebuffer if the buffer is already full */
|
||||||
if (this->totalBufferSize > this->maxBufferSize) {
|
if (this->totalBufferSize > this->maxBufferSize) {
|
||||||
@ -285,7 +284,6 @@ bool Player::PreBuffer() {
|
|||||||
boost::mutex::scoped_lock lock(this->mutex);
|
boost::mutex::scoped_lock lock(this->mutex);
|
||||||
this->bufferQueue.push_back(newBuffer);
|
this->bufferQueue.push_back(newBuffer);
|
||||||
this->totalBufferSize += newBuffer->Bytes();
|
this->totalBufferSize += newBuffer->Bytes();
|
||||||
this->waitCondition.notify_all(); /* TODO: what's waiting on this? */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -317,16 +315,13 @@ void Player::OnBufferProcessedByOutput(IBuffer *buffer) {
|
|||||||
this->currentPosition = this->lockedBuffers.front()->Position();
|
this->currentPosition = this->lockedBuffers.front()->Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->waitCondition.notify_all(); /* TODO: what's waiting on this? */
|
/* if the output device's internal buffers are full, it will stop
|
||||||
|
accepting new samples. now that a buffer has been processed, we can
|
||||||
|
try to enqueue another sample. the thread loop blocks on this condition */
|
||||||
|
this->writeToOutputCondition.notify_all();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::Notify() {
|
|
||||||
this->waitCondition.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ namespace musik { namespace core { namespace audio {
|
|||||||
~Player(void);
|
~Player(void);
|
||||||
|
|
||||||
virtual void OnBufferProcessedByOutput(IBuffer *buffer);
|
virtual void OnBufferProcessedByOutput(IBuffer *buffer);
|
||||||
virtual void Notify();
|
|
||||||
|
|
||||||
void Play();
|
void Play();
|
||||||
void Stop();
|
void Stop();
|
||||||
@ -90,7 +89,6 @@ namespace musik { namespace core { namespace audio {
|
|||||||
void ThreadLoop();
|
void ThreadLoop();
|
||||||
bool PreBuffer();
|
bool PreBuffer();
|
||||||
int State();
|
int State();
|
||||||
bool BufferQueueEmpty();
|
|
||||||
void ReleaseAllBuffers();
|
void ReleaseAllBuffers();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -114,7 +112,7 @@ namespace musik { namespace core { namespace audio {
|
|||||||
BufferList lockedBuffers;
|
BufferList lockedBuffers;
|
||||||
|
|
||||||
boost::mutex mutex;
|
boost::mutex mutex;
|
||||||
boost::condition waitCondition;
|
boost::condition writeToOutputCondition;
|
||||||
|
|
||||||
double volume;
|
double volume;
|
||||||
double currentPosition;
|
double currentPosition;
|
||||||
|
@ -134,7 +134,7 @@ BufferPtr Stream::GetNextBufferFromDecoder() {
|
|||||||
this->decoderSamplePosition += buffer->Samples();
|
this->decoderSamplePosition += buffer->Samples();
|
||||||
|
|
||||||
/* calculate the position (seconds) in the buffer */
|
/* calculate the position (seconds) in the buffer */
|
||||||
buffer->position = ((double)this->decoderSamplePosition) / ((double)this->decoderSampleRate);
|
buffer->position = ((double) this->decoderSamplePosition) / ((double) this->decoderSampleRate);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -54,12 +54,6 @@ class IDecoder{
|
|||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual void Destroy() = 0;
|
virtual void Destroy() = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
|
||||||
///\brief
|
|
||||||
///Get the length of the track in seconds
|
|
||||||
//////////////////////////////////////////
|
|
||||||
//virtual double Length() = 0;
|
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
///Set the position in the source (in seconds)
|
///Set the position in the source (in seconds)
|
||||||
|
@ -43,7 +43,7 @@ namespace musik { namespace core { namespace audio {
|
|||||||
///\brief
|
///\brief
|
||||||
///Interface for the audio::Player to make IOuput plugins be able to make callbacks
|
///Interface for the audio::Player to make IOuput plugins be able to make callbacks
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
class IPlayer{
|
class IPlayer {
|
||||||
public:
|
public:
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
@ -51,14 +51,6 @@ class IPlayer{
|
|||||||
///processing.
|
///processing.
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual void OnBufferProcessedByOutput(IBuffer *buffer) = 0;
|
virtual void OnBufferProcessedByOutput(IBuffer *buffer) = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
|
||||||
///\brief
|
|
||||||
///Notifies the Player that there may be buffer.
|
|
||||||
///ready to be released in the output plugin.
|
|
||||||
///TOOD: ugh... what?
|
|
||||||
//////////////////////////////////////////
|
|
||||||
virtual void Notify() = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user