// // InboundAudioStream.h // libraries/audio/src // // Created by Yixin Wang on 7/17/2014. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_InboundAudioStream_h #define hifi_InboundAudioStream_h #include "NodeData.h" #include "AudioRingBuffer.h" #include "MovingMinMaxAvg.h" #include "SequenceNumberStats.h" #include "AudioStreamStats.h" #include "PacketHeaders.h" // the time gaps stats for _desiredJitterBufferFrames calculation // will recalculate the max for the past 5000 samples every 500 samples const int TIME_GAPS_FOR_JITTER_CALC_INTERVAL_SAMPLES = 500; const int TIME_GAPS_FOR_JITTER_CALC_WINDOW_INTERVALS = 10; // the time gap stats for constructing AudioStreamStats will // recalculate min/max/avg every ~1 second for the past ~30 seconds of time gap data const int TIME_GAPS_FOR_STATS_PACKET_INTERVAL_SAMPLES = USECS_PER_SECOND / BUFFER_SEND_INTERVAL_USECS; const int TIME_GAPS_FOR_STATS_PACKET_WINDOW_INTERVALS = 30; // the stats for calculating the average frames available will recalculate every ~1 second // and will include data for the past ~2 seconds const int FRAMES_AVAILABLE_STATS_INTERVAL_SAMPLES = USECS_PER_SECOND / BUFFER_SEND_INTERVAL_USECS; const int FRAMES_AVAILABLE_STATS_WINDOW_INTERVALS = 2; // the internal history buffer of the incoming seq stats will cover 30s to calculate // packet loss % over last 30s const int INCOMING_SEQ_STATS_HISTORY_LENGTH_SECONDS = 30; const int INBOUND_RING_BUFFER_FRAME_CAPACITY = 100; class InboundAudioStream : public NodeData { Q_OBJECT public: InboundAudioStream(int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers); void reset(); void resetStats(); void clearBuffer(); virtual int parseData(const QByteArray& packet); bool popFrames(int numFrames, bool starveOnFail = true); bool lastPopSucceeded() const { return _lastPopSucceeded; }; const AudioRingBuffer::ConstIterator& getLastPopOutput() const { return _lastPopOutput; } void setToStarved(); /// this function should be called once per second to ensure the seq num stats history spans ~30 seconds AudioStreamStats updateSeqHistoryAndGetAudioStreamStats(); virtual AudioStreamStats getAudioStreamStats() const; int getCalculatedDesiredJitterBufferFrames() const; int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; } int getNumFrameSamples() const { return _ringBuffer.getNumFrameSamples(); } int getFrameCapacity() const { return _ringBuffer.getFrameCapacity(); } int getFramesAvailable() const { return _ringBuffer.framesAvailable(); } double getFramesAvailableAverage() const { return _framesAvailableStats.getWindowAverage(); } bool isStarved() const { return _isStarved; } bool hasStarted() const { return _hasStarted; } int getConsecutiveNotMixedCount() const { return _consecutiveNotMixedCount; } int getStarveCount() const { return _starveCount; } int getSilentFramesDropped() const { return _silentFramesDropped; } int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } private: void starved(); protected: // disallow copying of InboundAudioStream objects InboundAudioStream(const InboundAudioStream&); InboundAudioStream& operator= (const InboundAudioStream&); /// parses the info between the seq num and the audio data in the network packet and calculates /// how many audio samples this packet contains virtual int parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) = 0; /// parses the audio data in the network packet virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) = 0; int writeDroppableSilentSamples(int numSilentSamples); int writeSamplesForDroppedPackets(int numSamples); SequenceNumberStats::ArrivalInfo frameReceivedUpdateNetworkStats(quint16 sequenceNumber, const QUuid& senderUUID); protected: AudioRingBuffer _ringBuffer; bool _lastPopSucceeded; AudioRingBuffer::ConstIterator _lastPopOutput; bool _dynamicJitterBuffers; int _desiredJitterBufferFrames; bool _isStarved; bool _hasStarted; // stats int _consecutiveNotMixedCount; int _starveCount; int _silentFramesDropped; SequenceNumberStats _incomingSequenceNumberStats; quint64 _lastFrameReceivedTime; MovingMinMaxAvg _interframeTimeGapStatsForJitterCalc; MovingMinMaxAvg _interframeTimeGapStatsForStatsPacket; // TODO: change this to time-weighted moving avg MovingMinMaxAvg _framesAvailableStats; }; #endif // hifi_InboundAudioStream_h