1/*
2 * Copyright (C) 2015-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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of Google Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "MockRealtimeAudioSource.h"
33
34#if ENABLE(MEDIA_STREAM)
35#include "CaptureDevice.h"
36#include "Logging.h"
37#include "MediaConstraints.h"
38#include "MockRealtimeMediaSourceCenter.h"
39#include "NotImplemented.h"
40#include "RealtimeMediaSourceSettings.h"
41#include <wtf/UUID.h>
42
43namespace WebCore {
44
45#if !PLATFORM(MAC) && !PLATFORM(IOS_FAMILY) && !(USE(GSTREAMER) && USE(LIBWEBRTC))
46CaptureSourceOrError MockRealtimeAudioSource::create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints* constraints)
47{
48#ifndef NDEBUG
49 auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
50 ASSERT(device);
51 if (!device)
52 return { };
53#endif
54
55 auto source = adoptRef(*new MockRealtimeAudioSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
56 if (constraints && source->applyConstraints(*constraints))
57 return { };
58
59 return CaptureSourceOrError(WTFMove(source));
60}
61#endif
62
63MockRealtimeAudioSource::MockRealtimeAudioSource(String&& deviceID, String&& name, String&& hashSalt)
64 : RealtimeMediaSource(RealtimeMediaSource::Type::Audio, WTFMove(name), WTFMove(deviceID), WTFMove(hashSalt))
65 , m_timer(RunLoop::current(), this, &MockRealtimeAudioSource::tick)
66{
67 auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(persistentID());
68 ASSERT(device);
69 m_device = *device;
70}
71
72MockRealtimeAudioSource::~MockRealtimeAudioSource()
73{
74#if PLATFORM(IOS_FAMILY)
75 RealtimeMediaSourceCenter::singleton().audioCaptureFactory().unsetActiveSource(*this);
76#endif
77}
78
79const RealtimeMediaSourceSettings& MockRealtimeAudioSource::settings()
80{
81 if (!m_currentSettings) {
82 RealtimeMediaSourceSettings settings;
83 settings.setDeviceId(hashedId());
84 settings.setVolume(volume());
85 settings.setEchoCancellation(echoCancellation());
86 settings.setSampleRate(sampleRate());
87
88 RealtimeMediaSourceSupportedConstraints supportedConstraints;
89 supportedConstraints.setSupportsDeviceId(true);
90 supportedConstraints.setSupportsVolume(true);
91 supportedConstraints.setSupportsEchoCancellation(true);
92 supportedConstraints.setSupportsSampleRate(true);
93 settings.setSupportedConstraints(supportedConstraints);
94
95 m_currentSettings = WTFMove(settings);
96 }
97 return m_currentSettings.value();
98}
99
100const RealtimeMediaSourceCapabilities& MockRealtimeAudioSource::capabilities()
101{
102 if (!m_capabilities) {
103 RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
104
105 capabilities.setDeviceId(hashedId());
106 capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
107 capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
108 capabilities.setSampleRate(CapabilityValueOrRange(44100, 48000));
109
110 m_capabilities = WTFMove(capabilities);
111 }
112 return m_capabilities.value();
113}
114
115void MockRealtimeAudioSource::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>)
116{
117 m_currentSettings = WTF::nullopt;
118}
119
120void MockRealtimeAudioSource::startProducingData()
121{
122#if PLATFORM(IOS_FAMILY)
123 RealtimeMediaSourceCenter::singleton().audioCaptureFactory().setActiveSource(*this);
124#endif
125
126 if (!sampleRate())
127 setSampleRate(WTF::get<MockMicrophoneProperties>(m_device.properties).defaultSampleRate);
128
129 m_startTime = MonotonicTime::now();
130 m_timer.startRepeating(renderInterval());
131}
132
133void MockRealtimeAudioSource::stopProducingData()
134{
135 m_timer.stop();
136 m_startTime = MonotonicTime::nan();
137}
138
139void MockRealtimeAudioSource::tick()
140{
141 if (std::isnan(m_lastRenderTime))
142 m_lastRenderTime = MonotonicTime::now();
143
144 MonotonicTime now = MonotonicTime::now();
145
146 if (m_delayUntil) {
147 if (m_delayUntil < now)
148 return;
149 m_delayUntil = MonotonicTime();
150 }
151
152 Seconds delta = now - m_lastRenderTime;
153 m_lastRenderTime = now;
154 render(delta);
155}
156
157void MockRealtimeAudioSource::delaySamples(Seconds delta)
158{
159 m_delayUntil = MonotonicTime::now() + delta;
160}
161
162} // namespace WebCore
163
164#endif // ENABLE(MEDIA_STREAM)
165