[iOS] Unset active media capture source when stopped capturing
[WebKit-https.git] / Source / WebCore / platform / mediastream / mac / CoreAudioCaptureSource.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "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 "Logging.h"
39 #include "MediaTimeAVFoundation.h"
40 #include "WebAudioSourceProviderAVFObjC.h"
41 #include <AudioToolbox/AudioConverter.h>
42 #include <AudioUnit/AudioUnit.h>
43 #include <CoreMedia/CMSync.h>
44 #include <mach/mach_time.h>
45 #include <sys/time.h>
46 #include <wtf/MainThread.h>
47 #include <wtf/NeverDestroyed.h>
48 #include "CoreMediaSoftLink.h"
49
50 namespace WebCore {
51
52 class CoreAudioCaptureSourceFactory : public RealtimeMediaSource::AudioCaptureFactory
53 #if PLATFORM(IOS)
54     , public RealtimeMediaSource::SingleSourceFactory<CoreAudioCaptureSource>
55 #endif
56 {
57 public:
58     CaptureSourceOrError createAudioCaptureSource(const String& deviceID, const MediaConstraints* constraints) final {
59         return CoreAudioCaptureSource::create(deviceID, constraints);
60     }
61 };
62
63 static CoreAudioCaptureSourceFactory& coreAudioCaptureSourceFactory()
64 {
65     static NeverDestroyed<CoreAudioCaptureSourceFactory> factory;
66     return factory.get();
67 }
68
69 const UInt32 outputBus = 0;
70 const UInt32 inputBus = 1;
71
72 class CoreAudioSharedUnit {
73 public:
74     static CoreAudioSharedUnit& singleton();
75     CoreAudioSharedUnit();
76
77     void addClient(CoreAudioCaptureSource&);
78     void removeClient(CoreAudioCaptureSource&);
79
80     void startProducingData();
81     void stopProducingData();
82     bool isProducingData() { return m_ioUnitStarted; }
83
84     OSStatus suspend();
85
86     OSStatus setupAudioUnit();
87     void cleanupAudioUnit();
88     OSStatus reconfigureAudioUnit();
89
90     void addEchoCancellationSource(AudioSampleDataSource&);
91     void removeEchoCancellationSource(AudioSampleDataSource&);
92
93     static size_t preferredIOBufferSize();
94
95     const CAAudioStreamDescription& microphoneFormat() const { return m_microphoneProcFormat; }
96
97     double volume() const { return m_volume; }
98     int sampleRate() const { return m_sampleRate; }
99     bool enableEchoCancellation() const { return m_enableEchoCancellation; }
100
101     void setVolume(double volume) { m_volume = volume; }
102     void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
103     void setEnableEchoCancellation(bool enableEchoCancellation) { m_enableEchoCancellation = enableEchoCancellation; }
104
105     bool hasAudioUnit() const { return m_ioUnit; }
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     Vector<std::reference_wrapper<CoreAudioCaptureSource>> m_clients;
120
121     AudioUnit m_ioUnit { nullptr };
122
123     // Only read/modified from the IO thread.
124     Vector<Ref<AudioSampleDataSource>> m_activeSources;
125
126     enum QueueAction { Add, Remove };
127     Vector<std::pair<QueueAction, Ref<AudioSampleDataSource>>> m_pendingSources;
128
129     uint32_t m_captureDeviceID { 0 };
130
131     CAAudioStreamDescription m_microphoneProcFormat;
132     RefPtr<AudioSampleBufferList> m_microphoneSampleBuffer;
133     uint64_t m_latestMicTimeStamp { 0 };
134
135     CAAudioStreamDescription m_speakerProcFormat;
136     RefPtr<AudioSampleBufferList> m_speakerSampleBuffer;
137
138     double m_DTSConversionRatio { 0 };
139
140     bool m_ioUnitInitialized { false };
141     bool m_ioUnitStarted { false };
142
143     Lock m_pendingSourceQueueLock;
144     Lock m_internalStateLock;
145
146     int32_t m_suspendCount { 0 };
147     int32_t m_producingCount { 0 };
148
149     mutable std::unique_ptr<RealtimeMediaSourceCapabilities> m_capabilities;
150     mutable std::optional<RealtimeMediaSourceSettings> m_currentSettings;
151
152 #if !LOG_DISABLED
153     void checkTimestamps(const AudioTimeStamp&, uint64_t, double);
154
155     String m_ioUnitName;
156     uint64_t m_speakerProcsCalled { 0 };
157     uint64_t m_microphoneProcsCalled { 0 };
158 #endif
159
160     bool m_enableEchoCancellation { true };
161     double m_volume { 1 };
162     int m_sampleRate;
163 };
164
165 CoreAudioSharedUnit& CoreAudioSharedUnit::singleton()
166 {
167     static NeverDestroyed<CoreAudioSharedUnit> singleton;
168     return singleton;
169 }
170
171 CoreAudioSharedUnit::CoreAudioSharedUnit()
172 {
173     m_sampleRate = AudioSession::sharedSession().sampleRate();
174 }
175
176 void CoreAudioSharedUnit::addClient(CoreAudioCaptureSource& client)
177 {
178     m_clients.append(client);
179 }
180
181 void CoreAudioSharedUnit::removeClient(CoreAudioCaptureSource& client)
182 {
183     m_clients.removeAllMatching([&](const auto& item) {
184         return &client == &item.get();
185     });
186 }
187
188 void CoreAudioSharedUnit::addEchoCancellationSource(AudioSampleDataSource& source)
189 {
190     if (!source.setOutputFormat(m_speakerProcFormat)) {
191         LOG(Media, "CoreAudioSharedUnit::addEchoCancellationSource: source %p configureOutput failed", &source);
192         return;
193     }
194
195     std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
196     m_pendingSources.append({ QueueAction::Add, source });
197 }
198
199 void CoreAudioSharedUnit::removeEchoCancellationSource(AudioSampleDataSource& source)
200 {
201     std::lock_guard<Lock> lock(m_pendingSourceQueueLock);
202     m_pendingSources.append({ QueueAction::Remove, source });
203 }
204
205 size_t CoreAudioSharedUnit::preferredIOBufferSize()
206 {
207     return AudioSession::sharedSession().bufferSize();
208 }
209
210 OSStatus CoreAudioSharedUnit::setupAudioUnit()
211 {
212     if (m_ioUnit)
213         return 0;
214
215     ASSERT(!m_clients.isEmpty());
216
217     mach_timebase_info_data_t timebaseInfo;
218     mach_timebase_info(&timebaseInfo);
219     m_DTSConversionRatio = 1e-9 * static_cast<double>(timebaseInfo.numer) / static_cast<double>(timebaseInfo.denom);
220
221     AudioComponentDescription ioUnitDescription = { kAudioUnitType_Output, kAudioUnitSubType_VoiceProcessingIO, kAudioUnitManufacturer_Apple, 0, 0 };
222     AudioComponent ioComponent = AudioComponentFindNext(nullptr, &ioUnitDescription);
223     ASSERT(ioComponent);
224     if (!ioComponent) {
225         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to find vpio unit component", this);
226         return -1;
227     }
228
229 #if !LOG_DISABLED
230     CFStringRef name = nullptr;
231     AudioComponentCopyName(ioComponent, &name);
232     if (name) {
233         m_ioUnitName = name;
234         CFRelease(name);
235         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) created \"%s\" component", this, m_ioUnitName.utf8().data());
236     }
237 #endif
238
239     auto err = AudioComponentInstanceNew(ioComponent, &m_ioUnit);
240     if (err) {
241         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to open vpio unit, error %d (%.4s)", this, (int)err, (char*)&err);
242         return err;
243     }
244
245     if (!m_enableEchoCancellation) {
246         uint32_t param = 0;
247         err = AudioUnitSetProperty(m_ioUnit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, inputBus, &param, sizeof(param));
248         if (err) {
249             LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio automatic gain control, error %d (%.4s)", this, (int)err, (char*)&err);
250             return err;
251         }
252         param = 1;
253         err = AudioUnitSetProperty(m_ioUnit, kAUVoiceIOProperty_BypassVoiceProcessing, kAudioUnitScope_Global, inputBus, &param, sizeof(param));
254         if (err) {
255             LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio unit echo cancellation, error %d (%.4s)", this, (int)err, (char*)&err);
256             return err;
257         }
258     }
259
260 #if PLATFORM(IOS)
261     uint32_t param = 1;
262     err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, inputBus, &param, sizeof(param));
263     if (err) {
264         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to enable vpio unit input, error %d (%.4s)", this, (int)err, (char*)&err);
265         return err;
266     }
267 #else
268     if (!m_captureDeviceID) {
269         err = defaultInputDevice(&m_captureDeviceID);
270         if (err)
271             return err;
272     }
273
274     err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, &m_captureDeviceID, sizeof(m_captureDeviceID));
275     if (err) {
276         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) unable to set vpio unit capture device ID, error %d (%.4s)", this, (int)err, (char*)&err);
277         return err;
278     }
279 #endif
280
281     err = configureMicrophoneProc();
282     if (err)
283         return err;
284
285     err = configureSpeakerProc();
286     if (err)
287         return err;
288
289     err = AudioUnitInitialize(m_ioUnit);
290     if (err) {
291         LOG(Media, "CoreAudioCaptureSource::setupAudioUnit(%p) AudioUnitInitialize() failed, error %d (%.4s)", this, (int)err, (char*)&err);
292         return err;
293     }
294     m_ioUnitInitialized = true;
295
296     return err;
297 }
298
299 OSStatus CoreAudioSharedUnit::configureMicrophoneProc()
300 {
301     AURenderCallbackStruct callback = { microphoneCallback, this };
302     auto err = AudioUnitSetProperty(m_ioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, inputBus, &callback, sizeof(callback));
303     if (err) {
304         LOG(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to set vpio unit mic proc, error %d (%.4s)", this, (int)err, (char*)&err);
305         return err;
306     }
307
308     AudioStreamBasicDescription microphoneProcFormat = { };
309
310     UInt32 size = sizeof(microphoneProcFormat);
311     err = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, &size);
312     if (err) {
313         LOG(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to get output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
314         return err;
315     }
316
317     microphoneProcFormat.mSampleRate = m_sampleRate;
318     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &microphoneProcFormat, size);
319     if (err) {
320         LOG(Media, "CoreAudioSharedUnit::configureMicrophoneProc(%p) unable to set output stream format, error %d (%.4s)", this, (int)err, (char*)&err);
321         return err;
322     }
323
324     m_microphoneSampleBuffer = AudioSampleBufferList::create(microphoneProcFormat, preferredIOBufferSize() * 2);
325     m_microphoneProcFormat = microphoneProcFormat;
326
327     return err;
328 }
329
330 OSStatus CoreAudioSharedUnit::configureSpeakerProc()
331 {
332     AURenderCallbackStruct callback = { speakerCallback, this };
333     auto err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, outputBus, &callback, sizeof(callback));
334     if (err) {
335         LOG(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to set vpio unit speaker proc, error %d (%.4s)", this, (int)err, (char*)&err);
336         return err;
337     }
338
339     AudioStreamBasicDescription speakerProcFormat = { };
340
341     UInt32 size = sizeof(speakerProcFormat);
342     err = AudioUnitGetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, &size);
343     if (err) {
344         LOG(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
345         return err;
346     }
347
348     speakerProcFormat.mSampleRate = m_sampleRate;
349     err = AudioUnitSetProperty(m_ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &speakerProcFormat, size);
350     if (err) {
351         LOG(Media, "CoreAudioSharedUnit::configureSpeakerProc(%p) unable to get input stream format, error %d (%.4s)", this, (int)err, (char*)&err);
352         return err;
353     }
354
355     m_speakerSampleBuffer = AudioSampleBufferList::create(speakerProcFormat, preferredIOBufferSize() * 2);
356     m_speakerProcFormat = speakerProcFormat;
357
358     return err;
359 }
360
361 #if !LOG_DISABLED
362 void CoreAudioSharedUnit::checkTimestamps(const AudioTimeStamp& timeStamp, uint64_t sampleTime, double hostTime)
363 {
364     if (!timeStamp.mSampleTime || sampleTime == m_latestMicTimeStamp || !hostTime)
365         LOG(Media, "CoreAudioSharedUnit::checkTimestamps: unusual timestamps, sample time = %lld, previous sample time = %lld, hostTime %f", sampleTime, m_latestMicTimeStamp, hostTime);
366 }
367 #endif
368
369 OSStatus CoreAudioSharedUnit::provideSpeakerData(AudioUnitRenderActionFlags& /*ioActionFlags*/, const AudioTimeStamp& timeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames, AudioBufferList* ioData)
370 {
371     // Called when the audio unit needs data to play through the speakers.
372 #if !LOG_DISABLED
373     ++m_speakerProcsCalled;
374 #endif
375
376     if (m_speakerSampleBuffer->sampleCapacity() < inNumberFrames) {
377         LOG(Media, "CoreAudioSharedUnit::provideSpeakerData: speaker sample buffer size (%d) too small for amount of sample data requested (%d)!", m_speakerSampleBuffer->sampleCapacity(), (int)inNumberFrames);
378         return kAudio_ParamError;
379     }
380
381     // Add/remove sources from the queue, but only if we get the lock immediately. Otherwise try
382     // again on the next callback.
383     {
384         std::unique_lock<Lock> lock(m_pendingSourceQueueLock, std::try_to_lock);
385         if (lock.owns_lock()) {
386             for (auto& pair : m_pendingSources) {
387                 if (pair.first == QueueAction::Add)
388                     m_activeSources.append(pair.second.copyRef());
389                 else {
390                     auto removeSource = pair.second.copyRef();
391                     m_activeSources.removeFirstMatching([&removeSource](auto& source) {
392                         return source.ptr() == removeSource.ptr();
393                     });
394                 }
395             }
396             m_pendingSources.clear();
397         }
398     }
399
400     if (m_activeSources.isEmpty())
401         return 0;
402
403     double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
404     uint64_t sampleTime = timeStamp.mSampleTime;
405 #if !LOG_DISABLED
406     checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
407 #endif
408     m_speakerSampleBuffer->setTimes(adjustedHostTime, sampleTime);
409
410     AudioBufferList& bufferList = m_speakerSampleBuffer->bufferList();
411     for (uint32_t i = 0; i < bufferList.mNumberBuffers; ++i)
412         bufferList.mBuffers[i] = ioData->mBuffers[i];
413
414     bool firstSource = true;
415     for (auto& source : m_activeSources) {
416         source->pullSamples(*m_speakerSampleBuffer.get(), inNumberFrames, adjustedHostTime, sampleTime, firstSource ? AudioSampleDataSource::Copy : AudioSampleDataSource::Mix);
417         firstSource = false;
418     }
419
420     return noErr;
421 }
422
423 OSStatus CoreAudioSharedUnit::speakerCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
424 {
425     ASSERT(ioActionFlags);
426     ASSERT(inTimeStamp);
427     auto dataSource = static_cast<CoreAudioSharedUnit*>(inRefCon);
428     return dataSource->provideSpeakerData(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
429 }
430
431 OSStatus CoreAudioSharedUnit::processMicrophoneSamples(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& timeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* /*ioData*/)
432 {
433 #if !LOG_DISABLED
434     ++m_microphoneProcsCalled;
435 #endif
436
437     // Pull through the vpio unit to our mic buffer.
438     m_microphoneSampleBuffer->reset();
439     AudioBufferList& bufferList = m_microphoneSampleBuffer->bufferList();
440     auto err = AudioUnitRender(m_ioUnit, &ioActionFlags, &timeStamp, inBusNumber, inNumberFrames, &bufferList);
441     if (err) {
442         LOG(Media, "CoreAudioSharedUnit::processMicrophoneSamples(%p) AudioUnitRender failed with error %d (%.4s)", this, (int)err, (char*)&err);
443         return err;
444     }
445
446     double adjustedHostTime = m_DTSConversionRatio * timeStamp.mHostTime;
447     uint64_t sampleTime = timeStamp.mSampleTime;
448 #if !LOG_DISABLED
449     checkTimestamps(timeStamp, sampleTime, adjustedHostTime);
450 #endif
451     m_latestMicTimeStamp = sampleTime;
452     m_microphoneSampleBuffer->setTimes(adjustedHostTime, sampleTime);
453
454     if (m_volume != 1.0)
455         m_microphoneSampleBuffer->applyGain(m_volume);
456
457     for (CoreAudioCaptureSource& client : m_clients) {
458         if (client.isProducingData())
459             client.audioSamplesAvailable(MediaTime(sampleTime, m_microphoneProcFormat.sampleRate()), m_microphoneSampleBuffer->bufferList(), m_microphoneProcFormat, inNumberFrames);
460     }
461     return noErr;
462 }
463
464 OSStatus CoreAudioSharedUnit::microphoneCallback(void *inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
465 {
466     ASSERT(ioActionFlags);
467     ASSERT(inTimeStamp);
468     CoreAudioSharedUnit* dataSource = static_cast<CoreAudioSharedUnit*>(inRefCon);
469     return dataSource->processMicrophoneSamples(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, ioData);
470 }
471
472 void CoreAudioSharedUnit::cleanupAudioUnit()
473 {
474     if (m_ioUnitInitialized) {
475         ASSERT(m_ioUnit);
476         auto err = AudioUnitUninitialize(m_ioUnit);
477         if (err)
478             LOG(Media, "CoreAudioSharedUnit::cleanupAudioUnit(%p) AudioUnitUninitialize failed with error %d (%.4s)", this, (int)err, (char*)&err);
479         m_ioUnitInitialized = false;
480     }
481
482     if (m_ioUnit) {
483         AudioComponentInstanceDispose(m_ioUnit);
484         m_ioUnit = nullptr;
485     }
486
487     m_microphoneSampleBuffer = nullptr;
488     m_speakerSampleBuffer = nullptr;
489 #if !LOG_DISABLED
490     m_ioUnitName = emptyString();
491 #endif
492 }
493
494 OSStatus CoreAudioSharedUnit::reconfigureAudioUnit()
495 {
496     OSStatus err;
497     if (!hasAudioUnit())
498         return 0;
499
500     if (m_ioUnitStarted) {
501         err = AudioOutputUnitStop(m_ioUnit);
502         if (err) {
503             LOG(Media, "CoreAudioSharedUnit::reconfigureAudioUnit(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
504             return err;
505         }
506     }
507
508     cleanupAudioUnit();
509     err = setupAudioUnit();
510     if (err)
511         return err;
512
513     if (m_ioUnitStarted) {
514         err = AudioOutputUnitStart(m_ioUnit);
515         if (err) {
516             LOG(Media, "CoreAudioSharedUnit::reconfigureAudioUnit(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
517             return err;
518         }
519     }
520     return err;
521 }
522
523 void CoreAudioSharedUnit::startProducingData()
524 {
525     ASSERT(isMainThread());
526
527     if (++m_producingCount != 1)
528         return;
529
530     if (m_ioUnitStarted)
531         return;
532
533     OSStatus err;
534     if (!m_ioUnit) {
535         err = setupAudioUnit();
536         if (err) {
537             cleanupAudioUnit();
538             ASSERT(!m_ioUnit);
539             return;
540         }
541         ASSERT(m_ioUnit);
542     }
543
544     err = AudioOutputUnitStart(m_ioUnit);
545     if (err) {
546         LOG(Media, "CoreAudioSharedUnit::start(%p) AudioOutputUnitStart failed with error %d (%.4s)", this, (int)err, (char*)&err);
547         return;
548     }
549
550     m_ioUnitStarted = true;
551 }
552
553 void CoreAudioSharedUnit::stopProducingData()
554 {
555     ASSERT(isMainThread());
556
557     if (--m_producingCount)
558         return;
559
560     if (!m_ioUnit || !m_ioUnitStarted)
561         return;
562
563     auto err = AudioOutputUnitStop(m_ioUnit);
564     if (err) {
565         LOG(Media, "CoreAudioSharedUnit::stop(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
566         return;
567     }
568
569     m_ioUnitStarted = false;
570 }
571
572 OSStatus CoreAudioSharedUnit::suspend()
573 {
574     ASSERT(isMainThread());
575
576     m_activeSources.clear();
577     m_pendingSources.clear();
578
579     if (m_ioUnitStarted) {
580         ASSERT(m_ioUnit);
581         auto err = AudioOutputUnitStop(m_ioUnit);
582         if (err) {
583             LOG(Media, "CoreAudioSharedUnit::resume(%p) AudioOutputUnitStop failed with error %d (%.4s)", this, (int)err, (char*)&err);
584             return err;
585         }
586         m_ioUnitStarted = false;
587     }
588
589     if (m_ioUnitInitialized) {
590         ASSERT(m_ioUnit);
591         auto err = AudioUnitUninitialize(m_ioUnit);
592         if (err) {
593             LOG(Media, "CoreAudioSharedUnit::resume(%p) AudioUnitUninitialize failed with error %d (%.4s)", this, (int)err, (char*)&err);
594             return err;
595         }
596         m_ioUnitInitialized = false;
597     }
598
599     return 0;
600 }
601
602 OSStatus CoreAudioSharedUnit::defaultInputDevice(uint32_t* deviceID)
603 {
604     ASSERT(m_ioUnit);
605
606     UInt32 propertySize = sizeof(*deviceID);
607     auto err = AudioUnitGetProperty(m_ioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, inputBus, deviceID, &propertySize);
608     if (err)
609         LOG(Media, "CoreAudioSharedUnit::defaultInputDevice(%p) unable to get default input device ID, error %d (%.4s)", this, (int)err, (char*)&err);
610
611     return err;
612 }
613
614 CaptureSourceOrError CoreAudioCaptureSource::create(const String& deviceID, const MediaConstraints* constraints)
615 {
616     String label;
617     uint32_t persistentID = 0;
618 #if PLATFORM(MAC)
619     auto device = CoreAudioCaptureDeviceManager::singleton().coreAudioDeviceWithUID(deviceID);
620     if (!device)
621         return { };
622
623     label = device->label();
624     persistentID = device->deviceID();
625 #elif PLATFORM(IOS)
626     auto device = AVAudioSessionCaptureDeviceManager::singleton().audioSessionDeviceWithUID(deviceID);
627     if (!device)
628         return { };
629
630     label = device->label();
631 #endif
632     auto source = adoptRef(*new CoreAudioCaptureSource(deviceID, label, persistentID));
633
634     if (constraints) {
635         auto result = source->applyConstraints(*constraints);
636         if (result)
637             return WTFMove(result.value().first);
638     }
639     return CaptureSourceOrError(WTFMove(source));
640 }
641
642 RealtimeMediaSource::AudioCaptureFactory& CoreAudioCaptureSource::factory()
643 {
644     return coreAudioCaptureSourceFactory();
645 }
646
647 CoreAudioCaptureSource::CoreAudioCaptureSource(const String& deviceID, const String& label, uint32_t persistentID)
648     : RealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Audio, label)
649     , m_captureDeviceID(persistentID)
650 {
651     m_muted = true;
652
653     auto& unit = CoreAudioSharedUnit::singleton();
654
655     initializeEchoCancellation(unit.enableEchoCancellation());
656     initializeSampleRate(unit.sampleRate());
657     initializeVolume(unit.volume());
658
659     unit.addClient(*this);
660 }
661
662 CoreAudioCaptureSource::~CoreAudioCaptureSource()
663 {
664 #if PLATFORM(IOS)
665     coreAudioCaptureSourceFactory().unsetActiveSource(*this);
666 #endif
667
668     CoreAudioSharedUnit::singleton().removeClient(*this);
669 }
670
671 void CoreAudioCaptureSource::addEchoCancellationSource(AudioSampleDataSource& source)
672 {
673     CoreAudioSharedUnit::singleton().addEchoCancellationSource(source);
674 }
675
676 void CoreAudioCaptureSource::removeEchoCancellationSource(AudioSampleDataSource& source)
677 {
678     CoreAudioSharedUnit::singleton().removeEchoCancellationSource(source);
679 }
680
681 void CoreAudioCaptureSource::startProducingData()
682 {
683     if (m_isProducingData)
684         return;
685
686 #if PLATFORM(IOS)
687     coreAudioCaptureSourceFactory().setActiveSource(*this);
688 #endif
689
690     CoreAudioSharedUnit::singleton().startProducingData();
691     m_isProducingData = CoreAudioSharedUnit::singleton().isProducingData();
692
693     if (!m_isProducingData)
694         return;
695
696     m_muted = false;
697
698     if (m_audioSourceProvider)
699         m_audioSourceProvider->prepare(&CoreAudioSharedUnit::singleton().microphoneFormat().streamDescription());
700 }
701
702 void CoreAudioCaptureSource::stopProducingData()
703 {
704     if (!m_isProducingData)
705         return;
706
707     CoreAudioSharedUnit::singleton().stopProducingData();
708     m_isProducingData = false;
709     m_muted = true;
710
711     if (m_audioSourceProvider)
712         m_audioSourceProvider->unprepare();
713 }
714
715 const RealtimeMediaSourceCapabilities& CoreAudioCaptureSource::capabilities() const
716 {
717     if (!m_capabilities) {
718         RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
719         capabilities.setDeviceId(id());
720         capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
721         capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
722         capabilities.setSampleRate(CapabilityValueOrRange(8000, 96000));
723         m_capabilities = WTFMove(capabilities);
724     }
725     return m_capabilities.value();
726 }
727
728 const RealtimeMediaSourceSettings& CoreAudioCaptureSource::settings() const
729 {
730     if (!m_currentSettings) {
731         RealtimeMediaSourceSettings settings;
732         settings.setVolume(volume());
733         settings.setSampleRate(sampleRate());
734         settings.setDeviceId(id());
735         settings.setEchoCancellation(echoCancellation());
736
737         RealtimeMediaSourceSupportedConstraints supportedConstraints;
738         supportedConstraints.setSupportsDeviceId(true);
739         supportedConstraints.setSupportsEchoCancellation(true);
740         supportedConstraints.setSupportsVolume(true);
741         supportedConstraints.setSupportsSampleRate(true);
742         settings.setSupportedConstraints(supportedConstraints);
743
744         m_currentSettings = WTFMove(settings);
745     }
746     return m_currentSettings.value();
747 }
748
749 void CoreAudioCaptureSource::settingsDidChange()
750 {
751     m_currentSettings = std::nullopt;
752     RealtimeMediaSource::settingsDidChange();
753 }
754
755 AudioSourceProvider* CoreAudioCaptureSource::audioSourceProvider()
756 {
757     if (!m_audioSourceProvider) {
758         m_audioSourceProvider = WebAudioSourceProviderAVFObjC::create(*this);
759         if (m_isProducingData)
760             m_audioSourceProvider->prepare(&CoreAudioSharedUnit::singleton().microphoneFormat().streamDescription());
761     }
762
763     return m_audioSourceProvider.get();
764 }
765
766 bool CoreAudioCaptureSource::applySampleRate(int sampleRate)
767 {
768     // FIXME: We should be able to describe sample rate as a discreet range constraint so that we only enter here with values that can be applied.
769     switch (sampleRate) {
770     case 8000:
771     case 16000:
772     case 32000:
773     case 44100:
774     case 48000:
775     case 96000:
776         break;
777     default:
778         return false;
779     }
780
781     CoreAudioSharedUnit::singleton().setSampleRate(sampleRate);
782
783     scheduleReconfiguration();
784     return true;
785 }
786
787 bool CoreAudioCaptureSource::applyEchoCancellation(bool enableEchoCancellation)
788 {
789     CoreAudioSharedUnit::singleton().setEnableEchoCancellation(enableEchoCancellation);
790
791     scheduleReconfiguration();
792     return true;
793 }
794
795 void CoreAudioCaptureSource::scheduleReconfiguration()
796 {
797     ASSERT(isMainThread());
798     auto& unit = CoreAudioSharedUnit::singleton();
799     if (!unit.hasAudioUnit() || m_reconfigurationOngoing)
800         return;
801
802     m_reconfigurationOngoing = true;
803     scheduleDeferredTask([this, &unit] {
804         unit.reconfigureAudioUnit();
805         m_reconfigurationOngoing = false;
806     });
807 }
808
809 } // namespace WebCore
810
811 #endif // ENABLE(MEDIA_STREAM)