OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2012 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include "talk/app/webrtc/jsepsessiondescription.h" | |
29 | |
30 #include "talk/app/webrtc/webrtcsdp.h" | |
31 #include "talk/session/media/mediasession.h" | |
32 #include "webrtc/base/arraysize.h" | |
33 #include "webrtc/base/stringencode.h" | |
34 | |
35 using rtc::scoped_ptr; | |
36 using cricket::SessionDescription; | |
37 | |
38 namespace webrtc { | |
39 | |
40 static const char* kSupportedTypes[] = { | |
41 JsepSessionDescription::kOffer, | |
42 JsepSessionDescription::kPrAnswer, | |
43 JsepSessionDescription::kAnswer | |
44 }; | |
45 | |
46 static bool IsTypeSupported(const std::string& type) { | |
47 bool type_supported = false; | |
48 for (size_t i = 0; i < arraysize(kSupportedTypes); ++i) { | |
49 if (kSupportedTypes[i] == type) { | |
50 type_supported = true; | |
51 break; | |
52 } | |
53 } | |
54 return type_supported; | |
55 } | |
56 | |
57 const char SessionDescriptionInterface::kOffer[] = "offer"; | |
58 const char SessionDescriptionInterface::kPrAnswer[] = "pranswer"; | |
59 const char SessionDescriptionInterface::kAnswer[] = "answer"; | |
60 | |
61 const int JsepSessionDescription::kDefaultVideoCodecId = 100; | |
62 // This is effectively a max value of the frame rate. 30 is default from camera. | |
63 const int JsepSessionDescription::kDefaultVideoCodecFramerate = 60; | |
64 const char JsepSessionDescription::kDefaultVideoCodecName[] = "VP8"; | |
65 // Used as default max video codec size before we have it in signaling. | |
66 #if defined(ANDROID) || defined(WEBRTC_IOS) | |
67 // Limit default max video codec size for Android to avoid | |
68 // HW VP8 codec initialization failure for resolutions higher | |
69 // than 1280x720 or 720x1280. | |
70 // Same patch for iOS to support 720P in portrait mode. | |
71 const int JsepSessionDescription::kMaxVideoCodecWidth = 1280; | |
72 const int JsepSessionDescription::kMaxVideoCodecHeight = 1280; | |
73 #else | |
74 const int JsepSessionDescription::kMaxVideoCodecWidth = 1920; | |
75 const int JsepSessionDescription::kMaxVideoCodecHeight = 1080; | |
76 #endif | |
77 const int JsepSessionDescription::kDefaultVideoCodecPreference = 1; | |
78 | |
79 SessionDescriptionInterface* CreateSessionDescription(const std::string& type, | |
80 const std::string& sdp, | |
81 SdpParseError* error) { | |
82 if (!IsTypeSupported(type)) { | |
83 return NULL; | |
84 } | |
85 | |
86 JsepSessionDescription* jsep_desc = new JsepSessionDescription(type); | |
87 if (!jsep_desc->Initialize(sdp, error)) { | |
88 delete jsep_desc; | |
89 return NULL; | |
90 } | |
91 return jsep_desc; | |
92 } | |
93 | |
94 JsepSessionDescription::JsepSessionDescription(const std::string& type) | |
95 : type_(type) { | |
96 } | |
97 | |
98 JsepSessionDescription::~JsepSessionDescription() {} | |
99 | |
100 bool JsepSessionDescription::Initialize( | |
101 cricket::SessionDescription* description, | |
102 const std::string& session_id, | |
103 const std::string& session_version) { | |
104 if (!description) | |
105 return false; | |
106 | |
107 session_id_ = session_id; | |
108 session_version_ = session_version; | |
109 description_.reset(description); | |
110 candidate_collection_.resize(number_of_mediasections()); | |
111 return true; | |
112 } | |
113 | |
114 bool JsepSessionDescription::Initialize(const std::string& sdp, | |
115 SdpParseError* error) { | |
116 return SdpDeserialize(sdp, this, error); | |
117 } | |
118 | |
119 bool JsepSessionDescription::AddCandidate( | |
120 const IceCandidateInterface* candidate) { | |
121 if (!candidate || candidate->sdp_mline_index() < 0) | |
122 return false; | |
123 size_t mediasection_index = 0; | |
124 if (!GetMediasectionIndex(candidate, &mediasection_index)) { | |
125 return false; | |
126 } | |
127 if (mediasection_index >= number_of_mediasections()) | |
128 return false; | |
129 const std::string& content_name = | |
130 description_->contents()[mediasection_index].name; | |
131 const cricket::TransportInfo* transport_info = | |
132 description_->GetTransportInfoByName(content_name); | |
133 if (!transport_info) { | |
134 return false; | |
135 } | |
136 | |
137 cricket::Candidate updated_candidate = candidate->candidate(); | |
138 if (updated_candidate.username().empty()) { | |
139 updated_candidate.set_username(transport_info->description.ice_ufrag); | |
140 } | |
141 if (updated_candidate.password().empty()) { | |
142 updated_candidate.set_password(transport_info->description.ice_pwd); | |
143 } | |
144 | |
145 scoped_ptr<JsepIceCandidate> updated_candidate_wrapper( | |
146 new JsepIceCandidate(candidate->sdp_mid(), | |
147 static_cast<int>(mediasection_index), | |
148 updated_candidate)); | |
149 if (!candidate_collection_[mediasection_index].HasCandidate( | |
150 updated_candidate_wrapper.get())) | |
151 candidate_collection_[mediasection_index].add( | |
152 updated_candidate_wrapper.release()); | |
153 | |
154 return true; | |
155 } | |
156 | |
157 size_t JsepSessionDescription::number_of_mediasections() const { | |
158 if (!description_) | |
159 return 0; | |
160 return description_->contents().size(); | |
161 } | |
162 | |
163 const IceCandidateCollection* JsepSessionDescription::candidates( | |
164 size_t mediasection_index) const { | |
165 if (mediasection_index >= candidate_collection_.size()) | |
166 return NULL; | |
167 return &candidate_collection_[mediasection_index]; | |
168 } | |
169 | |
170 bool JsepSessionDescription::ToString(std::string* out) const { | |
171 if (!description_ || !out) | |
172 return false; | |
173 *out = SdpSerialize(*this); | |
174 return !out->empty(); | |
175 } | |
176 | |
177 bool JsepSessionDescription::GetMediasectionIndex( | |
178 const IceCandidateInterface* candidate, | |
179 size_t* index) { | |
180 if (!candidate || !index) { | |
181 return false; | |
182 } | |
183 *index = static_cast<size_t>(candidate->sdp_mline_index()); | |
184 if (description_ && !candidate->sdp_mid().empty()) { | |
185 bool found = false; | |
186 // Try to match the sdp_mid with content name. | |
187 for (size_t i = 0; i < description_->contents().size(); ++i) { | |
188 if (candidate->sdp_mid() == description_->contents().at(i).name) { | |
189 *index = i; | |
190 found = true; | |
191 break; | |
192 } | |
193 } | |
194 if (!found) { | |
195 // If the sdp_mid is presented but we can't find a match, we consider | |
196 // this as an error. | |
197 return false; | |
198 } | |
199 } | |
200 return true; | |
201 } | |
202 | |
203 } // namespace webrtc | |
OLD | NEW |