Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 : #ifndef MOZILLA_AUDIOBLOCK_H_
7 : #define MOZILLA_AUDIOBLOCK_H_
8 :
9 : #include "AudioSegment.h"
10 :
11 : namespace mozilla {
12 :
13 : /**
14 : * An AudioChunk whose buffer contents need to be valid only for one
15 : * processing block iteration, after which contents can be overwritten if the
16 : * buffer has not been passed to longer term storage or to another thread,
17 : * which may happen though AsAudioChunk() or AsMutableChunk().
18 : *
19 : * Use on graph thread only.
20 : */
21 : class AudioBlock : private AudioChunk
22 : {
23 : public:
24 0 : AudioBlock() {
25 0 : mDuration = WEBAUDIO_BLOCK_SIZE;
26 0 : mBufferFormat = AUDIO_FORMAT_SILENCE;
27 0 : }
28 : // No effort is made in constructors to ensure that mBufferIsDownstreamRef
29 : // is set because the block is expected to be a temporary and so the
30 : // reference will be released before the next iteration.
31 : // The custom copy constructor is required so as not to set
32 : // mBufferIsDownstreamRef without notifying AudioBlockBuffer.
33 0 : AudioBlock(const AudioBlock& aBlock) : AudioChunk(aBlock.AsAudioChunk()) {}
34 : explicit AudioBlock(const AudioChunk& aChunk)
35 : : AudioChunk(aChunk)
36 : {
37 : MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
38 : }
39 : ~AudioBlock();
40 :
41 : using AudioChunk::GetDuration;
42 : using AudioChunk::IsNull;
43 : using AudioChunk::ChannelCount;
44 : using AudioChunk::ChannelData;
45 : using AudioChunk::SizeOfExcludingThisIfUnshared;
46 : using AudioChunk::SizeOfExcludingThis;
47 : // mDuration is not exposed. Use GetDuration().
48 : // mBuffer is not exposed. Use SetBuffer().
49 : using AudioChunk::mChannelData;
50 : using AudioChunk::mVolume;
51 : using AudioChunk::mBufferFormat;
52 :
53 0 : const AudioChunk& AsAudioChunk() const { return *this; }
54 0 : AudioChunk* AsMutableChunk() {
55 0 : ClearDownstreamMark();
56 0 : return this;
57 : }
58 :
59 : /**
60 : * Allocates, if necessary, aChannelCount buffers of WEBAUDIO_BLOCK_SIZE float
61 : * samples for writing.
62 : */
63 : void AllocateChannels(uint32_t aChannelCount);
64 :
65 : /**
66 : * ChannelFloatsForWrite() should only be used when the buffers have been
67 : * created with AllocateChannels().
68 : */
69 0 : float* ChannelFloatsForWrite(size_t aChannel)
70 : {
71 0 : MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
72 0 : MOZ_ASSERT(CanWrite());
73 0 : return static_cast<float*>(const_cast<void*>(mChannelData[aChannel]));
74 : }
75 :
76 : void SetBuffer(ThreadSharedObject* aNewBuffer);
77 0 : void SetNull(StreamTime aDuration) {
78 0 : MOZ_ASSERT(aDuration == WEBAUDIO_BLOCK_SIZE);
79 0 : SetBuffer(nullptr);
80 0 : mChannelData.Clear();
81 0 : mVolume = 1.0f;
82 0 : mBufferFormat = AUDIO_FORMAT_SILENCE;
83 0 : }
84 :
85 0 : AudioBlock& operator=(const AudioBlock& aBlock) {
86 : // Instead of just copying, mBufferIsDownstreamRef must be first cleared
87 : // if set. It is set again for the new mBuffer if possible. This happens
88 : // in SetBuffer().
89 0 : return *this = aBlock.AsAudioChunk();
90 : }
91 0 : AudioBlock& operator=(const AudioChunk& aChunk) {
92 0 : MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
93 0 : SetBuffer(aChunk.mBuffer);
94 0 : mChannelData = aChunk.mChannelData;
95 0 : mVolume = aChunk.mVolume;
96 0 : mBufferFormat = aChunk.mBufferFormat;
97 0 : return *this;
98 : }
99 :
100 0 : bool IsMuted() const { return mVolume == 0.0f; }
101 :
102 0 : bool IsSilentOrSubnormal() const
103 : {
104 0 : if (!mBuffer) {
105 0 : return true;
106 : }
107 :
108 0 : for (uint32_t i = 0, length = mChannelData.Length(); i < length; ++i) {
109 0 : const float* channel = static_cast<const float*>(mChannelData[i]);
110 0 : for (StreamTime frame = 0; frame < mDuration; ++frame) {
111 0 : if (fabs(channel[frame]) >= FLT_MIN) {
112 0 : return false;
113 : }
114 : }
115 : }
116 :
117 0 : return true;
118 : }
119 :
120 : private:
121 : void ClearDownstreamMark();
122 : bool CanWrite();
123 :
124 : // mBufferIsDownstreamRef is set only when mBuffer references an
125 : // AudioBlockBuffer created in a different AudioBlock. That can happen when
126 : // this AudioBlock is on a node downstream from the node which created the
127 : // buffer. When this is set, the AudioBlockBuffer is notified that this
128 : // reference does prevent the upstream node from re-using the buffer next
129 : // iteration and modifying its contents. The AudioBlockBuffer is also
130 : // notified when mBuffer releases this reference.
131 : bool mBufferIsDownstreamRef = false;
132 : };
133 :
134 : } // namespace mozilla
135 :
136 : #endif // MOZILLA_AUDIOBLOCK_H_
|