Unreviewed, rolling out r244627.
[WebKit-https.git] / Source / WebCore / platform / mediastream / ios / AVAudioSessionCaptureDeviceManager.mm
1 /*
2  * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "AVAudioSessionCaptureDeviceManager.h"
28
29 #if ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY)
30
31 #include "AVAudioSessionCaptureDevice.h"
32 #include "RealtimeMediaSourceCenter.h"
33 #include <AVFoundation/AVAudioSession.h>
34 #include <wtf/SoftLinking.h>
35 #include <wtf/Vector.h>
36
37 SOFT_LINK_FRAMEWORK(AVFoundation)
38 SOFT_LINK_CLASS(AVFoundation, AVAudioSession)
39 #define AVAudioSession getAVAudioSessionClass()
40
41 void* AvailableInputsContext = &AvailableInputsContext;
42
43 @interface WebAVAudioSessionAvailableInputsListener : NSObject {
44     WTF::Function<void()> _callback;
45 }
46 @end
47
48 @implementation WebAVAudioSessionAvailableInputsListener
49 - (id)initWithCallback:(WTF::Function<void()>&&)callback
50 {
51     self = [super init];
52     if (!self)
53         return nil;
54
55     _callback = WTFMove(callback);
56     return self;
57 }
58
59 - (void)invalidate
60 {
61     _callback = nullptr;
62 }
63
64 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
65 {
66     UNUSED_PARAM(keyPath);
67     UNUSED_PARAM(object);
68     UNUSED_PARAM(change);
69     if (context == AvailableInputsContext && _callback)
70         _callback();
71 }
72 @end
73
74 namespace WebCore {
75
76 AVAudioSessionCaptureDeviceManager& AVAudioSessionCaptureDeviceManager::singleton()
77 {
78     static NeverDestroyed<AVAudioSessionCaptureDeviceManager> manager;
79     return manager;
80 }
81
82 AVAudioSessionCaptureDeviceManager::~AVAudioSessionCaptureDeviceManager()
83 {
84     [m_listener invalidate];
85     m_listener = nullptr;
86 }
87
88 const Vector<CaptureDevice>& AVAudioSessionCaptureDeviceManager::captureDevices()
89 {
90     if (!m_devices)
91         refreshAudioCaptureDevices();
92     return m_devices.value();
93 }
94
95 Optional<CaptureDevice> AVAudioSessionCaptureDeviceManager::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& deviceID)
96 {
97     ASSERT_UNUSED(type, type == CaptureDevice::DeviceType::Microphone);
98     for (auto& device : captureDevices()) {
99         if (device.persistentId() == deviceID)
100             return device;
101     }
102     return WTF::nullopt;
103 }
104
105 Vector<AVAudioSessionCaptureDevice>& AVAudioSessionCaptureDeviceManager::audioSessionCaptureDevices()
106 {
107     if (!m_audioSessionCaptureDevices)
108         refreshAudioCaptureDevices();
109     return m_audioSessionCaptureDevices.value();
110 }
111
112 Optional<AVAudioSessionCaptureDevice> AVAudioSessionCaptureDeviceManager::audioSessionDeviceWithUID(const String& deviceID)
113 {
114     if (!m_audioSessionCaptureDevices)
115         refreshAudioCaptureDevices();
116
117     for (auto& device : audioSessionCaptureDevices()) {
118         if (device.persistentId() == deviceID)
119             return device;
120     }
121     return WTF::nullopt;
122 }
123
124 void AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
125 {
126     if (!m_listener) {
127         m_listener = adoptNS([[WebAVAudioSessionAvailableInputsListener alloc] initWithCallback:[this] {
128             refreshAudioCaptureDevices();
129         }]);
130         [[AVAudioSession sharedInstance] addObserver:m_listener.get() forKeyPath:@"availableInputs" options:0 context:AvailableInputsContext];
131     }
132
133     Vector<AVAudioSessionCaptureDevice> newAudioDevices;
134     Vector<CaptureDevice> newDevices;
135
136     for (AVAudioSessionPortDescription *portDescription in [AVAudioSession sharedInstance].availableInputs) {
137         auto audioDevice = AVAudioSessionCaptureDevice::create(portDescription);
138         newDevices.append(audioDevice);
139         newAudioDevices.append(WTFMove(audioDevice));
140     }
141
142     m_audioSessionCaptureDevices = WTFMove(newAudioDevices);
143     m_devices = WTFMove(newDevices);
144
145     deviceChanged();
146 }
147
148 } // namespace WebCore
149
150 #endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)