c71d357faf3085e4cf155193937e9dd5171a5722
[WebKit-https.git] / Source / WebCore / platform / mediastream / mac / CoreAudioCaptureSource.cpp
1 /*
2  * Copyright (C) 2017-2018 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 "CoreAudioCaptureSource.h"
28
29 #if ENABLE(MEDIA_STREAM)
30
31 #include "AVAudioSessionCaptureDevice.h"
32 #include "AVAudioSessionCaptureDeviceManager.h"
33 #include "AudioSampleBufferList.h"
34 #include "AudioSampleDataSource.h"
35 #include "AudioSession.h"
36 #include "CoreAudioCaptureDevice.h"
37 #include "CoreAudioCaptureDeviceManager.h"
38 #include "CoreAudioCaptureSourceIOS.h"
39 #include "Logging.h"
40 #include "Timer.h"
41 #include "WebAudioSourceProviderAVFObjC.h"
42 #include <AudioToolbox/AudioConverter.h>
43 #include <AudioUnit/AudioUnit.h>
44 #include <CoreMedia/CMSync.h>
45 #include <mach/mach_time.h>
46 #include <pal/avfoundation/MediaTimeAVFoundation.h>
47 #include <pal/spi/cf/CoreAudioSPI.h>
48 #include <sys/time.h>
49 #include <wtf/Algorithms.h>
50 #include <wtf/MainThread.h>
51 #include <wtf/NeverDestroyed.h>
52 #include <pal/cf/CoreMediaSoftLink.h>
53
54 namespace WebCore {
55 using namespace PAL;
56
57 #if PLATFORM(MAC)
58 CoreAudioCaptureSourceFactory& CoreAudioCaptureSourceFactory::singleton()
59 {
60     static NeverDestroyed<CoreAudioCaptureSourceFactory> factory;
61     return factory.get();
62 }
63 #endif
64
65 const UInt32 outputBus = 0;
66 const UInt32 inputBus = 1;
67
68 class CoreAudioSharedUnit {
69 public:
70     static CoreAudioSharedUnit& singleton();
71     CoreAudioSharedUnit();
72
73     void addClient(CoreAudioCaptureSource&);
74     void removeClient(CoreAudioCaptureSource&);
75
76     void startProducingData();
77     void stopProducingData();
78     bool isProducingData() { return m_ioUnitStarted; }
79
80     OSStatus suspend();
81     OSStatus resume();
82
83     bool isSuspended() const { return m_suspended; }
84
85     OSStatus setupAudioUnit();
86     void cleanupAudioUnit();
87     OSStatus reconfigureAudioUnit();
88
89     void addEchoCancellationSource(AudioSampleDataSource&);
90     void removeEchoCancellationSource(AudioSampleDataSource&);
91
92     static size_t preferredIOBufferSize();
93
94     const CAAudioStreamDescription& microphoneFormat() const { return m_microphoneProcFormat; }
95
96     double volume() const { return m_volume; }
97     int sampleRate() const { return m_sampleRate; }
98     bool enableEchoCancellation() const { return m_enableEchoCancellation; }
99
100     void setVolume(double volume) { m_volume = volume; }
101     void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
102     void setEnableEchoCancellation(bool enableEchoCancellation) { m_enableEchoCancellation = enableEchoCancellation; }
103
104     bool hasAudioUnit() const { return m_ioUnit; }
105
106     void setCaptureDevice(String&&, uint32_t);
107
108     void devicesChanged(const Vector<CaptureDevice>&);
109
110 private:
111     OSStatus configureSpeakerProc();
112     OSStatus configureMicrophoneProc();
113     OSStatus defaultOutputDevice(uint32_t*);
114     OSStatus defaultInputDevice(uint32_t*);
115
116     static OSStatus microphoneCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
117     OSStatus processMicrophoneSamples(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
118
119     static OSStatus speakerCallback(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
120     OSStatus provideSpeakerData(AudioUnitRenderActionFlags&, const AudioTimeStamp&, UInt32, UInt32, AudioBufferList*);
121
122     OSStatus startInternal();
123     void stopInternal();
124
125     void unduck();
126
127     void verifyIsCapturing();
128     void devicesChanged();
129     void captureFailed();
130
131     Vector<std::reference_wrapper<CoreAudioCaptureSource>> m_clients;
132
133     AudioUnit m_ioUnit { nullptr };
134
135     // Only read/modified from the IO thread.
136     Vector<Ref<AudioSampleDataSource>> m_activeSources;
137
138     enum QueueAction { Add, Remove };
139     Vector<std::pair<QueueAction, Ref<AudioSampleDataSource>>> m_pendingSources;
140
141 #if PLATFORM(MAC)
142     uint32_t m_captureDeviceID { 0 };
143 #endif
144
145     CAAudioStreamDescription m_microphoneProcFormat;
146     RefPtr<AudioSampleBufferList> m_microphoneSampleBuffer;
147     uint64_t m_latestMicTimeStamp { 0 };
148
149     CAAudioStreamDescription m_speakerProcFormat;
150     RefPtr<AudioSampleBufferList> m_speakerSampleBuffer;
151
152     double m_DTSConversionRatio { 0 };
153
154     bool m_ioUnitInitialized { false };
155     bool m_ioUnitStarted { false };
156
157     Lock m_pendingSourceQueueLock;
158     Lock m_internalStateLock;
159
160     int32_t m_producingCount { 0 };
161
162     mutable std::unique_ptr<RealtimeMediaSourceCapabilities> m_capabilities;
163     mutable Optional<RealtimeMediaSourceSettings> m_currentSettings;
164
165 #if !LOG_DISABLED
166     void checkTimestamps(const AudioTimeStamp&, uint64_t, double);
167
168     String m_ioUnitName;
169     uint64_t m_speakerProcsCalled { 0 };
170 #endif
171
172     String m_persistentID;
173
174     uint64_t m_microphoneProcsCalled { 0 };
175     uint64_t m_microphoneProcsCalledLastTime { 0 };
176     Timer m_verifyCapturingTimer;
177
178     bool m_enableEchoCancellation { true };
179     double m_volume { 1 };
180     int m_sampleRate;
181
182     bool m_suspended { false };
183 };
184
185 CoreAudioSharedUnit& CoreAudioSharedUnit::singleton()
186 {
187     static NeverDestroyed<CoreAudioSharedUnit> singleton;
188     return singleton;
189 }
190
191 CoreAudioSharedUnit::CoreAudioSharedUnit()
192     : m_verifyCapturingTimer(*this, &CoreAudioSharedUnit::verifyIsCapturing)
193 {
194     m_sampleRate = AudioSession::sharedSession().sampleRate();
195 }
196
197 void CoreAudioSharedUnit::addClient(CoreAudioCaptureSource& client)
198 {
199     m_clients.append(client);
200 }
201
202 void CoreAudioSharedUnit::removeClient(CoreAudioCaptureSource& client)
203 {
204     m_clients.removeAllMatching([&](const auto& item) {
205         return &client == &item.get();
206     });
207 }
208
209 void CoreAudioSharedUnit::setCaptureDevice(String&& persistentID, uint32_t captureDeviceID)
210 {
211     m_persistentID = WTFMove(persistentID);
212
213 #if PLATFORM(MAC)
214     if (m_captureDeviceID == captureDeviceID)
215         return;
216
217     m_captureDeviceID = captureDeviceID;
218     reconfigureAudioUnit();
219 #else
220     UNUSED_PARAM(captureDeviceID);
221 #endif
222 }
223
224 void CoreAudioSharedUnit::devicesChanged(const Vector<CaptureDevice>& devices)
225 {
226     if (!m_ioUnit)
227         return;
228
229     if (WTF::anyOf(devices, [this] (auto& device) { return m_persistentID == device.persistentId(); }))
230         return;
231
232     captureFailed();
233 }
234
235 void CoreAudioSharedUnit::addEchoCancellationSource(AudioSampleDataSource& source)
236 {
237     if (!source.setOutputFormat(m_speakerProcFormat)) {
238         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::addEchoCancellationSource: source %p configureOutput failed", &source);
239         return;
240     }
241
242     std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
243     m_pendingSources.append({ QueueAction::Add, source });
244 }
245
246 void CoreAudioSharedUnit::removeEchoCancellationSource(AudioSampleDataSource& source)
247 {
248     std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
249     m_pendingSources.append({ QueueAction::Remove, source });
250 }
251
252 size_t CoreAudioSharedUnit::preferredIOBufferSize()
253 {
254     return AudioSession::sharedSession().bufferSize();
255 }
256
257 OSStatus CoreAudioSharedUnit::setupAudioUnit()
258 {
259     if (m_ioUnit)
260         return 0;
261
262     ASSERT(!m_clients.isEmpty());
263
264     mach_timebase_info_data_t timebaseInfo;
265     mach_timebase_info(&timebaseInfo);
266     m_DTSConversionRatio = 1e-9 * static_cast<double>(timebaseInfo.numer) / static_cast<double>(timebaseInfo.denom);
267
268     AudioComponentDescription ioUnitDescription = { kAudioUnitType_Output, kAudioUnitSubType_VoiceProcessingIO, kAudioUnitManufacturer_Apple, 0, 0 };
269     AudioComponent ioComponent = AudioComponentFindNext(nullptr, &ioUnitDescription);
270     ASSERT(ioComponent);
271     if (!ioComponent) {
272         RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to find vpio unit component", this);
273         return -1;
274     }
275
276 #if !LOG_DISABLED
277     CFStringRef name = nullptr;
278     AudioComponentCopyName(ioComponent, &name);
279     if (name) {
280         m_ioUnitName = name;
281         CFRelease(name);
282         RELEASE_LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) created \"%s\" component", this, m_ioUnitName.utf8().data());
283     }
284 #endif
285
286     auto err = AudioComponentInstanceNew(ioComponent, &m_ioUnit);
287     if (err) {
288         RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to open vpio unit, error %d (%.4s)", this, (int)err, (char*)&err);
289         return err;
290     }
291
292     if (!m_enableEchoCancellation) {
293         uint32_t param = 0;
294         err = AudioUnitSetProperty(m_ioUnit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, inputBus, &param, sizeof(param));
295         if (err) {
296             RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio automatic gain control, error %d (%.4s)", this, (int)err, (char*)&err);
297             return err;
298         }
299         param = 1;
300         err = AudioUnitSetProperty(m_ioUnit, kAUVoiceIOProperty_BypassVoiceProcessing, kAudioUnitScope_Global, inputBus, &param, sizeof(param));
301         if (err) {
302             RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio unit echo cancellation, error %d (%.4s)", this, (int)err, (char*)&err);
303             return err;
304         }
305     }
306
307 #if PLATFORM(IOS_FAMILY)
308     uint32_t param = 1;
309     err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, inputBus, &param, sizeof(param));
310     if (err) {
311         RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to enable vpio unit input, error %d (%.4s)", this, (int)err, (char*)&err);
312         return err;
313     }
314 #else
315     if (!m_captureDeviceID) {
316         err = defaultInputDevice(&m_captureDeviceID);
317         if (err)
318             return err;
319     }
320
321     err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, &m_captureDeviceID, sizeof(m_captureDeviceID));
322     if (err) {
323         RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio unit capture device ID, error %d (%.4s)", this, (int)err, (char*)&err);
324         return err;
325     }
326 #endif
327
328     err = configureMicrophoneProc();
329     if (err)
330         return err;
331
332     err = configureSpeakerProc();
333     if (err)
334         return err;
335
336     err = AudioUnitInitialize(m_ioUnit);
337     if (err) {
338         RELEASE_LOG_ERROR(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) AudioUnitInitialize() failed, error %d (%.4s)", this, (int)err, (char*)&err);
339         return err;
340     }
341     m_ioUnitInitialized = true;
342     m_suspended = false;
343
344     unduck();
345
346     return err;
347 }
348
349 void CoreAudioSharedUnit::unduck()
350 {
351     uint32_t outputDevice;
352     if (!defaultOutputDevice(&outputDevice))
353         AudioDeviceDuck(outputDevice, 1.0, nullptr, 0);
354 }
355
356 OSStatus CoreAudioSharedUnit::configureMicrophoneProc()
357 {
358     AURenderCallbackStruct callback = { microphoneCallback, this };
359     auto err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, inputBus, &callback, sizeof(callback));
360     if (err) {
361         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to set vpio unit mic proc, error %d (%.4s)", this, (int)err, (char*)&err);
362         return err;
363     }
364
365     AudioStreamBasicDescription microphoneProcFormat = { };
366
367     UInt32 size = sizeof(microphoneProcFormat);
368     err = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, &size);
369     if (err) {
370         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to get output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
371         return err;
372     }
373
374     microphoneProcFormat.mSampleRate = m_sampleRate;
375     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, size);
376     if (err) {
377         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to set output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
378         return err;
379     }
380
381     m_microphoneSampleBuffer = AudioSampleBufferList::create(microphoneProcFormat, preferredIOBufferSize() * 2);
382     m_microphoneProcFormat = microphoneProcFormat;
383
384     return err;
385 }
386
387 OSStatus CoreAudioSharedUnit::configureSpeakerProc()
388 {
389     AURenderCallbackStruct callback = { speakerCallback, this };
390     auto err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, outputBus, &callback, sizeof(callback));
391     if (err) {
392         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to set vpio unit speaker proc, error %d (%.4s)", this, (int)err, (char*)&err);
393         return err;
394     }
395
396     AudioStreamBasicDescription speakerProcFormat = { };
397
398     UInt32 size = sizeof(speakerProcFormat);
399     err = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, &size);
400     if (err) {
401         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
402         return err;
403     }
404
405     speakerProcFormat.mSampleRate = m_sampleRate;
406     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, size);
407     if (err) {
408         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
409         return err;
410     }
411
412     m_speakerSampleBuffer = AudioSampleBufferList::create(speakerProcFormat, preferredIOBufferSize() * 2);
413     m_speakerProcFormat = speakerProcFormat;
414
415     return err;
416 }
417
418 #if !LOG_DISABLED
419 void CoreAudioSharedUnit::checkTimestamps(const AudioTimeStamp& timeStamp, uint64_t sampleTime, double hostTime)
420 {
421     if (!timeStamp.mSampleTime || sampleTime == m_latestMicTimeStamp || !hostTime)
422         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::checkTimestamps: unusual timestamps, sample time = %lld, previous sample time = %lld, hostTime %f", sampleTime, m_latestMicTimeStamp, hostTime);
423 }
424 #endif
425
426 OSStatus CoreAudioSharedUnit::provideSpeakerData(AudioUnitRenderActionFlags& /*ioActionFlags*/, const AudioTimeStamp& timeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames, AudioBufferList* ioData)
427 {
428     // Called when the audio unit needs data to play through the speakers.
429 #if !LOG_DISABLED
430     ++m_speakerProcsCalled;
431 #endif
432
433     if (m_speakerSampleBuffer->sampleCapacity() < inNumberFrames) {
434         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::provideSpeakerData: speaker sample buffer size (%d) too small for amount of sample data requested (%d)!", m_speakerSampleBuffer->sampleCapacity(), (int)inNumberFrames);
435         return kAudio_ParamError;
436     }
437
438     // Add/remove sources from the queue, but only if we get the lock immediately. Otherwise try
439     // again on the next callback.
440     {
441         std::unique_lock<Lock> lock(m_pendingSourceQueueLock, std::try_to_lock);
442         if (lock.owns_lock()) {
443             for (auto& pair : m_pendingSources) {
444                 if (pair.first == QueueAction::Add)
445                     m_activeSources.append(pair.second.copyRef());
446                 else {
447                     auto removeSource = pair.second.copyRef();
448                     m_activeSources.removeFirstMatching([&removeSource](auto& source) {
449                         return source.ptr() == removeSource.ptr();
450                     });
451                 }
452             }
453             m_pendingSources.clear();
454         }
455     }
456
457     if (m_activeSources.isEmpty())
458         return 0;
459
460     double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
461     uint64_t sampleTime = timeStamp.mSampleTime;
462 #if !LOG_DISABLED
463     checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
464 #endif
465     m_speakerSampleBuffer->setTimes(adjustedHostTime, sampleTime);
466
467     AudioBufferList& bufferList = m_speakerSampleBuffer->bufferList();
468     for (uint32_t i = 0; i < bufferList.mNumberBuffers; ++i)
469         bufferList.mBuffers[i] = ioData->mBuffers[i];
470
471     bool firstSource = true;
472     for (auto& source : m_activeSources) {
473         source->pullSamples(*m_speakerSampleBuffer.get(), inNumberFrames, adjustedHostTime, sampleTime, firstSource ? AudioSampleDataSource::Copy : AudioSampleDataSource::Mix);
474         firstSource = false;
475     }
476
477     return noErr;
478 }
479
480 OSStatus CoreAudioSharedUnit::speakerCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
481 {
482     ASSERT(ioActionFlags);
483     ASSERT(inTimeStamp);
484     auto dataSource = static_cast<CoreAudioSharedUnit*>(inRefCon);
485     return dataSource->provideSpeakerData(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
486 }
487
488 OSStatus CoreAudioSharedUnit::processMicrophoneSamples(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& timeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* /*ioData*/)
489 {
490     ++m_microphoneProcsCalled;
491
492     // Pull through the vpio unit to our mic buffer.
493     m_microphoneSampleBuffer->reset();
494     AudioBufferList& bufferList = m_microphoneSampleBuffer->bufferList();
495     auto err = AudioUnitRender(m_ioUnit, &ioActionFlags, &timeStamp, inBusNumber, inNumberFrames, &bufferList);
496     if (err) {
497         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::processMicrophoneSamples(%p) AudioUnitRender failed with error %d (%.4s)", this, (int)err, (char*)&err);
498         return err;
499     }
500
501     double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
502     uint64_t sampleTime = timeStamp.mSampleTime;
503 #if !LOG_DISABLED
504     checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
505 #endif
506     m_latestMicTimeStamp = sampleTime;
507     m_microphoneSampleBuffer->setTimes(adjustedHostTime, sampleTime);
508
509     if (m_volume != 1.0)
510         m_microphoneSampleBuffer->applyGain(m_volume);
511
512     for (CoreAudioCaptureSource& client : m_clients) {
513         if (client.isProducingData())
514             client.audioSamplesAvailable(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
515     }
516     return noErr;
517 }
518
519 OSStatus CoreAudioSharedUnit::microphoneCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
520 {
521     ASSERT(ioActionFlags);
522     ASSERT(inTimeStamp);
523     CoreAudioSharedUnit* dataSource = static_cast<CoreAudioSharedUnit*>(inRefCon);
524     return dataSource->processMicrophoneSamples(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
525 }
526
527 void CoreAudioSharedUnit::cleanupAudioUnit()
528 {
529     if (m_ioUnitInitialized) {
530         ASSERT(m_ioUnit);
531         auto err = AudioUnitUninitialize(m_ioUnit);
532         if (err)
533             RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::cleanupAudioUnit(%p) AudioUnitUninitialize failed with error %d (%.4s)", this, (int)err, (char*)&err);
534         m_ioUnitInitialized = false;
535     }
536
537     if (m_ioUnit) {
538         AudioComponentInstanceDispose(m_ioUnit);
539         m_ioUnit = nullptr;
540     }
541
542     m_microphoneSampleBuffer = nullptr;
543     m_speakerSampleBuffer = nullptr;
544 #if !LOG_DISABLED
545     m_ioUnitName = emptyString();
546 #endif
547 }
548
549 OSStatus CoreAudioSharedUnit::reconfigureAudioUnit()
550 {
551     OSStatus err;
552     if (!hasAudioUnit())
553         return 0;
554
555     if (m_ioUnitStarted) {
556         err = AudioOutputUnitStop(m_ioUnit);
557         if (err) {
558             RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::reconfigureAudioUnit(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
559             return err;
560         }
561     }
562
563     cleanupAudioUnit();
564     err = setupAudioUnit();
565     if (err)
566         return err;
567
568     if (m_ioUnitStarted) {
569         err = AudioOutputUnitStart(m_ioUnit);
570         if (err) {
571             RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::reconfigureAudioUnit(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
572             return err;
573         }
574     }
575     return err;
576 }
577
578 void CoreAudioSharedUnit::startProducingData()
579 {
580     ASSERT(isMainThread());
581
582     if (++m_producingCount != 1)
583         return;
584
585     if (m_ioUnitStarted)
586         return;
587
588     if (m_ioUnit) {
589         cleanupAudioUnit();
590         ASSERT(!m_ioUnit);
591     }
592
593     if (startInternal())
594         captureFailed();
595 }
596
597 OSStatus CoreAudioSharedUnit::resume()
598 {
599     ASSERT(isMainThread());
600     ASSERT(m_suspended);
601     ASSERT(!m_ioUnitStarted);
602
603     m_suspended = false;
604
605     if (!m_ioUnit)
606         return 0;
607
608     startInternal();
609
610     return 0;
611 }
612
613 OSStatus CoreAudioSharedUnit::startInternal()
614 {
615     OSStatus err;
616     if (!m_ioUnit) {
617         err = setupAudioUnit();
618         if (err) {
619             cleanupAudioUnit();
620             ASSERT(!m_ioUnit);
621             return err;
622         }
623         ASSERT(m_ioUnit);
624     }
625
626     unduck();
627
628     err = AudioOutputUnitStart(m_ioUnit);
629     if (err) {
630         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::start(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
631         return err;
632     }
633
634     m_ioUnitStarted = true;
635
636     m_verifyCapturingTimer.startRepeating(10_s);
637     m_microphoneProcsCalled = 0;
638     m_microphoneProcsCalledLastTime = 0;
639
640     return 0;
641 }
642
643 void CoreAudioSharedUnit::verifyIsCapturing()
644 {
645     if (m_microphoneProcsCalledLastTime != m_microphoneProcsCalled) {
646         m_microphoneProcsCalledLastTime = m_microphoneProcsCalled;
647         if (m_verifyCapturingTimer.repeatInterval() == 10_s)
648             m_verifyCapturingTimer.startRepeating(2_s);
649         return;
650     }
651
652     captureFailed();
653 }
654
655 void CoreAudioSharedUnit::captureFailed()
656 {
657 #if !RELEASE_LOG_DISABLED
658     RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::captureFailed - capture failed");
659 #endif
660     for (CoreAudioCaptureSource& client : m_clients)
661         client.captureFailed();
662
663     m_producingCount = 0;
664     m_clients.clear();
665     stopInternal();
666     cleanupAudioUnit();
667 }
668
669 void CoreAudioSharedUnit::stopProducingData()
670 {
671     ASSERT(isMainThread());
672     ASSERT(m_producingCount);
673
674     if (m_producingCount && --m_producingCount)
675         return;
676
677     stopInternal();
678     cleanupAudioUnit();
679 }
680
681 OSStatus CoreAudioSharedUnit::suspend()
682 {
683     ASSERT(isMainThread());
684
685     m_suspended = true;
686     stopInternal();
687
688     return 0;
689 }
690
691 void CoreAudioSharedUnit::stopInternal()
692 {
693     m_verifyCapturingTimer.stop();
694
695     if (!m_ioUnit || !m_ioUnitStarted)
696         return;
697
698     auto err = AudioOutputUnitStop(m_ioUnit);
699     if (err) {
700         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::stop(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
701         return;
702     }
703
704     m_ioUnitStarted = false;
705 }
706
707 OSStatus CoreAudioSharedUnit::defaultInputDevice(uint32_t* deviceID)
708 {
709     ASSERT(m_ioUnit);
710
711     UInt32 propertySize = sizeof(*deviceID);
712     auto err = AudioUnitGetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, deviceID, &propertySize);
713     if (err)
714         RELEASE_LOG_ERROR(Media, "CoreAudioSharedUnit::defaultInputDevice(%p) unable to get default input device ID, error %d (%.4s)", this, (int)err, (char*)&err);
715
716     return err;
717 }
718
719 OSStatus CoreAudioSharedUnit::defaultOutputDevice(uint32_t* deviceID)
720 {
721     OSErr err = -1;
722 #if PLATFORM(MAC)
723     AudioObjectPropertyAddress address = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
724
725     if (AudioObjectHasProperty(kAudioObjectSystemObject, &address)) {
726         UInt32 propertySize = sizeof(AudioDeviceID);
727         err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, nullptr, &propertySize, deviceID);
728     }
729 #else
730     UNUSED_PARAM(deviceID);
731 #endif
732     return err;
733 }
734
735 CaptureSourceOrError CoreAudioCaptureSource::create(String&& deviceID, String&& hashSalt, const MediaConstraints* constraints)
736 {
737 #if PLATFORM(MAC)
738     auto device = CoreAudioCaptureDeviceManager::singleton().coreAudioDeviceWithUID(deviceID);
739     if (!device)
740         return { };
741
742     auto source = adoptRef(*new CoreAudioCaptureSource(WTFMove(deviceID), String { device->label() }, WTFMove(hashSalt), device->deviceID()));
743 #elif PLATFORM(IOS_FAMILY)
744     auto device = AVAudioSessionCaptureDeviceManager::singleton().audioSessionDeviceWithUID(WTFMove(deviceID));
745     if (!device)
746         return { };
747
748     auto source = adoptRef(*new CoreAudioCaptureSource(WTFMove(deviceID), String { device->label() }, WTFMove(hashSalt), 0));
749 #endif
750
751     if (constraints) {
752         if (auto result = source->applyConstraints(*constraints))
753             return WTFMove(result->badConstraint);
754     }
755     return CaptureSourceOrError(WTFMove(source));
756 }
757
758 void CoreAudioCaptureSourceFactory::beginInterruption()
759 {
760     if (!isMainThread()) {
761         callOnMainThread([this] {
762             beginInterruption();
763         });
764         return;
765     }
766     ASSERT(isMainThread());
767
768     if (auto* source = coreAudioActiveSource()) {
769         source->beginInterruption();
770         return;
771     }
772     CoreAudioSharedUnit::singleton().suspend();
773 }
774
775 void CoreAudioCaptureSourceFactory::endInterruption()
776 {
777     if (!isMainThread()) {
778         callOnMainThread([this] {
779             endInterruption();
780         });
781         return;
782     }
783     ASSERT(isMainThread());
784
785     if (auto* source = coreAudioActiveSource()) {
786         source->endInterruption();
787         return;
788     }
789     CoreAudioSharedUnit::singleton().reconfigureAudioUnit();
790 }
791
792 void CoreAudioCaptureSourceFactory::scheduleReconfiguration()
793 {
794     if (!isMainThread()) {
795         callOnMainThread([this] {
796             scheduleReconfiguration();
797         });
798         return;
799     }
800     ASSERT(isMainThread());
801
802     if (auto* source = coreAudioActiveSource()) {
803         source->scheduleReconfiguration();
804         return;
805     }
806     CoreAudioSharedUnit::singleton().reconfigureAudioUnit();
807 }
808
809 AudioCaptureFactory& CoreAudioCaptureSource::factory()
810 {
811     return CoreAudioCaptureSourceFactory::singleton();
812 }
813
814 CaptureDeviceManager& CoreAudioCaptureSourceFactory::audioCaptureDeviceManager()
815 {
816 #if PLATFORM(MAC)
817     return CoreAudioCaptureDeviceManager::singleton();
818 #else
819     return AVAudioSessionCaptureDeviceManager::singleton();
820 #endif
821 }
822
823 void CoreAudioCaptureSourceFactory::devicesChanged(const Vector<CaptureDevice>& devices)
824 {
825     CoreAudioSharedUnit::singleton().devicesChanged(devices);
826 }
827
828 CoreAudioCaptureSource::CoreAudioCaptureSource(String&& deviceID, String&& label, String&& hashSalt, uint32_t captureDeviceID)
829     : RealtimeMediaSource(RealtimeMediaSource::Type::Audio, WTFMove(label), WTFMove(deviceID), WTFMove(hashSalt))
830     , m_captureDeviceID(captureDeviceID)
831 {
832 }
833
834 void CoreAudioCaptureSource::initializeToStartProducingData()
835 {
836     if (m_isReadyToStart)
837         return;
838
839     m_isReadyToStart = true;
840
841     auto& unit = CoreAudioSharedUnit::singleton();
842     unit.setCaptureDevice(String { persistentID() }, m_captureDeviceID);
843
844     initializeEchoCancellation(unit.enableEchoCancellation());
845     initializeSampleRate(unit.sampleRate());
846     initializeVolume(unit.volume());
847
848     unit.addClient(*this);
849
850 #if PLATFORM(IOS_FAMILY)
851     // We ensure that we unsuspend ourselves on the constructor as a capture source
852     // is created when getUserMedia grants access which only happens when the process is foregrounded.
853     if (unit.isSuspended())
854         unit.reconfigureAudioUnit();
855 #endif
856 }
857
858 CoreAudioCaptureSource::~CoreAudioCaptureSource()
859 {
860 #if PLATFORM(IOS_FAMILY)
861     CoreAudioCaptureSourceFactory::singleton().unsetCoreAudioActiveSource(*this);
862 #endif
863
864     CoreAudioSharedUnit::singleton().removeClient(*this);
865 }
866
867 void CoreAudioCaptureSource::addEchoCancellationSource(AudioSampleDataSource& source)
868 {
869     CoreAudioSharedUnit::singleton().addEchoCancellationSource(source);
870 }
871
872 void CoreAudioCaptureSource::removeEchoCancellationSource(AudioSampleDataSource& source)
873 {
874     CoreAudioSharedUnit::singleton().removeEchoCancellationSource(source);
875 }
876
877 void CoreAudioCaptureSource::startProducingData()
878 {
879 #if PLATFORM(IOS_FAMILY)
880     CoreAudioCaptureSourceFactory::singleton().setCoreAudioActiveSource(*this);
881 #endif
882
883     auto& unit = CoreAudioSharedUnit::singleton();
884     if (unit.isSuspended()) {
885         m_suspendType = SuspensionType::WhilePlaying;
886         return;
887     }
888
889     initializeToStartProducingData();
890     unit.startProducingData();
891 }
892
893 void CoreAudioCaptureSource::stopProducingData()
894 {
895     auto& unit = CoreAudioSharedUnit::singleton();
896
897     if (unit.isSuspended()) {
898         m_suspendType = SuspensionType::WhilePaused;
899         return;
900     }
901
902     unit.stopProducingData();
903 }
904
905 const RealtimeMediaSourceCapabilities& CoreAudioCaptureSource::capabilities()
906 {
907     if (!m_capabilities) {
908         RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
909         capabilities.setDeviceId(hashedId());
910         capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
911         capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
912         capabilities.setSampleRate(CapabilityValueOrRange(8000, 96000));
913         m_capabilities = WTFMove(capabilities);
914     }
915     return m_capabilities.value();
916 }
917
918 const RealtimeMediaSourceSettings& CoreAudioCaptureSource::settings()
919 {
920     if (!m_currentSettings) {
921         RealtimeMediaSourceSettings settings;
922         settings.setVolume(volume());
923         settings.setSampleRate(sampleRate());
924         settings.setDeviceId(hashedId());
925         settings.setLabel(name());
926         settings.setEchoCancellation(echoCancellation());
927
928         RealtimeMediaSourceSupportedConstraints supportedConstraints;
929         supportedConstraints.setSupportsDeviceId(true);
930         supportedConstraints.setSupportsEchoCancellation(true);
931         supportedConstraints.setSupportsVolume(true);
932         supportedConstraints.setSupportsSampleRate(true);
933         settings.setSupportedConstraints(supportedConstraints);
934
935         m_currentSettings = WTFMove(settings);
936     }
937     return m_currentSettings.value();
938 }
939
940 void CoreAudioCaptureSource::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
941 {
942     if (settings.contains(RealtimeMediaSourceSettings::Flag::EchoCancellation)) {
943         CoreAudioSharedUnit::singleton().setEnableEchoCancellation(echoCancellation());
944         scheduleReconfiguration();
945     }
946     if (settings.contains(RealtimeMediaSourceSettings::Flag::SampleRate)) {
947         CoreAudioSharedUnit::singleton().setSampleRate(sampleRate());
948         scheduleReconfiguration();
949     }
950
951     m_currentSettings = WTF::nullopt;
952 }
953
954 void CoreAudioCaptureSource::scheduleReconfiguration()
955 {
956     ASSERT(isMainThread());
957     auto& unit = CoreAudioSharedUnit::singleton();
958     if (!unit.hasAudioUnit() || m_reconfigurationState != ReconfigurationState::None)
959         return;
960
961     m_reconfigurationState = ReconfigurationState::Ongoing;
962     scheduleDeferredTask([this, &unit] {
963         if (unit.isSuspended()) {
964             m_reconfigurationState = ReconfigurationState::Required;
965             return;
966         }
967
968         unit.reconfigureAudioUnit();
969         m_reconfigurationState = ReconfigurationState::None;
970     });
971 }
972
973 void CoreAudioCaptureSource::beginInterruption()
974 {
975     ASSERT(isMainThread());
976     auto& unit = CoreAudioSharedUnit::singleton();
977     if (!unit.hasAudioUnit() || unit.isSuspended() || m_suspendPending)
978         return;
979
980     m_suspendPending = true;
981     scheduleDeferredTask([this, &unit] {
982         m_suspendType = unit.isProducingData() ? SuspensionType::WhilePlaying : SuspensionType::WhilePaused;
983         unit.suspend();
984         notifyMutedChange(true);
985         m_suspendPending = false;
986     });
987 }
988
989 void CoreAudioCaptureSource::endInterruption()
990 {
991     ASSERT(isMainThread());
992     auto& unit = CoreAudioSharedUnit::singleton();
993     if (!unit.hasAudioUnit() || !unit.isSuspended() || m_resumePending)
994         return;
995
996     auto type = m_suspendType;
997     m_suspendType = SuspensionType::None;
998     if (type != SuspensionType::WhilePlaying && m_reconfigurationState != ReconfigurationState::Required)
999         return;
1000
1001     m_resumePending = true;
1002     scheduleDeferredTask([this, type, &unit] {
1003         if (m_reconfigurationState == ReconfigurationState::Required)
1004             unit.reconfigureAudioUnit();
1005         if (type == SuspensionType::WhilePlaying) {
1006             unit.resume();
1007             notifyMutedChange(false);
1008         }
1009         m_reconfigurationState = ReconfigurationState::None;
1010         m_resumePending = false;
1011     });
1012 }
1013
1014 bool CoreAudioCaptureSource::interrupted() const
1015 {
1016     auto& unit = CoreAudioSharedUnit::singleton();
1017     if (unit.isSuspended())
1018         return true;
1019
1020     return RealtimeMediaSource::interrupted();
1021 }
1022
1023 } // namespace WebCore
1024
1025 #endif // ENABLE(MEDIA_STREAM)