Index: webrtc/pc/webrtcsdp.cc |
diff --git a/webrtc/pc/webrtcsdp.cc b/webrtc/pc/webrtcsdp.cc |
index 13d09a6ee96efd33219e6e7df89ba5983cb49d7e..3953773d83f361837e7239ef81550da44635d247 100644 |
--- a/webrtc/pc/webrtcsdp.cc |
+++ b/webrtc/pc/webrtcsdp.cc |
@@ -249,11 +249,13 @@ static void BuildIceOptions(const std::vector<std::string>& transport_options, |
std::string* message); |
static bool IsRtp(const std::string& protocol); |
static bool IsDtlsSctp(const std::string& protocol); |
-static bool ParseSessionDescription(const std::string& message, size_t* pos, |
+static bool ParseSessionDescription(const std::string& message, |
+ size_t* pos, |
std::string* session_id, |
std::string* session_version, |
TransportDescription* session_td, |
RtpHeaderExtensions* session_extmaps, |
+ rtc::SocketAddress* connection_addr, |
cricket::SessionDescription* desc, |
SdpParseError* error); |
static bool ParseGroupAttribute(const std::string& line, |
@@ -263,7 +265,9 @@ static bool ParseMediaDescription( |
const std::string& message, |
const TransportDescription& session_td, |
const RtpHeaderExtensions& session_extmaps, |
- size_t* pos, cricket::SessionDescription* desc, |
+ size_t* pos, |
+ const rtc::SocketAddress& session_connection_addr, |
+ cricket::SessionDescription* desc, |
std::vector<JsepIceCandidate*>* candidates, |
SdpParseError* error); |
static bool ParseContent(const std::string& message, |
@@ -713,47 +717,6 @@ static void GetDefaultDestination( |
} |
} |
-// Update |mline|'s default destination and append a c line after it. |
-static void UpdateMediaDefaultDestination( |
- const std::vector<Candidate>& candidates, |
- const std::string& mline, |
- std::string* message) { |
- std::string new_lines; |
- AddLine(mline, &new_lines); |
- // RFC 4566 |
- // m=<media> <port> <proto> <fmt> ... |
- std::vector<std::string> fields; |
- rtc::split(mline, kSdpDelimiterSpace, &fields); |
- if (fields.size() < 3) { |
- return; |
- } |
- |
- std::ostringstream os; |
- std::string rtp_port, rtp_ip, addr_type; |
- GetDefaultDestination(candidates, ICE_CANDIDATE_COMPONENT_RTP, |
- &rtp_port, &rtp_ip, &addr_type); |
- // Found default RTP candidate. |
- // RFC 5245 |
- // The default candidates are added to the SDP as the default |
- // destination for media. For streams based on RTP, this is done by |
- // placing the IP address and port of the RTP candidate into the c and m |
- // lines, respectively. |
- // Update the port in the m line. |
- // If this is a m-line with port equal to 0, we don't change it. |
- if (fields[1] != kMediaPortRejected) { |
- new_lines.replace(fields[0].size() + 1, |
- fields[1].size(), |
- rtp_port); |
- } |
- // Add the c line. |
- // RFC 4566 |
- // c=<nettype> <addrtype> <connection-address> |
- InitLine(kLineTypeConnection, kConnectionNettype, &os); |
- os << " " << addr_type << " " << rtp_ip; |
- AddLine(os.str(), &new_lines); |
- message->append(new_lines); |
-} |
- |
// Gets "a=rtcp" line if found default RTCP candidate from |candidates|. |
static std::string GetRtcpLine(const std::vector<Candidate>& candidates) { |
std::string rtcp_line, rtcp_port, rtcp_ip, addr_type; |
@@ -902,6 +865,7 @@ bool SdpDeserialize(const std::string& message, |
std::string session_version; |
TransportDescription session_td("", ""); |
RtpHeaderExtensions session_extmaps; |
+ rtc::SocketAddress session_connection_addr; |
cricket::SessionDescription* desc = new cricket::SessionDescription(); |
std::vector<JsepIceCandidate*> candidates; |
size_t current_pos = 0; |
@@ -909,14 +873,15 @@ bool SdpDeserialize(const std::string& message, |
// Session Description |
if (!ParseSessionDescription(message, ¤t_pos, &session_id, |
&session_version, &session_td, &session_extmaps, |
- desc, error)) { |
+ &session_connection_addr, desc, error)) { |
delete desc; |
return false; |
} |
// Media Description |
if (!ParseMediaDescription(message, session_td, session_extmaps, ¤t_pos, |
- desc, &candidates, error)) { |
+ session_connection_addr, desc, &candidates, |
+ error)) { |
delete desc; |
for (std::vector<JsepIceCandidate*>::const_iterator |
it = candidates.begin(); it != candidates.end(); ++it) { |
@@ -1315,9 +1280,12 @@ void BuildMediaDescription(const ContentInfo* content_info, |
// |
// However, the BUNDLE draft adds a new meaning to port zero, when used along |
// with a=bundle-only. |
- const std::string& port = |
- (content_info->rejected || content_info->bundle_only) ? kMediaPortRejected |
- : kDummyPort; |
+ std::string port = kDummyPort; |
+ if (content_info->rejected || content_info->bundle_only) { |
+ port = kMediaPortRejected; |
+ } else if (!media_desc->connection_address().IsNil()) { |
+ port = rtc::ToString(media_desc->connection_address().port()); |
+ } |
rtc::SSLFingerprint* fp = (transport_info) ? |
transport_info->description.identity_fingerprint.get() : NULL; |
@@ -1325,8 +1293,19 @@ void BuildMediaDescription(const ContentInfo* content_info, |
// Add the m and c lines. |
InitLine(kLineTypeMedia, type, &os); |
os << " " << port << " " << media_desc->protocol() << fmt; |
- std::string mline = os.str(); |
- UpdateMediaDefaultDestination(candidates, mline, message); |
+ AddLine(os.str(), message); |
+ |
+ InitLine(kLineTypeConnection, kConnectionNettype, &os); |
+ if (media_desc->connection_address().IsNil()) { |
+ os << " " << kConnectionIpv4Addrtype << " " << kDummyAddress; |
+ } else if (media_desc->connection_address().family() == AF_INET) { |
+ os << " " << kConnectionIpv4Addrtype << " " |
+ << media_desc->connection_address().ipaddr().ToString(); |
+ } else { |
+ os << " " << kConnectionIpv6Addrtype << " " |
+ << media_desc->connection_address().ipaddr().ToString(); |
+ } |
+ AddLine(os.str(), message); |
// RFC 4566 |
// b=AS:<bandwidth> |
@@ -1900,11 +1879,62 @@ bool IsDtlsSctp(const std::string& protocol) { |
return protocol.find(cricket::kMediaProtocolDtlsSctp) != std::string::npos; |
} |
-bool ParseSessionDescription(const std::string& message, size_t* pos, |
+bool ParseConnectionData(const std::string& line, |
+ rtc::SocketAddress* addr, |
+ SdpParseError* error) { |
+ // Parse the line from left to right. |
+ std::string token; |
+ std::string rightpart; |
+ // RFC 4566 |
+ // c=<nettype> <addrtype> <connection-address> |
+ // Skip the "c=" |
+ if (!rtc::tokenize_first(line, kSdpDelimiterEqual, &token, &rightpart)) { |
+ return ParseFailed(line, "Failed to parse the network type.", error); |
+ } |
+ |
+ // Extract and verify the <nettype> |
+ if (!rtc::tokenize_first(rightpart, kSdpDelimiterSpace, &token, &rightpart) || |
+ token != kConnectionNettype) { |
+ return ParseFailed(line, |
+ "Failed to parse the connection data. The network type " |
+ "is not currently supported.", |
+ error); |
+ } |
+ |
+ // Extract the "<addrtype>" and "<connection-address>". |
+ if (!rtc::tokenize_first(rightpart, kSdpDelimiterSpace, &token, &rightpart)) { |
+ return ParseFailed(line, "Failed to parse the address type.", error); |
+ } |
+ |
+ // The rightpart part should be the IP address without the slash which is used |
+ // for multicast. |
+ if (rightpart.find('/') != std::string::npos) { |
+ return ParseFailed(line, |
+ "Failed to parse the connection data. Multicast is not " |
+ "currently supported.", |
+ error); |
+ } |
+ addr->SetIP(rightpart); |
+ |
+ // Verify that the addrtype matches the type of the parsed address. |
+ if ((addr->family() == AF_INET && token != "IP4") || |
+ (addr->family() == AF_INET6 && token != "IP6")) { |
+ addr->Clear(); |
+ return ParseFailed( |
+ line, |
+ "Failed to parse the connection data. The address type is mismatching.", |
+ error); |
+ } |
+ return true; |
+} |
+ |
+bool ParseSessionDescription(const std::string& message, |
+ size_t* pos, |
std::string* session_id, |
std::string* session_version, |
TransportDescription* session_td, |
RtpHeaderExtensions* session_extmaps, |
+ rtc::SocketAddress* connection_addr, |
cricket::SessionDescription* desc, |
SdpParseError* error) { |
std::string line; |
@@ -1962,7 +1992,11 @@ bool ParseSessionDescription(const std::string& message, size_t* pos, |
// RFC 4566 |
// c=* (connection information -- not required if included in |
// all media) |
- GetLineWithType(message, pos, &line, kLineTypeConnection); |
+ if (GetLineWithType(message, pos, &line, kLineTypeConnection)) { |
+ if (!ParseConnectionData(line, connection_addr, error)) { |
+ return false; |
+ } |
+ } |
// RFC 4566 |
// b=* (zero or more bandwidth information lines) |
@@ -2266,7 +2300,7 @@ static C* ParseContentDescription(const std::string& message, |
pos, content_name, bundle_only, media_desc, transport, |
candidates, error)) { |
delete media_desc; |
- return NULL; |
+ return nullptr; |
} |
// Sort the codecs according to the m-line fmt list. |
std::unordered_map<int, int> payload_type_preferences; |
@@ -2291,6 +2325,7 @@ bool ParseMediaDescription(const std::string& message, |
const TransportDescription& session_td, |
const RtpHeaderExtensions& session_extmaps, |
size_t* pos, |
+ const rtc::SocketAddress& session_connection_addr, |
cricket::SessionDescription* desc, |
std::vector<JsepIceCandidate*>* candidates, |
SdpParseError* error) { |
@@ -2320,6 +2355,10 @@ bool ParseMediaDescription(const std::string& message, |
port_rejected = true; |
} |
+ int port = 0; |
+ if (!rtc::FromString<int>(fields[1], &port) || !IsValidPort(port)) { |
+ return ParseFailed(line, "The port number is invalid", error); |
+ } |
std::string protocol = fields[2]; |
// <fmt> |
@@ -2420,6 +2459,16 @@ bool ParseMediaDescription(const std::string& message, |
} |
} |
content->set_protocol(protocol); |
+ |
+ // Use the session level connection address if the media level addresses are |
+ // not specified. |
+ rtc::SocketAddress address; |
+ address = content->connection_address().IsNil() |
+ ? session_connection_addr |
+ : content->connection_address(); |
+ address.SetPort(port); |
+ content->set_connection_address(address); |
+ |
desc->AddContent(content_name, |
IsDtlsSctp(protocol) ? cricket::NS_JINGLE_DRAFT_SCTP |
: cricket::NS_JINGLE_RTP, |
@@ -2668,6 +2717,16 @@ bool ParseContent(const std::string& message, |
continue; |
} |
+ // Parse the media level connection data. |
+ if (IsLineType(line, kLineTypeConnection)) { |
+ rtc::SocketAddress addr; |
+ if (!ParseConnectionData(line, &addr, error)) { |
+ return false; |
+ } |
+ media_desc->set_connection_address(addr); |
+ continue; |
+ } |
+ |
if (!IsLineType(line, kLineTypeAttributes)) { |
// TODO: Handle other lines if needed. |
LOG(LS_INFO) << "Ignored line: " << line; |