2 * Copyright (C) 2015 Ericsson AB. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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
14 * 3. Neither the name of Ericsson 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.
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.
34 #include "MockMediaEndpoint.h"
36 #include "MediaEndpointSessionConfiguration.h"
37 #include "MediaPayload.h"
38 #include "MockRealtimeAudioSource.h"
39 #include "MockRealtimeVideoSource.h"
40 #include "RealtimeMediaSource.h"
41 #include <wtf/MainThread.h>
45 static const char* fingerprint = "8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B";
46 static const char* fingerprintFunction = "sha-256";
48 std::unique_ptr<MediaEndpoint> MockMediaEndpoint::create(MediaEndpointClient& client)
50 return std::unique_ptr<MediaEndpoint>(new MockMediaEndpoint(client));
53 MockMediaEndpoint::MockMediaEndpoint(MediaEndpointClient& client)
55 , m_iceCandidateTimer(*this, &MockMediaEndpoint::iceCandidateTimerFired)
56 , m_iceTransportTimer(*this, &MockMediaEndpoint::iceTransportTimerFired)
57 , m_unmuteTimer(*this, &MockMediaEndpoint::unmuteTimerFired)
61 MockMediaEndpoint::~MockMediaEndpoint()
66 void MockMediaEndpoint::setConfiguration(RefPtr<MediaEndpointConfiguration>&& configuration)
68 UNUSED_PARAM(configuration);
71 void MockMediaEndpoint::generateDtlsInfo()
73 callOnMainThread([this]() {
74 m_client.gotDtlsFingerprint(String(fingerprint), String(fingerprintFunction));
78 MediaPayloadVector MockMediaEndpoint::getDefaultAudioPayloads()
80 MediaPayloadVector payloads;
82 RefPtr<MediaPayload> payload = MediaPayload::create();
83 payload->setType(111);
84 payload->setEncodingName("OPUS");
85 payload->setClockRate(48000);
86 payload->setChannels(2);
87 payloads.append(payload);
89 payload = MediaPayload::create();
91 payload->setEncodingName("PCMA");
92 payload->setClockRate(8000);
93 payload->setChannels(1);
94 payloads.append(payload);
96 payload = MediaPayload::create();
98 payload->setEncodingName("PCMU");
99 payload->setClockRate(8000);
100 payload->setChannels(1);
101 payloads.append(payload);
106 MediaPayloadVector MockMediaEndpoint::getDefaultVideoPayloads()
108 MediaPayloadVector payloads;
110 RefPtr<MediaPayload> payload = MediaPayload::create();
111 payload->setType(103);
112 payload->setEncodingName("H264");
113 payload->setClockRate(90000);
114 payload->setCcmfir(true);
115 payload->setNackpli(true);
116 payload->addParameter("packetizationMode", 1);
117 payloads.append(payload);
119 payload = MediaPayload::create();
120 payload->setType(100);
121 payload->setEncodingName("VP8");
122 payload->setClockRate(90000);
123 payload->setCcmfir(true);
124 payload->setNackpli(true);
125 payload->setNack(true);
126 payloads.append(payload);
128 payload = MediaPayload::create();
129 payload->setType(120);
130 payload->setEncodingName("RTX");
131 payload->setClockRate(90000);
132 payload->addParameter("apt", 100);
133 payload->addParameter("rtxTime", 200);
134 payloads.append(payload);
139 MediaPayloadVector MockMediaEndpoint::filterPayloads(const MediaPayloadVector& remotePayloads, const MediaPayloadVector& defaultPayloads)
141 MediaPayloadVector filteredPayloads;
143 for (auto& remotePayload : remotePayloads) {
144 MediaPayload* defaultPayload = nullptr;
145 for (auto& payload : defaultPayloads) {
146 if (payload->encodingName() == remotePayload->encodingName().convertToASCIIUppercase()) {
147 defaultPayload = payload.get();
154 if (defaultPayload->parameters().contains("packetizationMode") && remotePayload->parameters().contains("packetizationMode")
155 && (defaultPayload->parameters().get("packetizationMode") != defaultPayload->parameters().get("packetizationMode")))
158 filteredPayloads.append(remotePayload);
161 return filteredPayloads;
164 MediaEndpoint::UpdateResult MockMediaEndpoint::updateReceiveConfiguration(MediaEndpointSessionConfiguration* configuration, bool isInitiator)
166 UNUSED_PARAM(isInitiator);
168 updateConfigurationMids(*configuration);
169 return UpdateResult::Success;
172 MediaEndpoint::UpdateResult MockMediaEndpoint::updateSendConfiguration(MediaEndpointSessionConfiguration* configuration, const RealtimeMediaSourceMap& sendSourceMap, bool isInitiator)
174 UNUSED_PARAM(sendSourceMap);
175 UNUSED_PARAM(isInitiator);
177 updateConfigurationMids(*configuration);
178 return UpdateResult::Success;
181 void MockMediaEndpoint::addRemoteCandidate(IceCandidate& candidate, const String& mid, const String& ufrag, const String& password)
183 UNUSED_PARAM(candidate);
186 UNUSED_PARAM(password);
189 Ref<RealtimeMediaSource> MockMediaEndpoint::createMutedRemoteSource(const String& mid, RealtimeMediaSource::Type type)
191 RefPtr<RealtimeMediaSource> source;
194 case RealtimeMediaSource::Audio: source = MockRealtimeAudioSource::createMuted("remote audio"); break;
195 case RealtimeMediaSource::Video: source = MockRealtimeVideoSource::createMuted("remote video"); break;
196 case RealtimeMediaSource::None:
197 ASSERT_NOT_REACHED();
200 m_mutedRemoteSources.set(mid, source);
204 void MockMediaEndpoint::replaceSendSource(RealtimeMediaSource& newSource, const String& mid)
206 UNUSED_PARAM(newSource);
210 void MockMediaEndpoint::replaceMutedRemoteSourceMid(const String& oldMid, const String& newMid)
212 RefPtr<RealtimeMediaSource> remoteSource = m_mutedRemoteSources.take(oldMid);
213 m_mutedRemoteSources.set(newMid, WTFMove(remoteSource));
216 void MockMediaEndpoint::stop()
220 void MockMediaEndpoint::emulatePlatformEvent(const String& action)
222 if (action == "dispatch-fake-ice-candidates")
223 dispatchFakeIceCandidates();
224 else if (action == "step-ice-transport-states")
225 stepIceTransportStates();
226 else if (action == "unmute-remote-sources-by-mid")
227 unmuteRemoteSourcesByMid();
230 void MockMediaEndpoint::updateConfigurationMids(const MediaEndpointSessionConfiguration& configuration)
233 for (const RefPtr<PeerMediaDescription>& mediaDescription : configuration.mediaDescriptions())
234 mids.append(mediaDescription->mid());
238 void MockMediaEndpoint::dispatchFakeIceCandidates()
240 RefPtr<IceCandidate> iceCandidate = IceCandidate::create();
241 iceCandidate->setType("host");
242 iceCandidate->setFoundation("1");
243 iceCandidate->setComponentId(1);
244 iceCandidate->setPriority(2013266431);
245 iceCandidate->setAddress("192.168.0.100");
246 iceCandidate->setPort(38838);
247 iceCandidate->setTransport("UDP");
248 m_fakeIceCandidates.append(WTFMove(iceCandidate));
250 iceCandidate = IceCandidate::create();
251 iceCandidate->setType("host");
252 iceCandidate->setFoundation("2");
253 iceCandidate->setComponentId(1);
254 iceCandidate->setPriority(1019216383);
255 iceCandidate->setAddress("192.168.0.100");
256 iceCandidate->setPort(9);
257 iceCandidate->setTransport("TCP");
258 iceCandidate->setTcpType("active");
259 m_fakeIceCandidates.append(WTFMove(iceCandidate));
261 iceCandidate = IceCandidate::create();
262 iceCandidate->setType("srflx");
263 iceCandidate->setFoundation("3");
264 iceCandidate->setComponentId(1);
265 iceCandidate->setPriority(1677722111);
266 iceCandidate->setAddress("172.18.0.1");
267 iceCandidate->setPort(47989);
268 iceCandidate->setTransport("UDP");
269 iceCandidate->setRelatedAddress("192.168.0.100");
270 iceCandidate->setRelatedPort(47989);
271 m_fakeIceCandidates.append(WTFMove(iceCandidate));
273 // Reverse order to use takeLast() while keeping the above order
274 m_fakeIceCandidates.reverse();
276 m_iceCandidateTimer.startOneShot(0);
279 void MockMediaEndpoint::iceCandidateTimerFired()
281 if (m_mids.isEmpty())
284 if (!m_fakeIceCandidates.isEmpty()) {
285 m_client.gotIceCandidate(m_mids[0], m_fakeIceCandidates.takeLast());
286 m_iceCandidateTimer.startOneShot(0);
288 m_client.doneGatheringCandidates(m_mids[0]);
291 void MockMediaEndpoint::stepIceTransportStates()
293 if (m_mids.size() != 3) {
294 LOG_ERROR("The 'step-ice-transport-states' action requires 3 transceivers");
300 m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Checking));
301 m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Checking));
302 m_iceTransportStateChanges.append(std::make_pair(m_mids[2], MediaEndpoint::IceTransportState::Checking));
305 m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Connected));
306 m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Completed));
307 m_iceTransportStateChanges.append(std::make_pair(m_mids[2], MediaEndpoint::IceTransportState::Closed));
310 m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Completed));
313 m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Failed));
316 m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Disconnected));
317 m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Closed));
320 m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Closed));
322 // Reverse order to use takeLast() while keeping the above order
323 m_iceTransportStateChanges.reverse();
325 m_iceTransportTimer.startOneShot(0);
328 void MockMediaEndpoint::iceTransportTimerFired()
330 if (m_iceTransportStateChanges.isEmpty() || m_mids.size() != 3)
333 auto stateChange = m_iceTransportStateChanges.takeLast();
334 m_client.iceTransportStateChanged(stateChange.first, stateChange.second);
336 m_iceTransportTimer.startOneShot(0);
339 void MockMediaEndpoint::unmuteRemoteSourcesByMid()
341 if (m_mids.isEmpty())
344 // Looking up each source by its mid, instead of simply iterating over the list of muted sources,
345 // emulates remote media arriving on a media description with a specific mid (RTCRtpTransceiver).
347 // Copy values in reverse order to maintain the original order while using takeLast()
348 for (int i = m_mids.size() - 1; i >= 0; --i)
349 m_midsOfSourcesToUnmute.append(m_mids[i]);
351 m_unmuteTimer.startOneShot(0);
354 void MockMediaEndpoint::unmuteTimerFired()
356 RefPtr<RealtimeMediaSource> source = m_mutedRemoteSources.get(m_midsOfSourcesToUnmute.takeLast());
358 source->setMuted(false);
360 if (!m_midsOfSourcesToUnmute.isEmpty())
361 m_unmuteTimer.startOneShot(0);
364 } // namespace WebCore
366 #endif // ENABLE(WEB_RTC)