前言

peerconnection收到sdp封装后的message后,将其解析。
1、发送消息
void PeerConnectionClient::SendToPeer(int peer_id, const std::string& message)
image.png
2、接收消息
void PeerConnectionClient::OnMessageFromPeer(int peer_id, const std::string& message)
image.png

PeerConnectionClient::OnMessageFromPeer

  1. void PeerConnectionClient::OnMessageFromPeer(int peer_id,
  2. const std::string& message) {
  3. if (message.length() == (sizeof(kByeMessage) - 1) &&
  4. message.compare(kByeMessage) == 0) {
  5. callback_->OnPeerDisconnected(peer_id);
  6. } else {
  7. callback_->OnMessageFromPeer(peer_id, message);
  8. }
  9. }

里面调用的OnMessageFromPeer是 Conductor::OnMessageFromPeer

Conductor::OnMessageFromPeer

  1. void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) {
  2. RTC_DCHECK(peer_id_ == peer_id || peer_id_ == -1);
  3. RTC_DCHECK(!message.empty());
  4. if (!peer_connection_.get()) {
  5. RTC_DCHECK(peer_id_ == -1);
  6. peer_id_ = peer_id;
  7. if (!InitializePeerConnection()) {
  8. RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
  9. client_->SignOut();
  10. return;
  11. }
  12. } else if (peer_id != peer_id_) {
  13. RTC_DCHECK(peer_id_ != -1);
  14. RTC_LOG(WARNING)
  15. << "Received a message from unknown peer while already in a "
  16. "conversation with a different peer.";
  17. return;
  18. }
  19. // json解析接收到的对端消息
  20. Json::Reader reader;
  21. Json::Value jmessage;
  22. if (!reader.parse(message, jmessage)) {
  23. RTC_LOG(WARNING) << "Received unknown message. " << message;
  24. return;
  25. }
  26. std::string type_str;
  27. std::string json_object;
  28. // 获取信令类型,type_str为answer或者offer,
  29. // 如果是本端发起通信,第一次会收到answer类型,后面收到的就是空类型
  30. rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName,
  31. &type_str);
  32. if (!type_str.empty()) { // 类型不为空
  33. if (type_str == "offer-loopback") {
  34. // This is a loopback call.
  35. // Recreate the peerconnection with DTLS disabled.
  36. if (!ReinitializePeerConnectionForLoopback()) {
  37. RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
  38. DeletePeerConnection();
  39. client_->SignOut();
  40. }
  41. return;
  42. }
  43. // 获取sdp类型
  44. absl::optional<webrtc::SdpType> type_maybe =
  45. webrtc::SdpTypeFromString(type_str);
  46. if (!type_maybe) {
  47. RTC_LOG(LS_ERROR) << "Unknown SDP type: " << type_str;
  48. return;
  49. }
  50. webrtc::SdpType type = *type_maybe;
  51. // 从json中解析出一个个的文本sdp消息
  52. std::string sdp;
  53. if (!rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName,
  54. &sdp)) {
  55. RTC_LOG(WARNING) << "Can't parse received session description message.";
  56. return;
  57. }
  58. // 创建SessionDescriptionInterface对象保存sdp
  59. webrtc::SdpParseError error;
  60. std::unique_ptr<webrtc::SessionDescriptionInterface> session_description =
  61. webrtc::CreateSessionDescription(type, sdp, &error);
  62. if (!session_description) {
  63. RTC_LOG(WARNING) << "Can't parse received session description message. "
  64. "SdpParseError was: "
  65. << error.description;
  66. return;
  67. }
  68. RTC_LOG(INFO) << " Received session description :" << message;
  69. // 设置远端的消息保存到内存
  70. peer_connection_->SetRemoteDescription(
  71. DummySetSessionDescriptionObserver::Create(),
  72. session_description.release());
  73. // 如果是offer消息,则代表是对端发起通信,需要发给对端answer
  74. if (type == webrtc::SdpType::kOffer) {
  75. peer_connection_->CreateAnswer(
  76. this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
  77. }
  78. } else {
  79. std::string sdp_mid;
  80. int sdp_mlineindex = 0;
  81. // 获取sdp信息
  82. std::string sdp;
  83. if (!rtc::GetStringFromJsonObject(jmessage, kCandidateSdpMidName,
  84. &sdp_mid) ||
  85. !rtc::GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName,
  86. &sdp_mlineindex) ||
  87. !rtc::GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) {
  88. RTC_LOG(WARNING) << "Can't parse received message.";
  89. return;
  90. }
  91. // 根据sdp,创建candidate
  92. webrtc::SdpParseError error;
  93. std::unique_ptr<webrtc::IceCandidateInterface> candidate(
  94. webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
  95. if (!candidate.get()) {
  96. RTC_LOG(WARNING) << "Can't parse received candidate message. "
  97. "SdpParseError was: "
  98. << error.description;
  99. return;
  100. }
  101. // 添加AddIceCandidate
  102. if (!peer_connection_->AddIceCandidate(candidate.get())) {
  103. RTC_LOG(WARNING) << "Failed to apply the received candidate";
  104. return;
  105. }
  106. RTC_LOG(INFO) << " Received candidate :" << message;
  107. }
  108. }

