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 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1632 } | 1633 } |
1633 | 1634 |
1634 bool AddSctpDataCodec(DataContentDescription* media_desc, | 1635 bool AddSctpDataCodec(DataContentDescription* media_desc, |
1635 int sctp_port) { | 1636 int sctp_port) { |
1636 if (media_desc->HasCodec(cricket::kGoogleSctpDataCodecId)) { | 1637 if (media_desc->HasCodec(cricket::kGoogleSctpDataCodecId)) { |
1637 return ParseFailed("", | 1638 return ParseFailed("", |
1638 "Can't have multiple sctp port attributes.", | 1639 "Can't have multiple sctp port attributes.", |
1639 NULL); | 1640 NULL); |
1640 } | 1641 } |
1641 // Add the SCTP Port number as a pseudo-codec "port" parameter | 1642 // Add the SCTP Port number as a pseudo-codec "port" parameter |
1642 cricket::DataCodec codec_port( | 1643 cricket::DataCodec codec_port(cricket::kGoogleSctpDataCodecId, |
1643 cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName, | 1644 cricket::kGoogleSctpDataCodecName); |
1644 0); | |
1645 codec_port.SetParam(cricket::kCodecParamPort, sctp_port); | 1645 codec_port.SetParam(cricket::kCodecParamPort, sctp_port); |
1646 LOG(INFO) << "AddSctpDataCodec: Got SCTP Port Number " | 1646 LOG(INFO) << "AddSctpDataCodec: Got SCTP Port Number " |
1647 << sctp_port; | 1647 << sctp_port; |
1648 media_desc->AddCodec(codec_port); | 1648 media_desc->AddCodec(codec_port); |
1649 return true; | 1649 return true; |
1650 } | 1650 } |
1651 | 1651 |
1652 bool GetMinValue(const std::vector<int>& values, int* value) { | 1652 bool GetMinValue(const std::vector<int>& values, int* value) { |
1653 if (values.empty()) { | 1653 if (values.empty()) { |
1654 return false; | 1654 return false; |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2160 { "DVI4", 11025, 1 }, | 2160 { "DVI4", 11025, 1 }, |
2161 { "DVI4", 22050, 1 }, | 2161 { "DVI4", 22050, 1 }, |
2162 { "G729", 8000, 1 }, | 2162 { "G729", 8000, 1 }, |
2163 }; | 2163 }; |
2164 | 2164 |
2165 void MaybeCreateStaticPayloadAudioCodecs( | 2165 void MaybeCreateStaticPayloadAudioCodecs( |
2166 const std::vector<int>& fmts, AudioContentDescription* media_desc) { | 2166 const std::vector<int>& fmts, AudioContentDescription* media_desc) { |
2167 if (!media_desc) { | 2167 if (!media_desc) { |
2168 return; | 2168 return; |
2169 } | 2169 } |
2170 int preference = static_cast<int>(fmts.size()); | 2170 RTC_DCHECK(media_desc->codecs().empty()); |
2171 std::vector<int>::const_iterator it = fmts.begin(); | 2171 std::vector<int>::const_iterator it = fmts.begin(); |
2172 bool add_new_codec = false; | |
2173 for (; it != fmts.end(); ++it) { | 2172 for (; it != fmts.end(); ++it) { |
2174 int payload_type = *it; | 2173 int payload_type = *it; |
2175 if (!media_desc->HasCodec(payload_type) && | 2174 if (!media_desc->HasCodec(payload_type) && |
2176 payload_type >= 0 && | 2175 payload_type >= 0 && |
2177 payload_type < arraysize(kStaticPayloadAudioCodecs)) { | 2176 payload_type < arraysize(kStaticPayloadAudioCodecs)) { |
2178 std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name; | 2177 std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name; |
2179 int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate; | 2178 int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate; |
2180 size_t channels = kStaticPayloadAudioCodecs[payload_type].channels; | 2179 size_t channels = kStaticPayloadAudioCodecs[payload_type].channels; |
2181 media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name, | 2180 media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name, |
2182 clock_rate, 0, channels, | 2181 clock_rate, 0, channels)); |
2183 preference)); | |
2184 add_new_codec = true; | |
2185 } | 2182 } |
2186 --preference; | |
2187 } | |
2188 if (add_new_codec) { | |
2189 media_desc->SortCodecs(); | |
2190 } | 2183 } |
2191 } | 2184 } |
2192 | 2185 |
2193 template <class C> | 2186 template <class C> |
2194 static C* ParseContentDescription(const std::string& message, | 2187 static C* ParseContentDescription(const std::string& message, |
2195 const MediaType media_type, | 2188 const MediaType media_type, |
2196 int mline_index, | 2189 int mline_index, |
2197 const std::string& protocol, | 2190 const std::string& protocol, |
2198 const std::vector<int>& codec_preference, | 2191 const std::vector<int>& payload_types, |
2199 size_t* pos, | 2192 size_t* pos, |
2200 std::string* content_name, | 2193 std::string* content_name, |
2201 TransportDescription* transport, | 2194 TransportDescription* transport, |
2202 std::vector<JsepIceCandidate*>* candidates, | 2195 std::vector<JsepIceCandidate*>* candidates, |
2203 webrtc::SdpParseError* error) { | 2196 webrtc::SdpParseError* error) { |
2204 C* media_desc = new C(); | 2197 C* media_desc = new C(); |
2205 switch (media_type) { | 2198 switch (media_type) { |
2206 case cricket::MEDIA_TYPE_AUDIO: | 2199 case cricket::MEDIA_TYPE_AUDIO: |
2207 *content_name = cricket::CN_AUDIO; | 2200 *content_name = cricket::CN_AUDIO; |
2208 break; | 2201 break; |
2209 case cricket::MEDIA_TYPE_VIDEO: | 2202 case cricket::MEDIA_TYPE_VIDEO: |
2210 *content_name = cricket::CN_VIDEO; | 2203 *content_name = cricket::CN_VIDEO; |
2211 break; | 2204 break; |
2212 case cricket::MEDIA_TYPE_DATA: | 2205 case cricket::MEDIA_TYPE_DATA: |
2213 *content_name = cricket::CN_DATA; | 2206 *content_name = cricket::CN_DATA; |
2214 break; | 2207 break; |
2215 default: | 2208 default: |
2216 ASSERT(false); | 2209 ASSERT(false); |
2217 break; | 2210 break; |
2218 } | 2211 } |
2219 if (!ParseContent(message, media_type, mline_index, protocol, | 2212 if (!ParseContent(message, media_type, mline_index, protocol, payload_types, |
2220 codec_preference, pos, content_name, | 2213 pos, content_name, media_desc, transport, candidates, |
2221 media_desc, transport, candidates, error)) { | 2214 error)) { |
2222 delete media_desc; | 2215 delete media_desc; |
2223 return NULL; | 2216 return NULL; |
2224 } | 2217 } |
2225 // Sort the codecs according to the m-line fmt list. | 2218 // Sort the codecs according to the m-line fmt list. |
2226 media_desc->SortCodecs(); | 2219 std::unordered_map<int, int> payload_type_preferences; |
2220 // "size + 1" so that the lowest preference payload type has a preference of | |
2221 // 1, which is greater than the default (0) for payload types not in the fmt | |
2222 // list. | |
2223 int preference = static_cast<int>(payload_types.size() + 1); | |
2224 for (int pt : payload_types) { | |
2225 payload_type_preferences[pt] = preference--; | |
2226 } | |
2227 std::vector<typename C::CodecType> codecs = media_desc->codecs(); | |
2228 std::sort(codecs.begin(), codecs.end(), [&payload_type_preferences]( | |
2229 const typename C::CodecType& a, | |
2230 const typename C::CodecType& b) { | |
2231 return payload_type_preferences[a.id] < payload_type_preferences[b.id]; | |
2232 }); | |
pthatcher1
2016/04/12 00:35:19
A https://en.wikipedia.org/wiki/Schwartzian_transf
Taylor Brandstetter
2016/04/12 01:23:29
Slightly, yes. But at least it's on the same order
| |
2233 media_desc->set_codecs(codecs); | |
2227 return media_desc; | 2234 return media_desc; |
2228 } | 2235 } |
2229 | 2236 |
2230 bool ParseMediaDescription(const std::string& message, | 2237 bool ParseMediaDescription(const std::string& message, |
2231 const TransportDescription& session_td, | 2238 const TransportDescription& session_td, |
2232 const RtpHeaderExtensions& session_extmaps, | 2239 const RtpHeaderExtensions& session_extmaps, |
2233 size_t* pos, | 2240 size_t* pos, |
2234 cricket::SessionDescription* desc, | 2241 cricket::SessionDescription* desc, |
2235 std::vector<JsepIceCandidate*>* candidates, | 2242 std::vector<JsepIceCandidate*>* candidates, |
2236 SdpParseError* error) { | 2243 SdpParseError* error) { |
(...skipping 18 matching lines...) Expand all Loading... | |
2255 // RFC 3264 | 2262 // RFC 3264 |
2256 // To reject an offered stream, the port number in the corresponding stream | 2263 // To reject an offered stream, the port number in the corresponding stream |
2257 // in the answer MUST be set to zero. | 2264 // in the answer MUST be set to zero. |
2258 if (fields[1] == kMediaPortRejected) { | 2265 if (fields[1] == kMediaPortRejected) { |
2259 rejected = true; | 2266 rejected = true; |
2260 } | 2267 } |
2261 | 2268 |
2262 std::string protocol = fields[2]; | 2269 std::string protocol = fields[2]; |
2263 | 2270 |
2264 // <fmt> | 2271 // <fmt> |
2265 std::vector<int> codec_preference; | 2272 std::vector<int> payload_types; |
2266 if (IsRtp(protocol)) { | 2273 if (IsRtp(protocol)) { |
2267 for (size_t j = 3 ; j < fields.size(); ++j) { | 2274 for (size_t j = 3 ; j < fields.size(); ++j) { |
2268 // TODO(wu): Remove when below bug is fixed. | 2275 // TODO(wu): Remove when below bug is fixed. |
2269 // https://bugzilla.mozilla.org/show_bug.cgi?id=996329 | 2276 // https://bugzilla.mozilla.org/show_bug.cgi?id=996329 |
2270 if (fields[j].empty() && j == fields.size() - 1) { | 2277 if (fields[j].empty() && j == fields.size() - 1) { |
2271 continue; | 2278 continue; |
2272 } | 2279 } |
2273 | 2280 |
2274 int pl = 0; | 2281 int pl = 0; |
2275 if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) { | 2282 if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) { |
2276 return false; | 2283 return false; |
2277 } | 2284 } |
2278 codec_preference.push_back(pl); | 2285 payload_types.push_back(pl); |
2279 } | 2286 } |
2280 } | 2287 } |
2281 | 2288 |
2282 // Make a temporary TransportDescription based on |session_td|. | 2289 // Make a temporary TransportDescription based on |session_td|. |
2283 // Some of this gets overwritten by ParseContent. | 2290 // Some of this gets overwritten by ParseContent. |
2284 TransportDescription transport( | 2291 TransportDescription transport( |
2285 session_td.transport_options, session_td.ice_ufrag, session_td.ice_pwd, | 2292 session_td.transport_options, session_td.ice_ufrag, session_td.ice_pwd, |
2286 session_td.ice_mode, session_td.connection_role, | 2293 session_td.ice_mode, session_td.connection_role, |
2287 session_td.identity_fingerprint.get()); | 2294 session_td.identity_fingerprint.get()); |
2288 | 2295 |
2289 rtc::scoped_ptr<MediaContentDescription> content; | 2296 rtc::scoped_ptr<MediaContentDescription> content; |
2290 std::string content_name; | 2297 std::string content_name; |
2291 if (HasAttribute(line, kMediaTypeVideo)) { | 2298 if (HasAttribute(line, kMediaTypeVideo)) { |
2292 content.reset(ParseContentDescription<VideoContentDescription>( | 2299 content.reset(ParseContentDescription<VideoContentDescription>( |
2293 message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol, | 2300 message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol, |
2294 codec_preference, pos, &content_name, | 2301 payload_types, pos, &content_name, &transport, candidates, error)); |
2295 &transport, candidates, error)); | |
2296 } else if (HasAttribute(line, kMediaTypeAudio)) { | 2302 } else if (HasAttribute(line, kMediaTypeAudio)) { |
2297 content.reset(ParseContentDescription<AudioContentDescription>( | 2303 content.reset(ParseContentDescription<AudioContentDescription>( |
2298 message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol, | 2304 message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol, |
2299 codec_preference, pos, &content_name, | 2305 payload_types, pos, &content_name, &transport, candidates, error)); |
2300 &transport, candidates, error)); | |
2301 } else if (HasAttribute(line, kMediaTypeData)) { | 2306 } else if (HasAttribute(line, kMediaTypeData)) { |
2302 DataContentDescription* data_desc = | 2307 DataContentDescription* data_desc = |
2303 ParseContentDescription<DataContentDescription>( | 2308 ParseContentDescription<DataContentDescription>( |
2304 message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, | 2309 message, cricket::MEDIA_TYPE_DATA, mline_index, protocol, |
2305 codec_preference, pos, &content_name, | 2310 payload_types, pos, &content_name, &transport, candidates, error); |
2306 &transport, candidates, error); | |
2307 content.reset(data_desc); | 2311 content.reset(data_desc); |
2308 | 2312 |
2309 int p; | 2313 int p; |
2310 if (data_desc && IsDtlsSctp(protocol) && rtc::FromString(fields[3], &p)) { | 2314 if (data_desc && IsDtlsSctp(protocol) && rtc::FromString(fields[3], &p)) { |
2311 if (!AddSctpDataCodec(data_desc, p)) | 2315 if (!AddSctpDataCodec(data_desc, p)) |
2312 return false; | 2316 return false; |
2313 } | 2317 } |
2314 } else { | 2318 } else { |
2315 LOG(LS_WARNING) << "Unsupported media type: " << line; | 2319 LOG(LS_WARNING) << "Unsupported media type: " << line; |
2316 continue; | 2320 continue; |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2503 iter != codecs.end(); ++iter) { | 2507 iter != codecs.end(); ++iter) { |
2504 iter->params[name] = value; | 2508 iter->params[name] = value; |
2505 } | 2509 } |
2506 audio_desc->set_codecs(codecs); | 2510 audio_desc->set_codecs(codecs); |
2507 } | 2511 } |
2508 | 2512 |
2509 bool ParseContent(const std::string& message, | 2513 bool ParseContent(const std::string& message, |
2510 const MediaType media_type, | 2514 const MediaType media_type, |
2511 int mline_index, | 2515 int mline_index, |
2512 const std::string& protocol, | 2516 const std::string& protocol, |
2513 const std::vector<int>& codec_preference, | 2517 const std::vector<int>& payload_types, |
2514 size_t* pos, | 2518 size_t* pos, |
2515 std::string* content_name, | 2519 std::string* content_name, |
2516 MediaContentDescription* media_desc, | 2520 MediaContentDescription* media_desc, |
2517 TransportDescription* transport, | 2521 TransportDescription* transport, |
2518 std::vector<JsepIceCandidate*>* candidates, | 2522 std::vector<JsepIceCandidate*>* candidates, |
2519 SdpParseError* error) { | 2523 SdpParseError* error) { |
2520 ASSERT(media_desc != NULL); | 2524 ASSERT(media_desc != NULL); |
2521 ASSERT(content_name != NULL); | 2525 ASSERT(content_name != NULL); |
2522 ASSERT(transport != NULL); | 2526 ASSERT(transport != NULL); |
2523 | 2527 |
2524 if (media_type == cricket::MEDIA_TYPE_AUDIO) { | 2528 if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
2525 MaybeCreateStaticPayloadAudioCodecs( | 2529 MaybeCreateStaticPayloadAudioCodecs( |
2526 codec_preference, static_cast<AudioContentDescription*>(media_desc)); | 2530 payload_types, static_cast<AudioContentDescription*>(media_desc)); |
2527 } | 2531 } |
2528 | 2532 |
2529 // The media level "ice-ufrag" and "ice-pwd". | 2533 // The media level "ice-ufrag" and "ice-pwd". |
2530 // The candidates before update the media level "ice-pwd" and "ice-ufrag". | 2534 // The candidates before update the media level "ice-pwd" and "ice-ufrag". |
2531 Candidates candidates_orig; | 2535 Candidates candidates_orig; |
2532 std::string line; | 2536 std::string line; |
2533 std::string mline_id; | 2537 std::string mline_id; |
2534 // Tracks created out of the ssrc attributes. | 2538 // Tracks created out of the ssrc attributes. |
2535 StreamParamsVec tracks; | 2539 StreamParamsVec tracks; |
2536 SsrcInfoVec ssrc_infos; | 2540 SsrcInfoVec ssrc_infos; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2651 } | 2655 } |
2652 } else if (HasAttribute(line, kAttributeSsrc)) { | 2656 } else if (HasAttribute(line, kAttributeSsrc)) { |
2653 if (!ParseSsrcAttribute(line, &ssrc_infos, error)) { | 2657 if (!ParseSsrcAttribute(line, &ssrc_infos, error)) { |
2654 return false; | 2658 return false; |
2655 } | 2659 } |
2656 } else if (HasAttribute(line, kAttributeCrypto)) { | 2660 } else if (HasAttribute(line, kAttributeCrypto)) { |
2657 if (!ParseCryptoAttribute(line, media_desc, error)) { | 2661 if (!ParseCryptoAttribute(line, media_desc, error)) { |
2658 return false; | 2662 return false; |
2659 } | 2663 } |
2660 } else if (HasAttribute(line, kAttributeRtpmap)) { | 2664 } else if (HasAttribute(line, kAttributeRtpmap)) { |
2661 if (!ParseRtpmapAttribute(line, media_type, codec_preference, | 2665 if (!ParseRtpmapAttribute(line, media_type, payload_types, media_desc, |
2662 media_desc, error)) { | 2666 error)) { |
2663 return false; | 2667 return false; |
2664 } | 2668 } |
2665 } else if (HasAttribute(line, kCodecParamMaxPTime)) { | 2669 } else if (HasAttribute(line, kCodecParamMaxPTime)) { |
2666 if (!GetValue(line, kCodecParamMaxPTime, &maxptime_as_string, error)) { | 2670 if (!GetValue(line, kCodecParamMaxPTime, &maxptime_as_string, error)) { |
2667 return false; | 2671 return false; |
2668 } | 2672 } |
2669 } else if (HasAttribute(line, kAttributeRtcpFb)) { | 2673 } else if (HasAttribute(line, kAttributeRtcpFb)) { |
2670 if (!ParseRtcpFbAttribute(line, media_type, media_desc, error)) { | 2674 if (!ParseRtcpFbAttribute(line, media_type, media_desc, error)) { |
2671 return false; | 2675 return false; |
2672 } | 2676 } |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2908 std::string session_params; | 2912 std::string session_params; |
2909 if (fields.size() > 3) { | 2913 if (fields.size() > 3) { |
2910 session_params = fields[3]; | 2914 session_params = fields[3]; |
2911 } | 2915 } |
2912 media_desc->AddCrypto(CryptoParams(tag, crypto_suite, key_params, | 2916 media_desc->AddCrypto(CryptoParams(tag, crypto_suite, key_params, |
2913 session_params)); | 2917 session_params)); |
2914 return true; | 2918 return true; |
2915 } | 2919 } |
2916 | 2920 |
2917 // Updates or creates a new codec entry in the audio description with according | 2921 // Updates or creates a new codec entry in the audio description with according |
2918 // to |name|, |clockrate|, |bitrate|, |channels| and |preference|. | 2922 // to |name|, |clockrate|, |bitrate|, and |channels|. |
2919 void UpdateCodec(int payload_type, const std::string& name, int clockrate, | 2923 void UpdateCodec(int payload_type, |
2920 int bitrate, size_t channels, int preference, | 2924 const std::string& name, |
2925 int clockrate, | |
2926 int bitrate, | |
2927 size_t channels, | |
2921 AudioContentDescription* audio_desc) { | 2928 AudioContentDescription* audio_desc) { |
2922 // Codec may already be populated with (only) optional parameters | 2929 // Codec may already be populated with (only) optional parameters |
2923 // (from an fmtp). | 2930 // (from an fmtp). |
2924 cricket::AudioCodec codec = | 2931 cricket::AudioCodec codec = |
2925 GetCodecWithPayloadType(audio_desc->codecs(), payload_type); | 2932 GetCodecWithPayloadType(audio_desc->codecs(), payload_type); |
2926 codec.name = name; | 2933 codec.name = name; |
2927 codec.clockrate = clockrate; | 2934 codec.clockrate = clockrate; |
2928 codec.bitrate = bitrate; | 2935 codec.bitrate = bitrate; |
2929 codec.channels = channels; | 2936 codec.channels = channels; |
2930 codec.preference = preference; | |
2931 AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc, | 2937 AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc, |
2932 codec); | 2938 codec); |
2933 } | 2939 } |
2934 | 2940 |
2935 // Updates or creates a new codec entry in the video description according to | 2941 // Updates or creates a new codec entry in the video description according to |
2936 // |name|, |width|, |height|, |framerate| and |preference|. | 2942 // |name|, |width|, |height|, and |framerate|. |
2937 void UpdateCodec(int payload_type, const std::string& name, int width, | 2943 void UpdateCodec(int payload_type, |
2938 int height, int framerate, int preference, | 2944 const std::string& name, |
2945 int width, | |
2946 int height, | |
2947 int framerate, | |
2939 VideoContentDescription* video_desc) { | 2948 VideoContentDescription* video_desc) { |
2940 // Codec may already be populated with (only) optional parameters | 2949 // Codec may already be populated with (only) optional parameters |
2941 // (from an fmtp). | 2950 // (from an fmtp). |
2942 cricket::VideoCodec codec = | 2951 cricket::VideoCodec codec = |
2943 GetCodecWithPayloadType(video_desc->codecs(), payload_type); | 2952 GetCodecWithPayloadType(video_desc->codecs(), payload_type); |
2944 codec.name = name; | 2953 codec.name = name; |
2945 codec.width = width; | 2954 codec.width = width; |
2946 codec.height = height; | 2955 codec.height = height; |
2947 codec.framerate = framerate; | 2956 codec.framerate = framerate; |
2948 codec.preference = preference; | |
2949 AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc, | 2957 AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc, |
2950 codec); | 2958 codec); |
2951 } | 2959 } |
2952 | 2960 |
2953 bool ParseRtpmapAttribute(const std::string& line, | 2961 bool ParseRtpmapAttribute(const std::string& line, |
2954 const MediaType media_type, | 2962 const MediaType media_type, |
2955 const std::vector<int>& codec_preference, | 2963 const std::vector<int>& payload_types, |
2956 MediaContentDescription* media_desc, | 2964 MediaContentDescription* media_desc, |
2957 SdpParseError* error) { | 2965 SdpParseError* error) { |
2958 std::vector<std::string> fields; | 2966 std::vector<std::string> fields; |
2959 rtc::split(line.substr(kLinePrefixLength), | 2967 rtc::split(line.substr(kLinePrefixLength), |
2960 kSdpDelimiterSpace, &fields); | 2968 kSdpDelimiterSpace, &fields); |
2961 // RFC 4566 | 2969 // RFC 4566 |
2962 // a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encodingparameters>] | 2970 // a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encodingparameters>] |
2963 const size_t expected_min_fields = 2; | 2971 const size_t expected_min_fields = 2; |
2964 if (fields.size() < expected_min_fields) { | 2972 if (fields.size() < expected_min_fields) { |
2965 return ParseFailedExpectMinFieldNum(line, expected_min_fields, error); | 2973 return ParseFailedExpectMinFieldNum(line, expected_min_fields, error); |
2966 } | 2974 } |
2967 std::string payload_type_value; | 2975 std::string payload_type_value; |
2968 if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) { | 2976 if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) { |
2969 return false; | 2977 return false; |
2970 } | 2978 } |
2971 int payload_type = 0; | 2979 int payload_type = 0; |
2972 if (!GetPayloadTypeFromString(line, payload_type_value, &payload_type, | 2980 if (!GetPayloadTypeFromString(line, payload_type_value, &payload_type, |
2973 error)) { | 2981 error)) { |
2974 return false; | 2982 return false; |
2975 } | 2983 } |
2976 | 2984 |
2977 // Set the preference order depending on the order of the pl type in the | 2985 if (std::find(payload_types.begin(), payload_types.end(), payload_type) == |
2978 // <fmt> of the m-line. | 2986 payload_types.end()) { |
2979 const int preference = codec_preference.end() - | |
2980 std::find(codec_preference.begin(), codec_preference.end(), | |
2981 payload_type); | |
2982 if (preference == 0) { | |
2983 LOG(LS_WARNING) << "Ignore rtpmap line that did not appear in the " | 2987 LOG(LS_WARNING) << "Ignore rtpmap line that did not appear in the " |
2984 << "<fmt> of the m-line: " << line; | 2988 << "<fmt> of the m-line: " << line; |
2985 return true; | 2989 return true; |
2986 } | 2990 } |
2987 const std::string& encoder = fields[1]; | 2991 const std::string& encoder = fields[1]; |
2988 std::vector<std::string> codec_params; | 2992 std::vector<std::string> codec_params; |
2989 rtc::split(encoder, '/', &codec_params); | 2993 rtc::split(encoder, '/', &codec_params); |
2990 // <encoding name>/<clock rate>[/<encodingparameters>] | 2994 // <encoding name>/<clock rate>[/<encodingparameters>] |
2991 // 2 mandatory fields | 2995 // 2 mandatory fields |
2992 if (codec_params.size() < 2 || codec_params.size() > 3) { | 2996 if (codec_params.size() < 2 || codec_params.size() > 3) { |
2993 return ParseFailed(line, | 2997 return ParseFailed(line, |
2994 "Expected format \"<encoding name>/<clock rate>" | 2998 "Expected format \"<encoding name>/<clock rate>" |
2995 "[/<encodingparameters>]\".", | 2999 "[/<encodingparameters>]\".", |
2996 error); | 3000 error); |
2997 } | 3001 } |
2998 const std::string& encoding_name = codec_params[0]; | 3002 const std::string& encoding_name = codec_params[0]; |
2999 int clock_rate = 0; | 3003 int clock_rate = 0; |
3000 if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) { | 3004 if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) { |
3001 return false; | 3005 return false; |
3002 } | 3006 } |
3003 if (media_type == cricket::MEDIA_TYPE_VIDEO) { | 3007 if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
3004 VideoContentDescription* video_desc = | 3008 VideoContentDescription* video_desc = |
3005 static_cast<VideoContentDescription*>(media_desc); | 3009 static_cast<VideoContentDescription*>(media_desc); |
3006 // TODO: We will send resolution in SDP. For now use | 3010 // TODO: We will send resolution in SDP. For now use |
3007 // JsepSessionDescription::kMaxVideoCodecWidth and kMaxVideoCodecHeight. | 3011 // JsepSessionDescription::kMaxVideoCodecWidth and kMaxVideoCodecHeight. |
3008 UpdateCodec(payload_type, encoding_name, | 3012 UpdateCodec(payload_type, encoding_name, |
3009 JsepSessionDescription::kMaxVideoCodecWidth, | 3013 JsepSessionDescription::kMaxVideoCodecWidth, |
3010 JsepSessionDescription::kMaxVideoCodecHeight, | 3014 JsepSessionDescription::kMaxVideoCodecHeight, |
3011 JsepSessionDescription::kDefaultVideoCodecFramerate, | 3015 JsepSessionDescription::kDefaultVideoCodecFramerate, |
3012 preference, video_desc); | 3016 video_desc); |
3013 } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { | 3017 } else if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
3014 // RFC 4566 | 3018 // RFC 4566 |
3015 // For audio streams, <encoding parameters> indicates the number | 3019 // For audio streams, <encoding parameters> indicates the number |
3016 // of audio channels. This parameter is OPTIONAL and may be | 3020 // of audio channels. This parameter is OPTIONAL and may be |
3017 // omitted if the number of channels is one, provided that no | 3021 // omitted if the number of channels is one, provided that no |
3018 // additional parameters are needed. | 3022 // additional parameters are needed. |
3019 size_t channels = 1; | 3023 size_t channels = 1; |
3020 if (codec_params.size() == 3) { | 3024 if (codec_params.size() == 3) { |
3021 if (!GetValueFromString(line, codec_params[2], &channels, error)) { | 3025 if (!GetValueFromString(line, codec_params[2], &channels, error)) { |
3022 return false; | 3026 return false; |
3023 } | 3027 } |
3024 } | 3028 } |
3025 int bitrate = 0; | 3029 int bitrate = 0; |
3026 // The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc | 3030 // The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc |
3027 // (specifically FindWebRtcCodec) is bandwidth-adaptive variable bitrate. | 3031 // (specifically FindWebRtcCodec) is bandwidth-adaptive variable bitrate. |
3028 // The bandwidth adaptation doesn't always work well, so this code | 3032 // The bandwidth adaptation doesn't always work well, so this code |
3029 // sets a fixed target bitrate instead. | 3033 // sets a fixed target bitrate instead. |
3030 if (_stricmp(encoding_name.c_str(), kIsacCodecName) == 0) { | 3034 if (_stricmp(encoding_name.c_str(), kIsacCodecName) == 0) { |
3031 if (clock_rate <= 16000) { | 3035 if (clock_rate <= 16000) { |
3032 bitrate = kIsacWbDefaultRate; | 3036 bitrate = kIsacWbDefaultRate; |
3033 } else { | 3037 } else { |
3034 bitrate = kIsacSwbDefaultRate; | 3038 bitrate = kIsacSwbDefaultRate; |
3035 } | 3039 } |
3036 } | 3040 } |
3037 AudioContentDescription* audio_desc = | 3041 AudioContentDescription* audio_desc = |
3038 static_cast<AudioContentDescription*>(media_desc); | 3042 static_cast<AudioContentDescription*>(media_desc); |
3039 UpdateCodec(payload_type, encoding_name, clock_rate, bitrate, channels, | 3043 UpdateCodec(payload_type, encoding_name, clock_rate, bitrate, channels, |
3040 preference, audio_desc); | 3044 audio_desc); |
3041 } else if (media_type == cricket::MEDIA_TYPE_DATA) { | 3045 } else if (media_type == cricket::MEDIA_TYPE_DATA) { |
3042 DataContentDescription* data_desc = | 3046 DataContentDescription* data_desc = |
3043 static_cast<DataContentDescription*>(media_desc); | 3047 static_cast<DataContentDescription*>(media_desc); |
3044 data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name, | 3048 data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name)); |
3045 preference)); | |
3046 } | 3049 } |
3047 return true; | 3050 return true; |
3048 } | 3051 } |
3049 | 3052 |
3050 bool ParseFmtpParam(const std::string& line, std::string* parameter, | 3053 bool ParseFmtpParam(const std::string& line, std::string* parameter, |
3051 std::string* value, SdpParseError* error) { | 3054 std::string* value, SdpParseError* error) { |
3052 if (!rtc::tokenize_first(line, kSdpDelimiterEqual, parameter, value)) { | 3055 if (!rtc::tokenize_first(line, kSdpDelimiterEqual, parameter, value)) { |
3053 ParseFailed(line, "Unable to parse fmtp parameter. \'=\' missing.", error); | 3056 ParseFailed(line, "Unable to parse fmtp parameter. \'=\' missing.", error); |
3054 return false; | 3057 return false; |
3055 } | 3058 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3156 UpdateCodec<AudioContentDescription, cricket::AudioCodec>( | 3159 UpdateCodec<AudioContentDescription, cricket::AudioCodec>( |
3157 media_desc, payload_type, feedback_param); | 3160 media_desc, payload_type, feedback_param); |
3158 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { | 3161 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
3159 UpdateCodec<VideoContentDescription, cricket::VideoCodec>( | 3162 UpdateCodec<VideoContentDescription, cricket::VideoCodec>( |
3160 media_desc, payload_type, feedback_param); | 3163 media_desc, payload_type, feedback_param); |
3161 } | 3164 } |
3162 return true; | 3165 return true; |
3163 } | 3166 } |
3164 | 3167 |
3165 } // namespace webrtc | 3168 } // namespace webrtc |
OLD | NEW |