Make passing PlatformAudioData in audioSamplesAvaliable const-correct.
[WebKit-https.git] / Source / WebCore / platform / audio / mac / AudioSampleBufferList.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "AudioSampleBufferList.h"
28
29 #if ENABLE(MEDIA_STREAM)
30
31 #include "Logging.h"
32 #include "VectorMath.h"
33 #include <Accelerate/Accelerate.h>
34 #include <AudioToolbox/AudioConverter.h>
35 #include <wtf/SetForScope.h>
36
37 namespace WebCore {
38
39 using namespace VectorMath;
40
41 Ref<AudioSampleBufferList> AudioSampleBufferList::create(const CAAudioStreamDescription& format, size_t maximumSampleCount)
42 {
43     return adoptRef(*new AudioSampleBufferList(format, maximumSampleCount));
44 }
45
46 AudioSampleBufferList::AudioSampleBufferList(const CAAudioStreamDescription& format, size_t maximumSampleCount)
47 {
48     m_internalFormat = std::make_unique<CAAudioStreamDescription>(format);
49
50     m_sampleCapacity = maximumSampleCount;
51     m_maxBufferSizePerChannel = maximumSampleCount * format.bytesPerFrame() / format.numberOfChannelStreams();
52
53     ASSERT(format.sampleRate() >= 0);
54     reset();
55 }
56
57 AudioSampleBufferList::~AudioSampleBufferList()
58 {
59     m_internalFormat = nullptr;
60     m_bufferList = nullptr;
61 }
62
63 void AudioSampleBufferList::setSampleCount(size_t count)
64 {
65     ASSERT(count <= m_sampleCapacity);
66     if (count <= m_sampleCapacity)
67         m_sampleCount = count;
68 }
69
70 void AudioSampleBufferList::applyGain(AudioBufferList& bufferList, float gain, AudioStreamDescription::PCMFormat format)
71 {
72     for (uint32_t i = 0; i < bufferList.mNumberBuffers; ++i) {
73         switch (format) {
74         case AudioStreamDescription::Int16: {
75             int16_t* buffer = static_cast<int16_t*>(bufferList.mBuffers[i].mData);
76             int frameCount = bufferList.mBuffers[i].mDataByteSize / sizeof(int16_t);
77             for (int i = 0; i < frameCount; i++)
78                 buffer[i] *= gain;
79             break;
80         }
81         case AudioStreamDescription::Int32: {
82             int32_t* buffer = static_cast<int32_t*>(bufferList.mBuffers[i].mData);
83             int frameCount = bufferList.mBuffers[i].mDataByteSize / sizeof(int32_t);
84             for (int i = 0; i < frameCount; i++)
85                 buffer[i] *= gain;
86             break;
87             break;
88         }
89         case AudioStreamDescription::Float32: {
90             float* buffer = static_cast<float*>(bufferList.mBuffers[i].mData);
91             vDSP_vsmul(buffer, 1, &gain, buffer, 1, bufferList.mBuffers[i].mDataByteSize / sizeof(float));
92             break;
93         }
94         case AudioStreamDescription::Float64: {
95             double* buffer = static_cast<double*>(bufferList.mBuffers[i].mData);
96             double gainAsDouble = gain;
97             vDSP_vsmulD(buffer, 1, &gainAsDouble, buffer, 1, bufferList.mBuffers[i].mDataByteSize / sizeof(double));
98             break;
99         }
100         case AudioStreamDescription::None:
101             ASSERT_NOT_REACHED();
102             break;
103         }
104     }
105 }
106
107 void AudioSampleBufferList::applyGain(float gain)
108 {
109     applyGain(*m_bufferList, gain, m_internalFormat->format());
110 }
111
112 OSStatus AudioSampleBufferList::mixFrom(const AudioSampleBufferList& source, size_t frameCount)
113 {
114     ASSERT(source.streamDescription() == streamDescription());
115
116     if (source.streamDescription() != streamDescription())
117         return kAudio_ParamError;
118
119     if (frameCount > source.sampleCount())
120         frameCount = source.sampleCount();
121
122     if (frameCount > m_sampleCapacity)
123         return kAudio_ParamError;
124
125     m_sampleCount = frameCount;
126
127     WebAudioBufferList& sourceBuffer = source.bufferList();
128     for (uint32_t i = 0; i < m_bufferList->bufferCount(); i++) {
129         switch (m_internalFormat->format()) {
130         case AudioStreamDescription::Int16: {
131             int16_t* destination = static_cast<int16_t*>(m_bufferList->buffer(i)->mData);
132             int16_t* source = static_cast<int16_t*>(sourceBuffer.buffer(i)->mData);
133             for (size_t i = 0; i < frameCount; i++)
134                 destination[i] += source[i];
135             break;
136         }
137         case AudioStreamDescription::Int32: {
138             int32_t* destination = static_cast<int32_t*>(m_bufferList->buffer(i)->mData);
139             vDSP_vaddi(destination, 1, reinterpret_cast<int32_t*>(sourceBuffer.buffer(i)->mData), 1, destination, 1, frameCount);
140             break;
141         }
142         case AudioStreamDescription::Float32: {
143             float* destination = static_cast<float*>(m_bufferList->buffer(i)->mData);
144             vDSP_vadd(destination, 1, reinterpret_cast<float*>(sourceBuffer.buffer(i)->mData), 1, destination, 1, frameCount);
145             break;
146         }
147         case AudioStreamDescription::Float64: {
148             double* destination = static_cast<double*>(m_bufferList->buffer(i)->mData);
149             vDSP_vaddD(destination, 1, reinterpret_cast<double*>(sourceBuffer.buffer(i)->mData), 1, destination, 1, frameCount);
150             break;
151         }
152         case AudioStreamDescription::None:
153             ASSERT_NOT_REACHED();
154             break;
155         }
156     }
157
158     return 0;
159 }
160
161 OSStatus AudioSampleBufferList::copyFrom(const AudioSampleBufferList& source, size_t frameCount)
162 {
163     ASSERT(source.streamDescription() == streamDescription());
164
165     if (source.streamDescription() != streamDescription())
166         return kAudio_ParamError;
167
168     if (frameCount > source.sampleCount())
169         frameCount = source.sampleCount();
170
171     if (frameCount > m_sampleCapacity)
172         return kAudio_ParamError;
173
174     m_sampleCount = frameCount;
175
176     for (uint32_t i = 0; i < m_bufferList->bufferCount(); i++) {
177         uint8_t* sourceData = static_cast<uint8_t*>(source.bufferList().buffer(i)->mData);
178         uint8_t* destination = static_cast<uint8_t*>(m_bufferList->buffer(i)->mData);
179         memcpy(destination, sourceData, frameCount * m_internalFormat->bytesPerPacket());
180     }
181
182     return 0;
183 }
184
185 OSStatus AudioSampleBufferList::copyTo(AudioBufferList& buffer, size_t frameCount)
186 {
187     if (frameCount > m_sampleCount)
188         return kAudio_ParamError;
189     if (buffer.mNumberBuffers > m_bufferList->bufferCount())
190         return kAudio_ParamError;
191
192     for (uint32_t i = 0; i < buffer.mNumberBuffers; i++) {
193         uint8_t* sourceData = static_cast<uint8_t*>(m_bufferList->buffer(i)->mData);
194         uint8_t* destination = static_cast<uint8_t*>(buffer.mBuffers[i].mData);
195         memcpy(destination, sourceData, frameCount * m_internalFormat->bytesPerPacket());
196     }
197
198     return 0;
199 }
200
201 void AudioSampleBufferList::reset()
202 {
203     m_sampleCount = 0;
204     m_timestamp = 0;
205     m_hostTime = -1;
206
207     m_bufferList = std::make_unique<WebAudioBufferList>(*m_internalFormat, m_maxBufferSizePerChannel);
208 }
209
210 void AudioSampleBufferList::zero()
211 {
212     zeroABL(*m_bufferList, m_internalFormat->bytesPerPacket() * m_sampleCapacity);
213 }
214
215 void AudioSampleBufferList::zeroABL(AudioBufferList& buffer, size_t byteCount)
216 {
217     for (uint32_t i = 0; i < buffer.mNumberBuffers; ++i)
218         memset(buffer.mBuffers[i].mData, 0, byteCount);
219 }
220
221 OSStatus AudioSampleBufferList::convertInput(UInt32* ioNumberDataPackets, AudioBufferList* ioData)
222 {
223     if (!ioNumberDataPackets || !ioData || !m_converterInputBuffer) {
224         LOG_ERROR("AudioSampleBufferList::reconfigureInput(%p) invalid input to AudioConverterInput", this);
225         return kAudioConverterErr_UnspecifiedError;
226     }
227
228     size_t packetCount = m_converterInputBuffer->mBuffers[0].mDataByteSize / m_converterInputBytesPerPacket;
229     if (*ioNumberDataPackets > m_sampleCapacity) {
230         LOG_ERROR("AudioSampleBufferList::convertInput(%p) not enough internal storage: needed = %zu, available = %lu", this, (size_t)*ioNumberDataPackets, m_sampleCapacity);
231         return kAudioConverterErr_InvalidInputSize;
232     }
233
234     *ioNumberDataPackets = static_cast<UInt32>(packetCount);
235     for (uint32_t i = 0; i < ioData->mNumberBuffers; ++i) {
236         ioData->mBuffers[i].mData = m_converterInputBuffer->mBuffers[i].mData;
237         ioData->mBuffers[i].mDataByteSize = m_converterInputBuffer->mBuffers[i].mDataByteSize;
238     }
239
240     return 0;
241 }
242
243 OSStatus AudioSampleBufferList::audioConverterCallback(AudioConverterRef, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription**, void* inRefCon)
244 {
245     return static_cast<AudioSampleBufferList*>(inRefCon)->convertInput(ioNumberDataPackets, ioData);
246 }
247
248 OSStatus AudioSampleBufferList::copyFrom(const AudioBufferList& source, AudioConverterRef converter)
249 {
250     reset();
251
252     AudioStreamBasicDescription inputFormat;
253     UInt32 propertyDataSize = sizeof(inputFormat);
254     AudioConverterGetProperty(converter, kAudioConverterCurrentInputStreamDescription, &propertyDataSize, &inputFormat);
255     m_converterInputBytesPerPacket = inputFormat.mBytesPerPacket;
256     SetForScope<const AudioBufferList*> scopedInputBuffer(m_converterInputBuffer, &source);
257
258 #if !LOG_DISABLED
259     AudioStreamBasicDescription outputFormat;
260     propertyDataSize = sizeof(outputFormat);
261     AudioConverterGetProperty(converter, kAudioConverterCurrentOutputStreamDescription, &propertyDataSize, &outputFormat);
262
263     ASSERT(outputFormat.mChannelsPerFrame == m_bufferList->bufferCount());
264     for (uint32_t i = 0; i < m_bufferList->bufferCount(); ++i) {
265         ASSERT(m_bufferList->buffer(i)->mData);
266         ASSERT(m_bufferList->buffer(i)->mDataByteSize);
267     }
268 #endif
269
270     UInt32 samplesConverted = static_cast<UInt32>(m_sampleCapacity);
271     OSStatus err = AudioConverterFillComplexBuffer(converter, audioConverterCallback, this, &samplesConverted, m_bufferList->list(), nullptr);
272     if (err) {
273         LOG_ERROR("AudioSampleBufferList::copyFrom(%p) AudioConverterFillComplexBuffer returned error %d (%.4s)", this, (int)err, (char*)&err);
274         m_sampleCount = std::min(m_sampleCapacity, static_cast<size_t>(samplesConverted));
275         zero();
276         return err;
277     }
278
279     m_sampleCount = samplesConverted;
280     return 0;
281 }
282
283 OSStatus AudioSampleBufferList::copyFrom(AudioSampleBufferList& source, AudioConverterRef converter)
284 {
285     return copyFrom(source.bufferList(), converter);
286 }
287
288 OSStatus AudioSampleBufferList::copyFrom(CARingBuffer& ringBuffer, size_t sampleCount, uint64_t startFrame, CARingBuffer::FetchMode mode)
289 {
290     reset();
291     if (ringBuffer.fetch(bufferList().list(), sampleCount, startFrame, mode) != CARingBuffer::Ok)
292         return kAudio_ParamError;
293
294     m_sampleCount = sampleCount;
295     return 0;
296 }
297
298 } // namespace WebCore
299
300 #endif // ENABLE(MEDIA_STREAM)