Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: remoting/protocol/webrtc_transport.cc

Issue 2536623003: Add SdpHelper for more reliable codec configuration in WebrtcTransport. (Closed)
Patch Set: address feedback Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/protocol/sdp_message_unittest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/protocol/webrtc_transport.h" 5 #include "remoting/protocol/webrtc_transport.h"
6 6
7 #include <string> 7 #include <string>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/base64.h" 11 #include "base/base64.h"
12 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_split.h" 18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
20 #include "base/task_runner_util.h" 20 #include "base/task_runner_util.h"
21 #include "base/threading/thread_task_runner_handle.h" 21 #include "base/threading/thread_task_runner_handle.h"
22 #include "jingle/glue/thread_wrapper.h" 22 #include "jingle/glue/thread_wrapper.h"
23 #include "remoting/protocol/authenticator.h" 23 #include "remoting/protocol/authenticator.h"
24 #include "remoting/protocol/port_allocator_factory.h" 24 #include "remoting/protocol/port_allocator_factory.h"
25 #include "remoting/protocol/sdp_message.h"
25 #include "remoting/protocol/stream_message_pipe_adapter.h" 26 #include "remoting/protocol/stream_message_pipe_adapter.h"
26 #include "remoting/protocol/transport_context.h" 27 #include "remoting/protocol/transport_context.h"
27 #include "remoting/protocol/webrtc_audio_module.h" 28 #include "remoting/protocol/webrtc_audio_module.h"
28 #include "remoting/protocol/webrtc_dummy_video_encoder.h" 29 #include "remoting/protocol/webrtc_dummy_video_encoder.h"
29 #include "third_party/webrtc/api/test/fakeconstraints.h" 30 #include "third_party/webrtc/api/test/fakeconstraints.h"
30 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" 31 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
31 32
32 using buzz::QName; 33 using buzz::QName;
33 using buzz::XmlElement; 34 using buzz::XmlElement;
34 35
(...skipping 14 matching lines...) Expand all
49 // Command line switch used to disable signature verification. 50 // Command line switch used to disable signature verification.
50 // TODO(sergeyu): Remove this flag. 51 // TODO(sergeyu): Remove this flag.
51 const char kDisableAuthenticationSwitchName[] = "disable-authentication"; 52 const char kDisableAuthenticationSwitchName[] = "disable-authentication";
52 #endif 53 #endif
53 54
54 bool IsValidSessionDescriptionType(const std::string& type) { 55 bool IsValidSessionDescriptionType(const std::string& type) {
55 return type == webrtc::SessionDescriptionInterface::kOffer || 56 return type == webrtc::SessionDescriptionInterface::kOffer ||
56 type == webrtc::SessionDescriptionInterface::kAnswer; 57 type == webrtc::SessionDescriptionInterface::kAnswer;
57 } 58 }
58 59
59 // Normalizes the SDP message to make sure the text used for HMAC signatures 60 void UpdateCodecParameters(SdpMessage* sdp_message, bool incoming) {
60 // verifications is the same that was signed on the sending side. This is 61 // Set bitrate range to 1-100 Mbps.
61 // necessary because WebRTC generates SDP with CRLF line endings which are 62 // - Setting min bitrate here enables padding.
62 // sometimes converted to LF after passing the signaling channel. 63 // - The default max bitrate is 600 kbps. Setting it to 100 Mbps allows to
63 std::string NormalizeSessionDescription(const std::string& sdp) { 64 // use higher bandwidth when it's available.
64 // Split SDP lines. The CR symbols is removed by the TRIM_WHITESPACE flag. 65 //
65 std::vector<std::string> lines = 66 // TODO(sergeyu): Padding needs to be enabled to workaround BW estimator not
66 SplitString(sdp, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); 67 // handling spiky traffic patterns well. This won't be necessary with a
67 return base::JoinString(lines, "\n") + "\n"; 68 // better bandwidth estimator.
69 // TODO(isheriff): The need for this should go away once we have a proper
70 // API to provide max bitrate for the case of handing over encoded
71 // frames to webrtc.
72 if (sdp_message->has_video() &&
73 !sdp_message->AddCodecParameter(
74 "VP8", "x-google-min-bitrate=1000; x-google-max-bitrate=100000")) {
75 if (incoming) {
76 LOG(WARNING) << "VP8 not found in an incoming SDP.";
77 } else {
78 LOG(FATAL) << "VP8 not found in SDP generated by WebRTC.";
79 }
80 }
81
82 // Update SDP format to use stereo for opus codec.
83 if (sdp_message->has_audio() &&
84 !sdp_message->AddCodecParameter("opus",
85 "stereo=1; x-google-min-bitrate=160")) {
86 if (incoming) {
87 LOG(WARNING) << "Opus not found in an incoming SDP.";
88 } else {
89 LOG(FATAL) << "Opus not found in SDP generated by WebRTC.";
90 }
91 }
68 } 92 }
69 93
70 // A webrtc::CreateSessionDescriptionObserver implementation used to receive the 94 // A webrtc::CreateSessionDescriptionObserver implementation used to receive the
71 // results of creating descriptions for this end of the PeerConnection. 95 // results of creating descriptions for this end of the PeerConnection.
72 class CreateSessionDescriptionObserver 96 class CreateSessionDescriptionObserver
73 : public webrtc::CreateSessionDescriptionObserver { 97 : public webrtc::CreateSessionDescriptionObserver {
74 public: 98 public:
75 typedef base::Callback<void( 99 typedef base::Callback<void(
76 std::unique_ptr<webrtc::SessionDescriptionInterface> description, 100 std::unique_ptr<webrtc::SessionDescriptionInterface> description,
77 const std::string& error)> 101 const std::string& error)>
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 webrtc::PeerConnectionInterface::SignalingState expected_state = 346 webrtc::PeerConnectionInterface::SignalingState expected_state =
323 transport_context_->role() == TransportRole::CLIENT 347 transport_context_->role() == TransportRole::CLIENT
324 ? webrtc::PeerConnectionInterface::kStable 348 ? webrtc::PeerConnectionInterface::kStable
325 : webrtc::PeerConnectionInterface::kHaveLocalOffer; 349 : webrtc::PeerConnectionInterface::kHaveLocalOffer;
326 if (peer_connection()->signaling_state() != expected_state) { 350 if (peer_connection()->signaling_state() != expected_state) {
327 LOG(ERROR) << "Received unexpected WebRTC session_description."; 351 LOG(ERROR) << "Received unexpected WebRTC session_description.";
328 return false; 352 return false;
329 } 353 }
330 354
331 std::string type = session_description->Attr(QName(std::string(), "type")); 355 std::string type = session_description->Attr(QName(std::string(), "type"));
332 std::string sdp = 356 std::string raw_sdp = session_description->BodyText();
333 NormalizeSessionDescription(session_description->BodyText()); 357 if (!IsValidSessionDescriptionType(type) || raw_sdp.empty()) {
334 if (!IsValidSessionDescriptionType(type) || sdp.empty()) {
335 LOG(ERROR) << "Incorrect session description format."; 358 LOG(ERROR) << "Incorrect session description format.";
336 return false; 359 return false;
337 } 360 }
338 361
362 SdpMessage sdp_message(raw_sdp);
363
339 std::string signature_base64 = 364 std::string signature_base64 =
340 session_description->Attr(QName(std::string(), "signature")); 365 session_description->Attr(QName(std::string(), "signature"));
341 std::string signature; 366 std::string signature;
342 if (!base::Base64Decode(signature_base64, &signature) || 367 if (!base::Base64Decode(signature_base64, &signature) ||
343 !handshake_hmac_.Verify(type + " " + sdp, signature)) { 368 !handshake_hmac_.Verify(type + " " + sdp_message.ToString(),
369 signature)) {
344 LOG(WARNING) << "Received session-description with invalid signature."; 370 LOG(WARNING) << "Received session-description with invalid signature.";
345 bool ignore_error = false; 371 bool ignore_error = false;
346 #if !defined(NDEBUG) 372 #if !defined(NDEBUG)
347 ignore_error = base::CommandLine::ForCurrentProcess()->HasSwitch( 373 ignore_error = base::CommandLine::ForCurrentProcess()->HasSwitch(
348 kDisableAuthenticationSwitchName); 374 kDisableAuthenticationSwitchName);
349 #endif 375 #endif
350 if (!ignore_error) { 376 if (!ignore_error) {
351 Close(AUTHENTICATION_FAILED); 377 Close(AUTHENTICATION_FAILED);
352 return true; 378 return true;
353 } 379 }
354 } 380 }
355 381
356 // Set bitrate range to 1-100 Mbps. 382 UpdateCodecParameters(&sdp_message, /*incoming=*/true);
357 // - Setting min bitrate here enables padding.
358 // - The default max bitrate is 600 kbps. Setting it to 100 Mbps allows to
359 // use higher bandwidth when it's available.
360 //
361 // TODO(sergeyu): Padding needs to be enabled to workaround BW estimator not
362 // handling spiky traffic patterns well. This won't be necessary with a
363 // better bandwidth estimator.
364 // TODO(isheriff): The need for this should go away once we have a proper
365 // API to provide max bitrate for the case of handing over encoded
366 // frames to webrtc.
367 std::string vp8line = "a=rtpmap:100 VP8/90000\n";
368 std::string vp8line_with_bitrate =
369 vp8line +
370 "a=fmtp:100 x-google-min-bitrate=1000\n"
371 "a=fmtp:100 x-google-max-bitrate=100000\n";
372 base::ReplaceSubstringsAfterOffset(&sdp, 0, vp8line, vp8line_with_bitrate);
373 383
374 webrtc::SdpParseError error; 384 webrtc::SdpParseError error;
375 std::unique_ptr<webrtc::SessionDescriptionInterface> session_description( 385 std::unique_ptr<webrtc::SessionDescriptionInterface> session_description(
376 webrtc::CreateSessionDescription(type, sdp, &error)); 386 webrtc::CreateSessionDescription(type, sdp_message.ToString(), &error));
377 if (!session_description) { 387 if (!session_description) {
378 LOG(ERROR) << "Failed to parse the session description: " 388 LOG(ERROR) << "Failed to parse the session description: "
379 << error.description << " line: " << error.line; 389 << error.description << " line: " << error.line;
380 return false; 390 return false;
381 } 391 }
382 392
383 peer_connection()->SetRemoteDescription( 393 peer_connection()->SetRemoteDescription(
384 SetSessionDescriptionObserver::Create( 394 SetSessionDescriptionObserver::Create(
385 base::Bind(&WebrtcTransport::OnRemoteDescriptionSet, 395 base::Bind(&WebrtcTransport::OnRemoteDescriptionSet,
386 weak_factory_.GetWeakPtr(), 396 weak_factory_.GetWeakPtr(),
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 Close(CHANNEL_CONNECTION_ERROR); 452 Close(CHANNEL_CONNECTION_ERROR);
443 return; 453 return;
444 } 454 }
445 455
446 std::string description_sdp; 456 std::string description_sdp;
447 if (!description->ToString(&description_sdp)) { 457 if (!description->ToString(&description_sdp)) {
448 LOG(ERROR) << "Failed to serialize description."; 458 LOG(ERROR) << "Failed to serialize description.";
449 Close(CHANNEL_CONNECTION_ERROR); 459 Close(CHANNEL_CONNECTION_ERROR);
450 return; 460 return;
451 } 461 }
452 description_sdp = NormalizeSessionDescription(description_sdp);
453 462
454 // Update SDP format to use stereo for opus codec. 463 SdpMessage sdp_message(description_sdp);
455 std::string opus_line = "a=rtpmap:111 opus/48000/2\n"; 464 UpdateCodecParameters(&sdp_message, /*incoming=*/false);
456 std::string opus_line_with_bitrate = 465 description_sdp = sdp_message.ToString();
457 opus_line + "a=fmtp:111 stereo=1; x-google-min-bitrate=160\n";
458 base::ReplaceSubstringsAfterOffset(&description_sdp, 0, opus_line,
459 opus_line_with_bitrate);
460 466
461 // Format and send the session description to the peer. 467 // Format and send the session description to the peer.
462 std::unique_ptr<XmlElement> transport_info( 468 std::unique_ptr<XmlElement> transport_info(
463 new XmlElement(QName(kTransportNamespace, "transport"), true)); 469 new XmlElement(QName(kTransportNamespace, "transport"), true));
464 XmlElement* offer_tag = 470 XmlElement* offer_tag =
465 new XmlElement(QName(kTransportNamespace, "session-description")); 471 new XmlElement(QName(kTransportNamespace, "session-description"));
466 transport_info->AddElement(offer_tag); 472 transport_info->AddElement(offer_tag);
467 offer_tag->SetAttr(QName(std::string(), "type"), description->type()); 473 offer_tag->SetAttr(QName(std::string(), "type"), description->type());
468 offer_tag->SetBodyText(description_sdp); 474 offer_tag->SetBodyText(description_sdp);
469 475
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 // the stack and so it must be destroyed later. 693 // the stack and so it must be destroyed later.
688 base::ThreadTaskRunnerHandle::Get()->DeleteSoon( 694 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
689 FROM_HERE, peer_connection_wrapper_.release()); 695 FROM_HERE, peer_connection_wrapper_.release());
690 696
691 if (error != OK) 697 if (error != OK)
692 event_handler_->OnWebrtcTransportError(error); 698 event_handler_->OnWebrtcTransportError(error);
693 } 699 }
694 700
695 } // namespace protocol 701 } // namespace protocol
696 } // namespace remoting 702 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/sdp_message_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698