AudibilityMonitor.h (3287B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_MEDIA_AUDIBILITYMONITOR_H_ 8 #define DOM_MEDIA_AUDIBILITYMONITOR_H_ 9 10 #include <cstdint> 11 12 #include "AudioBlock.h" 13 #include "AudioSampleFormat.h" 14 #include "MediaData.h" 15 #include "WebAudioUtils.h" 16 17 namespace mozilla { 18 19 class AudibilityMonitor { 20 public: 21 // ≈ 20 * log10(pow(2, 12)), noise floor of 12bit audio 22 const float AUDIBILITY_THRESHOLD = 23 dom::WebAudioUtils::ConvertDecibelsToLinear(-72.); 24 25 AudibilityMonitor(uint32_t aSamplerate, float aSilenceDurationSeconds) 26 : mSamplerate(aSamplerate), 27 mSilenceDurationSeconds(aSilenceDurationSeconds), 28 mSilentFramesInARow(0), 29 mEverAudible(false) {} 30 31 void Process(const AudioData* aData) { 32 ProcessInterleaved(aData->Data(), aData->mChannels); 33 } 34 35 void Process(const AudioBlock& aData) { 36 if (aData.IsNull() || aData.IsMuted()) { 37 mSilentFramesInARow += aData.GetDuration(); 38 return; 39 } 40 ProcessPlanar(aData.ChannelData<float>(), aData.GetDuration()); 41 } 42 43 void ProcessPlanar(Span<const float* const> aPlanar, TrackTime aFrames) { 44 uint32_t lastFrameAudibleAcrossChannels = 0; 45 for (uint32_t channel = 0; channel < aPlanar.Length(); channel++) { 46 uint32_t lastSampleAudible = 0; 47 for (uint32_t frame = 0; frame < aFrames; frame++) { 48 if (std::fabs(aPlanar[channel][frame]) > AUDIBILITY_THRESHOLD) { 49 mEverAudible = true; 50 mSilentFramesInARow = 0; 51 lastSampleAudible = frame; 52 } 53 } 54 lastFrameAudibleAcrossChannels = 55 std::max(lastFrameAudibleAcrossChannels, lastSampleAudible); 56 } 57 mSilentFramesInARow += aFrames - lastFrameAudibleAcrossChannels - 1; 58 } 59 60 void ProcessInterleaved(const Span<AudioDataValue>& aInterleaved, 61 size_t aChannels) { 62 MOZ_ASSERT(aInterleaved.Length() % aChannels == 0); 63 uint32_t frameCount = aInterleaved.Length() / aChannels; 64 AudioDataValue* samples = aInterleaved.Elements(); 65 66 uint32_t readIndex = 0; 67 for (uint32_t i = 0; i < frameCount; i++) { 68 bool atLeastOneAudible = false; 69 for (uint32_t j = 0; j < aChannels; j++) { 70 if (std::fabs(ConvertAudioSample<float>(samples[readIndex++])) > 71 AUDIBILITY_THRESHOLD) { 72 atLeastOneAudible = true; 73 } 74 } 75 if (atLeastOneAudible) { 76 mSilentFramesInARow = 0; 77 mEverAudible = true; 78 } else { 79 mSilentFramesInARow++; 80 } 81 } 82 } 83 84 // A stream is considered audible if there was audible content in the last 85 // `mSilenceDurationSeconds` seconds, or it has never been audible for now. 86 bool RecentlyAudible() { 87 return mEverAudible && (static_cast<float>(mSilentFramesInARow) / 88 mSamplerate) < mSilenceDurationSeconds; 89 } 90 91 private: 92 const uint32_t mSamplerate; 93 const float mSilenceDurationSeconds; 94 uint64_t mSilentFramesInARow; 95 bool mEverAudible; 96 }; 97 98 }; // namespace mozilla 99 100 #endif // DOM_MEDIA_AUDIBILITYMONITOR_H_