image.png
image.png
取出type_str和sdp后,创建session_description,
std::unique_ptr session_description =
webrtc::CreateSessionDescription(type, sdp, &error);

webrtc::CreateSessionDescription

  1. std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription(
  2. SdpType type,
  3. const std::string& sdp,
  4. SdpParseError* error_out) {
  5. auto jsep_desc = std::make_unique<JsepSessionDescription>(type);
  6. if (type != SdpType::kRollback) {
  7. if (!SdpDeserialize(sdp, jsep_desc.get(), error_out)) {
  8. return nullptr;
  9. }
  10. }
  11. return std::move(jsep_desc);
  12. }

里面主要是调用了SdpDeserialize,反序列化解析sdp文本出来。跟之前的序列化SdpSerialize函数相对应。

SdpDeserialize

  1. bool SdpDeserialize(const std::string& message,
  2. JsepSessionDescription* jdesc,
  3. SdpParseError* error) {
  4. std::string session_id;
  5. std::string session_version;
  6. TransportDescription session_td("", "");
  7. RtpHeaderExtensions session_extmaps;
  8. rtc::SocketAddress session_connection_addr;
  9. auto desc = std::make_unique<cricket::SessionDescription>();
  10. size_t current_pos = 0;
  11. // Session Description
  12. if (!ParseSessionDescription(message, &current_pos, &session_id,
  13. &session_version, &session_td, &session_extmaps,
  14. &session_connection_addr, desc.get(), error)) {
  15. return false;
  16. }
  17. // Media Description
  18. std::vector<std::unique_ptr<JsepIceCandidate>> candidates;
  19. if (!ParseMediaDescription(message, session_td, session_extmaps, &current_pos,
  20. session_connection_addr, desc.get(), &candidates,
  21. error)) {
  22. return false;
  23. }
  24. jdesc->Initialize(std::move(desc), session_id, session_version);
  25. for (const auto& candidate : candidates) {
  26. jdesc->AddCandidate(candidate.get());
  27. }
  28. return true;
  29. }

重点看媒体会话描述ParseMediaDescription

