Bug 1943650 - Command-line --help output misformatted after --dbus-service. r=emilio
[gecko.git] / dom / media / driftcontrol / AudioChunkList.h
blob2c10db942d3323546581adf28774a9c6094b429b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef DOM_MEDIA_DRIFTCONTROL_AUDIOCHUNKLIST_H_
7 #define DOM_MEDIA_DRIFTCONTROL_AUDIOCHUNKLIST_H_
9 #include "AudioSegment.h"
10 #include "TimeUnits.h"
12 namespace mozilla {
14 /**
15 * AudioChunkList provides a way to have preallocated audio buffers in
16 * AudioSegment. The idea is that the amount of AudioChunks is created in
17 * advance. Each AudioChunk is able to hold a specific amount of audio
18 * (capacity). The total capacity of AudioChunkList is specified by the number
19 * of AudioChunks. The important aspect of the AudioChunkList is that
20 * preallocates everything and reuse the same chunks similar to a ring buffer.
22 * Why the whole AudioChunk is preallocated and not some raw memory buffer? This
23 * is due to the limitations of MediaTrackGraph. The way that MTG works depends
24 * on `AudioSegment`s to convey the actual audio data. An AudioSegment consists
25 * of AudioChunks. The AudioChunk is built in a way, that owns and allocates the
26 * audio buffers. Thus, since the use of AudioSegment is mandatory if the audio
27 * data was in a different form, the only way to use it from the audio thread
28 * would be to create the AudioChunk there. That would result in a copy
29 * operation (not very important) and most of all an allocation of the audio
30 * buffer in the audio thread. This happens in many places inside MTG it's a bad
31 * practice, though, and it has been avoided due to the AudioChunkList.
33 * After construction the sample format must be set, when it is available. It
34 * can be set in the audio thread. Before setting the sample format is not
35 * possible to use any method of AudioChunkList.
37 * Every AudioChunk in the AudioChunkList is preallocated with a capacity of 128
38 * frames of float audio. Nevertheless, the sample format is not available at
39 * that point. Thus if the sample format is set to short, the capacity of each
40 * chunk changes to 256 number of frames, and the total duration becomes twice
41 * big. There are methods to get the chunk capacity and total capacity in frames
42 * and must always be used.
44 * Two things to note. First, when the channel count changes everything is
45 * recreated which means reallocations. Second, the total capacity might differs
46 * from the requested total capacity for two reasons. First, if the sample
47 * format is set to short and second because the number of chunks in the list
48 * divides exactly the final total capacity. The corresponding method must
49 * always be used to query the total capacity.
51 class AudioChunkList {
52 public:
53 /**
54 * Constructor, the final total duration might be different from the requested
55 * `aTotalDuration`. Memory allocation takes place.
57 AudioChunkList(uint32_t aTotalDuration, uint32_t aChannels,
58 const PrincipalHandle& aPrincipalHandle);
59 AudioChunkList(const AudioChunkList&) = delete;
60 AudioChunkList(AudioChunkList&&) = delete;
61 ~AudioChunkList() = default;
63 /**
64 * Set sample format. It must be done before any other method being used.
66 void SetSampleFormat(AudioSampleFormat aFormat);
67 /**
68 * Get the next available AudioChunk. The duration of the chunk will be zero
69 * and the volume 1.0. However, the buffers will be there ready to be written.
70 * Please note, that a reference of the preallocated chunk is returned. Thus
71 * it _must not be consumed_ directly. If the chunk needs to be consumed it
72 * must be copied to a temporary chunk first. For example:
73 * ```
74 * AudioChunk& chunk = audioChunklist.GetNext();
75 * // Set up the chunk
76 * AudioChunk tmp = chunk;
77 * audioSegment.AppendAndConsumeChunk(std::move(tmp));
78 * ```
79 * This way no memory allocation or copy, takes place.
81 AudioChunk& GetNext();
83 /**
84 * Get the capacity of each individual AudioChunk in the list.
86 uint32_t ChunkCapacity() const {
87 MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
88 mSampleFormat == AUDIO_FORMAT_FLOAT32);
89 return mChunkCapacity;
91 /**
92 * Get the total capacity of AudioChunkList.
94 uint32_t TotalCapacity() const {
95 MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
96 mSampleFormat == AUDIO_FORMAT_FLOAT32);
97 return CheckedInt<uint32_t>(mChunkCapacity * mChunks.Length()).value();
101 * Update the channel count of the AudioChunkList. Memory allocation is
102 * taking place.
104 void Update(uint32_t aChannels);
106 private:
107 void IncrementIndex() {
108 ++mIndex;
109 mIndex = CheckedInt<uint32_t>(mIndex % mChunks.Length()).value();
111 void CreateChunks(uint32_t aNumOfChunks, uint32_t aChannels);
112 void UpdateToMonoOrStereo(uint32_t aChannels);
114 private:
115 const PrincipalHandle mPrincipalHandle;
116 nsTArray<AudioChunk> mChunks;
117 uint32_t mIndex = 0;
118 uint32_t mChunkCapacity = WEBAUDIO_BLOCK_SIZE;
119 AudioSampleFormat mSampleFormat = AUDIO_FORMAT_SILENCE;
122 } // namespace mozilla
124 #endif // DOM_MEDIA_DRIFTCONTROL_AUDIOCHUNKLIST_H_