Bumping manifests a=b2g-bump
[gecko.git] / media / mtransport / nricemediastream.cpp
bloba69afa40dd895a005c0bc37917b9a58d98340ce4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Original author: ekr@rtfm.com
9 // Some of this code is cut-and-pasted from nICEr. Copyright is:
12 Copyright (c) 2007, Adobe Systems, Incorporated
13 All rights reserved.
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are
17 met:
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
22 * Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
26 * Neither the name of Adobe Systems, Network Resonance nor the names of its
27 contributors may be used to endorse or promote products derived from
28 this software without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 #include <string>
45 #include <vector>
47 #include "logging.h"
48 #include "nsError.h"
49 #include "mozilla/Scoped.h"
51 // nICEr includes
52 extern "C" {
53 #include "nr_api.h"
54 #include "registry.h"
55 #include "async_timer.h"
56 #include "ice_util.h"
57 #include "transport_addr.h"
58 #include "nr_crypto.h"
59 #include "nr_socket.h"
60 #include "nr_socket_local.h"
61 #include "stun_client_ctx.h"
62 #include "stun_server_ctx.h"
63 #include "ice_ctx.h"
64 #include "ice_candidate.h"
65 #include "ice_handler.h"
68 // Local includes
69 #include "nricectx.h"
70 #include "nricemediastream.h"
72 namespace mozilla {
74 MOZ_MTLOG_MODULE("mtransport")
76 static bool ToNrIceAddr(nr_transport_addr &addr,
77 NrIceAddr *out) {
78 int r;
79 char addrstring[INET6_ADDRSTRLEN + 1];
81 r = nr_transport_addr_get_addrstring(&addr, addrstring, sizeof(addrstring));
82 if (r)
83 return false;
84 out->host = addrstring;
86 int port;
87 r = nr_transport_addr_get_port(&addr, &port);
88 if (r)
89 return false;
91 out->port = port;
93 switch (addr.protocol) {
94 case IPPROTO_TCP:
95 out->transport = kNrIceTransportTcp;
96 break;
97 case IPPROTO_UDP:
98 out->transport = kNrIceTransportUdp;
99 break;
100 default:
101 MOZ_CRASH();
102 return false;
105 return true;
108 static bool ToNrIceCandidate(const nr_ice_candidate& candc,
109 NrIceCandidate* out) {
110 MOZ_ASSERT(out);
111 int r;
112 // Const-cast because the internal nICEr code isn't const-correct.
113 nr_ice_candidate *cand = const_cast<nr_ice_candidate *>(&candc);
115 if (!ToNrIceAddr(cand->addr, &out->cand_addr))
116 return false;
118 if (cand->isock) {
119 nr_transport_addr addr;
120 r = nr_socket_getaddr(cand->isock->sock, &addr);
121 if (r)
122 return false;
124 if (!ToNrIceAddr(addr, &out->local_addr))
125 return false;
128 NrIceCandidate::Type type;
130 switch (cand->type) {
131 case HOST:
132 type = NrIceCandidate::ICE_HOST;
133 break;
134 case SERVER_REFLEXIVE:
135 type = NrIceCandidate::ICE_SERVER_REFLEXIVE;
136 break;
137 case PEER_REFLEXIVE:
138 type = NrIceCandidate::ICE_PEER_REFLEXIVE;
139 break;
140 case RELAYED:
141 type = NrIceCandidate::ICE_RELAYED;
142 break;
143 default:
144 return false;
147 out->type = type;
148 out->codeword = candc.codeword;
149 return true;
152 // Make an NrIceCandidate from the candidate |cand|.
153 // This is not a member fxn because we want to hide the
154 // defn of nr_ice_candidate but we pass by reference.
155 static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) {
156 ScopedDeletePtr<NrIceCandidate> out(new NrIceCandidate());
158 if (!ToNrIceCandidate(candc, out)) {
159 return nullptr;
161 return out.forget();
164 // NrIceMediaStream
165 RefPtr<NrIceMediaStream>
166 NrIceMediaStream::Create(NrIceCtx *ctx,
167 const std::string& name,
168 int components) {
169 RefPtr<NrIceMediaStream> stream =
170 new NrIceMediaStream(ctx, name, components);
172 int r = nr_ice_add_media_stream(ctx->ctx(),
173 const_cast<char *>(name.c_str()),
174 components, &stream->stream_);
175 if (r) {
176 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '"
177 << name << "'");
178 return nullptr;
181 return stream;
184 NrIceMediaStream::~NrIceMediaStream() {
185 // We do not need to destroy anything. All major resources
186 // are attached to the ice ctx.
189 nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
190 attributes) {
191 if (!stream_)
192 return NS_ERROR_FAILURE;
194 std::vector<char *> attributes_in;
196 for (size_t i=0; i<attributes.size(); ++i) {
197 attributes_in.push_back(const_cast<char *>(attributes[i].c_str()));
200 // Still need to call nr_ice_ctx_parse_stream_attributes.
201 int r = nr_ice_peer_ctx_parse_stream_attributes(ctx_->peer(),
202 stream_,
203 attributes_in.size() ?
204 &attributes_in[0] : nullptr,
205 attributes_in.size());
206 if (r) {
207 MOZ_MTLOG(ML_ERROR, "Couldn't parse attributes for stream "
208 << name_ << "'");
209 return NS_ERROR_FAILURE;
212 return NS_OK;
215 // Parse trickle ICE candidate
216 nsresult NrIceMediaStream::ParseTrickleCandidate(const std::string& candidate) {
217 int r;
219 MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << ctx_->name() << ")/STREAM(" <<
220 name() << ") : parsing trickle candidate " << candidate);
222 r = nr_ice_peer_ctx_parse_trickle_candidate(ctx_->peer(),
223 stream_,
224 const_cast<char *>(
225 candidate.c_str())
227 if (r) {
228 if (r == R_ALREADY) {
229 MOZ_MTLOG(ML_ERROR, "Trickle candidates are redundant for stream '"
230 << name_ << "' because it is completed");
232 } else {
233 MOZ_MTLOG(ML_ERROR, "Couldn't parse trickle candidate for stream '"
234 << name_ << "'");
235 return NS_ERROR_FAILURE;
239 return NS_OK;
242 // Returns NS_ERROR_NOT_AVAILABLE if component is unpaired or disabled.
243 nsresult NrIceMediaStream::GetActivePair(int component,
244 NrIceCandidate **localp,
245 NrIceCandidate **remotep) {
246 int r;
247 nr_ice_candidate *local_int;
248 nr_ice_candidate *remote_int;
250 r = nr_ice_media_stream_get_active(ctx_->peer(),
251 stream_,
252 component,
253 &local_int, &remote_int);
254 // If result is R_REJECTED then component is unpaired or disabled.
255 if (r == R_REJECTED)
256 return NS_ERROR_NOT_AVAILABLE;
258 if (r)
259 return NS_ERROR_FAILURE;
261 ScopedDeletePtr<NrIceCandidate> local(
262 MakeNrIceCandidate(*local_int));
263 if (!local)
264 return NS_ERROR_FAILURE;
266 ScopedDeletePtr<NrIceCandidate> remote(
267 MakeNrIceCandidate(*remote_int));
268 if (!remote)
269 return NS_ERROR_FAILURE;
271 if (localp)
272 *localp = local.forget();
273 if (remotep)
274 *remotep = remote.forget();
276 return NS_OK;
280 nsresult NrIceMediaStream::GetCandidatePairs(std::vector<NrIceCandidatePair>*
281 out_pairs) const {
282 MOZ_ASSERT(out_pairs);
284 // Get the check_list on the peer stream (this is where the check_list
285 // actually lives, not in stream_)
286 nr_ice_media_stream* peer_stream;
287 int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream);
288 if (r != 0) {
289 return NS_ERROR_FAILURE;
292 nr_ice_cand_pair *p1;
293 out_pairs->clear();
295 TAILQ_FOREACH(p1, &peer_stream->check_list, entry) {
296 MOZ_ASSERT(p1);
297 MOZ_ASSERT(p1->local);
298 MOZ_ASSERT(p1->remote);
299 NrIceCandidatePair pair;
301 switch (p1->state) {
302 case NR_ICE_PAIR_STATE_FROZEN:
303 pair.state = NrIceCandidatePair::State::STATE_FROZEN;
304 break;
305 case NR_ICE_PAIR_STATE_WAITING:
306 pair.state = NrIceCandidatePair::State::STATE_WAITING;
307 break;
308 case NR_ICE_PAIR_STATE_IN_PROGRESS:
309 pair.state = NrIceCandidatePair::State::STATE_IN_PROGRESS;
310 break;
311 case NR_ICE_PAIR_STATE_FAILED:
312 pair.state = NrIceCandidatePair::State::STATE_FAILED;
313 break;
314 case NR_ICE_PAIR_STATE_SUCCEEDED:
315 pair.state = NrIceCandidatePair::State::STATE_SUCCEEDED;
316 break;
317 case NR_ICE_PAIR_STATE_CANCELLED:
318 pair.state = NrIceCandidatePair::State::STATE_CANCELLED;
319 break;
320 default:
321 MOZ_ASSERT(0);
324 pair.priority = p1->priority;
325 pair.nominated = p1->peer_nominated || p1->nominated;
326 pair.selected = p1->remote->component &&
327 p1->remote->component->active == p1;
328 pair.codeword = p1->codeword;
330 if (!ToNrIceCandidate(*(p1->local), &pair.local) ||
331 !ToNrIceCandidate(*(p1->remote), &pair.remote)) {
332 return NS_ERROR_FAILURE;
335 out_pairs->push_back(pair);
338 return NS_OK;
341 std::vector<std::string> NrIceMediaStream::GetCandidates() const {
342 char **attrs = 0;
343 int attrct;
344 int r;
345 std::vector<std::string> ret;
347 r = nr_ice_media_stream_get_attributes(stream_,
348 &attrs, &attrct);
349 if (r) {
350 MOZ_MTLOG(ML_ERROR, "Couldn't get ICE candidates for '"
351 << name_ << "'");
352 return ret;
355 for (int i=0; i<attrct; i++) {
356 ret.push_back(attrs[i]);
357 RFREE(attrs[i]);
360 RFREE(attrs);
362 return ret;
365 static nsresult GetCandidatesFromStream(
366 nr_ice_media_stream *stream,
367 std::vector<NrIceCandidate> *candidates) {
368 MOZ_ASSERT(candidates);
369 nr_ice_component* comp=STAILQ_FIRST(&stream->components);
370 while(comp){
371 if (comp->state != NR_ICE_COMPONENT_DISABLED) {
372 nr_ice_candidate *cand = TAILQ_FIRST(&comp->candidates);
373 while(cand){
374 NrIceCandidate new_cand;
375 // This can fail if the candidate is server reflexive or relayed, and
376 // has not yet received a response (ie; it doesn't know its address
377 // yet). For the purposes of this code, this isn't a candidate we're
378 // interested in, since it is not fully baked yet.
379 if (ToNrIceCandidate(*cand, &new_cand)) {
380 candidates->push_back(new_cand);
382 cand=TAILQ_NEXT(cand,entry_comp);
385 comp=STAILQ_NEXT(comp,entry);
388 return NS_OK;
391 nsresult NrIceMediaStream::GetLocalCandidates(
392 std::vector<NrIceCandidate>* candidates) const {
393 return GetCandidatesFromStream(stream_, candidates);
396 nsresult NrIceMediaStream::GetRemoteCandidates(
397 std::vector<NrIceCandidate>* candidates) const {
398 nr_ice_media_stream* peer_stream;
399 int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream);
400 if (r != 0) {
401 return NS_ERROR_FAILURE;
404 return GetCandidatesFromStream(peer_stream, candidates);
408 nsresult NrIceMediaStream::DisableComponent(int component_id) {
409 if (!stream_)
410 return NS_ERROR_FAILURE;
412 int r = nr_ice_media_stream_disable_component(stream_,
413 component_id);
414 if (r) {
415 MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" <<
416 component_id);
417 return NS_ERROR_FAILURE;
420 return NS_OK;
423 nsresult NrIceMediaStream::SendPacket(int component_id,
424 const unsigned char *data,
425 size_t len) {
426 if (!stream_)
427 return NS_ERROR_FAILURE;
429 int r = nr_ice_media_stream_send(ctx_->peer(), stream_,
430 component_id,
431 const_cast<unsigned char *>(data), len);
432 if (r) {
433 MOZ_MTLOG(ML_ERROR, "Couldn't send media on '" << name_ << "'");
434 if (r == R_WOULDBLOCK) {
435 return NS_BASE_STREAM_WOULD_BLOCK;
438 return NS_BASE_STREAM_OSERROR;
441 return NS_OK;
445 void NrIceMediaStream::Ready() {
446 // This function is called whenever a stream becomes ready, but it
447 // gets fired multiple times when a stream gets nominated repeatedly.
448 if (state_ != ICE_OPEN) {
449 MOZ_MTLOG(ML_DEBUG, "Marking stream ready '" << name_ << "'");
450 state_ = ICE_OPEN;
451 SignalReady(this);
453 else {
454 MOZ_MTLOG(ML_DEBUG, "Stream ready callback fired again for '" << name_ << "'");
458 void NrIceMediaStream::Close() {
459 MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'");
460 state_ = ICE_CLOSED;
461 stream_ = nullptr;
463 } // close namespace