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