WebRTC: Implement MediaEndpointPeerConnection::createOffer()
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaEndpointPeerConnection.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(MEDIA_STREAM)
34 #include "MediaEndpointPeerConnection.h"
35
36 #include "DOMError.h"
37 #include "JSDOMError.h"
38 #include "JSRTCSessionDescription.h"
39 #include "MediaEndpointSessionConfiguration.h"
40 #include "MediaStreamTrack.h"
41 #include "RTCOfferAnswerOptions.h"
42 #include "RTCRtpSender.h"
43 #include "SDPProcessor.h"
44 #include <wtf/MainThread.h>
45 #include <wtf/text/Base64.h>
46
47 namespace WebCore {
48
49 using namespace PeerConnection;
50
51 static std::unique_ptr<PeerConnectionBackend> createMediaEndpointPeerConnection(PeerConnectionBackendClient* client)
52 {
53     return std::unique_ptr<PeerConnectionBackend>(new MediaEndpointPeerConnection(client));
54 }
55
56 CreatePeerConnectionBackend PeerConnectionBackend::create = createMediaEndpointPeerConnection;
57
58 class WrappedSessionDescriptionPromise : public RefCounted<WrappedSessionDescriptionPromise> {
59 public:
60     static Ref<WrappedSessionDescriptionPromise> create(SessionDescriptionPromise&& promise)
61     {
62         return *adoptRef(new WrappedSessionDescriptionPromise(WTFMove(promise)));
63     }
64
65     SessionDescriptionPromise& promise() { return m_promise; }
66
67 private:
68     WrappedSessionDescriptionPromise(SessionDescriptionPromise&& promise)
69         : m_promise(WTFMove(promise))
70     { }
71
72     SessionDescriptionPromise m_promise;
73 };
74
75 static String randomString(size_t length)
76 {
77     const size_t size = ceil(length * 3 / 4);
78     unsigned char randomValues[size];
79     cryptographicallyRandomValues(randomValues, size);
80     return base64Encode(randomValues, size);
81 }
82
83 MediaEndpointPeerConnection::MediaEndpointPeerConnection(PeerConnectionBackendClient* client)
84     : m_client(client)
85     , m_sdpProcessor(std::unique_ptr<SDPProcessor>(new SDPProcessor(m_client->scriptExecutionContext())))
86     , m_cname(randomString(16))
87     , m_iceUfrag(randomString(4))
88     , m_icePassword(randomString(22))
89 {
90     m_mediaEndpoint = MediaEndpoint::create(*this);
91     ASSERT(m_mediaEndpoint);
92
93     m_defaultAudioPayloads = m_mediaEndpoint->getDefaultAudioPayloads();
94     m_defaultVideoPayloads = m_mediaEndpoint->getDefaultVideoPayloads();
95
96     // Tasks (see runTask()) will be deferred until we get the DTLS fingerprint.
97     m_mediaEndpoint->generateDtlsInfo();
98 }
99
100 void MediaEndpointPeerConnection::runTask(std::function<void()> task)
101 {
102     if (m_dtlsFingerprint.isNull()) {
103         // Only one task needs to be deferred since it will hold off any others until completed.
104         ASSERT(!m_initialDeferredTask);
105         m_initialDeferredTask = task;
106     } else
107         callOnMainThread(task);
108 }
109
110 void MediaEndpointPeerConnection::startRunningTasks()
111 {
112     if (!m_initialDeferredTask)
113         return;
114
115     m_initialDeferredTask();
116     m_initialDeferredTask = nullptr;
117 }
118
119 void MediaEndpointPeerConnection::createOffer(RTCOfferOptions& options, SessionDescriptionPromise&& promise)
120 {
121     const RefPtr<RTCOfferOptions> protectedOptions = &options;
122     RefPtr<WrappedSessionDescriptionPromise> wrappedPromise = WrappedSessionDescriptionPromise::create(WTFMove(promise));
123
124     runTask([this, protectedOptions, wrappedPromise]() {
125         createOfferTask(*protectedOptions, wrappedPromise->promise());
126     });
127 }
128
129 void MediaEndpointPeerConnection::createOfferTask(RTCOfferOptions&, SessionDescriptionPromise& promise)
130 {
131     ASSERT(!m_dtlsFingerprint.isEmpty());
132
133     RefPtr<MediaEndpointSessionConfiguration> configurationSnapshot = MediaEndpointSessionConfiguration::create();
134
135     configurationSnapshot->setSessionVersion(m_sdpSessionVersion++);
136
137     RtpSenderVector senders = m_client->getSenders();
138
139     // Add media descriptions for senders.
140     for (auto& sender : senders) {
141         RefPtr<PeerMediaDescription> mediaDescription = PeerMediaDescription::create();
142         MediaStreamTrack* track = sender->track();
143
144         mediaDescription->setMediaStreamId(sender->mediaStreamIds()[0]);
145         mediaDescription->setMediaStreamTrackId(track->id());
146         mediaDescription->setType(track->kind());
147         mediaDescription->setPayloads(track->kind() == "audio" ? m_defaultAudioPayloads : m_defaultVideoPayloads);
148         mediaDescription->setDtlsFingerprintHashFunction(m_dtlsFingerprintFunction);
149         mediaDescription->setDtlsFingerprint(m_dtlsFingerprint);
150         mediaDescription->setCname(m_cname);
151         mediaDescription->addSsrc(cryptographicallyRandomNumber());
152         mediaDescription->setIceUfrag(m_iceUfrag);
153         mediaDescription->setIcePassword(m_icePassword);
154
155         configurationSnapshot->addMediaDescription(WTFMove(mediaDescription));
156     }
157
158     String sdpString;
159     SDPProcessor::Result result = m_sdpProcessor->generate(*configurationSnapshot, sdpString);
160     if (result != SDPProcessor::Result::Success) {
161         LOG_ERROR("SDPProcessor internal error");
162         return;
163     }
164
165     promise.resolve(RTCSessionDescription::create("offer", sdpString));
166 }
167
168 void MediaEndpointPeerConnection::createAnswer(RTCAnswerOptions& options, SessionDescriptionPromise&& promise)
169 {
170     UNUSED_PARAM(options);
171
172     notImplemented();
173
174     promise.reject(DOMError::create("NotSupportedError"));
175 }
176
177 void MediaEndpointPeerConnection::setLocalDescription(RTCSessionDescription& description, VoidPromise&& promise)
178 {
179     UNUSED_PARAM(description);
180
181     notImplemented();
182
183     promise.reject(DOMError::create("NotSupportedError"));
184 }
185
186 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::localDescription() const
187 {
188     notImplemented();
189
190     return nullptr;
191 }
192
193 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentLocalDescription() const
194 {
195     notImplemented();
196
197     return nullptr;
198 }
199
200 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingLocalDescription() const
201 {
202     notImplemented();
203
204     return nullptr;
205 }
206
207 void MediaEndpointPeerConnection::setRemoteDescription(RTCSessionDescription& description, VoidPromise&& promise)
208 {
209     UNUSED_PARAM(description);
210
211     notImplemented();
212
213     promise.reject(DOMError::create("NotSupportedError"));
214 }
215
216 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::remoteDescription() const
217 {
218     notImplemented();
219
220     return nullptr;
221 }
222
223 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::currentRemoteDescription() const
224 {
225     notImplemented();
226
227     return nullptr;
228 }
229
230 RefPtr<RTCSessionDescription> MediaEndpointPeerConnection::pendingRemoteDescription() const
231 {
232     notImplemented();
233
234     return nullptr;
235 }
236
237 void MediaEndpointPeerConnection::setConfiguration(RTCConfiguration& configuration)
238 {
239     UNUSED_PARAM(configuration);
240
241     notImplemented();
242 }
243
244 void MediaEndpointPeerConnection::addIceCandidate(RTCIceCandidate& rtcCandidate, PeerConnection::VoidPromise&& promise)
245 {
246     UNUSED_PARAM(rtcCandidate);
247
248     notImplemented();
249
250     promise.reject(DOMError::create("NotSupportedError"));
251 }
252
253 void MediaEndpointPeerConnection::getStats(MediaStreamTrack*, PeerConnection::StatsPromise&& promise)
254 {
255     notImplemented();
256
257     promise.reject(DOMError::create("NotSupportedError"));
258 }
259
260 void MediaEndpointPeerConnection::replaceTrack(RTCRtpSender& sender, MediaStreamTrack& withTrack, PeerConnection::VoidPromise&& promise)
261 {
262     UNUSED_PARAM(sender);
263     UNUSED_PARAM(withTrack);
264     UNUSED_PARAM(promise);
265
266     notImplemented();
267
268     promise.reject(DOMError::create("NotSupportedError"));
269 }
270
271 void MediaEndpointPeerConnection::stop()
272 {
273     notImplemented();
274 }
275
276 void MediaEndpointPeerConnection::markAsNeedingNegotiation()
277 {
278     notImplemented();
279 }
280
281 void MediaEndpointPeerConnection::gotDtlsFingerprint(const String& fingerprint, const String& fingerprintFunction)
282 {
283     ASSERT(isMainThread());
284
285     m_dtlsFingerprint = fingerprint;
286     m_dtlsFingerprintFunction = fingerprintFunction;
287
288     startRunningTasks();
289 }
290
291 void MediaEndpointPeerConnection::gotIceCandidate(unsigned mdescIndex, RefPtr<IceCandidate>&& candidate)
292 {
293     ASSERT(isMainThread());
294
295     UNUSED_PARAM(mdescIndex);
296     UNUSED_PARAM(candidate);
297
298     notImplemented();
299 }
300
301 void MediaEndpointPeerConnection::doneGatheringCandidates(unsigned mdescIndex)
302 {
303     ASSERT(isMainThread());
304
305     UNUSED_PARAM(mdescIndex);
306
307     notImplemented();
308 }
309
310 void MediaEndpointPeerConnection::gotRemoteSource(unsigned mdescIndex, RefPtr<RealtimeMediaSource>&& source)
311 {
312     ASSERT(isMainThread());
313
314     UNUSED_PARAM(mdescIndex);
315     UNUSED_PARAM(source);
316
317     notImplemented();
318 }
319
320 } // namespace WebCore
321
322 #endif // ENABLE(MEDIA_STREAM)