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 #if !defined(AudioCompactor_h)
7 # define AudioCompactor_h
9 # include "MediaQueue.h"
10 # include "MediaData.h"
11 # include "VideoUtils.h"
15 class AudioCompactor
{
17 explicit AudioCompactor(MediaQueue
<AudioData
>& aQueue
) : mQueue(aQueue
) {
18 // Determine padding size used by AlignedBuffer.
19 size_t paddedSize
= AlignedAudioBuffer::AlignmentPaddingSize();
20 mSamplesPadding
= paddedSize
/ sizeof(AudioDataValue
);
21 if (mSamplesPadding
* sizeof(AudioDataValue
) < paddedSize
) {
27 // Push audio data into the underlying queue with minimal heap allocation
28 // slop. This method is responsible for allocating AudioDataValue[] buffers.
29 // The caller must provide a functor to copy the data into the buffers. The
30 // functor must provide the following signature:
32 // uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
34 // The functor must copy as many complete frames as possible to the provided
35 // buffer given its length (in AudioDataValue elements). The number of frames
36 // copied must be returned. This copy functor must support being called
37 // multiple times in order to copy the audio data fully. The copy functor
38 // must copy full frames as partial frames will be ignored.
39 template <typename CopyFunc
>
40 bool Push(int64_t aOffset
, int64_t aTime
, int32_t aSampleRate
,
41 uint32_t aFrames
, uint32_t aChannels
, CopyFunc aCopyFunc
) {
42 auto time
= media::TimeUnit::FromMicroseconds(aTime
);
44 // If we are losing more than a reasonable amount to padding, try to chunk
46 size_t maxSlop
= AudioDataSize(aFrames
, aChannels
) / MAX_SLOP_DIVISOR
;
49 uint32_t samples
= GetChunkSamples(aFrames
, aChannels
, maxSlop
);
50 if (samples
/ aChannels
> mSamplesPadding
/ aChannels
+ 1) {
51 samples
-= mSamplesPadding
;
53 AlignedAudioBuffer
buffer(samples
);
58 // Copy audio data to buffer using caller-provided functor.
59 uint32_t framesCopied
= aCopyFunc(buffer
.get(), samples
);
61 NS_ASSERTION(framesCopied
<= aFrames
, "functor copied too many frames");
62 buffer
.SetLength(size_t(framesCopied
) * aChannels
);
64 auto duration
= FramesToTimeUnit(framesCopied
, aSampleRate
);
65 if (!duration
.IsValid()) {
69 RefPtr
<AudioData
> data
= new AudioData(aOffset
, time
, std::move(buffer
),
70 aChannels
, aSampleRate
);
71 MOZ_DIAGNOSTIC_ASSERT(duration
== data
->mDuration
, "must be equal");
74 // Remove the frames we just pushed into the queue and loop if there is
77 aFrames
-= framesCopied
;
79 // NOTE: No need to update aOffset as its only an approximation anyway.
85 // Copy functor suitable for copying audio samples already in the
86 // AudioDataValue format/layout expected by AudioStream on this platform.
89 NativeCopy(const uint8_t* aSource
, size_t aSourceBytes
, uint32_t aChannels
)
91 mSourceBytes(aSourceBytes
),
95 uint32_t operator()(AudioDataValue
* aBuffer
, uint32_t aSamples
);
98 const uint8_t* const mSource
;
99 const size_t mSourceBytes
;
100 const uint32_t mChannels
;
104 // Allow 12.5% slop before chunking kicks in. Public so that the gtest can
106 static const size_t MAX_SLOP_DIVISOR
= 8;
109 // Compute the number of AudioDataValue samples that will be fit the most
110 // frames while keeping heap allocation slop less than the given threshold.
111 static uint32_t GetChunkSamples(uint32_t aFrames
, uint32_t aChannels
,
114 static size_t BytesPerFrame(uint32_t aChannels
) {
115 return sizeof(AudioDataValue
) * aChannels
;
118 static size_t AudioDataSize(uint32_t aFrames
, uint32_t aChannels
) {
119 return aFrames
* BytesPerFrame(aChannels
);
122 MediaQueue
<AudioData
>& mQueue
;
123 size_t mSamplesPadding
;
126 } // namespace mozilla
128 #endif // AudioCompactor_h