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/. */
7 #ifndef DOM_MEDIA_AUDIBILITYMONITOR_H_
8 #define DOM_MEDIA_AUDIBILITYMONITOR_H_
12 #include "AudioSampleFormat.h"
13 #include "WebAudioUtils.h"
14 #include "AudioBlock.h"
15 #include "MediaData.h"
19 class AudibilityMonitor
{
21 // ≈ 20 * log10(pow(2, 12)), noise floor of 12bit audio
22 const float AUDIBILITY_THRESHOLD
=
23 dom::WebAudioUtils::ConvertDecibelsToLinear(-72.);
25 AudibilityMonitor(uint32_t aSamplerate
, float aSilenceDurationSeconds
)
26 : mSamplerate(aSamplerate
),
27 mSilenceDurationSeconds(aSilenceDurationSeconds
),
28 mSilentFramesInARow(0),
29 mEverAudible(false) {}
31 void Process(const AudioData
* aData
) {
32 ProcessInterleaved(aData
->Data(), aData
->mChannels
);
35 void Process(const AudioBlock
& aData
) {
36 if (aData
.IsNull() || aData
.IsMuted()) {
37 mSilentFramesInARow
+= aData
.GetDuration();
40 ProcessPlanar(aData
.ChannelData
<float>(), aData
.GetDuration());
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
) {
50 mSilentFramesInARow
= 0;
51 lastSampleAudible
= frame
;
54 lastFrameAudibleAcrossChannels
=
55 std::max(lastFrameAudibleAcrossChannels
, lastSampleAudible
);
57 mSilentFramesInARow
+= aFrames
- lastFrameAudibleAcrossChannels
- 1;
60 void ProcessInterleaved(const Span
<AudioDataValue
>& aInterleaved
,
62 MOZ_ASSERT(aInterleaved
.Length() % aChannels
== 0);
63 uint32_t frameCount
= aInterleaved
.Length() / aChannels
;
64 AudioDataValue
* samples
= aInterleaved
.Elements();
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;
75 if (atLeastOneAudible
) {
76 mSilentFramesInARow
= 0;
79 mSilentFramesInARow
++;
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
;
92 const uint32_t mSamplerate
;
93 const float mSilenceDurationSeconds
;
94 uint64_t mSilentFramesInARow
;
98 }; // namespace mozilla
100 #endif // DOM_MEDIA_AUDIBILITYMONITOR_H_