Skip to content

Commit

Permalink
SOUND: Copy xoreos' QueuingAudioStream
Browse files Browse the repository at this point in the history
  • Loading branch information
DrMcCoy committed Aug 18, 2018
1 parent b587242 commit b48f5f8
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/sound/audiostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,120 @@ uint64 LoopingAudioStream::getDurationOnce() const {
return _parent->getDuration();
}

class QueuingAudioStreamImpl : public QueuingAudioStream {
private:
/**
* We queue a number of (pointers to) audio stream objects.
* In addition, we need to remember for each stream whether
* to dispose it after all data has been read from it.
* Hence, we don't store pointers to stream objects directly,
* but rather StreamHolder structs.
*/
struct StreamHolder {
AudioStream *_stream;
bool _disposeAfterUse;
StreamHolder(AudioStream *stream, bool disposeAfterUse)
: _stream(stream),
_disposeAfterUse(disposeAfterUse) {}
};

/**
* The sampling rate of this audio stream.
*/
const int _rate;

/**
* The number of channels in this audio stream.
*/
const int _channels;

/**
* This flag is set by the finish() method only. See there for more details.
*/
bool _finished;

/**
* A mutex to avoid access problems (causing e.g. corruption of
* the linked list) in thread aware environments.
*/
Common::Mutex _mutex;

/**
* The queue of audio streams.
*/
std::queue<StreamHolder> _queue;

public:
QueuingAudioStreamImpl(int rate, int channels)
: _rate(rate), _channels(channels), _finished(false) {}
~QueuingAudioStreamImpl();

// Implement the AudioStream API
virtual size_t readBuffer(int16 *buffer, const size_t numSamples);
virtual int getChannels() const { return _channels; }
virtual int getRate() const { return _rate; }
virtual bool endOfData() const {
//Common::StackLock lock(_mutex);
return _queue.empty();
}
virtual bool endOfStream() const { return _finished && _queue.empty(); }

// Implement the QueuingAudioStream API
virtual void queueAudioStream(AudioStream *stream, bool disposeAfterUse);
virtual void finish() { _finished = true; }

size_t numQueuedStreams() const {
//Common::StackLock lock(_mutex);
return _queue.size();
}
};

QueuingAudioStreamImpl::~QueuingAudioStreamImpl() {
while (!_queue.empty()) {
StreamHolder tmp = _queue.front();
_queue.pop();
if (tmp._disposeAfterUse)
delete tmp._stream;
}
}

void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, bool disposeAfterUse) {
if (_finished)
throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): Trying to queue another audio stream, but the QueuingAudioStream is finished.");

if ((stream->getRate() != getRate()) || (stream->getChannels() != getChannels()))
throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): stream has mismatched parameters");

Common::StackLock lock(_mutex);
_queue.push(StreamHolder(stream, disposeAfterUse));
}

size_t QueuingAudioStreamImpl::readBuffer(int16 *buffer, const size_t numSamples) {
Common::StackLock lock(_mutex);
size_t samplesDecoded = 0;

while (samplesDecoded < numSamples && !_queue.empty()) {
AudioStream *stream = _queue.front()._stream;

const size_t n = stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
if (n == kSizeInvalid)
return kSizeInvalid;

samplesDecoded += n;

if (stream->endOfData()) {
StreamHolder tmp = _queue.front();
_queue.pop();
if (tmp._disposeAfterUse)
delete stream;
}
}

return samplesDecoded;
}

QueuingAudioStream *makeQueuingAudioStream(int rate, int channels) {
return new QueuingAudioStreamImpl(rate, channels);
}

} // End of namespace Sound
30 changes: 30 additions & 0 deletions src/sound/audiostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,36 @@ class LoopingAudioStream : public AudioStream {
*/
AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, size_t loops);

class QueuingAudioStream : public AudioStream {
public:

/**
* Queue an audio stream for playback. This stream plays all queued
* streams, in the order they were queued. If disposeAfterUse is set to
* DisposeAfterUse::YES, then the queued stream is deleted after all data
* contained in it has been played.
*/
virtual void queueAudioStream(AudioStream *audStream, bool disposeAfterUse = true) = 0;

/**
* Mark this stream as finished. That is, signal that no further data
* will be queued to it. Only after this has been done can this
* stream ever 'end'.
*/
virtual void finish() = 0;

/**
* Return the number of streams still queued for playback (including
* the currently playing stream).
*/
virtual size_t numQueuedStreams() const = 0;
};

/**
* Factory function for an QueuingAudioStream.
*/
QueuingAudioStream *makeQueuingAudioStream(int rate, int channels);

} // End of namespace Sound

#endif // SOUND_AUDIOSTREAM_H

0 comments on commit b48f5f8

Please sign in to comment.