OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2011 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/api/webrtcsdp.h" | 11 #include "webrtc/api/webrtcsdp.h" |
12 | 12 |
13 #include <ctype.h> | 13 #include <ctype.h> |
14 #include <limits.h> | 14 #include <limits.h> |
15 #include <stdio.h> | 15 #include <stdio.h> |
16 #include <algorithm> | 16 #include <algorithm> |
17 #include <string> | 17 #include <string> |
| 18 #include <unordered_map> |
18 #include <vector> | 19 #include <vector> |
19 | 20 |
20 #include "webrtc/api/jsepicecandidate.h" | 21 #include "webrtc/api/jsepicecandidate.h" |
21 #include "webrtc/api/jsepsessiondescription.h" | 22 #include "webrtc/api/jsepsessiondescription.h" |
22 #include "webrtc/base/arraysize.h" | 23 #include "webrtc/base/arraysize.h" |
23 #include "webrtc/base/common.h" | 24 #include "webrtc/base/common.h" |
24 #include "webrtc/base/logging.h" | 25 #include "webrtc/base/logging.h" |
25 #include "webrtc/base/messagedigest.h" | 26 #include "webrtc/base/messagedigest.h" |
26 #include "webrtc/base/stringutils.h" | 27 #include "webrtc/base/stringutils.h" |
27 #include "webrtc/media/base/codec.h" | 28 #include "webrtc/media/base/codec.h" |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 const std::string& message, | 263 const std::string& message, |
263 const TransportDescription& session_td, | 264 const TransportDescription& session_td, |
264 const RtpHeaderExtensions& session_extmaps, | 265 const RtpHeaderExtensions& session_extmaps, |
265 size_t* pos, cricket::SessionDescription* desc, | 266 size_t* pos, cricket::SessionDescription* desc, |
266 std::vector<JsepIceCandidate*>* candidates, | 267 std::vector<JsepIceCandidate*>* candidates, |
267 SdpParseError* error); | 268 SdpParseError* error); |
268 static bool ParseContent(const std::string& message, | 269 static bool ParseContent(const std::string& message, |
269 const MediaType media_type, | 270 const MediaType media_type, |
270 int mline_index, | 271 int mline_index, |
271 const std::string& protocol, | 272 const std::string& protocol, |
272 const std::vector<int>& codec_preference, | 273 const std::vector<int>& payload_types, |
273 size_t* pos, | 274 size_t* pos, |
274 std::string* content_name, | 275 std::string* content_name, |
275 MediaContentDescription* media_desc, | 276 MediaContentDescription* media_desc, |
276 TransportDescription* transport, | 277 TransportDescription* transport, |
277 std::vector<JsepIceCandidate*>* candidates, | 278 std::vector<JsepIceCandidate*>* candidates, |
278 SdpParseError* error); | 279 SdpParseError* error); |
279 static bool ParseSsrcAttribute(const std::string& line, | 280 static bool ParseSsrcAttribute(const std::string& line, |
280 SsrcInfoVec* ssrc_infos, | 281 SsrcInfoVec* ssrc_infos, |
281 SdpParseError* error); | 282 SdpParseError* error); |
282 static bool ParseSsrcGroupAttribute(const std::string& line, | 283 static bool ParseSsrcGroupAttribute(const std::string& line, |
283 SsrcGroupVec* ssrc_groups, | 284 SsrcGroupVec* ssrc_groups, |
284 SdpParseError* error); | 285 SdpParseError* error); |
285 static bool ParseCryptoAttribute(const std::string& line, | 286 static bool ParseCryptoAttribute(const std::string& line, |
286 MediaContentDescription* media_desc, | 287 MediaContentDescription* media_desc, |
287 SdpParseError* error); | 288 SdpParseError* error); |
288 static bool ParseRtpmapAttribute(const std::string& line, | 289 static bool ParseRtpmapAttribute(const std::string& line, |
289 const MediaType media_type, | 290 const MediaType media_type, |
290 const std::vector<int>& codec_preference, | 291 const std::vector<int>& payload_types, |
291 MediaContentDescription* media_desc, | 292 MediaContentDescription* media_desc, |
292 SdpParseError* error); | 293 SdpParseError* error); |
293 static bool ParseFmtpAttributes(const std::string& line, | 294 static bool ParseFmtpAttributes(const std::string& line, |
294 const MediaType media_type, | 295 const MediaType media_type, |
295 MediaContentDescription* media_desc, | 296 MediaContentDescription* media_desc, |
296 SdpParseError* error); | 297 SdpParseError* error); |
297 static bool ParseFmtpParam(const std::string& line, std::string* parameter, | 298 static bool ParseFmtpParam(const std::string& line, std::string* parameter, |
298 std::string* value, SdpParseError* error); | 299 std::string* value, SdpParseError* error); |
299 static bool ParseCandidate(const std::string& message, Candidate* candidate, | 300 static bool ParseCandidate(const std::string& message, Candidate* candidate, |
300 SdpParseError* error, bool is_raw); | 301 SdpParseError* error, bool is_raw); |
(...skipping 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1644 } | 1645 } |
1645 | 1646 |
1646 bool AddSctpDataCodec(DataContentDescription* media_desc, | 1647 bool AddSctpDataCodec(DataContentDescription* media_desc, |
1647 int sctp_port) { | 1648 int sctp_port) { |
1648 if (media_desc->HasCodec(cricket::kGoogleSctpDataCodecId)) { | 1649 if (media_desc->HasCodec(cricket::kGoogleSctpDataCodecId)) { |
1649 return ParseFailed("", | 1650 return ParseFailed("", |
1650 "Can't have multiple sctp port attributes.", | 1651 "Can't have multiple sctp port attributes.", |
1651 NULL); | 1652 NULL); |
1652 } | 1653 } |
1653 // Add the SCTP Port number as a pseudo-codec "port" parameter | 1654 // Add the SCTP Port number as a pseudo-codec "port" parameter |
1654 cricket::DataCodec codec_port( | 1655 cricket::DataCodec codec_port(cricket::kGoogleSctpDataCodecId, |
1655 cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName, | 1656 cricket::kGoogleSctpDataCodecName); |
1656 0); | |
1657 codec_port.SetParam(cricket::kCodecParamPort, sctp_port); | 1657 codec_port.SetParam(cricket::kCodecParamPort, sctp_port); |
1658 LOG(INFO) << "AddSctpDataCodec: Got SCTP Port Number " | 1658 LOG(INFO) << "AddSctpDataCodec: Got SCTP Port Number " |
1659 << sctp_port; | 1659 << sctp_port; |
1660 media_desc->AddCodec(codec_port); | 1660 media_desc->AddCodec(codec_port); |
1661 return true; | 1661 return true; |
1662 } | 1662 } |
1663 | 1663 |
1664 bool GetMinValue(const std::vector<int>& values, int* value) { | 1664 bool GetMinValue(const std::vector<int>& values, int* value) { |
1665 if (values.empty()) { | 1665 if (values.empty()) { |
1666 return false; | 1666 return false; |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2172 { "DVI4", 11025, 1 }, | 2172 { "DVI4", 11025, 1 }, |
2173 { "DVI4", 22050, 1 }, | 2173 { "DVI4", 22050, 1 }, |
2174 { "G729", 8000, 1 }, | 2174 { "G729", 8000, 1 }, |
2175 }; | 2175 }; |
2176 | 2176 |
2177 void MaybeCreateStaticPayloadAudioCodecs( | 2177 void MaybeCreateStaticPayloadAudioCodecs( |
2178 const std::vector<int>& fmts, AudioContentDescription* media_desc) { | 2178 const std::vector<int>& fmts, AudioContentDescription* media_desc) { |
2179 if (!media_desc) { | 2179 if (!media_desc) { |
2180 return; | 2180 return; |
2181 } | 2181 } |
2182 int preference = static_cast<int>(fmts.size()); | 2182 RTC_DCHECK(media_desc->codecs().empty()); |
2183 std::vector<int>::const_iterator it = fmts.begin(); | 2183 std::vector<int>::const_iterator it = fmts.begin(); |
2184 bool add_new_codec = false; | |
2185 for (; it != fmts.end(); ++it) { | 2184 for (; it != fmts.end(); ++it) { |
2186 int payload_type = *it; | 2185 int payload_type = *it; |
2187 if (!media_desc->HasCodec(payload_type) && | 2186 if (!media_desc->HasCodec(payload_type) && |
2188 payload_type >= 0 && | 2187 payload_type >= 0 && |
2189 payload_type < arraysize(kStaticPayloadAudioCodecs)) { | 2188 payload_type < arraysize(kStaticPayloadAudioCodecs)) { |
2190 std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name; | 2189 std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name; |
2191 int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate; | 2190 int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate; |
2192 size_t channels = kStaticPayloadAudioCodecs[payload_type].channels; | 2191 size_t channels = kStaticPayloadAudioCodecs[payload_type].channels; |
2193 media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name, | 2192 media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name, |
2194 clock_rate, 0, channels, | 2193 clock_rate, 0, channels)); |
2195 preference)); | |
2196 add_new_codec = true; | |
2197 } | 2194 } |
2198 --preference; | |
2199 } | |
2200 if (add_new_codec) { | |
2201 media_desc->SortCodecs(); | |
2202 } | 2195 } |
2203 } | 2196 } |
2204 | 2197 |
2205 template <class C> | 2198 template <class C> |
2206 static C* ParseContentDescription(const std::string& message, | 2199 static C* ParseContentDescription(const std::string& message, |
2207 const MediaType media_type, | 2200 const MediaType media_type, |
2208 int mline_index, | 2201 int mline_index, |
2209 const std::string& protocol, | 2202 const std::string& protocol, |
2210 const std::vector<int>& codec_preference, | 2203 const std::vector<int>& payload_types, |
2211 size_t* pos, | 2204 size_t* pos, |
2212 std::string* content_name, | 2205 std::string* content_name, |
2213 TransportDescription* transport, | 2206 TransportDescription* transport, |
2214 std::vector<JsepIceCandidate*>* candidates, | 2207 std::vector<JsepIceCandidate*>* candidates, |
2215 webrtc::SdpParseError* error) { | 2208 webrtc::SdpParseError* error) { |
2216 C* media_desc = new C(); | 2209 C* media_desc = new C(); |
2217 switch (media_type) { | 2210 switch (media_type) { |
2218 case cricket::MEDIA_TYPE_AUDIO: | 2211 case cricket::MEDIA_TYPE_AUDIO: |
2219 *content_name = cricket::CN_AUDIO; | 2212 *content_name = cricket::CN_AUDIO; |
2220 break; | 2213 break; |
2221 case cricket::MEDIA_TYPE_VIDEO: | 2214 case cricket::MEDIA_TYPE_VIDEO: |
2222 *content_name = cricket::CN_VIDEO; | 2215 *content_name = cricket::CN_VIDEO; |
2223 break; | 2216 break; |
2224 case cricket::MEDIA_TYPE_DATA: | 2217 case cricket::MEDIA_TYPE_DATA: |
2225 *content_name = cricket::CN_DATA; | 2218 *content_name = cricket::CN_DATA; |
2226 break; | 2219 break; |
2227 default: | 2220 default: |
2228 ASSERT(false); | 2221 ASSERT(false); |
2229 break; | 2222 break; |
2230 } | 2223 } |
2231 if (!ParseContent(message, media_type, mline_index, protocol, | 2224 if (!ParseContent(message, media_type, mline_index, protocol, payload_types, |
2232 codec_preference, pos, content_name, | 2225 pos, content_name, media_desc, transport, candidates, |
2233 media_desc, transport, candidates, error)) { | 2226 error)) { |
2234 delete media_desc; | 2227 delete media_desc; |
2235 return NULL; | 2228 return NULL; |
2236 } | 2229 } |
2237 // Sort the codecs according to the m-line fmt list. | 2230 // Sort the codecs according to the m-line fmt list. |
2238 media_desc->SortCodecs(); | 2231 std::unordered_map<int, int> payload_type_preferences; |
| 2232 // "size + 1" so that the lowest preference payload type has a preference of |
| 2233 // 1, which is greater than the default (0) for payload types not in the fmt |
| 2234 // list. |
| 2235 int preference = static_cast<int>(payload_types.size() + 1); |
| 2236 for (int pt : payload_types) { |
| 2237 payload_type_preferences[pt] = preference--; |
| 2238 } |
| 2239 std::vector<typename C::CodecType> codecs = media_desc->codecs(); |
| 2240 std::sort(codecs.begin(), codecs.end(), [&payload_type_preferences]( |
| 2241 const typename C::CodecType& a, |
| 2242 const typename C::CodecType& b) { |
| 2243 return payload_type_preferences[a.id] > payload_type_preferences[b.id]; |
| 2244 }); |
| 2245 media_desc->set_codecs(codecs); |
2239 return media_desc; | 2246 return media_desc; |
2240 } | 2247 } |
2241 | 2248 |
2242 bool ParseMediaDescription(const std::string& message, | 2249 bool ParseMediaDescription(const std::string& message, |
2243 const TransportDescription& session_td, | 2250 const TransportDescription& session_td, |
2244 const RtpHeaderExtensions& session_extmaps, | 2251 const RtpHeaderExtensions& session_extmaps, |
2245 size_t* pos, | 2252 size_t* pos, |
2246 cricket::SessionDescription* desc, | 2253 cricket::SessionDescription* desc, |
2247 std::vector<JsepIceCandidate*>* candidates, | 2254 std::vector<JsepIceCandidate*>* candidates, |
2248 SdpParseError* error) { | 2255 SdpParseError* error) { |
(...skipping 18 matching lines...) Expand all Loading... |
2267 // RFC 3264 | 2274 // RFC 3264 |
2268 // To reject an offered stream, the port number in the corresponding stream | 2275 // To reject an offered stream, the port number in the corresponding stream |
2269 // in the answer MUST be set to zero. | 2276 // in the answer MUST be set to zero. |
2270 if (fields[1] == kMediaPortRejected) { | 2277 if (fields[1] == kMediaPortRejected) { |
2271 rejected = true; | 2278 rejected = true; |
2272 } | 2279 } |
2273 | 2280 |
2274 std::string protocol = fields[2]; | 2281 std::string protocol = fields[2]; |
2275 | 2282 |
2276 // <fmt> | 2283 // <fmt> |
2277 std::vector<int> codec_preference; | 2284 std::vector<int> payload_types; |
2278 if (IsRtp(protocol)) { | 2285 if (IsRtp(protocol)) { |
2279 for (size_t j = 3 ; j < fields.size(); ++j) { | 2286 for (size_t j = 3 ; j < fields.size(); ++j) { |
2280 // TODO(wu): Remove when below bug is fixed. | 2287 // TODO(wu): Remove when below bug is fixed. |
2281 // https://bugzilla.mozilla.org/show_bug.cgi?id=996329 | 2288 // https://bugzilla.mozilla.org/show_bug.cgi?id=996329 |
2282 if (fields[j].empty() && j == fields.size() - 1) { | 2289 if (fields[j].empty() && j == fields.size() - 1) { |
2283 continue; | 2290 continue; |
2284 } | 2291 } |
2285 | 2292 |
2286 int pl = 0; | 2293 int pl = 0; |
2287 if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) { | 2294 if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) { |
2288 return false; | 2295 return false; |
2289 } | 2296 } |
2290 codec_preference.push_back(pl); | 2297 payload_types.push_back(pl); |
2291 } | 2298 } |
2292 } | 2299 } |
2293 | 2300 |
2294 // Make a temporary TransportDescription based on |session_td|. | 2301 // Make a temporary TransportDescription based on |session_td|. |
2295 // Some of this gets overwritten by ParseContent. | 2302 // Some of this gets overwritten by ParseContent. |
2296 TransportDescription transport( | 2303 TransportDescription transport( |
2297 session_td.transport_options, session_td.ice_ufrag, session_td.ice_pwd, | 2304 session_td.transport_options, session_td.ice_ufrag, session_td.ice_pwd, |
2298 session_td.ice_mode, session_td.connection_role, | 2305 session_td.ice_mode, session_td.connection_role, |
2299 session_td.identity_fingerprint.get()); | 2306 session_td.identity_fingerprint.get()); |
2300 | 2307 |
2301 rtc::scoped_ptr<MediaContentDescription> content; | 2308 rtc::scoped_ptr<MediaContentDescription> content; |
2302 std::string content_name; | 2309 std::string content_name; |
2303 if (HasAttribute(line, kMediaTypeVideo)) { | 2310 if (HasAttribute(line, kMediaTypeVideo)) { |
2304 content.reset(ParseContentDescription<VideoContentDescription>( | 2311 content.reset(ParseContentDescription<VideoContentDescription>( |
2305 message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol, | 2312 message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol, |
2306 codec_preference, pos, &content_name, | 2313 payload_types, pos, &content_name, &transport, candidates, error)); |
2307 &transport, candidates, error)); | |
2308 } else if (HasAttribute(line, kMediaTypeAudio)) { | 2314 } else if (HasAttribute(line, kMediaTypeAudio)) { |
2309 content.reset(ParseContentDescription<AudioContentDescription>( | 2315 content.reset(ParseContentDescription<AudioContentDescription>( |
2310 message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol, | 2316 message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol, |
2311 codec_preference, pos, &content_name, | 2317 payload_types, pos, &content_name, &transport, candidates, error)); |
2312 &transport, candidates, error)); | |
2313 } else if (HasAttribute(line, kMediaTypeData)) { | 2318 } else if (HasAttribute(line, kMediaTypeData)) { |
2314 DataContentDescription* data_desc = | 2319 DataContentDescription* data_desc = |
2315 ParseContentDescription<DataContentDescription>( | 2320 ParseContentDescription<DataContentDescription>( |
2316 message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, | 2321 message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, |
2317 codec_preference, pos, &content_name, | 2322 payload_types, pos, &content_name, &transport, candidates, error); |
2318 &transport, candidates, error); | |
2319 content.reset(data_desc); | 2323 content.reset(data_desc); |
2320 | 2324 |
2321 int p; | 2325 int p; |
2322 if (data_desc && IsDtlsSctp(protocol) && rtc::FromString(fields[3], &p)) { | 2326 if (data_desc && IsDtlsSctp(protocol) && rtc::FromString(fields[3], &p)) { |
2323 if (!AddSctpDataCodec(data_desc, p)) | 2327 if (!AddSctpDataCodec(data_desc, p)) |
2324 return false; | 2328 return false; |
2325 } | 2329 } |
2326 } else { | 2330 } else { |
2327 LOG(LS_WARNING) << "Unsupported media type: " << line; | 2331 LOG(LS_WARNING) << "Unsupported media type: " << line; |
2328 continue; | 2332 continue; |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2515 iter != codecs.end(); ++iter) { | 2519 iter != codecs.end(); ++iter) { |
2516 iter->params[name] = value; | 2520 iter->params[name] = value; |
2517 } | 2521 } |
2518 audio_desc->set_codecs(codecs); | 2522 audio_desc->set_codecs(codecs); |
2519 } | 2523 } |
2520 | 2524 |
2521 bool ParseContent(const std::string& message, | 2525 bool ParseContent(const std::string& message, |
2522 const MediaType media_type, | 2526 const MediaType media_type, |
2523 int mline_index, | 2527 int mline_index, |
2524 const std::string& protocol, | 2528 const std::string& protocol, |
2525 const std::vector<int>& codec_preference, | 2529 const std::vector<int>& payload_types, |
2526 size_t* pos, | 2530 size_t* pos, |
2527 std::string* content_name, | 2531 std::string* content_name, |
2528 MediaContentDescription* media_desc, | 2532 MediaContentDescription* media_desc, |
2529 TransportDescription* transport, | 2533 TransportDescription* transport, |
2530 std::vector<JsepIceCandidate*>* candidates, | 2534 std::vector<JsepIceCandidate*>* candidates, |
2531 SdpParseError* error) { | 2535 SdpParseError* error) { |
2532 ASSERT(media_desc != NULL); | 2536 ASSERT(media_desc != NULL); |
2533 ASSERT(content_name != NULL); | 2537 ASSERT(content_name != NULL); |
2534 ASSERT(transport != NULL); | 2538 ASSERT(transport != NULL); |
2535 | 2539 |
2536 if (media_type == cricket::MEDIA_TYPE_AUDIO) { | 2540 if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
2537 MaybeCreateStaticPayloadAudioCodecs( | 2541 MaybeCreateStaticPayloadAudioCodecs( |
2538 codec_preference, static_cast<AudioContentDescription*>(media_desc)); | 2542 payload_types, static_cast<AudioContentDescription*>(media_desc)); |
2539 } | 2543 } |
2540 | 2544 |
2541 // The media level "ice-ufrag" and "ice-pwd". | 2545 // The media level "ice-ufrag" and "ice-pwd". |
2542 // The candidates before update the media level "ice-pwd" and "ice-ufrag". | 2546 // The candidates before update the media level "ice-pwd" and "ice-ufrag". |
2543 Candidates candidates_orig; | 2547 Candidates candidates_orig; |
2544 std::string line; | 2548 std::string line; |
2545 std::string mline_id; | 2549 std::string mline_id; |
2546 // Tracks created out of the ssrc attributes. | 2550 // Tracks created out of the ssrc attributes. |
2547 StreamParamsVec tracks; | 2551 StreamParamsVec tracks; |
2548 SsrcInfoVec ssrc_infos; | 2552 SsrcInfoVec ssrc_infos; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2663 } | 2667 } |
2664 } else if (HasAttribute(line, kAttributeSsrc)) { | 2668 } else if (HasAttribute(line, kAttributeSsrc)) { |
2665 if (!ParseSsrcAttribute(line, &ssrc_infos, error)) { | 2669 if (!ParseSsrcAttribute(line, &ssrc_infos, error)) { |
2666 return false; | 2670 return false; |
2667 } | 2671 } |
2668 } else if (HasAttribute(line, kAttributeCrypto)) { | 2672 } else if (HasAttribute(line, kAttributeCrypto)) { |
2669 if (!ParseCryptoAttribute(line, media_desc, error)) { | 2673 if (!ParseCryptoAttribute(line, media_desc, error)) { |
2670 return false; | 2674 return false; |
2671 } | 2675 } |
2672 } else if (HasAttribute(line, kAttributeRtpmap)) { | 2676 } else if (HasAttribute(line, kAttributeRtpmap)) { |
2673 if (!ParseRtpmapAttribute(line, media_type, codec_preference, | 2677 if (!ParseRtpmapAttribute(line, media_type, payload_types, media_desc, |
2674 media_desc, error)) { | 2678 error)) { |
2675 return false; | 2679 return false; |
2676 } | 2680 } |
2677 } else if (HasAttribute(line, kCodecParamMaxPTime)) { | 2681 } else if (HasAttribute(line, kCodecParamMaxPTime)) { |
2678 if (!GetValue(line, kCodecParamMaxPTime, &maxptime_as_string, error)) { | 2682 if (!GetValue(line, kCodecParamMaxPTime, &maxptime_as_string, error)) { |
2679 return false; | 2683 return false; |
2680 } | 2684 } |
2681 } else if (HasAttribute(line, kAttributeRtcpFb)) { | 2685 } else if (HasAttribute(line, kAttributeRtcpFb)) { |
2682 if (!ParseRtcpFbAttribute(line, media_type, media_desc, error)) { | 2686 if (!ParseRtcpFbAttribute(line, media_type, media_desc, error)) { |
2683 return false; | 2687 return false; |
2684 } | 2688 } |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2920 std::string session_params; | 2924 std::string session_params; |
2921 if (fields.size() > 3) { | 2925 if (fields.size() > 3) { |
2922 session_params = fields[3]; | 2926 session_params = fields[3]; |
2923 } | 2927 } |
2924 media_desc->AddCrypto(CryptoParams(tag, crypto_suite, key_params, | 2928 media_desc->AddCrypto(CryptoParams(tag, crypto_suite, key_params, |
2925 session_params)); | 2929 session_params)); |
2926 return true; | 2930 return true; |
2927 } | 2931 } |
2928 | 2932 |
2929 // Updates or creates a new codec entry in the audio description with according | 2933 // Updates or creates a new codec entry in the audio description with according |
2930 // to |name|, |clockrate|, |bitrate|, |channels| and |preference|. | 2934 // to |name|, |clockrate|, |bitrate|, and |channels|. |
2931 void UpdateCodec(int payload_type, const std::string& name, int clockrate, | 2935 void UpdateCodec(int payload_type, |
2932 int bitrate, size_t channels, int preference, | 2936 const std::string& name, |
| 2937 int clockrate, |
| 2938 int bitrate, |
| 2939 size_t channels, |
2933 AudioContentDescription* audio_desc) { | 2940 AudioContentDescription* audio_desc) { |
2934 // Codec may already be populated with (only) optional parameters | 2941 // Codec may already be populated with (only) optional parameters |
2935 // (from an fmtp). | 2942 // (from an fmtp). |
2936 cricket::AudioCodec codec = | 2943 cricket::AudioCodec codec = |
2937 GetCodecWithPayloadType(audio_desc->codecs(), payload_type); | 2944 GetCodecWithPayloadType(audio_desc->codecs(), payload_type); |
2938 codec.name = name; | 2945 codec.name = name; |
2939 codec.clockrate = clockrate; | 2946 codec.clockrate = clockrate; |
2940 codec.bitrate = bitrate; | 2947 codec.bitrate = bitrate; |
2941 codec.channels = channels; | 2948 codec.channels = channels; |
2942 codec.preference = preference; | |
2943 AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc, | 2949 AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc, |
2944 codec); | 2950 codec); |
2945 } | 2951 } |
2946 | 2952 |
2947 // Updates or creates a new codec entry in the video description according to | 2953 // Updates or creates a new codec entry in the video description according to |
2948 // |name|, |width|, |height|, |framerate| and |preference|. | 2954 // |name|, |width|, |height|, and |framerate|. |
2949 void UpdateCodec(int payload_type, const std::string& name, int width, | 2955 void UpdateCodec(int payload_type, |
2950 int height, int framerate, int preference, | 2956 const std::string& name, |
| 2957 int width, |
| 2958 int height, |
| 2959 int framerate, |
2951 VideoContentDescription* video_desc) { | 2960 VideoContentDescription* video_desc) { |
2952 // Codec may already be populated with (only) optional parameters | 2961 // Codec may already be populated with (only) optional parameters |
2953 // (from an fmtp). | 2962 // (from an fmtp). |
2954 cricket::VideoCodec codec = | 2963 cricket::VideoCodec codec = |
2955 GetCodecWithPayloadType(video_desc->codecs(), payload_type); | 2964 GetCodecWithPayloadType(video_desc->codecs(), payload_type); |
2956 codec.name = name; | 2965 codec.name = name; |
2957 codec.width = width; | 2966 codec.width = width; |
2958 codec.height = height; | 2967 codec.height = height; |
2959 codec.framerate = framerate; | 2968 codec.framerate = framerate; |
2960 codec.preference = preference; | |
2961 AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc, | 2969 AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc, |
2962 codec); | 2970 codec); |
2963 } | 2971 } |
2964 | 2972 |
2965 bool ParseRtpmapAttribute(const std::string& line, | 2973 bool ParseRtpmapAttribute(const std::string& line, |
2966 const MediaType media_type, | 2974 const MediaType media_type, |
2967 const std::vector<int>& codec_preference, | 2975 const std::vector<int>& payload_types, |
2968 MediaContentDescription* media_desc, | 2976 MediaContentDescription* media_desc, |
2969 SdpParseError* error) { | 2977 SdpParseError* error) { |
2970 std::vector<std::string> fields; | 2978 std::vector<std::string> fields; |
2971 rtc::split(line.substr(kLinePrefixLength), | 2979 rtc::split(line.substr(kLinePrefixLength), |
2972 kSdpDelimiterSpace, &fields); | 2980 kSdpDelimiterSpace, &fields); |
2973 // RFC 4566 | 2981 // RFC 4566 |
2974 // a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encodingparameters>] | 2982 // a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encodingparameters>] |
2975 const size_t expected_min_fields = 2; | 2983 const size_t expected_min_fields = 2; |
2976 if (fields.size() < expected_min_fields) { | 2984 if (fields.size() < expected_min_fields) { |
2977 return ParseFailedExpectMinFieldNum(line, expected_min_fields, error); | 2985 return ParseFailedExpectMinFieldNum(line, expected_min_fields, error); |
2978 } | 2986 } |
2979 std::string payload_type_value; | 2987 std::string payload_type_value; |
2980 if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) { | 2988 if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) { |
2981 return false; | 2989 return false; |
2982 } | 2990 } |
2983 int payload_type = 0; | 2991 int payload_type = 0; |
2984 if (!GetPayloadTypeFromString(line, payload_type_value, &payload_type, | 2992 if (!GetPayloadTypeFromString(line, payload_type_value, &payload_type, |
2985 error)) { | 2993 error)) { |
2986 return false; | 2994 return false; |
2987 } | 2995 } |
2988 | 2996 |
2989 // Set the preference order depending on the order of the pl type in the | 2997 if (std::find(payload_types.begin(), payload_types.end(), payload_type) == |
2990 // <fmt> of the m-line. | 2998 payload_types.end()) { |
2991 const int preference = codec_preference.end() - | |
2992 std::find(codec_preference.begin(), codec_preference.end(), | |
2993 payload_type); | |
2994 if (preference == 0) { | |
2995 LOG(LS_WARNING) << "Ignore rtpmap line that did not appear in the " | 2999 LOG(LS_WARNING) << "Ignore rtpmap line that did not appear in the " |
2996 << "<fmt> of the m-line: " << line; | 3000 << "<fmt> of the m-line: " << line; |
2997 return true; | 3001 return true; |
2998 } | 3002 } |
2999 const std::string& encoder = fields[1]; | 3003 const std::string& encoder = fields[1]; |
3000 std::vector<std::string> codec_params; | 3004 std::vector<std::string> codec_params; |
3001 rtc::split(encoder, '/', &codec_params); | 3005 rtc::split(encoder, '/', &codec_params); |
3002 // <encoding name>/<clock rate>[/<encodingparameters>] | 3006 // <encoding name>/<clock rate>[/<encodingparameters>] |
3003 // 2 mandatory fields | 3007 // 2 mandatory fields |
3004 if (codec_params.size() < 2 || codec_params.size() > 3) { | 3008 if (codec_params.size() < 2 || codec_params.size() > 3) { |
3005 return ParseFailed(line, | 3009 return ParseFailed(line, |
3006 "Expected format \"<encoding name>/<clock rate>" | 3010 "Expected format \"<encoding name>/<clock rate>" |
3007 "[/<encodingparameters>]\".", | 3011 "[/<encodingparameters>]\".", |
3008 error); | 3012 error); |
3009 } | 3013 } |
3010 const std::string& encoding_name = codec_params[0]; | 3014 const std::string& encoding_name = codec_params[0]; |
3011 int clock_rate = 0; | 3015 int clock_rate = 0; |
3012 if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) { | 3016 if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) { |
3013 return false; | 3017 return false; |
3014 } | 3018 } |
3015 if (media_type == cricket::MEDIA_TYPE_VIDEO) { | 3019 if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
3016 VideoContentDescription* video_desc = | 3020 VideoContentDescription* video_desc = |
3017 static_cast<VideoContentDescription*>(media_desc); | 3021 static_cast<VideoContentDescription*>(media_desc); |
3018 // TODO: We will send resolution in SDP. For now use | 3022 // TODO: We will send resolution in SDP. For now use |
3019 // JsepSessionDescription::kMaxVideoCodecWidth and kMaxVideoCodecHeight. | 3023 // JsepSessionDescription::kMaxVideoCodecWidth and kMaxVideoCodecHeight. |
3020 UpdateCodec(payload_type, encoding_name, | 3024 UpdateCodec(payload_type, encoding_name, |
3021 JsepSessionDescription::kMaxVideoCodecWidth, | 3025 JsepSessionDescription::kMaxVideoCodecWidth, |
3022 JsepSessionDescription::kMaxVideoCodecHeight, | 3026 JsepSessionDescription::kMaxVideoCodecHeight, |
3023 JsepSessionDescription::kDefaultVideoCodecFramerate, | 3027 JsepSessionDescription::kDefaultVideoCodecFramerate, |
3024 preference, video_desc); | 3028 video_desc); |
3025 } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { | 3029 } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
3026 // RFC 4566 | 3030 // RFC 4566 |
3027 // For audio streams, <encoding parameters> indicates the number | 3031 // For audio streams, <encoding parameters> indicates the number |
3028 // of audio channels. This parameter is OPTIONAL and may be | 3032 // of audio channels. This parameter is OPTIONAL and may be |
3029 // omitted if the number of channels is one, provided that no | 3033 // omitted if the number of channels is one, provided that no |
3030 // additional parameters are needed. | 3034 // additional parameters are needed. |
3031 size_t channels = 1; | 3035 size_t channels = 1; |
3032 if (codec_params.size() == 3) { | 3036 if (codec_params.size() == 3) { |
3033 if (!GetValueFromString(line, codec_params[2], &channels, error)) { | 3037 if (!GetValueFromString(line, codec_params[2], &channels, error)) { |
3034 return false; | 3038 return false; |
3035 } | 3039 } |
3036 } | 3040 } |
3037 int bitrate = 0; | 3041 int bitrate = 0; |
3038 // The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc | 3042 // The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc |
3039 // (specifically FindWebRtcCodec) is bandwidth-adaptive variable bitrate. | 3043 // (specifically FindWebRtcCodec) is bandwidth-adaptive variable bitrate. |
3040 // The bandwidth adaptation doesn't always work well, so this code | 3044 // The bandwidth adaptation doesn't always work well, so this code |
3041 // sets a fixed target bitrate instead. | 3045 // sets a fixed target bitrate instead. |
3042 if (_stricmp(encoding_name.c_str(), kIsacCodecName) == 0) { | 3046 if (_stricmp(encoding_name.c_str(), kIsacCodecName) == 0) { |
3043 if (clock_rate <= 16000) { | 3047 if (clock_rate <= 16000) { |
3044 bitrate = kIsacWbDefaultRate; | 3048 bitrate = kIsacWbDefaultRate; |
3045 } else { | 3049 } else { |
3046 bitrate = kIsacSwbDefaultRate; | 3050 bitrate = kIsacSwbDefaultRate; |
3047 } | 3051 } |
3048 } | 3052 } |
3049 AudioContentDescription* audio_desc = | 3053 AudioContentDescription* audio_desc = |
3050 static_cast<AudioContentDescription*>(media_desc); | 3054 static_cast<AudioContentDescription*>(media_desc); |
3051 UpdateCodec(payload_type, encoding_name, clock_rate, bitrate, channels, | 3055 UpdateCodec(payload_type, encoding_name, clock_rate, bitrate, channels, |
3052 preference, audio_desc); | 3056 audio_desc); |
3053 } else if (media_type == cricket::MEDIA_TYPE_DATA) { | 3057 } else if (media_type == cricket::MEDIA_TYPE_DATA) { |
3054 DataContentDescription* data_desc = | 3058 DataContentDescription* data_desc = |
3055 static_cast<DataContentDescription*>(media_desc); | 3059 static_cast<DataContentDescription*>(media_desc); |
3056 data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name, | 3060 data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name)); |
3057 preference)); | |
3058 } | 3061 } |
3059 return true; | 3062 return true; |
3060 } | 3063 } |
3061 | 3064 |
3062 bool ParseFmtpParam(const std::string& line, std::string* parameter, | 3065 bool ParseFmtpParam(const std::string& line, std::string* parameter, |
3063 std::string* value, SdpParseError* error) { | 3066 std::string* value, SdpParseError* error) { |
3064 if (!rtc::tokenize_first(line, kSdpDelimiterEqual, parameter, value)) { | 3067 if (!rtc::tokenize_first(line, kSdpDelimiterEqual, parameter, value)) { |
3065 ParseFailed(line, "Unable to parse fmtp parameter. \'=\' missing.", error); | 3068 ParseFailed(line, "Unable to parse fmtp parameter. \'=\' missing.", error); |
3066 return false; | 3069 return false; |
3067 } | 3070 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3168 UpdateCodec<AudioContentDescription, cricket::AudioCodec>( | 3171 UpdateCodec<AudioContentDescription, cricket::AudioCodec>( |
3169 media_desc, payload_type, feedback_param); | 3172 media_desc, payload_type, feedback_param); |
3170 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { | 3173 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
3171 UpdateCodec<VideoContentDescription, cricket::VideoCodec>( | 3174 UpdateCodec<VideoContentDescription, cricket::VideoCodec>( |
3172 media_desc, payload_type, feedback_param); | 3175 media_desc, payload_type, feedback_param); |
3173 } | 3176 } |
3174 return true; | 3177 return true; |
3175 } | 3178 } |
3176 | 3179 |
3177 } // namespace webrtc | 3180 } // namespace webrtc |
OLD | NEW |