[Mac] Add classes to manage audio samples
[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
36 namespace WebCore {
37
38 using namespace VectorMath;
39
40 Ref<AudioSampleBufferList> AudioSampleBufferList::create(const CAAudioStreamDescription& format, size_t maximumSampleCount)
41 {
42     return adoptRef(*new AudioSampleBufferList(format, maximumSampleCount));
43 }
44
45 AudioSampleBufferList::AudioSampleBufferList(const CAAudioStreamDescription& format, size_t maximumSampleCount)
46 {
47     m_internalFormat = std::make_unique<CAAudioStreamDescription>(format);
48
49     m_sampleCapacity = maximumSampleCount;
50     m_sampleCount = 0;
51     m_maxBufferSizePerChannel = maximumSampleCount * format.bytesPerFrame() / format.numberOfChannelStreams();
52
53     ASSERT(format.sampleRate() >= 0);
54
55     size_t bufferSize = format.numberOfChannelStreams() * m_maxBufferSizePerChannel;
56     ASSERT(bufferSize <= SIZE_MAX);
57     if (bufferSize > SIZE_MAX)
58         return;
59
60     m_bufferListBaseSize = audioBufferListSizeForStream(format);
61     ASSERT(m_bufferListBaseSize <= SIZE_MAX);
62     if (m_bufferListBaseSize > SIZE_MAX)
63         return;
64
65     size_t allocSize = m_bufferListBaseSize + bufferSize;
66     m_bufferList = std::unique_ptr<AudioBufferList>(static_cast<AudioBufferList*>(::operator new (allocSize)));
67
68     reset();
69 }
70
71 AudioSampleBufferList::~AudioSampleBufferList()
72 {
73     m_internalFormat = nullptr;
74     m_bufferList = nullptr;
75 }
76
77 void AudioSampleBufferList::setSampleCount(size_t count)
78 {
79     ASSERT(count <= m_sampleCapacity);
80     if (count <= m_sampleCapacity)
81         m_sampleCount = count;
82 }
83
84 void AudioSampleBufferList::applyGain(AudioBufferList& bufferList, float gain, AudioStreamDescription::PCMFormat format)
85 {
86     for (uint32_t i = 0; i < bufferList.mNumberBuffers; ++i) {
87         switch (format) {
88         case AudioStreamDescription::Int16: {
89             int16_t* buffer = static_cast<int16_t*>(bufferList.mBuffers[i].mData);
90             int frameCount = bufferList.mBuffers[i].mDataByteSize / sizeof(int16_t);
91             for (int i = 0; i < frameCount; i++)
92                 buffer[i] *= gain;
93             break;
94         }
95         case AudioStreamDescription::Int32: {
96             int32_t* buffer = static_cast<int32_t*>(bufferList.mBuffers[i].mData);
97             int frameCount = bufferList.mBuffers[i].mDataByteSize / sizeof(int32_t);
98             for (int i = 0; i < frameCount; i++)
99                 buffer[i] *= gain;
100             break;
101             break;
102         }
103         case AudioStreamDescription::Float32: {
104             float* buffer = static_cast<float*>(bufferList.mBuffers[i].mData);
105             vDSP_vsmul(buffer, 1, &gain, buffer, 1, bufferList.mBuffers[i].mDataByteSize / sizeof(float));
106             break;
107         }
108         case AudioStreamDescription::Float64: {
109             double* buffer = static_cast<double*>(bufferList.mBuffers[i].mData);
110             double gainAsDouble = gain;
111             vDSP_vsmulD(buffer, 1, &gainAsDouble, buffer, 1, bufferList.mBuffers[i].mDataByteSize / sizeof(double));
112             break;
113         }
114         case AudioStreamDescription::None:
115             ASSERT_NOT_REACHED();
116             break;
117         }
118     }
119 }
120
121 void AudioSampleBufferList::applyGain(float gain)
122 {
123     applyGain(*m_bufferList, gain, m_internalFormat->format());
124 }
125
126 OSStatus AudioSampleBufferList::mixFrom(const AudioSampleBufferList& source, size_t frameCount)
127 {
128     ASSERT(source.streamDescription() == streamDescription());
129
130     if (source.streamDescription() != streamDescription())
131         return kAudio_ParamError;
132
133     if (frameCount > source.sampleCount())
134         frameCount = source.sampleCount();
135
136     if (frameCount > m_sampleCapacity)
137         return kAudio_ParamError;
138
139     m_sampleCount = frameCount;
140
141     AudioBufferList& sourceBuffer = source.bufferList();
142     for (uint32_t i = 0; i < m_bufferList->mNumberBuffers; i++) {
143         switch (m_internalFormat->format()) {
144         case AudioStreamDescription::Int16: {
145             int16_t* destination = static_cast<int16_t*>(m_bufferList->mBuffers[i].mData);
146             int16_t* source = static_cast<int16_t*>(sourceBuffer.mBuffers[i].mData);
147             for (size_t i = 0; i < frameCount; i++)
148                 destination[i] += source[i];
149             break;
150         }
151         case AudioStreamDescription::Int32: {
152             int32_t* destination = static_cast<int32_t*>(m_bufferList->mBuffers[i].mData);
153             vDSP_vaddi(destination, 1, reinterpret_cast<int32_t*>(sourceBuffer.mBuffers[i].mData), 1, destination, 1, frameCount);
154             break;
155         }
156         case AudioStreamDescription::Float32: {
157             float* destination = static_cast<float*>(m_bufferList->mBuffers[i].mData);
158             vDSP_vadd(destination, 1, reinterpret_cast<float*>(sourceBuffer.mBuffers[i].mData), 1, destination, 1, frameCount);
159             break;
160         }
161         case AudioStreamDescription::Float64: {
162             double* destination = static_cast<double*>(m_bufferList->mBuffers[i].mData);
163             vDSP_vaddD(destination, 1, reinterpret_cast<double*>(sourceBuffer.mBuffers[i].mData), 1, destination, 1, frameCount);
164             break;
165         }
166         case AudioStreamDescription::None:
167             ASSERT_NOT_REACHED();
168             break;
169         }
170     }
171
172     return 0;
173 }
174
175 OSStatus AudioSampleBufferList::copyFrom(const AudioSampleBufferList& source, size_t frameCount)
176 {
177     ASSERT(source.streamDescription() == streamDescription());
178
179     if (source.streamDescription() != streamDescription())
180         return kAudio_ParamError;
181
182     if (frameCount > source.sampleCount())
183         frameCount = source.sampleCount();
184
185     if (frameCount > m_sampleCapacity)
186         return kAudio_ParamError;
187
188     m_sampleCount = frameCount;
189
190     for (uint32_t i = 0; i < m_bufferList->mNumberBuffers; i++) {
191         uint8_t* sourceData = static_cast<uint8_t*>(source.bufferList().mBuffers[i].mData);
192         uint8_t* destination = static_cast<uint8_t*>(m_bufferList->mBuffers[i].mData);
193         memcpy(destination, sourceData, frameCount * m_internalFormat->bytesPerPacket());
194     }
195
196     return 0;
197 }
198
199 OSStatus AudioSampleBufferList::copyTo(AudioBufferList& buffer, size_t frameCount)
200 {
201     if (frameCount > m_sampleCount)
202         return kAudio_ParamError;
203     if (buffer.mNumberBuffers > m_bufferList->mNumberBuffers)
204         return kAudio_ParamError;
205
206     for (uint32_t i = 0; i < buffer.mNumberBuffers; i++) {
207         uint8_t* sourceData = static_cast<uint8_t*>(m_bufferList->mBuffers[i].mData);
208         uint8_t* destination = static_cast<uint8_t*>(buffer.mBuffers[i].mData);
209         memcpy(destination, sourceData, frameCount * m_internalFormat->bytesPerPacket());
210     }
211
212     return 0;
213 }
214
215 void AudioSampleBufferList::reset()
216 {
217     m_sampleCount = 0;
218     m_timestamp = 0;
219     m_hostTime = -1;
220
221     uint8_t* data = reinterpret_cast<uint8_t*>(m_bufferList.get()) + m_bufferListBaseSize;
222     m_bufferList->mNumberBuffers = m_internalFormat->numberOfChannelStreams();
223     for (uint32_t i = 0; i < m_bufferList->mNumberBuffers; ++i) {
224         auto& buffer = m_bufferList->mBuffers[i];
225         buffer.mData = data;
226         buffer.mDataByteSize = m_maxBufferSizePerChannel;
227         buffer.mNumberChannels = m_internalFormat->numberOfInterleavedChannels();
228         data = data + m_maxBufferSizePerChannel;
229     }
230 }
231
232 void AudioSampleBufferList::zero()
233 {
234     zeroABL(*m_bufferList, m_internalFormat->bytesPerPacket() * m_sampleCapacity);
235 }
236
237 void AudioSampleBufferList::zeroABL(AudioBufferList& buffer, size_t byteCount)
238 {
239     for (uint32_t i = 0; i < buffer.mNumberBuffers; ++i)
240         memset(buffer.mBuffers[i].mData, 0, byteCount);
241 }
242
243 OSStatus AudioSampleBufferList::convertInput(UInt32* ioNumberDataPackets, AudioBufferList* ioData)
244 {
245     if (!ioNumberDataPackets || !ioData || !m_converterInputBuffer) {
246         LOG_ERROR("AudioSampleBufferList::reconfigureInput(%p) invalid input to AudioConverterInput", this);
247         return kAudioConverterErr_UnspecifiedError;
248     }
249
250     size_t packetCount = m_converterInputBuffer->mBuffers[0].mDataByteSize / m_converterInputBytesPerPacket;
251     if (*ioNumberDataPackets > m_sampleCapacity) {
252         LOG_ERROR("AudioSampleBufferList::convertInput(%p) not enough internal storage: needed = %u, available = %lu", this, *ioNumberDataPackets, m_sampleCapacity);
253         return kAudioConverterErr_InvalidInputSize;
254     }
255
256     *ioNumberDataPackets = static_cast<UInt32>(packetCount);
257     for (uint32_t i = 0; i < ioData->mNumberBuffers; ++i) {
258         ioData->mBuffers[i].mData = m_converterInputBuffer->mBuffers[i].mData;
259         ioData->mBuffers[i].mDataByteSize = m_converterInputBuffer->mBuffers[i].mDataByteSize;
260     }
261
262     return 0;
263 }
264
265 OSStatus AudioSampleBufferList::audioConverterCallback(AudioConverterRef, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription**, void* inRefCon)
266 {
267     return static_cast<AudioSampleBufferList*>(inRefCon)->convertInput(ioNumberDataPackets, ioData);
268 }
269
270 OSStatus AudioSampleBufferList::copyFrom(AudioBufferList& source, AudioConverterRef converter)
271 {
272     reset();
273
274     AudioStreamBasicDescription inputFormat;
275     UInt32 propertyDataSize = sizeof(inputFormat);
276     AudioConverterGetProperty(converter, kAudioConverterCurrentInputStreamDescription, &propertyDataSize, &inputFormat);
277     m_converterInputBytesPerPacket = inputFormat.mBytesPerPacket;
278     m_converterInputBuffer = &source;
279
280     auto* outputData = m_bufferList.get();
281
282 #if !LOG_DISABLED
283     AudioStreamBasicDescription outputFormat;
284     propertyDataSize = sizeof(outputFormat);
285     AudioConverterGetProperty(converter, kAudioConverterCurrentOutputStreamDescription, &propertyDataSize, &outputFormat);
286
287     ASSERT(outputFormat.mChannelsPerFrame == outputData->mNumberBuffers);
288     for (uint32_t i = 0; i < outputData->mNumberBuffers; ++i) {
289         ASSERT(outputData->mBuffers[i].mData);
290         ASSERT(outputData->mBuffers[i].mDataByteSize);
291     }
292 #endif
293
294     UInt32 samplesConverted = static_cast<UInt32>(m_sampleCapacity);
295     OSStatus err = AudioConverterFillComplexBuffer(converter, audioConverterCallback, this, &samplesConverted, outputData, nullptr);
296     if (err) {
297         LOG_ERROR("AudioSampleBufferList::copyFrom(%p) AudioConverterFillComplexBuffer returned error %d (%.4s)", this, err, (char*)&err);
298         m_sampleCount = std::min(m_sampleCapacity, static_cast<size_t>(samplesConverted));
299         zero();
300         return err;
301     }
302
303     m_sampleCount = samplesConverted;
304     return 0;
305 }
306
307 OSStatus AudioSampleBufferList::copyFrom(AudioSampleBufferList& source, AudioConverterRef converter)
308 {
309     return copyFrom(source.bufferList(), converter);
310 }
311
312 OSStatus AudioSampleBufferList::copyFrom(CARingBuffer& ringBuffer, size_t sampleCount, uint64_t startFrame, CARingBuffer::FetchMode mode)
313 {
314     reset();
315     if (ringBuffer.fetch(&bufferList(), sampleCount, startFrame, mode) != CARingBuffer::Ok)
316         return kAudio_ParamError;
317
318     m_sampleCount = sampleCount;
319     return 0;
320 }
321
322 void AudioSampleBufferList::configureBufferListForStream(AudioBufferList& bufferList, const CAAudioStreamDescription& format, uint8_t* bufferData, size_t sampleCount)
323 {
324     size_t bufferCount = format.numberOfChannelStreams();
325     size_t channelCount = format.numberOfInterleavedChannels();
326     size_t bytesPerChannel = sampleCount * format.bytesPerFrame();
327
328     bufferList.mNumberBuffers = bufferCount;
329     for (unsigned i = 0; i < bufferCount; ++i) {
330         bufferList.mBuffers[i].mNumberChannels = channelCount;
331         bufferList.mBuffers[i].mDataByteSize = bytesPerChannel;
332         bufferList.mBuffers[i].mData = bufferData;
333         if (bufferData)
334             bufferData = bufferData + bytesPerChannel;
335     }
336 }
337
338 } // namespace WebCore
339
340 #endif // ENABLE(MEDIA_STREAM)