diff --git a/src/media/audio/ringbuffer.h b/src/media/audio/ringbuffer.h index 28bf28f0e84c270ae7fb4f1bf6c3081ec36185f3..bff88de2fadda14a2133f1541708124e4c3b13bf 100644 --- a/src/media/audio/ringbuffer.h +++ b/src/media/audio/ringbuffer.h @@ -35,169 +35,168 @@ #include <vector> #include <fstream> - namespace ring { /** * A ring buffer for mutichannel audio samples */ class RingBuffer { - public: - using clock = std::chrono::high_resolution_clock; - using time_point = clock::time_point; - using FrameCallback = std::function<void(const std::shared_ptr<AudioFrame>&)>; - - /** - * Constructor - * @param size Size of the buffer to create - */ - RingBuffer(const std::string& id, size_t size, - AudioFormat format=AudioFormat::MONO()); - - const std::string& getId() const { return id; } - - /** - * Reset the counters to 0 for this read offset - */ - void flush(const std::string &call_id); - - void flushAll(); - - inline AudioFormat getFormat() const { - return format_; - } - - inline void setFormat(const AudioFormat& format) { - format_ = format; - resizer_.setFormat(format, format.sample_rate / 50); - } - - /** - * Add a new readoffset for this ringbuffer - */ - void createReadOffset(const std::string &call_id); - - void createReadOffset(const std::string &call_id, FrameCallback cb); - - /** - * Remove a readoffset for this ringbuffer - */ - void removeReadOffset(const std::string &call_id); - - size_t readOffsetCount() const { return readoffsets_.size(); } - - /** - * Write data in the ring buffer - * @param buffer Data to copied - * @param toCopy Number of bytes to copy - */ - void put(std::shared_ptr<AudioFrame>&& data); - - /** - * To get how much samples are available in the buffer to read in - * @return int The available (multichannel) samples number - */ - size_t availableForGet(const std::string &call_id) const; - - /** - * Get data in the ring buffer - * @param buffer Data to copied - * @param toCopy Number of bytes to copy - * @return size_t Number of bytes copied - */ - std::shared_ptr<AudioFrame> get(const std::string &call_id); - - /** - * Discard data from the buffer - * @param toDiscard Number of samples to discard - * @return size_t Number of samples discarded - */ - size_t discard(size_t toDiscard, const std::string &call_id); - - /** - * Total length of the ring buffer which is available for "putting" - * @return int - */ - size_t putLength() const; - - size_t getLength(const std::string &call_id) const; - - inline bool isFull() const { - return putLength() == buffer_.size(); - } - - inline bool isEmpty() const { - return putLength() == 0; - } - - /** - * Blocks until min_data_length samples of data is available, or until deadline has passed. - * - * @param call_id The read offset for which data should be available. - * @param min_data_length Minimum number of samples that should be available for the call to return - * @param deadline The call is guaranteed to end after this time point. If no deadline is provided, the call blocks indefinitely. - * @return available data for call_id after the call returned (same as calling getLength(call_id) ). - */ - size_t waitForDataAvailable(const std::string& call_id, const time_point& deadline = time_point::max()) const; - - /** - * Debug function print mEnd, mStart, mBufferSize - */ - void debug(); - - private: - struct ReadOffset { - size_t offset; - FrameCallback callback; - }; - using ReadOffsetMap = std::map<std::string, ReadOffset>; - NON_COPYABLE(RingBuffer); - - void putToBuffer(std::shared_ptr<AudioFrame>&& data); - - bool hasNoReadOffsets() const; - - /** - * Return the smalest readoffset. Useful to evaluate if ringbuffer is full - */ - size_t getSmallestReadOffset() const; - - /** - * Get read offset coresponding to this call - */ - size_t getReadOffset(const std::string &call_id) const; - - /** - * Move readoffset forward by offset - */ - void storeReadOffset(size_t offset, const std::string &call_id); - - /** - * Test if readoffset coresponding to this call is still active - */ - bool hasThisReadOffset(const std::string &call_id) const; - - /** - * Discard data from all read offsets to make place for new data. - */ - size_t discard(size_t toDiscard); - - const std::string id; - - /** Offset on the last data */ - size_t endPos_; - - /** Data */ - AudioFormat format_ {AudioFormat::DEFAULT()}; - std::vector<std::shared_ptr<AudioFrame>> buffer_ {8}; - - mutable std::mutex lock_; - mutable std::condition_variable not_empty_; - - ReadOffsetMap readoffsets_; - - Resampler resampler_; - AudioFrameResizer resizer_; +public: + using clock = std::chrono::high_resolution_clock; + using time_point = clock::time_point; + using FrameCallback = std::function<void(const std::shared_ptr<AudioFrame>&)>; + + /** + * Constructor + * @param size Size of the buffer to create + */ + RingBuffer(const std::string& id, size_t size, + AudioFormat format=AudioFormat::MONO()); + + const std::string& getId() const { return id; } + + /** + * Reset the counters to 0 for this read offset + */ + void flush(const std::string &call_id); + + void flushAll(); + + inline AudioFormat getFormat() const { + return format_; + } + + inline void setFormat(const AudioFormat& format) { + format_ = format; + resizer_.setFormat(format, format.sample_rate / 50); + } + + /** + * Add a new readoffset for this ringbuffer + */ + void createReadOffset(const std::string &call_id); + + void createReadOffset(const std::string &call_id, FrameCallback cb); + + /** + * Remove a readoffset for this ringbuffer + */ + void removeReadOffset(const std::string &call_id); + + size_t readOffsetCount() const { return readoffsets_.size(); } + + /** + * Write data in the ring buffer + * @param buffer Data to copied + * @param toCopy Number of bytes to copy + */ + void put(std::shared_ptr<AudioFrame>&& data); + + /** + * To get how much samples are available in the buffer to read in + * @return int The available (multichannel) samples number + */ + size_t availableForGet(const std::string &call_id) const; + + /** + * Get data in the ring buffer + * @param buffer Data to copied + * @param toCopy Number of bytes to copy + * @return size_t Number of bytes copied + */ + std::shared_ptr<AudioFrame> get(const std::string &call_id); + + /** + * Discard data from the buffer + * @param toDiscard Number of samples to discard + * @return size_t Number of samples discarded + */ + size_t discard(size_t toDiscard, const std::string &call_id); + + /** + * Total length of the ring buffer which is available for "putting" + * @return int + */ + size_t putLength() const; + + size_t getLength(const std::string &call_id) const; + + inline bool isFull() const { + return putLength() == buffer_.size(); + } + + inline bool isEmpty() const { + return putLength() == 0; + } + + /** + * Blocks until min_data_length samples of data is available, or until deadline has passed. + * + * @param call_id The read offset for which data should be available. + * @param min_data_length Minimum number of samples that should be available for the call to return + * @param deadline The call is guaranteed to end after this time point. If no deadline is provided, the call blocks indefinitely. + * @return available data for call_id after the call returned (same as calling getLength(call_id) ). + */ + size_t waitForDataAvailable(const std::string& call_id, const time_point& deadline = time_point::max()) const; + + /** + * Debug function print mEnd, mStart, mBufferSize + */ + void debug(); + +private: + struct ReadOffset { + size_t offset; + FrameCallback callback; + }; + using ReadOffsetMap = std::map<std::string, ReadOffset>; + NON_COPYABLE(RingBuffer); + + void putToBuffer(std::shared_ptr<AudioFrame>&& data); + + bool hasNoReadOffsets() const; + + /** + * Return the smalest readoffset. Useful to evaluate if ringbuffer is full + */ + size_t getSmallestReadOffset() const; + + /** + * Get read offset coresponding to this call + */ + size_t getReadOffset(const std::string &call_id) const; + + /** + * Move readoffset forward by offset + */ + void storeReadOffset(size_t offset, const std::string &call_id); + + /** + * Test if readoffset coresponding to this call is still active + */ + bool hasThisReadOffset(const std::string &call_id) const; + + /** + * Discard data from all read offsets to make place for new data. + */ + size_t discard(size_t toDiscard); + + const std::string id; + + /** Offset on the last data */ + size_t endPos_; + + /** Data */ + AudioFormat format_ {AudioFormat::DEFAULT()}; + std::vector<std::shared_ptr<AudioFrame>> buffer_ {8}; + + mutable std::mutex lock_; + mutable std::condition_variable not_empty_; + + ReadOffsetMap readoffsets_; + + Resampler resampler_; + AudioFrameResizer resizer_; }; } // namespace ring diff --git a/src/media/audio/ringbufferpool.h b/src/media/audio/ringbufferpool.h index 171f0b711f2c2ea594dcceb13418897ae24c5116..b0c3076413456e8ba2bb66cec6d59e372823e963 100644 --- a/src/media/audio/ringbufferpool.h +++ b/src/media/audio/ringbufferpool.h @@ -35,120 +35,116 @@ namespace ring { class RingBuffer; class RingBufferPool { - public: - static const char * const DEFAULT_ID; - - RingBufferPool(); - - ~RingBufferPool(); - - int getInternalSamplingRate() const { - return internalAudioFormat_.sample_rate; - } - - AudioFormat getInternalAudioFormat() const { - return internalAudioFormat_; - } - - void setInternalSamplingRate(unsigned sr); - - void setInternalAudioFormat(AudioFormat format); - - /** - * Bind together two audio streams so that a client will be able - * to put and get data specifying its callid only. - */ - void bindCallID(const std::string& call_id1, +public: + static const char * const DEFAULT_ID; + + RingBufferPool(); + ~RingBufferPool(); + + int getInternalSamplingRate() const { + return internalAudioFormat_.sample_rate; + } + + AudioFormat getInternalAudioFormat() const { + return internalAudioFormat_; + } + + void setInternalSamplingRate(unsigned sr); + + void setInternalAudioFormat(AudioFormat format); + + /** + * Bind together two audio streams so that a client will be able + * to put and get data specifying its callid only. + */ + void bindCallID(const std::string& call_id1, + const std::string& call_id2); + + /** + * Add a new call_id to unidirectional outgoing stream + * \param call_id New call id to be added for this stream + * \param process_id Process that require this stream + */ + void bindHalfDuplexOut(const std::string& process_id, + const std::string& call_id); + + /** + * Unbind two calls + */ + void unBindCallID(const std::string& call_id1, const std::string& call_id2); - /** - * Add a new call_id to unidirectional outgoing stream - * \param call_id New call id to be added for this stream - * \param process_id Process that require this stream - */ - void bindHalfDuplexOut(const std::string& process_id, - const std::string& call_id); - - /** - * Unbind two calls - */ - void unBindCallID(const std::string& call_id1, - const std::string& call_id2); - - /** - * Unbind a unidirectional stream - */ - void unBindHalfDuplexOut(const std::string& process_id, - const std::string& call_id); - - void unBindAll(const std::string& call_id); + /** + * Unbind a unidirectional stream + */ + void unBindHalfDuplexOut(const std::string& process_id, + const std::string& call_id); - bool waitForDataAvailable(const std::string& call_id, - const std::chrono::microseconds& max_wait) const; + void unBindAll(const std::string& call_id); - std::shared_ptr<AudioFrame> getData(const std::string& call_id); + bool waitForDataAvailable(const std::string& call_id, + const std::chrono::microseconds& max_wait) const; - std::shared_ptr<AudioFrame> getAvailableData(const std::string& call_id); + std::shared_ptr<AudioFrame> getData(const std::string& call_id); - size_t availableForGet(const std::string& call_id) const; + std::shared_ptr<AudioFrame> getAvailableData(const std::string& call_id); - size_t discard(size_t toDiscard, const std::string& call_id); + size_t availableForGet(const std::string& call_id) const; - void flush(const std::string& call_id); + size_t discard(size_t toDiscard, const std::string& call_id); - void flushAllBuffers(); + void flush(const std::string& call_id); - /** - * Create a new ringbuffer with a default readoffset. - * This class keeps a weak reference on returned pointer, - * so the caller is responsible of the referred instance. - */ - std::shared_ptr<RingBuffer> createRingBuffer(const std::string& id); + void flushAllBuffers(); - /** - * Obtain a shared pointer on a RingBuffer given by its ID. - * If the ID doesn't match to any RingBuffer, the shared pointer - * is empty. This non-const version flushes internal weak pointers - * if the ID was used and the associated RingBuffer has been deleted. - */ - std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id); + /** + * Create a new ringbuffer with a default readoffset. + * This class keeps a weak reference on returned pointer, + * so the caller is responsible of the referred instance. + */ + std::shared_ptr<RingBuffer> createRingBuffer(const std::string& id); - /** - * Works as non-const getRingBuffer, without the weak reference flush. - */ - std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id) const; + /** + * Obtain a shared pointer on a RingBuffer given by its ID. + * If the ID doesn't match to any RingBuffer, the shared pointer + * is empty. This non-const version flushes internal weak pointers + * if the ID was used and the associated RingBuffer has been deleted. + */ + std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id); - private: - NON_COPYABLE(RingBufferPool); + /** + * Works as non-const getRingBuffer, without the weak reference flush. + */ + std::shared_ptr<RingBuffer> getRingBuffer(const std::string& id) const; - // A set of RingBuffers readable by a call - typedef std::set<std::shared_ptr<RingBuffer>, - std::owner_less<std::shared_ptr<RingBuffer>> > ReadBindings; +private: + NON_COPYABLE(RingBufferPool); - const RingBufferPool::ReadBindings* - getReadBindings(const std::string& call_id) const; + // A set of RingBuffers readable by a call + using ReadBindings = std::set<std::shared_ptr<RingBuffer>, std::owner_less<std::shared_ptr<RingBuffer>>>; - RingBufferPool::ReadBindings* getReadBindings(const std::string& call_id); + const ReadBindings* getReadBindings(const std::string& call_id) const; + ReadBindings* getReadBindings(const std::string& call_id); - void removeReadBindings(const std::string& call_id); + void removeReadBindings(const std::string& call_id); - void addReaderToRingBuffer(const std::shared_ptr<RingBuffer>& rbuf, - const std::string& call_id); + void addReaderToRingBuffer(const std::shared_ptr<RingBuffer>& rbuf, + const std::string& call_id); - void removeReaderFromRingBuffer(const std::shared_ptr<RingBuffer>& rbuf, - const std::string& call_id); + void removeReaderFromRingBuffer(const std::shared_ptr<RingBuffer>& rbuf, + const std::string& call_id); - // A cache of created RingBuffers listed by IDs. - std::map<std::string, std::weak_ptr<RingBuffer> > ringBufferMap_ {}; + // A cache of created RingBuffers listed by IDs. + std::map<std::string, std::weak_ptr<RingBuffer>> ringBufferMap_ {}; - // A map of which RingBuffers a call has some ReadOffsets - std::map<std::string, ReadBindings> readBindingsMap_ {}; + // A map of which RingBuffers a call has some ReadOffsets + std::map<std::string, ReadBindings> readBindingsMap_ {}; - mutable std::recursive_mutex stateLock_ {}; + mutable std::recursive_mutex stateLock_ {}; - AudioFormat internalAudioFormat_ {AudioFormat::DEFAULT()}; + AudioFormat internalAudioFormat_ {AudioFormat::DEFAULT()}; - std::shared_ptr<RingBuffer> defaultRingBuffer_; + std::shared_ptr<RingBuffer> defaultRingBuffer_; }; } // namespace ring