ParseMediaDescription

  1. bool ParseMediaDescription(***){
  2. ***
  3. // Zero or more media descriptions
  4. // RFC 4566
  5. // m=<media> <port> <proto> <fmt> 获取每一行
  6. while (GetLineWithType(message, pos, &line, kLineTypeMedia)) {
  7. ++mline_index;
  8. // 按照空格来分割,将分割后的内容保存到fields
  9. std::vector<std::string> fields;
  10. rtc::split(line.substr(kLinePrefixLength), kSdpDelimiterSpaceChar, &fields);
  11. const size_t expected_min_fields = 4;
  12. if (fields.size() < expected_min_fields) {
  13. return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
  14. }
  15. bool port_rejected = false;
  16. // RFC 3264
  17. // To reject an offered stream, the port number in the corresponding stream
  18. // in the answer MUST be set to zero.
  19. if (fields[1] == kMediaPortRejected) {
  20. port_rejected = true;
  21. }
  22. int port = 0;
  23. if (!rtc::FromString<int>(fields[1], &port) || !IsValidPort(port)) {
  24. return ParseFailed(line, "The port number is invalid", error);
  25. }
  26. const std::string& protocol = fields[2];
  27. // <fmt> 获取payload_types
  28. std::vector<int> payload_types;
  29. if (cricket::IsRtpProtocol(protocol)) {
  30. for (size_t j = 3; j < fields.size(); ++j) {
  31. int pl = 0;
  32. if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) {
  33. return false;
  34. }
  35. payload_types.push_back(pl);
  36. }
  37. }
  38. // 构建临时的TransportDescription
  39. // Make a temporary TransportDescription based on |session_td|.
  40. // Some of this gets overwritten by ParseContent.
  41. TransportDescription transport(
  42. session_td.transport_options, session_td.ice_ufrag, session_td.ice_pwd,
  43. session_td.ice_mode, session_td.connection_role,
  44. session_td.identity_fingerprint.get());
  45. //媒体信息解析
  46. std::unique_ptr<MediaContentDescription> content;
  47. std::string content_name;
  48. bool bundle_only = false;
  49. int section_msid_signaling = 0;
  50. const std::string& media_type = fields[0];
  51. if ((media_type == kMediaTypeVideo || media_type == kMediaTypeAudio) &&
  52. !cricket::IsRtpProtocol(protocol)) {
  53. return ParseFailed(line, "Unsupported protocol for media type", error);
  54. }
  55. if (media_type == kMediaTypeVideo) { 视频
  56. content = ParseContentDescription<VideoContentDescription>(
  57. message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol,
  58. payload_types, pos, &content_name, &bundle_only,
  59. &section_msid_signaling, &transport, candidates, error);
  60. } else if (media_type == kMediaTypeAudio) {
  61. content = ParseContentDescription<AudioContentDescription>(
  62. message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol,
  63. payload_types, pos, &content_name, &bundle_only,
  64. &section_msid_signaling, &transport, candidates, error);
  65. } else if (media_type == kMediaTypeData) { 媒体类型数据
  66. if (cricket::IsDtlsSctp(protocol)) {
  67. ***
  68. }
  69. if (!ParseContent(message, cricket::MEDIA_TYPE_DATA, mline_index,
  70. protocol, payload_types, pos, &content_name,
  71. &bundle_only, &section_msid_signaling,
  72. data_desc.get(), &transport, candidates, error)) {
  73. return false;
  74. }
  75. **
  76. } else if (cricket::IsRtpProtocol(protocol)) {
  77. // RTP
  78. std::unique_ptr<RtpDataContentDescription> data_desc =
  79. ParseContentDescription<RtpDataContentDescription>***
  80. } else {
  81. return ParseFailed(line, "Unsupported protocol for media type", error);
  82. }
  83. } else {
  84. RTC_LOG(LS_WARNING) << "Unsupported media type: " << line;
  85. auto unsupported_desc =
  86. std::make_unique<UnsupportedContentDescription>(media_type);
  87. if (!ParseContent(message, cricket::MEDIA_TYPE_UNSUPPORTED, mline_index,
  88. protocol, payload_types, pos, &content_name,
  89. &bundle_only, &section_msid_signaling,
  90. unsupported_desc.get(), &transport, candidates,
  91. error)) {
  92. return false;
  93. }
  94. ***
  95. bool content_rejected = false;
  96. // A port of 0 is not interpreted as a rejected m= section when it's
  97. // used along with a=bundle-only.
  98. if (bundle_only) {
  99. if (!port_rejected) {
  100. // Usage of bundle-only with a nonzero port is unspecified. So just
  101. // ignore bundle-only if we see this.
  102. bundle_only = false;
  103. RTC_LOG(LS_WARNING)
  104. << "a=bundle-only attribute observed with a nonzero "
  105. "port; this usage is unspecified so the attribute is being "
  106. "ignored.";
  107. }
  108. } else {
  109. // If not using bundle-only, interpret port 0 in the normal way; the m=
  110. // section is being rejected.
  111. content_rejected = port_rejected;
  112. }
  113. ***
  114. for (size_t i = 0; i < session_extmaps.size(); ++i) {
  115. content->AddRtpHeaderExtension(session_extmaps[i]);
  116. }
  117. } else if (content->as_sctp()) {
  118. // Do nothing, it's OK
  119. } else {
  120. RTC_LOG(LS_WARNING) << "Parse failed with unknown protocol " << protocol;
  121. return false;
  122. }
  123. // Use the session level connection address if the media level addresses are
  124. // not specified.
  125. rtc::SocketAddress address;
  126. address = content->connection_address().IsNil()
  127. ? session_connection_addr
  128. : content->connection_address();
  129. address.SetPort(port);
  130. content->set_connection_address(address);
  131. desc->AddContent(content_name,
  132. cricket::IsDtlsSctp(protocol) ? MediaProtocolType::kSctp
  133. : MediaProtocolType::kRtp,
  134. content_rejected, bundle_only, std::move(content));
  135. // Create TransportInfo with the media level "ice-pwd" and "ice-ufrag".
  136. desc->AddTransportInfo(TransportInfo(content_name, transport));
  137. }
  138. desc->set_msid_signaling(msid_signaling);
  139. **
  140. return true;
  141. }

