ae18dd1571a9ecdd0eebdfe378454a6bcb973c00
[WebKit-https.git] / Source / WebCore / platform / mock / MockMediaEndpoint.cpp
1 /*
2  * Copyright (C) 2015 Ericsson AB. 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 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.
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
33 #if ENABLE(WEB_RTC)
34 #include "MockMediaEndpoint.h"
35
36 #include "MediaEndpointSessionConfiguration.h"
37 #include "MediaPayload.h"
38 #include "MockRealtimeAudioSource.h"
39 #include "MockRealtimeVideoSource.h"
40 #include <wtf/MainThread.h>
41
42 namespace WebCore {
43
44 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";
45 static const char* fingerprintFunction = "sha-256";
46
47 std::unique_ptr<MediaEndpoint> MockMediaEndpoint::create(MediaEndpointClient& client)
48 {
49     return std::unique_ptr<MediaEndpoint>(new MockMediaEndpoint(client));
50 }
51
52 MockMediaEndpoint::MockMediaEndpoint(MediaEndpointClient& client)
53     : m_client(client)
54     , m_iceCandidateTimer(*this, &MockMediaEndpoint::iceCandidateTimerFired)
55     , m_iceTransportTimer(*this, &MockMediaEndpoint::iceTransportTimerFired)
56 {
57 }
58
59 MockMediaEndpoint::~MockMediaEndpoint()
60 {
61     stop();
62 }
63
64 void MockMediaEndpoint::setConfiguration(RefPtr<MediaEndpointConfiguration>&& configuration)
65 {
66     UNUSED_PARAM(configuration);
67 }
68
69 void MockMediaEndpoint::generateDtlsInfo()
70 {
71     callOnMainThread([this]() {
72         m_client.gotDtlsFingerprint(String(fingerprint), String(fingerprintFunction));
73     });
74 }
75
76 MediaPayloadVector MockMediaEndpoint::getDefaultAudioPayloads()
77 {
78     MediaPayloadVector payloads;
79
80     RefPtr<MediaPayload> payload = MediaPayload::create();
81     payload->setType(111);
82     payload->setEncodingName("OPUS");
83     payload->setClockRate(48000);
84     payload->setChannels(2);
85     payloads.append(payload);
86
87     payload = MediaPayload::create();
88     payload->setType(8);
89     payload->setEncodingName("PCMA");
90     payload->setClockRate(8000);
91     payload->setChannels(1);
92     payloads.append(payload);
93
94     payload = MediaPayload::create();
95     payload->setType(0);
96     payload->setEncodingName("PCMU");
97     payload->setClockRate(8000);
98     payload->setChannels(1);
99     payloads.append(payload);
100
101     return payloads;
102 }
103
104 MediaPayloadVector MockMediaEndpoint::getDefaultVideoPayloads()
105 {
106     MediaPayloadVector payloads;
107
108     RefPtr<MediaPayload> payload = MediaPayload::create();
109     payload->setType(103);
110     payload->setEncodingName("H264");
111     payload->setClockRate(90000);
112     payload->setCcmfir(true);
113     payload->setNackpli(true);
114     payload->addParameter("packetizationMode", 1);
115     payloads.append(payload);
116
117     payload = MediaPayload::create();
118     payload->setType(100);
119     payload->setEncodingName("VP8");
120     payload->setClockRate(90000);
121     payload->setCcmfir(true);
122     payload->setNackpli(true);
123     payload->setNack(true);
124     payloads.append(payload);
125
126     payload = MediaPayload::create();
127     payload->setType(120);
128     payload->setEncodingName("RTX");
129     payload->setClockRate(90000);
130     payload->addParameter("apt", 100);
131     payload->addParameter("rtxTime", 200);
132     payloads.append(payload);
133
134     return payloads;
135 }
136
137 MediaPayloadVector MockMediaEndpoint::filterPayloads(const MediaPayloadVector& remotePayloads, const MediaPayloadVector& defaultPayloads)
138 {
139     MediaPayloadVector filteredPayloads;
140
141     for (auto& remotePayload : remotePayloads) {
142         MediaPayload* defaultPayload = nullptr;
143         for (auto& payload : defaultPayloads) {
144             if (payload->encodingName() == remotePayload->encodingName().convertToASCIIUppercase()) {
145                 defaultPayload = payload.get();
146                 break;
147             }
148         }
149         if (!defaultPayload)
150             continue;
151
152         if (defaultPayload->parameters().contains("packetizationMode") && remotePayload->parameters().contains("packetizationMode")
153             && (defaultPayload->parameters().get("packetizationMode") != defaultPayload->parameters().get("packetizationMode")))
154             continue;
155
156         filteredPayloads.append(remotePayload);
157     }
158
159     return filteredPayloads;
160 }
161
162 MediaEndpoint::UpdateResult MockMediaEndpoint::updateReceiveConfiguration(MediaEndpointSessionConfiguration* configuration, bool isInitiator)
163 {
164     UNUSED_PARAM(isInitiator);
165
166     Vector<String> mids;
167     for (const RefPtr<PeerMediaDescription>& mediaDescription : configuration->mediaDescriptions())
168         mids.append(mediaDescription->mid());
169     m_mids.swap(mids);
170
171     return UpdateResult::Success;
172 }
173
174 MediaEndpoint::UpdateResult MockMediaEndpoint::updateSendConfiguration(MediaEndpointSessionConfiguration* configuration, const RealtimeMediaSourceMap& sendSourceMap, bool isInitiator)
175 {
176     UNUSED_PARAM(configuration);
177     UNUSED_PARAM(sendSourceMap);
178     UNUSED_PARAM(isInitiator);
179
180     return UpdateResult::Success;
181 }
182
183 void MockMediaEndpoint::addRemoteCandidate(IceCandidate& candidate, const String& mid, const String& ufrag, const String& password)
184 {
185     UNUSED_PARAM(candidate);
186     UNUSED_PARAM(mid);
187     UNUSED_PARAM(ufrag);
188     UNUSED_PARAM(password);
189 }
190
191 Ref<RealtimeMediaSource> MockMediaEndpoint::createMutedRemoteSource(const String&, RealtimeMediaSource::Type type)
192 {
193     if (type == RealtimeMediaSource::Audio)
194         return MockRealtimeAudioSource::createMuted("remote audio");
195
196     ASSERT(type == RealtimeMediaSource::Video);
197     return MockRealtimeVideoSource::createMuted("remote video");
198 }
199
200 void MockMediaEndpoint::replaceSendSource(RealtimeMediaSource& newSource, const String& mid)
201 {
202     UNUSED_PARAM(newSource);
203     UNUSED_PARAM(mid);
204 }
205
206 void MockMediaEndpoint::stop()
207 {
208 }
209
210 void MockMediaEndpoint::emulatePlatformEvent(const String& action)
211 {
212     if (action == "dispatch-fake-ice-candidates")
213         dispatchFakeIceCandidates();
214     else if (action == "step-ice-transport-states")
215         stepIceTransportStates();
216 }
217
218 void MockMediaEndpoint::dispatchFakeIceCandidates()
219 {
220     RefPtr<IceCandidate> iceCandidate = IceCandidate::create();
221     iceCandidate->setType("host");
222     iceCandidate->setFoundation("1");
223     iceCandidate->setComponentId(1);
224     iceCandidate->setPriority(2013266431);
225     iceCandidate->setAddress("192.168.0.100");
226     iceCandidate->setPort(38838);
227     iceCandidate->setTransport("UDP");
228     m_fakeIceCandidates.append(WTFMove(iceCandidate));
229
230     iceCandidate = IceCandidate::create();
231     iceCandidate->setType("host");
232     iceCandidate->setFoundation("2");
233     iceCandidate->setComponentId(1);
234     iceCandidate->setPriority(1019216383);
235     iceCandidate->setAddress("192.168.0.100");
236     iceCandidate->setPort(9);
237     iceCandidate->setTransport("TCP");
238     iceCandidate->setTcpType("active");
239     m_fakeIceCandidates.append(WTFMove(iceCandidate));
240
241     iceCandidate = IceCandidate::create();
242     iceCandidate->setType("srflx");
243     iceCandidate->setFoundation("3");
244     iceCandidate->setComponentId(1);
245     iceCandidate->setPriority(1677722111);
246     iceCandidate->setAddress("172.18.0.1");
247     iceCandidate->setPort(47989);
248     iceCandidate->setTransport("UDP");
249     iceCandidate->setRelatedAddress("192.168.0.100");
250     iceCandidate->setRelatedPort(47989);
251     m_fakeIceCandidates.append(WTFMove(iceCandidate));
252
253     // Reverse order to use takeLast() while keeping the above order
254     m_fakeIceCandidates.reverse();
255
256     m_iceCandidateTimer.startOneShot(0);
257 }
258
259 void MockMediaEndpoint::iceCandidateTimerFired()
260 {
261     if (m_mids.isEmpty())
262         return;
263
264     if (!m_fakeIceCandidates.isEmpty()) {
265         m_client.gotIceCandidate(m_mids[0], m_fakeIceCandidates.takeLast());
266         m_iceCandidateTimer.startOneShot(0);
267     } else
268         m_client.doneGatheringCandidates(m_mids[0]);
269 }
270
271 void MockMediaEndpoint::stepIceTransportStates()
272 {
273     if (m_mids.size() != 3) {
274         LOG_ERROR("The 'step-ice-transport-states' action requires 3 transceivers");
275         return;
276     }
277
278     // Should go to:
279     // 'checking'
280     m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Checking));
281     m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Checking));
282     m_iceTransportStateChanges.append(std::make_pair(m_mids[2], MediaEndpoint::IceTransportState::Checking));
283
284     // 'connected'
285     m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Connected));
286     m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Completed));
287     m_iceTransportStateChanges.append(std::make_pair(m_mids[2], MediaEndpoint::IceTransportState::Closed));
288
289     // 'completed'
290     m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Completed));
291
292     // 'failed'
293     m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Failed));
294
295     // 'disconnected'
296     m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Disconnected));
297     m_iceTransportStateChanges.append(std::make_pair(m_mids[0], MediaEndpoint::IceTransportState::Closed));
298
299     // 'new'
300     m_iceTransportStateChanges.append(std::make_pair(m_mids[1], MediaEndpoint::IceTransportState::Closed));
301
302     // Reverse order to use takeLast() while keeping the above order
303     m_iceTransportStateChanges.reverse();
304
305     m_iceTransportTimer.startOneShot(0);
306 }
307
308 void MockMediaEndpoint::iceTransportTimerFired()
309 {
310     if (m_iceTransportStateChanges.isEmpty() || m_mids.size() != 3)
311         return;
312
313     auto stateChange = m_iceTransportStateChanges.takeLast();
314     m_client.iceTransportStateChanged(stateChange.first, stateChange.second);
315
316     m_iceTransportTimer.startOneShot(0);
317 }
318
319 } // namespace WebCore
320
321 #endif // ENABLE(WEB_RTC)