a576b6b71149421932c1433c950de5897a4a5b07
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / AudioSourceProviderAVFObjC.mm
1 /*
2  * Copyright (C) 2014, 2015 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 COMPUTER, 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 COMPUTER, 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 #import "config.h"
27 #import "AudioSourceProviderAVFObjC.h"
28
29 #if ENABLE(WEB_AUDIO) && USE(MEDIATOOLBOX)
30
31 #import "AudioBus.h"
32 #import "AudioChannel.h"
33 #import "AudioSourceProviderClient.h"
34 #import "CARingBuffer.h"
35 #import "Logging.h"
36 #import <AVFoundation/AVAssetTrack.h>
37 #import <AVFoundation/AVAudioMix.h>
38 #import <AVFoundation/AVMediaFormat.h>
39 #import <AVFoundation/AVPlayerItem.h>
40 #import <mutex>
41 #import <objc/runtime.h>
42 #import <pal/avfoundation/MediaTimeAVFoundation.h>
43 #import <wtf/Lock.h>
44 #import <wtf/MainThread.h>
45
46 #if !LOG_DISABLED
47 #import <wtf/StringPrintStream.h>
48 #endif
49
50 #import <pal/cf/CoreMediaSoftLink.h>
51 #import <pal/cocoa/AVFoundationSoftLink.h>
52
53 SOFT_LINK_FRAMEWORK(MediaToolbox)
54 SOFT_LINK_FRAMEWORK(AudioToolbox)
55
56 SOFT_LINK(AudioToolbox, AudioConverterConvertComplexBuffer, OSStatus, (AudioConverterRef inAudioConverter, UInt32 inNumberPCMFrames, const AudioBufferList* inInputData, AudioBufferList* outOutputData), (inAudioConverter, inNumberPCMFrames, inInputData, outOutputData))
57 SOFT_LINK(AudioToolbox, AudioConverterNew, OSStatus, (const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat, AudioConverterRef* outAudioConverter), (inSourceFormat, inDestinationFormat, outAudioConverter))
58
59 SOFT_LINK(MediaToolbox, MTAudioProcessingTapGetStorage, void*, (MTAudioProcessingTapRef tap), (tap))
60 SOFT_LINK(MediaToolbox, MTAudioProcessingTapGetSourceAudio, OSStatus, (MTAudioProcessingTapRef tap, CMItemCount numberFrames, AudioBufferList *bufferListInOut, MTAudioProcessingTapFlags *flagsOut, CMTimeRange *timeRangeOut, CMItemCount *numberFramesOut), (tap, numberFrames, bufferListInOut, flagsOut, timeRangeOut, numberFramesOut))
61 SOFT_LINK_MAY_FAIL(MediaToolbox, MTAudioProcessingTapCreate, OSStatus, (CFAllocatorRef allocator, const MTAudioProcessingTapCallbacks *callbacks, MTAudioProcessingTapCreationFlags flags, MTAudioProcessingTapRef *tapOut), (allocator, callbacks, flags, tapOut))
62
63 namespace WebCore {
64
65 using namespace PAL;
66 static const double kRingBufferDuration = 1;
67
68 class AudioSourceProviderAVFObjC::TapStorage : public ThreadSafeRefCounted<AudioSourceProviderAVFObjC::TapStorage> {
69 public:
70     TapStorage(AudioSourceProviderAVFObjC* _this) : _this(_this) { }
71     AudioSourceProviderAVFObjC* _this;
72     Lock mutex;
73 };
74
75 RefPtr<AudioSourceProviderAVFObjC> AudioSourceProviderAVFObjC::create(AVPlayerItem *item)
76 {
77     if (!canLoadMTAudioProcessingTapCreate())
78         return nullptr;
79     return adoptRef(*new AudioSourceProviderAVFObjC(item));
80 }
81
82 AudioSourceProviderAVFObjC::AudioSourceProviderAVFObjC(AVPlayerItem *item)
83     : m_avPlayerItem(item)
84 {
85 }
86
87 AudioSourceProviderAVFObjC::~AudioSourceProviderAVFObjC()
88 {
89     setClient(nullptr);
90     if (m_tapStorage) {
91         std::lock_guard<Lock> lock(m_tapStorage->mutex);
92         m_tapStorage->_this = nullptr;
93         m_tapStorage = nullptr;
94     }
95 }
96
97 void AudioSourceProviderAVFObjC::provideInput(AudioBus* bus, size_t framesToProcess)
98 {
99     // Protect access to m_ringBuffer by try_locking the mutex. If we failed
100     // to aquire, a re-configure is underway, and m_ringBuffer is unsafe to access.
101     // Emit silence.
102     if (!m_tapStorage) {
103         bus->zero();
104         return;
105     }
106
107     std::unique_lock<Lock> lock(m_tapStorage->mutex, std::try_to_lock);
108     if (!lock.owns_lock() || !m_ringBuffer) {
109         bus->zero();
110         return;
111     }
112
113     uint64_t startFrame = 0;
114     uint64_t endFrame = 0;
115     uint64_t seekTo = m_seekTo.exchange(NoSeek);
116     uint64_t writeAheadCount = m_writeAheadCount.load();
117     if (seekTo != NoSeek)
118         m_readCount = seekTo;
119
120     m_ringBuffer->getCurrentFrameBounds(startFrame, endFrame);
121
122     size_t framesAvailable = static_cast<size_t>(endFrame - (m_readCount + writeAheadCount));
123     if (!framesAvailable) {
124         bus->zero();
125         return;
126     }
127
128     if (framesAvailable < framesToProcess) {
129         framesToProcess = framesAvailable;
130         bus->zero();
131     }
132
133     ASSERT(bus->numberOfChannels() == m_ringBuffer->channelCount());
134
135     for (unsigned i = 0; i < m_list->mNumberBuffers; ++i) {
136         AudioChannel* channel = bus->channel(i);
137         m_list->mBuffers[i].mNumberChannels = 1;
138         m_list->mBuffers[i].mData = channel->mutableData();
139         m_list->mBuffers[i].mDataByteSize = channel->length() * sizeof(float);
140     }
141
142     m_ringBuffer->fetch(m_list.get(), framesToProcess, m_readCount);
143     m_readCount += framesToProcess;
144
145     if (m_converter)
146         AudioConverterConvertComplexBuffer(m_converter.get(), framesToProcess, m_list.get(), m_list.get());
147 }
148
149 void AudioSourceProviderAVFObjC::setClient(AudioSourceProviderClient* client)
150 {
151     if (m_client == client)
152         return;
153
154     if (m_avAudioMix)
155         destroyMix();
156
157     m_client = client;
158
159     if (m_client && m_avPlayerItem)
160         createMix();
161 }
162
163 void AudioSourceProviderAVFObjC::setPlayerItem(AVPlayerItem *avPlayerItem)
164 {
165     if (m_avPlayerItem == avPlayerItem)
166         return;
167
168     if (m_avAudioMix)
169         destroyMix();
170
171     m_avPlayerItem = avPlayerItem;
172
173     if (m_client && m_avPlayerItem && m_avAssetTrack)
174         createMix();
175 }
176
177 void AudioSourceProviderAVFObjC::setAudioTrack(AVAssetTrack *avAssetTrack)
178 {
179     if (m_avAssetTrack == avAssetTrack)
180         return;
181
182     if (m_avAudioMix)
183         destroyMix();
184
185     m_avAssetTrack = avAssetTrack;
186
187     if (m_client && m_avPlayerItem && m_avAssetTrack)
188         createMix();
189 }
190
191 void AudioSourceProviderAVFObjC::destroyMix()
192 {
193     if (m_avPlayerItem)
194         [m_avPlayerItem setAudioMix:nil];
195     [m_avAudioMix setInputParameters:@[ ]];
196     m_avAudioMix.clear();
197     m_tap.clear();
198 }
199
200 void AudioSourceProviderAVFObjC::createMix()
201 {
202     ASSERT(!m_avAudioMix);
203     ASSERT(m_avPlayerItem);
204     ASSERT(m_client);
205
206     m_avAudioMix = adoptNS([PAL::allocAVMutableAudioMixInstance() init]);
207
208     MTAudioProcessingTapCallbacks callbacks = {
209         0,
210         this,
211         initCallback,
212         finalizeCallback,
213         prepareCallback,
214         unprepareCallback,
215         processCallback,
216     };
217
218     MTAudioProcessingTapRef tap = nullptr;
219     MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks, 1, &tap);
220     ASSERT(tap);
221     ASSERT(m_tap == tap);
222
223     RetainPtr<AVMutableAudioMixInputParameters> parameters = adoptNS([PAL::allocAVMutableAudioMixInputParametersInstance() init]);
224     [parameters setAudioTapProcessor:m_tap.get()];
225
226     CMPersistentTrackID trackID = m_avAssetTrack.get().trackID;
227     [parameters setTrackID:trackID];
228     
229     [m_avAudioMix setInputParameters:@[parameters.get()]];
230     [m_avPlayerItem setAudioMix:m_avAudioMix.get()];
231 }
232
233 void AudioSourceProviderAVFObjC::initCallback(MTAudioProcessingTapRef tap, void* clientInfo, void** tapStorageOut)
234 {
235     ASSERT(tap);
236     AudioSourceProviderAVFObjC* _this = static_cast<AudioSourceProviderAVFObjC*>(clientInfo);
237     _this->m_tap = adoptCF(tap);
238     _this->m_tapStorage = adoptRef(new TapStorage(_this));
239     _this->init(clientInfo, tapStorageOut);
240     *tapStorageOut = _this->m_tapStorage.get();
241
242     // ref balanced by deref in finalizeCallback:
243     _this->m_tapStorage->ref();
244 }
245
246 void AudioSourceProviderAVFObjC::finalizeCallback(MTAudioProcessingTapRef tap)
247 {
248     ASSERT(tap);
249     TapStorage* tapStorage = static_cast<TapStorage*>(MTAudioProcessingTapGetStorage(tap));
250
251     {
252         std::lock_guard<Lock> lock(tapStorage->mutex);
253         if (tapStorage->_this)
254             tapStorage->_this->finalize();
255     }
256     tapStorage->deref();
257 }
258
259 void AudioSourceProviderAVFObjC::prepareCallback(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat)
260 {
261     ASSERT(tap);
262     TapStorage* tapStorage = static_cast<TapStorage*>(MTAudioProcessingTapGetStorage(tap));
263
264     std::lock_guard<Lock> lock(tapStorage->mutex);
265
266     if (tapStorage->_this)
267         tapStorage->_this->prepare(maxFrames, processingFormat);
268 }
269
270 void AudioSourceProviderAVFObjC::unprepareCallback(MTAudioProcessingTapRef tap)
271 {
272     ASSERT(tap);
273     TapStorage* tapStorage = static_cast<TapStorage*>(MTAudioProcessingTapGetStorage(tap));
274
275     std::lock_guard<Lock> lock(tapStorage->mutex);
276
277     if (tapStorage->_this)
278         tapStorage->_this->unprepare();
279 }
280
281 void AudioSourceProviderAVFObjC::processCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
282 {
283     ASSERT(tap);
284     TapStorage* tapStorage = static_cast<TapStorage*>(MTAudioProcessingTapGetStorage(tap));
285
286     std::lock_guard<Lock> lock(tapStorage->mutex);
287
288     if (tapStorage->_this)
289         tapStorage->_this->process(tap, numberFrames, flags, bufferListInOut, numberFramesOut, flagsOut);
290 }
291
292 void AudioSourceProviderAVFObjC::init(void* clientInfo, void** tapStorageOut)
293 {
294     ASSERT(clientInfo == this);
295     UNUSED_PARAM(clientInfo);
296     *tapStorageOut = this;
297 }
298
299 void AudioSourceProviderAVFObjC::finalize()
300 {
301     if (m_tapStorage) {
302         m_tapStorage->_this = nullptr;
303         m_tapStorage = nullptr;
304     }
305 }
306
307 void AudioSourceProviderAVFObjC::prepare(CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat)
308 {
309     ASSERT(maxFrames >= 0);
310
311     m_tapDescription = std::make_unique<AudioStreamBasicDescription>(*processingFormat);
312     int numberOfChannels = processingFormat->mChannelsPerFrame;
313     double sampleRate = processingFormat->mSampleRate;
314     ASSERT(sampleRate >= 0);
315
316     m_outputDescription = std::make_unique<AudioStreamBasicDescription>();
317     m_outputDescription->mSampleRate = sampleRate;
318     m_outputDescription->mFormatID = kAudioFormatLinearPCM;
319     m_outputDescription->mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
320     m_outputDescription->mBitsPerChannel = 8 * sizeof(Float32);
321     m_outputDescription->mChannelsPerFrame = numberOfChannels;
322     m_outputDescription->mFramesPerPacket = 1;
323     m_outputDescription->mBytesPerPacket = sizeof(Float32);
324     m_outputDescription->mBytesPerFrame = sizeof(Float32);
325     m_outputDescription->mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
326
327     if (*m_tapDescription != *m_outputDescription) {
328         AudioConverterRef outConverter = nullptr;
329         AudioConverterNew(m_tapDescription.get(), m_outputDescription.get(), &outConverter);
330         m_converter = outConverter;
331     }
332
333     // Make the ringbuffer large enough to store at least two callbacks worth of audio, or 1s, whichever is larger.
334     size_t capacity = std::max(static_cast<size_t>(2 * maxFrames), static_cast<size_t>(kRingBufferDuration * sampleRate));
335
336     m_ringBuffer = std::make_unique<CARingBuffer>();
337     m_ringBuffer->allocate(CAAudioStreamDescription(*processingFormat), capacity);
338
339     // AudioBufferList is a variable-length struct, so create on the heap with a generic new() operator
340     // with a custom size, and initialize the struct manually.
341     size_t bufferListSize = sizeof(AudioBufferList) + (sizeof(AudioBuffer) * std::max(1, numberOfChannels - 1));
342     m_list = std::unique_ptr<AudioBufferList>((AudioBufferList*) ::operator new (bufferListSize));
343     memset(m_list.get(), 0, bufferListSize);
344     m_list->mNumberBuffers = numberOfChannels;
345
346     callOnMainThread([protectedThis = makeRef(*this), numberOfChannels, sampleRate] {
347         protectedThis->m_client->setFormat(numberOfChannels, sampleRate);
348     });
349 }
350
351 void AudioSourceProviderAVFObjC::unprepare()
352 {
353     m_tapDescription = nullptr;
354     m_outputDescription = nullptr;
355     m_ringBuffer = nullptr;
356     m_list = nullptr;
357 }
358
359 void AudioSourceProviderAVFObjC::process(MTAudioProcessingTapRef tap, CMItemCount numberOfFrames, MTAudioProcessingTapFlags flags, AudioBufferList* bufferListInOut, CMItemCount* numberFramesOut, MTAudioProcessingTapFlags* flagsOut)
360 {
361     UNUSED_PARAM(flags);
362     
363     CMItemCount itemCount = 0;
364     CMTimeRange rangeOut;
365     OSStatus status = MTAudioProcessingTapGetSourceAudio(tap, numberOfFrames, bufferListInOut, flagsOut, &rangeOut, &itemCount);
366     if (status != noErr || !itemCount)
367         return;
368
369     MediaTime rangeStart = PAL::toMediaTime(rangeOut.start);
370     MediaTime rangeDuration = PAL::toMediaTime(rangeOut.duration);
371
372     if (rangeStart.isInvalid())
373         return;
374
375     MediaTime currentTime = PAL::toMediaTime(PAL::CMTimebaseGetTime([m_avPlayerItem timebase]));
376     if (currentTime.isInvalid())
377         return;
378
379     // The audio tap will generate silence when the media is paused, and will not advance the
380     // tap currentTime.
381     if (rangeStart == m_startTimeAtLastProcess || rangeDuration == MediaTime::zeroTime()) {
382         m_paused = true;
383         return;
384     }
385
386     if (m_paused) {
387         // Only check the write-ahead time when playback begins.
388         m_paused = false;
389         MediaTime earlyBy = rangeStart - currentTime;
390         m_writeAheadCount.store(m_tapDescription->mSampleRate * earlyBy.toDouble());
391     }
392
393     uint64_t startFrame = 0;
394     uint64_t endFrame = 0;
395     m_ringBuffer->getCurrentFrameBounds(startFrame, endFrame);
396
397     // Check to see if the underlying media has seeked, which would require us to "flush"
398     // our outstanding buffers.
399     if (rangeStart != m_endTimeAtLastProcess)
400         m_seekTo.store(endFrame);
401
402     m_startTimeAtLastProcess = rangeStart;
403     m_endTimeAtLastProcess = rangeStart + rangeDuration;
404
405     // StartOfStream indicates a discontinuity, such as when an AVPlayerItem is re-added
406     // to an AVPlayer, so "flush" outstanding buffers.
407     if (flagsOut && *flagsOut & kMTAudioProcessingTapFlag_StartOfStream)
408         m_seekTo.store(endFrame);
409
410     m_ringBuffer->store(bufferListInOut, itemCount, endFrame);
411
412     // Mute the default audio playback by zeroing the tap-owned buffers.
413     for (uint32_t i = 0; i < bufferListInOut->mNumberBuffers; ++i) {
414         AudioBuffer& buffer = bufferListInOut->mBuffers[i];
415         memset(buffer.mData, 0, buffer.mDataByteSize);
416     }
417     *numberFramesOut = 0;
418 }
419
420 }
421
422 #endif // ENABLE(WEB_AUDIO) && USE(MEDIATOOLBOX)