blob: 8e0b334c3cccabf3b3137946ddd916dc062a24f9 [file] [log] [blame]
sergeyu1ac2609e2016-11-29 01:08:121// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/sdp_message.h"
6
Zijie Hecd945d732017-10-02 18:14:347#include <algorithm>
Zijie He455b8d62017-10-09 22:52:048#include <utility>
Zijie Hecd945d732017-10-02 18:14:349
Hans Wennborg828a0972020-04-27 18:10:0910#include "base/notreached.h"
Zijie Hecd945d732017-10-02 18:14:3411#include "base/strings/string_piece.h"
sergeyu1ac2609e2016-11-29 01:08:1212#include "base/strings/string_split.h"
13#include "base/strings/string_util.h"
14
15namespace remoting {
16namespace protocol {
17
18SdpMessage::SdpMessage(const std::string& sdp) {
Zijie Hecd945d732017-10-02 18:14:3419 sdp_lines_ = base::SplitString(
20 sdp, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
sergeyu1ac2609e2016-11-29 01:08:1221 for (const auto& line : sdp_lines_) {
22 if (base::StartsWith(line, "m=audio", base::CompareCase::SENSITIVE))
23 has_audio_ = true;
24 if (base::StartsWith(line, "m=video", base::CompareCase::SENSITIVE))
25 has_video_ = true;
26 }
27}
28
Chris Watkins6fe52aa2017-11-28 03:24:0529SdpMessage::~SdpMessage() = default;
sergeyu1ac2609e2016-11-29 01:08:1230
31std::string SdpMessage::ToString() const {
Lambros Lambrou34aaa2b22018-04-10 18:03:2132 return base::JoinString(sdp_lines_, "\r\n") + "\r\n";
33}
34
35std::string SdpMessage::NormalizedForSignature() const {
sergeyu1ac2609e2016-11-29 01:08:1236 return base::JoinString(sdp_lines_, "\n") + "\n";
37}
38
39bool SdpMessage::AddCodecParameter(const std::string& codec,
40 const std::string& parameters_to_add) {
Zijie Hef912ff72017-10-10 18:11:4041 std::vector<std::pair<int, std::string>> payload_types = FindCodec(codec);
42 if (payload_types.empty()) {
sergeyu1ac2609e2016-11-29 01:08:1243 return false;
44 }
Zijie Hef912ff72017-10-10 18:11:4045
46 for (size_t i = 0; i < payload_types.size(); i++) {
47 sdp_lines_.insert(
48 sdp_lines_.begin() + payload_types[i].first + i + 1,
49 "a=fmtp:" + payload_types[i].second + ' ' + parameters_to_add);
50 }
sergeyu1ac2609e2016-11-29 01:08:1251 return true;
52}
53
Zijie Hecd945d732017-10-02 18:14:3454bool SdpMessage::PreferVideoCodec(const std::string& codec) {
55 if (!has_video_) {
56 return false;
57 }
Zijie He455b8d62017-10-09 22:52:0458 std::vector<std::pair<int, std::string>> payload_types = FindCodec(codec);
59 if (payload_types.empty()) {
Zijie Hecd945d732017-10-02 18:14:3460 return false;
61 }
62
63 for (size_t i = 0; i < sdp_lines_.size(); i++) {
64 if (!base::StartsWith(sdp_lines_[i],
65 "m=video",
66 base::CompareCase::SENSITIVE)) {
67 continue;
68 }
69
70 // A valid SDP contains only one "m=video" line. So instead of continue, if
71 // this line is invalid, we should return false immediately.
72 std::vector<base::StringPiece> fields = base::SplitStringPiece(
73 sdp_lines_[i], " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
74 // The first three fields are "m=video", port and proto.
75 static constexpr int kSkipFields = 3;
76 if (fields.size() <= kSkipFields) {
77 return false;
78 }
79
80 const auto first_codec_pos = fields.begin() + kSkipFields;
Zijie He455b8d62017-10-09 22:52:0481
82 for (const auto& payload : payload_types) {
83 auto pos = std::find(first_codec_pos,
84 fields.end(),
85 base::StringPiece(payload.second));
86 // The codec has not been found in codec list.
87 if (pos == fields.end()) {
88 continue;
89 }
90
91 std::rotate(first_codec_pos, pos, pos + 1);
Zijie Hecd945d732017-10-02 18:14:3492 }
93
Zijie Hecd945d732017-10-02 18:14:3494 sdp_lines_[i] = base::JoinString(fields, " ");
95 return true;
96 }
97
98 // If has_video_ is true (tested at the very beginning of the function), we
99 // should always return within the for-loop above.
100 NOTREACHED();
101 return false;
102}
103
Zijie He455b8d62017-10-09 22:52:04104std::vector<std::pair<int, std::string>> SdpMessage::FindCodec(
105 const std::string& codec) const {
sergeyu1ac2609e2016-11-29 01:08:12106 const std::string kRtpMapPrefix = "a=rtpmap:";
Zijie He455b8d62017-10-09 22:52:04107 std::vector<std::pair<int, std::string>> results;
sergeyu1ac2609e2016-11-29 01:08:12108 for (size_t i = 0; i < sdp_lines_.size(); ++i) {
109 const auto& line = sdp_lines_[i];
Zijie He455b8d62017-10-09 22:52:04110 if (!base::StartsWith(line, kRtpMapPrefix, base::CompareCase::SENSITIVE)) {
sergeyu1ac2609e2016-11-29 01:08:12111 continue;
Zijie He455b8d62017-10-09 22:52:04112 }
sergeyu1ac2609e2016-11-29 01:08:12113 size_t space_pos = line.find(' ');
Zijie He455b8d62017-10-09 22:52:04114 if (space_pos == std::string::npos) {
sergeyu1ac2609e2016-11-29 01:08:12115 continue;
Zijie He455b8d62017-10-09 22:52:04116 }
sergeyu1ac2609e2016-11-29 01:08:12117 if (line.substr(space_pos + 1, codec.size()) == codec &&
118 line[space_pos + 1 + codec.size()] == '/') {
Zijie He455b8d62017-10-09 22:52:04119 std::string payload_type =
120 line.substr(kRtpMapPrefix.size(), space_pos - kRtpMapPrefix.size());
121 results.push_back(std::make_pair(i, std::move(payload_type)));
sergeyu1ac2609e2016-11-29 01:08:12122 }
123 }
Zijie He455b8d62017-10-09 22:52:04124 return results;
sergeyu1ac2609e2016-11-29 01:08:12125}
126
127} // namespace protocol
128} // namespace remoting