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