diff --git a/inc/streams/MemorySource.h b/inc/streams/MemorySource.h index e157dce3..8fb2e388 100644 --- a/inc/streams/MemorySource.h +++ b/inc/streams/MemorySource.h @@ -16,11 +16,20 @@ namespace codal private: int outputFormat; // The format to output in. By default, this is the same as the input. int outputBufferSize; // The maximum size of an output buffer. - int bytesSent; // The number of bytes sent in the current buffer ManagedBuffer buffer; // The output buffer being filled + uint8_t *data; // The input data being played (immutable) + uint8_t *in; // The input data being played (mutable) + int length; // The lenght of the input buffer (immutable) + int bytesToSend; // The lenght of the input buffer (mutable) + int count; // The number of times left to repeat + + DataSink *downstream; // Pointer to our downstream component + bool blockingPlayout; // Set to true if a blocking playout has been requested + FiberLock lock; // used to synchronise blocking play calls. + public: - DataStream output; + DataSource &output; // DEPRECATED: backward compatilbity only /** * Default Constructor. @@ -52,6 +61,12 @@ namespace codal */ virtual int setFormat(int format); + /* + * Allow out downstream component to register itself with us + */ + virtual void connect(DataSink &sink); + + /** * Determine the maximum size of the buffers streamed out of this component. * @return The maximum size of this component's output buffers, in bytes. @@ -68,16 +83,35 @@ namespace codal * Perform a blocking playout of the data buffer. Returns when all the data has been queued. * @param data pointer to memory location to playout * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param loop if repeat playback of buffer when completed the given number of times. Defaults to one. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. */ - void play(const void *data, int length, int loop = 1); + void play(const void *data, int length, int count = 1); /** * Perform a blocking playout of the data buffer. Returns when all the data has been queued. * @param b the buffer to playout - * @param loop if repeat playback of buffer when completed the given number of times. Defaults to one. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. */ - void play(ManagedBuffer b, int loop = 1); + void play(ManagedBuffer b, int count = 1); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param data pointer to memory location to playout + * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + */ + void playAsync(const void *data, int length, int count = 1); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param b the buffer to playout + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + */ + void playAsync(ManagedBuffer b, int count = 1); + + + private: + void _play(const void *data, int length, int count, bool mode); }; } #endif \ No newline at end of file diff --git a/source/streams/MemorySource.cpp b/source/streams/MemorySource.cpp index 1e02e1ee..7a7687ba 100644 --- a/source/streams/MemorySource.cpp +++ b/source/streams/MemorySource.cpp @@ -11,11 +11,21 @@ using namespace codal; */ MemorySource::MemorySource() : output(*this) { - this->bytesSent = 0; + this->downstream = NULL; this->setFormat(DATASTREAM_FORMAT_8BIT_UNSIGNED); this->setBufferSize(MEMORY_SOURCE_DEFAULT_MAX_BUFFER); + lock.wait(); } +/* + * Allow out downstream component to register itself with us + */ +void MemorySource::connect(DataSink &sink) +{ + this->downstream = &sink; +} + + /** * Determine the data format of the buffers streamed out of this component. */ @@ -62,59 +72,93 @@ MemorySource::setBufferSize(int size) */ ManagedBuffer MemorySource::pull() { + // Calculate the amount of data we can transfer. + int l = min(bytesToSend, outputBufferSize); + buffer = ManagedBuffer(l); + + memcpy(&buffer[0], in, l); + + bytesToSend -= l; + in += l; + + // If we've consumed the input buffer, see if we need to reload it + if (bytesToSend == 0) + { + if (count > 0) + count--; + + if (count != 0) + { + bytesToSend = length; + in = data; + } + } + + // If we still have data to send, indicate this to our downstream component + if (bytesToSend > 0) + downstream->pullRequest(); + + // If we have completed playback and blockingbehaviour was requested, wake the fiber that is blocked waiting. + if (bytesToSend == 0 && count == 0 && blockingPlayout) + lock.notify(); + return buffer; -} +} /** - * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * Perform a non-blocking playout of the data buffer. Returns when all the data has been queued. * @param data pointer to memory location to playout * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param loop if repeat playback of buffer when completed the given number of times. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. */ -void MemorySource::play(const void *data, int length, int loop) +void MemorySource::playAsync(const void *data, int length, int count) { - uint8_t *out; - uint8_t *in; - - in = (uint8_t *)data; - length = length * DATASTREAM_FORMAT_BYTES_PER_SAMPLE(outputFormat); - - do - { - while (bytesSent < length) - { - int size = min(length - bytesSent, outputBufferSize); - buffer = ManagedBuffer(size); - out = &buffer[0]; - - memcpy(out, in, size); - in += size; - bytesSent += size; - - output.pullRequest(); - } + _play(data, length, count, false); +} - bytesSent = 0; - if (loop > 0) - loop--; +/** + * Perform a non-blocking playout of the data buffer. Returns when all the data has been queued. + * @param b the buffer to playout + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + */ +void MemorySource::playAsync(ManagedBuffer b, int count) +{ + this->play(&b[0], b.length(), count); +} - } while (loop); +/** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param data pointer to memory location to playout + * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + */ +void MemorySource::play(const void *data, int length, int count) +{ + _play(data, length, count, true); } /** * Perform a blocking playout of the data buffer. Returns when all the data has been queued. * @param b the buffer to playout - * @param loop if repeat playback of buffer when completed the given number of times. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. */ -void MemorySource::play(ManagedBuffer b, int loop) +void MemorySource::play(ManagedBuffer b, int count) { - do - { - buffer = b; - output.pullRequest(); - - if (loop > 0) - loop--; + this->play(&b[0], b.length(), count); +} - } while (loop); -} +void MemorySource::_play(const void *data, int length, int count, bool mode) +{ + if (downstream == NULL || length <= 0 || count == 0) + return; + + this->data = this->in = (uint8_t *)data; + this->length =this->bytesToSend = length; + this->count = count; + this->blockingPlayout = mode; + + downstream->pullRequest(); + + if (this->blockingPlayout) + lock.wait(); +} \ No newline at end of file