image.png
查看payload_types
image.png
后面以media_type == kMediaTypeAudio为例子,看音频类型的解析content
content = ParseContentDescription(
message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol,
payload_types, pos, &content_name, &bundle_only,
&section_msid_signaling, &transport, candidates, error);

ParseContentDescription

  1. template <class C>
  2. static std::unique_ptr<C> ParseContentDescription(
  3. const std::string& message,
  4. const cricket::MediaType media_type,
  5. int mline_index,
  6. const std::string& protocol,
  7. const std::vector<int>& payload_types,
  8. size_t* pos,
  9. std::string* content_name,
  10. bool* bundle_only,
  11. int* msid_signaling,
  12. TransportDescription* transport,
  13. std::vector<std::unique_ptr<JsepIceCandidate>>* candidates,
  14. webrtc::SdpParseError* error) {
  15. auto media_desc = std::make_unique<C>();
  16. media_desc->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
  17. if (!ParseContent(message, media_type, mline_index, protocol, payload_types,
  18. pos, content_name, bundle_only, msid_signaling,
  19. media_desc.get(), transport, candidates, error)) {
  20. return nullptr;
  21. }
  22. // Sort the codecs according to the m-line fmt list.
  23. std::unordered_map<int, int> payload_type_preferences;
  24. // "size + 1" so that the lowest preference payload type has a preference of
  25. // 1, which is greater than the default (0) for payload types not in the fmt
  26. // list.
  27. int preference = static_cast<int>(payload_types.size() + 1);
  28. for (int pt : payload_types) {
  29. payload_type_preferences[pt] = preference--;
  30. }
  31. std::vector<typename C::CodecType> codecs = media_desc->codecs();
  32. absl::c_sort(
  33. codecs, [&payload_type_preferences](const typename C::CodecType& a,
  34. const typename C::CodecType& b) {
  35. return payload_type_preferences[a.id] > payload_type_preferences[b.id];
  36. });
  37. media_desc->set_codecs(codecs);
  38. return media_desc;
  39. }

