// // AudioMixer.h // assignment-client/src/audio // // Created by Stephen Birarda on 8/22/13. // 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_AudioMixer_h #define hifi_AudioMixer_h #include #include #include #include #include #include "AudioMixerStats.h" #include "AudioMixerSlavePool.h" class PositionalAudioStream; class AvatarAudioStream; class AudioHRTF; class AudioMixerClientData; /// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients. class AudioMixer : public ThreadedAssignment { Q_OBJECT public: AudioMixer(ReceivedMessage& message); struct ZoneSettings { QString source; QString listener; float coefficient; }; struct ReverbSettings { QString zone; float reverbTime; float wetLevel; }; static int getStaticJitterFrames() { return _numStaticJitterFrames; } static bool shouldMute(float quietestFrame) { return quietestFrame > _noiseMutingThreshold; } static float getAttenuationPerDoublingInDistance() { return _attenuationPerDoublingInDistance; } static const QHash& getAudioZones() { return _audioZones; } static const QVector& getZoneSettings() { return _zoneSettings; } static const QVector& getReverbSettings() { return _zoneReverbSettings; } static const std::pair negotiateCodec(std::vector codecs); public slots: void run() override; void sendStatsPacket() override; private slots: // packet handlers void handleMuteEnvironmentPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeKilled(SharedNodePointer killedNode); void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); void handleNodeIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeMuteRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handlePerAvatarGainSetDataPacket(QSharedPointer packet, SharedNodePointer sendingNode); void queueAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); void removeHRTFsForFinishedInjector(const QUuid& streamID); void start(); private: // mixing helpers std::chrono::microseconds timeFrame(p_high_resolution_clock::time_point& timestamp); void throttle(std::chrono::microseconds frameDuration, int frame); // pop a frame from any streams on the node // returns the number of available streams int prepareFrame(const SharedNodePointer& node, unsigned int frame); AudioMixerClientData* getOrCreateClientData(Node* node); QString percentageForMixStats(int counter); void parseSettingsObject(const QJsonObject& settingsObject); float _trailingMixRatio { 0.0f }; float _throttlingRatio { 0.0f }; int _numSilentPackets { 0 }; int _numStatFrames { 0 }; AudioMixerStats _stats; AudioMixerSlavePool _slavePool; class Timer { public: class Timing{ public: Timing(uint64_t& sum); ~Timing(); private: p_high_resolution_clock::time_point _timing; uint64_t& _sum; }; Timing timer() { return Timing(_sum); } void get(uint64_t& timing, uint64_t& trailing); private: static const int TIMER_TRAILING_SECONDS = 10; uint64_t _sum { 0 }; uint64_t _trailing { 0 }; uint64_t _history[TIMER_TRAILING_SECONDS] {}; int _index { 0 }; }; Timer _ticTiming; Timer _sleepTiming; Timer _frameTiming; Timer _prepareTiming; Timer _mixTiming; Timer _eventsTiming; Timer _packetsTiming; static int _numStaticJitterFrames; // -1 denotes dynamic jitter buffering static float _noiseMutingThreshold; static float _attenuationPerDoublingInDistance; static QString _codecPreferenceOrder; static QHash _audioZones; static QVector _zoneSettings; static QVector _zoneReverbSettings; }; #endif // hifi_AudioMixer_h