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