ParseContent

  1. bool ParseContent(const std::string& message,
  2. const cricket::MediaType media_type,
  3. int mline_index,
  4. const std::string& protocol,
  5. const std::vector<int>& payload_types,
  6. size_t* pos,
  7. std::string* content_name,
  8. bool* bundle_only,
  9. int* msid_signaling,
  10. MediaContentDescription* media_desc,
  11. TransportDescription* transport,
  12. std::vector<std::unique_ptr<JsepIceCandidate>>* candidates,
  13. SdpParseError* error) {
  14. RTC_DCHECK(media_desc != NULL);
  15. RTC_DCHECK(content_name != NULL);
  16. RTC_DCHECK(transport != NULL);
  17. if (media_type == cricket::MEDIA_TYPE_AUDIO) {
  18. MaybeCreateStaticPayloadAudioCodecs(payload_types, media_desc->as_audio());
  19. }
  20. // The media level "ice-ufrag" and "ice-pwd".
  21. // The candidates before update the media level "ice-pwd" and "ice-ufrag".
  22. Candidates candidates_orig;
  23. std::string line;
  24. std::string mline_id;
  25. // Tracks created out of the ssrc attributes.
  26. StreamParamsVec tracks;
  27. SsrcInfoVec ssrc_infos;
  28. SsrcGroupVec ssrc_groups;
  29. std::string maxptime_as_string;
  30. std::string ptime_as_string;
  31. std::vector<std::string> stream_ids;
  32. std::string track_id;
  33. SdpSerializer deserializer;
  34. std::vector<RidDescription> rids;
  35. SimulcastDescription simulcast;
  36. // Loop until the next m line
  37. // 循环直到下一个m行
  38. while (!IsLineType(message, kLineTypeMedia, *pos)) {
  39. ***
  40. }
  41. // Remove duplicate or inconsistent rids.
  42. RemoveInvalidRidDescriptions(payload_types, &rids);
  43. // If simulcast is specifed, split the rids into send and receive.
  44. // Rids that do not appear in simulcast attribute will be removed.
  45. // If it is not specified, we assume that all rids are for send layers.
  46. std::vector<RidDescription> send_rids;
  47. std::vector<RidDescription> receive_rids;
  48. if (!simulcast.empty()) {
  49. // Verify that the rids in simulcast match rids in sdp.
  50. RemoveInvalidRidsFromSimulcast(rids, &simulcast);
  51. // Use simulcast description to figure out Send / Receive RIDs.
  52. std::map<std::string, RidDescription> rid_map;
  53. for (const RidDescription& rid : rids) {
  54. rid_map[rid.rid] = rid;
  55. }
  56. for (const auto& layer : simulcast.send_layers().GetAllLayers()) {
  57. auto iter = rid_map.find(layer.rid);
  58. RTC_DCHECK(iter != rid_map.end());
  59. send_rids.push_back(iter->second);
  60. }
  61. for (const auto& layer : simulcast.receive_layers().GetAllLayers()) {
  62. auto iter = rid_map.find(layer.rid);
  63. RTC_DCHECK(iter != rid_map.end());
  64. receive_rids.push_back(iter->second);
  65. }
  66. media_desc->set_simulcast_description(simulcast);
  67. } else {
  68. send_rids = rids;
  69. }
  70. media_desc->set_receive_rids(receive_rids);
  71. // Create tracks from the |ssrc_infos|.
  72. // If the stream_id/track_id for all SSRCS are identical, one StreamParams
  73. // will be created in CreateTracksFromSsrcInfos, containing all the SSRCs from
  74. // the m= section.
  75. if (!ssrc_infos.empty()) {
  76. CreateTracksFromSsrcInfos(ssrc_infos, stream_ids, track_id, &tracks,
  77. *msid_signaling);
  78. } else if (media_type != cricket::MEDIA_TYPE_DATA &&
  79. (*msid_signaling & cricket::kMsidSignalingMediaSection)) {
  80. // If the stream_ids/track_id was signaled but SSRCs were unsignaled we
  81. // still create a track. This isn't done for data media types because
  82. // StreamParams aren't used for SCTP streams, and RTP data channels don't
  83. // support unsignaled SSRCs.
  84. CreateTrackWithNoSsrcs(stream_ids, track_id, send_rids, &tracks);
  85. }
  86. // Add the ssrc group to the track.
  87. for (const SsrcGroup& ssrc_group : ssrc_groups) {
  88. if (ssrc_group.ssrcs.empty()) {
  89. continue;
  90. }
  91. uint32_t ssrc = ssrc_group.ssrcs.front();
  92. for (StreamParams& track : tracks) {
  93. if (track.has_ssrc(ssrc)) {
  94. track.ssrc_groups.push_back(ssrc_group);
  95. }
  96. }
  97. }
  98. // Add the new tracks to the |media_desc|.
  99. for (StreamParams& track : tracks) {
  100. media_desc->AddStream(track);
  101. }
  102. if (media_type == cricket::MEDIA_TYPE_AUDIO) {
  103. AudioContentDescription* audio_desc = media_desc->as_audio();
  104. UpdateFromWildcardCodecs(audio_desc);
  105. // Verify audio codec ensures that no audio codec has been populated with
  106. // only fmtp.
  107. if (!VerifyAudioCodecs(audio_desc)) {
  108. return ParseFailed("Failed to parse audio codecs correctly.", error);
  109. }
  110. AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, audio_desc);
  111. AddAudioAttribute(kCodecParamPTime, ptime_as_string, audio_desc);
  112. }
  113. if (media_type == cricket::MEDIA_TYPE_VIDEO) {
  114. VideoContentDescription* video_desc = media_desc->as_video();
  115. UpdateFromWildcardCodecs(video_desc);
  116. // Verify video codec ensures that no video codec has been populated with
  117. // only rtcp-fb.
  118. if (!VerifyVideoCodecs(video_desc)) {
  119. return ParseFailed("Failed to parse video codecs correctly.", error);
  120. }
  121. }
  122. // RFC 5245
  123. // Update the candidates with the media level "ice-pwd" and "ice-ufrag".
  124. for (Candidate& candidate : candidates_orig) {
  125. RTC_DCHECK(candidate.username().empty() ||
  126. candidate.username() == transport->ice_ufrag);
  127. candidate.set_username(transport->ice_ufrag);
  128. RTC_DCHECK(candidate.password().empty());
  129. candidate.set_password(transport->ice_pwd);
  130. candidates->push_back(
  131. std::make_unique<JsepIceCandidate>(mline_id, mline_index, candidate));
  132. }
  133. return true;