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