Make CreateOffer/CreateAnswer return RTCErrorOr<SessionDescription>

BUG=webrtc:15499

Change-Id: I8b128fcd9a1114ae4625777a27f074a8314ef190
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/320720
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#40812}
This commit is contained in:
Philipp Hancke 2023-09-26 09:04:46 +02:00 committed by WebRTC LUCI CQ
parent 06fbe63cbf
commit 2bf1b99c6d
5 changed files with 755 additions and 646 deletions

View File

@ -43,6 +43,8 @@
namespace { namespace {
using rtc::UniqueRandomIdGenerator; using rtc::UniqueRandomIdGenerator;
using webrtc::RTCError;
using webrtc::RTCErrorType;
using webrtc::RtpTransceiverDirection; using webrtc::RtpTransceiverDirection;
const char kInline[] = "inline:"; const char kInline[] = "inline:";
@ -661,7 +663,7 @@ static std::vector<const ContentInfo*> GetActiveContents(
// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is // crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
// created (according to crypto_suites). The created content is added to the // created (according to crypto_suites). The created content is added to the
// offer. // offer.
static bool CreateContentOffer( static RTCError CreateContentOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const SecurePolicy& secure_policy, const SecurePolicy& secure_policy,
@ -701,18 +703,20 @@ static bool CreateContentOffer(
} }
if (offer->cryptos().empty()) { if (offer->cryptos().empty()) {
if (!CreateMediaCryptos(crypto_suites, offer)) { if (!CreateMediaCryptos(crypto_suites, offer)) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create crypto parameters");
} }
} }
} }
if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) { if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create crypto parameters");
} }
return true; return RTCError::OK();
} }
static bool CreateMediaContentOffer( static RTCError CreateMediaContentOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const std::vector<Codec>& codecs, const std::vector<Codec>& codecs,
@ -728,7 +732,8 @@ static bool CreateMediaContentOffer(
if (!AddStreamParams(media_description_options.sender_options, if (!AddStreamParams(media_description_options.sender_options,
session_options.rtcp_cname, ssrc_generator, session_options.rtcp_cname, ssrc_generator,
current_streams, offer, field_trials)) { current_streams, offer, field_trials)) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to add stream parameters");
} }
return CreateContentOffer(media_description_options, session_options, return CreateContentOffer(media_description_options, session_options,
@ -1666,7 +1671,8 @@ MediaSessionDescriptionFactory::filtered_rtp_header_extensions(
return extensions; return extensions;
} }
std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer( webrtc::RTCErrorOr<std::unique_ptr<SessionDescription>>
MediaSessionDescriptionFactory::CreateOfferOrError(
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const SessionDescription* current_description) const { const SessionDescription* current_description) const {
// Must have options for each existing section. // Must have options for each existing section.
@ -1712,43 +1718,37 @@ std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
IsMediaContentOfType(current_content, IsMediaContentOfType(current_content,
media_description_options.type)); media_description_options.type));
} }
RTCError error;
switch (media_description_options.type) { switch (media_description_options.type) {
case MEDIA_TYPE_AUDIO: case MEDIA_TYPE_AUDIO:
if (!AddAudioContentForOffer(media_description_options, session_options, error = AddAudioContentForOffer(
current_content, current_description, media_description_options, session_options, current_content,
extensions_with_ids.audio, current_description, extensions_with_ids.audio, offer_audio_codecs,
offer_audio_codecs, &current_streams, &current_streams, offer.get(), &ice_credentials);
offer.get(), &ice_credentials)) {
return nullptr;
}
break; break;
case MEDIA_TYPE_VIDEO: case MEDIA_TYPE_VIDEO:
if (!AddVideoContentForOffer(media_description_options, session_options, error = AddVideoContentForOffer(
current_content, current_description, media_description_options, session_options, current_content,
extensions_with_ids.video, current_description, extensions_with_ids.video, offer_video_codecs,
offer_video_codecs, &current_streams, &current_streams, offer.get(), &ice_credentials);
offer.get(), &ice_credentials)) {
return nullptr;
}
break; break;
case MEDIA_TYPE_DATA: case MEDIA_TYPE_DATA:
if (!AddDataContentForOffer(media_description_options, session_options, error = AddDataContentForOffer(media_description_options,
current_content, current_description, session_options, current_content,
&current_streams, offer.get(), current_description, &current_streams,
&ice_credentials)) { offer.get(), &ice_credentials);
return nullptr;
}
break; break;
case MEDIA_TYPE_UNSUPPORTED: case MEDIA_TYPE_UNSUPPORTED:
if (!AddUnsupportedContentForOffer( error = AddUnsupportedContentForOffer(
media_description_options, session_options, current_content, media_description_options, session_options, current_content,
current_description, offer.get(), &ice_credentials)) { current_description, offer.get(), &ice_credentials);
return nullptr;
}
break; break;
default: default:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
} }
if (!error.ok()) {
return error;
}
++msection_index; ++msection_index;
} }
@ -1770,14 +1770,14 @@ std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
if (!offer_bundle.content_names().empty()) { if (!offer_bundle.content_names().empty()) {
offer->AddGroup(offer_bundle); offer->AddGroup(offer_bundle);
if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) { if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
RTC_LOG(LS_ERROR) LOG_AND_RETURN_ERROR(
<< "CreateOffer failed to UpdateTransportInfoForBundle."; RTCErrorType::INTERNAL_ERROR,
return nullptr; "CreateOffer failed to UpdateTransportInfoForBundle");
} }
if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) { if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
RTC_LOG(LS_ERROR) LOG_AND_RETURN_ERROR(
<< "CreateOffer failed to UpdateCryptoParamsForBundle."; RTCErrorType::INTERNAL_ERROR,
return nullptr; "CreateOffer failed to UpdateCryptoParamsForBundle.");
} }
} }
} }
@ -1800,13 +1800,13 @@ std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
return offer; return offer;
} }
std::unique_ptr<SessionDescription> webrtc::RTCErrorOr<std::unique_ptr<SessionDescription>>
MediaSessionDescriptionFactory::CreateAnswer( MediaSessionDescriptionFactory::CreateAnswerOrError(
const SessionDescription* offer, const SessionDescription* offer,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const SessionDescription* current_description) const { const SessionDescription* current_description) const {
if (!offer) { if (!offer) {
return nullptr; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Called without offer.");
} }
// Must have options for exactly as many sections as in the offer. // Must have options for exactly as many sections as in the offer.
@ -1887,44 +1887,40 @@ MediaSessionDescriptionFactory::CreateAnswer(
RtpHeaderExtensions header_extensions = RtpHeaderExtensionsFromCapabilities( RtpHeaderExtensions header_extensions = RtpHeaderExtensionsFromCapabilities(
UnstoppedRtpHeaderExtensionCapabilities( UnstoppedRtpHeaderExtensionCapabilities(
media_description_options.header_extensions)); media_description_options.header_extensions));
RTCError error;
switch (media_description_options.type) { switch (media_description_options.type) {
case MEDIA_TYPE_AUDIO: case MEDIA_TYPE_AUDIO:
if (!AddAudioContentForAnswer( error = AddAudioContentForAnswer(
media_description_options, session_options, offer_content, media_description_options, session_options, offer_content, offer,
offer, current_content, current_description, bundle_transport, current_content, current_description, bundle_transport,
answer_audio_codecs, header_extensions, &current_streams, answer_audio_codecs, header_extensions, &current_streams,
answer.get(), &ice_credentials)) { answer.get(), &ice_credentials);
return nullptr;
}
break; break;
case MEDIA_TYPE_VIDEO: case MEDIA_TYPE_VIDEO:
if (!AddVideoContentForAnswer( error = AddVideoContentForAnswer(
media_description_options, session_options, offer_content, media_description_options, session_options, offer_content, offer,
offer, current_content, current_description, bundle_transport, current_content, current_description, bundle_transport,
answer_video_codecs, header_extensions, &current_streams, answer_video_codecs, header_extensions, &current_streams,
answer.get(), &ice_credentials)) { answer.get(), &ice_credentials);
return nullptr;
}
break; break;
case MEDIA_TYPE_DATA: case MEDIA_TYPE_DATA:
if (!AddDataContentForAnswer( error = AddDataContentForAnswer(
media_description_options, session_options, offer_content, media_description_options, session_options, offer_content, offer,
offer, current_content, current_description, bundle_transport, current_content, current_description, bundle_transport,
&current_streams, answer.get(), &ice_credentials)) { &current_streams, answer.get(), &ice_credentials);
return nullptr;
}
break; break;
case MEDIA_TYPE_UNSUPPORTED: case MEDIA_TYPE_UNSUPPORTED:
if (!AddUnsupportedContentForAnswer( error = AddUnsupportedContentForAnswer(
media_description_options, session_options, offer_content, media_description_options, session_options, offer_content, offer,
offer, current_content, current_description, bundle_transport, current_content, current_description, bundle_transport,
answer.get(), &ice_credentials)) { answer.get(), &ice_credentials);
return nullptr;
}
break; break;
default: default:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
} }
if (!error.ok()) {
return error;
}
++msection_index; ++msection_index;
// See if we can add the newly generated m= section to the BUNDLE group in // See if we can add the newly generated m= section to the BUNDLE group in
// the answer. // the answer.
@ -1953,15 +1949,15 @@ MediaSessionDescriptionFactory::CreateAnswer(
// Share the same ICE credentials and crypto params across all contents, // Share the same ICE credentials and crypto params across all contents,
// as BUNDLE requires. // as BUNDLE requires.
if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) { if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
RTC_LOG(LS_ERROR) LOG_AND_RETURN_ERROR(
<< "CreateAnswer failed to UpdateTransportInfoForBundle."; RTCErrorType::INTERNAL_ERROR,
return NULL; "CreateAnswer failed to UpdateTransportInfoForBundle.");
} }
if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) { if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
RTC_LOG(LS_ERROR) LOG_AND_RETURN_ERROR(
<< "CreateAnswer failed to UpdateCryptoParamsForBundle."; RTCErrorType::INTERNAL_ERROR,
return NULL; "CreateAnswer failed to UpdateCryptoParamsForBundle.");
} }
} }
} }
@ -2249,14 +2245,16 @@ MediaSessionDescriptionFactory::GetOfferedRtpHeaderExtensionsWithIds(
return offered_extensions; return offered_extensions;
} }
bool MediaSessionDescriptionFactory::AddTransportOffer( RTCError MediaSessionDescriptionFactory::AddTransportOffer(
const std::string& content_name, const std::string& content_name,
const TransportOptions& transport_options, const TransportOptions& transport_options,
const SessionDescription* current_desc, const SessionDescription* current_desc,
SessionDescription* offer_desc, SessionDescription* offer_desc,
IceCredentialsIterator* ice_credentials) const { IceCredentialsIterator* ice_credentials) const {
if (!transport_desc_factory_) if (!transport_desc_factory_) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Missing transport description factory");
}
const TransportDescription* current_tdesc = const TransportDescription* current_tdesc =
GetTransportDescription(content_name, current_desc); GetTransportDescription(content_name, current_desc);
std::unique_ptr<TransportDescription> new_tdesc( std::unique_ptr<TransportDescription> new_tdesc(
@ -2267,7 +2265,7 @@ bool MediaSessionDescriptionFactory::AddTransportOffer(
<< content_name; << content_name;
} }
offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)); offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
return true; return RTCError::OK();
} }
std::unique_ptr<TransportDescription> std::unique_ptr<TransportDescription>
@ -2278,8 +2276,9 @@ MediaSessionDescriptionFactory::CreateTransportAnswer(
const SessionDescription* current_desc, const SessionDescription* current_desc,
bool require_transport_attributes, bool require_transport_attributes,
IceCredentialsIterator* ice_credentials) const { IceCredentialsIterator* ice_credentials) const {
if (!transport_desc_factory_) if (!transport_desc_factory_) {
return NULL; return nullptr;
}
const TransportDescription* offer_tdesc = const TransportDescription* offer_tdesc =
GetTransportDescription(content_name, offer_desc); GetTransportDescription(content_name, offer_desc);
const TransportDescription* current_tdesc = const TransportDescription* current_tdesc =
@ -2289,12 +2288,12 @@ MediaSessionDescriptionFactory::CreateTransportAnswer(
current_tdesc, ice_credentials); current_tdesc, ice_credentials);
} }
bool MediaSessionDescriptionFactory::AddTransportAnswer( RTCError MediaSessionDescriptionFactory::AddTransportAnswer(
const std::string& content_name, const std::string& content_name,
const TransportDescription& transport_desc, const TransportDescription& transport_desc,
SessionDescription* answer_desc) const { SessionDescription* answer_desc) const {
answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc)); answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
return true; return RTCError::OK();
} }
// `audio_codecs` = set of all possible codecs that can be used, with correct // `audio_codecs` = set of all possible codecs that can be used, with correct
@ -2309,7 +2308,7 @@ bool MediaSessionDescriptionFactory::AddTransportAnswer(
// from acd->codecs() and then supported_codecs, to ensure that re-offers don't // from acd->codecs() and then supported_codecs, to ensure that re-offers don't
// change existing codec priority, and that new codecs are added with the right // change existing codec priority, and that new codecs are added with the right
// priority. // priority.
bool MediaSessionDescriptionFactory::AddAudioContentForOffer( RTCError MediaSessionDescriptionFactory::AddAudioContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -2342,10 +2341,10 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) { if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) {
// TODO(bugs.webrtc.org/15471): add a unit test for this since // TODO(bugs.webrtc.org/15471): add a unit test for this since
// it is not clear how this can happen for offers. // it is not clear how this can happen for offers.
RTC_LOG(LS_ERROR) << "Media type for content with mid='" LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
<< current_content->name "Media type for content with mid='" +
<< "' does not match previous type."; current_content->name +
return false; "' does not match previous type.");
} }
const AudioContentDescription* acd = const AudioContentDescription* acd =
current_content->media_description()->as_audio(); current_content->media_description()->as_audio();
@ -2383,12 +2382,13 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
std::vector<std::string> crypto_suites; std::vector<std::string> crypto_suites;
GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options, GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
&crypto_suites); &crypto_suites);
if (!CreateMediaContentOffer( auto error = CreateMediaContentOffer(
media_description_options, session_options, filtered_codecs, media_description_options, session_options, filtered_codecs, sdes_policy,
sdes_policy, GetCryptos(current_content), crypto_suites, GetCryptos(current_content), crypto_suites, audio_rtp_extensions,
audio_rtp_extensions, ssrc_generator(), current_streams, audio.get(), ssrc_generator(), current_streams, audio.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials());
return false; if (!error.ok()) {
return error;
} }
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
@ -2398,18 +2398,19 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
media_description_options.stopped, std::move(audio)); media_description_options.stopped, std::move(audio));
if (!AddTransportOffer(media_description_options.mid, error = AddTransportOffer(media_description_options.mid,
media_description_options.transport_options, media_description_options.transport_options,
current_description, desc, ice_credentials)) { current_description, desc, ice_credentials);
return false; if (!error.ok()) {
return error;
} }
return true; return RTCError::OK();
} }
// TODO(kron): This function is very similar to AddAudioContentForOffer. // TODO(kron): This function is very similar to AddAudioContentForOffer.
// Refactor to reuse shared code. // Refactor to reuse shared code.
bool MediaSessionDescriptionFactory::AddVideoContentForOffer( RTCError MediaSessionDescriptionFactory::AddVideoContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -2442,10 +2443,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) { if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) {
// TODO(bugs.webrtc.org/15471): add a unit test for this since // TODO(bugs.webrtc.org/15471): add a unit test for this since
// it is not clear how this can happen for offers. // it is not clear how this can happen for offers.
RTC_LOG(LS_ERROR) << "Media type for content with mid='" LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
<< current_content->name "Media type for content with mid='" +
<< "' does not match previous type."; current_content->name +
return false; "' does not match previous type.");
} }
const VideoContentDescription* vcd = const VideoContentDescription* vcd =
@ -2503,12 +2504,13 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
std::vector<std::string> crypto_suites; std::vector<std::string> crypto_suites;
GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options, GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
&crypto_suites); &crypto_suites);
if (!CreateMediaContentOffer( auto error = CreateMediaContentOffer(
media_description_options, session_options, filtered_codecs, media_description_options, session_options, filtered_codecs, sdes_policy,
sdes_policy, GetCryptos(current_content), crypto_suites, GetCryptos(current_content), crypto_suites, video_rtp_extensions,
video_rtp_extensions, ssrc_generator(), current_streams, video.get(), ssrc_generator(), current_streams, video.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials());
return false; if (!error.ok()) {
return error;
} }
video->set_bandwidth(kAutoBandwidth); video->set_bandwidth(kAutoBandwidth);
@ -2520,16 +2522,12 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp, desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
media_description_options.stopped, std::move(video)); media_description_options.stopped, std::move(video));
if (!AddTransportOffer(media_description_options.mid, return AddTransportOffer(media_description_options.mid,
media_description_options.transport_options, media_description_options.transport_options,
current_description, desc, ice_credentials)) { current_description, desc, ice_credentials);
return false;
}
return true;
} }
bool MediaSessionDescriptionFactory::AddDataContentForOffer( RTCError MediaSessionDescriptionFactory::AddDataContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -2557,24 +2555,22 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer(
data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp); data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
data->set_max_message_size(kSctpSendBufferSize); data->set_max_message_size(kSctpSendBufferSize);
if (!CreateContentOffer(media_description_options, session_options, auto error = CreateContentOffer(
sdes_policy, GetCryptos(current_content), media_description_options, session_options, sdes_policy,
crypto_suites, RtpHeaderExtensions(), GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
ssrc_generator(), current_streams, data.get())) { ssrc_generator(), current_streams, data.get());
return false; if (!error.ok()) {
return error;
} }
desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp, desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
media_description_options.stopped, std::move(data)); media_description_options.stopped, std::move(data));
if (!AddTransportOffer(media_description_options.mid, return AddTransportOffer(media_description_options.mid,
media_description_options.transport_options, media_description_options.transport_options,
current_description, desc, ice_credentials)) { current_description, desc, ice_credentials);
return false;
}
return true;
} }
bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer( RTCError MediaSessionDescriptionFactory::AddUnsupportedContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -2591,12 +2587,9 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer(
desc->AddContent(media_description_options.mid, MediaProtocolType::kOther, desc->AddContent(media_description_options.mid, MediaProtocolType::kOther,
/*rejected=*/true, std::move(unsupported)); /*rejected=*/true, std::move(unsupported));
if (!AddTransportOffer(media_description_options.mid, return AddTransportOffer(media_description_options.mid,
media_description_options.transport_options, media_description_options.transport_options,
current_description, desc, ice_credentials)) { current_description, desc, ice_credentials);
return false;
}
return true;
} }
// `audio_codecs` = set of all possible codecs that can be used, with correct // `audio_codecs` = set of all possible codecs that can be used, with correct
@ -2611,7 +2604,7 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer(
// from acd->codecs() and then supported_codecs, to ensure that re-offers don't // from acd->codecs() and then supported_codecs, to ensure that re-offers don't
// change existing codec priority, and that new codecs are added with the right // change existing codec priority, and that new codecs are added with the right
// priority. // priority.
bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( RTCError MediaSessionDescriptionFactory::AddAudioContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -2635,7 +2628,9 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
media_description_options.transport_options, current_description, media_description_options.transport_options, current_description,
bundle_transport != nullptr, ice_credentials); bundle_transport != nullptr, ice_credentials);
if (!audio_transport) { if (!audio_transport) {
return false; LOG_AND_RETURN_ERROR(
RTCErrorType::INTERNAL_ERROR,
"Failed to create transport answer, audio transport is missing");
} }
// Pick codecs based on the requested communications direction in the offer // Pick codecs based on the requested communications direction in the offer
@ -2660,10 +2655,10 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
current_content->name == media_description_options.mid) { current_content->name == media_description_options.mid) {
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) { if (!IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO)) {
// Can happen if the remote side re-uses a MID while recycling. // Can happen if the remote side re-uses a MID while recycling.
RTC_LOG(LS_ERROR) << "Media type for content with mid='" LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
<< current_content->name "Media type for content with mid='" +
<< "' does not match previous type."; current_content->name +
return false; "' does not match previous type.");
} }
const AudioContentDescription* acd = const AudioContentDescription* acd =
current_content->media_description()->as_audio(); current_content->media_description()->as_audio();
@ -2708,7 +2703,8 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
media_description_options, session_options, media_description_options, session_options,
ssrc_generator(), current_streams, audio_answer.get(), ssrc_generator(), current_streams, audio_answer.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to set codecs in answer");
} }
if (!CreateMediaContentAnswer( if (!CreateMediaContentAnswer(
offer_audio_description, media_description_options, session_options, offer_audio_description, media_description_options, session_options,
@ -2716,7 +2712,8 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
filtered_rtp_header_extensions(rtp_header_extensions), filtered_rtp_header_extensions(rtp_header_extensions),
ssrc_generator(), enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, audio_answer.get())) { current_streams, bundle_enabled, audio_answer.get())) {
return false; // Fails the session setup. LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create answer");
} }
bool secure = bundle_transport ? bundle_transport->description.secure() bool secure = bundle_transport ? bundle_transport->description.secure()
@ -2725,9 +2722,10 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
offer_content->rejected || !has_common_media_codecs || offer_content->rejected || !has_common_media_codecs ||
!IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
audio_answer->protocol(), secure); audio_answer->protocol(), secure);
if (!AddTransportAnswer(media_description_options.mid, auto error = AddTransportAnswer(media_description_options.mid,
*(audio_transport.get()), answer)) { *(audio_transport.get()), answer);
return false; if (!error.ok()) {
return error;
} }
if (rejected) { if (rejected) {
@ -2737,12 +2735,12 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
answer->AddContent(media_description_options.mid, offer_content->type, answer->AddContent(media_description_options.mid, offer_content->type,
rejected, std::move(audio_answer)); rejected, std::move(audio_answer));
return true; return RTCError::OK();
} }
// TODO(kron): This function is very similar to AddAudioContentForAnswer. // TODO(kron): This function is very similar to AddAudioContentForAnswer.
// Refactor to reuse shared code. // Refactor to reuse shared code.
bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( RTCError MediaSessionDescriptionFactory::AddVideoContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -2766,7 +2764,9 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
media_description_options.transport_options, current_description, media_description_options.transport_options, current_description,
bundle_transport != nullptr, ice_credentials); bundle_transport != nullptr, ice_credentials);
if (!video_transport) { if (!video_transport) {
return false; LOG_AND_RETURN_ERROR(
RTCErrorType::INTERNAL_ERROR,
"Failed to create transport answer, video transport is missing");
} }
// Pick codecs based on the requested communications direction in the offer // Pick codecs based on the requested communications direction in the offer
@ -2791,10 +2791,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
current_content->name == media_description_options.mid) { current_content->name == media_description_options.mid) {
if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) { if (!IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO)) {
// Can happen if the remote side re-uses a MID while recycling. // Can happen if the remote side re-uses a MID while recycling.
RTC_LOG(LS_ERROR) << "Media type for content with mid='" LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
<< current_content->name "Media type for content with mid='" +
<< "' does not match previous type."; current_content->name +
return false; "' does not match previous type.");
} }
const VideoContentDescription* vcd = const VideoContentDescription* vcd =
current_content->media_description()->as_video(); current_content->media_description()->as_video();
@ -2849,7 +2849,8 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
media_description_options, session_options, media_description_options, session_options,
ssrc_generator(), current_streams, video_answer.get(), ssrc_generator(), current_streams, video_answer.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to set codecs in answer");
} }
if (!CreateMediaContentAnswer( if (!CreateMediaContentAnswer(
offer_video_description, media_description_options, session_options, offer_video_description, media_description_options, session_options,
@ -2857,7 +2858,8 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
filtered_rtp_header_extensions(default_video_rtp_header_extensions), filtered_rtp_header_extensions(default_video_rtp_header_extensions),
ssrc_generator(), enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, video_answer.get())) { current_streams, bundle_enabled, video_answer.get())) {
return false; // Failed the session setup. LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create answer");
} }
bool secure = bundle_transport ? bundle_transport->description.secure() bool secure = bundle_transport ? bundle_transport->description.secure()
: video_transport->secure(); : video_transport->secure();
@ -2865,9 +2867,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
offer_content->rejected || !has_common_media_codecs || offer_content->rejected || !has_common_media_codecs ||
!IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
video_answer->protocol(), secure); video_answer->protocol(), secure);
if (!AddTransportAnswer(media_description_options.mid, auto error = AddTransportAnswer(media_description_options.mid,
*(video_transport.get()), answer)) { *(video_transport.get()), answer);
return false; if (!error.ok()) {
return error;
} }
if (!rejected) { if (!rejected) {
@ -2878,10 +2881,10 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
} }
answer->AddContent(media_description_options.mid, offer_content->type, answer->AddContent(media_description_options.mid, offer_content->type,
rejected, std::move(video_answer)); rejected, std::move(video_answer));
return true; return RTCError::OK();
} }
bool MediaSessionDescriptionFactory::AddDataContentForAnswer( RTCError MediaSessionDescriptionFactory::AddDataContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -2897,7 +2900,9 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
media_description_options.transport_options, current_description, media_description_options.transport_options, current_description,
bundle_transport != nullptr, ice_credentials); bundle_transport != nullptr, ice_credentials);
if (!data_transport) { if (!data_transport) {
return false; LOG_AND_RETURN_ERROR(
RTCErrorType::INTERNAL_ERROR,
"Failed to create transport answer, data transport is missing");
} }
// Do not require or create SDES cryptos if DTLS is used. // Do not require or create SDES cryptos if DTLS is used.
@ -2930,7 +2935,8 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
ssrc_generator(), enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, data_answer.get())) { current_streams, bundle_enabled, data_answer.get())) {
return false; // Fails the session setup. LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create answer");
} }
// Respond with sctpmap if the offer uses sctpmap. // Respond with sctpmap if the offer uses sctpmap.
bool offer_uses_sctpmap = offer_data_description->use_sctpmap(); bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
@ -2946,17 +2952,17 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
offer_content->rejected || offer_content->rejected ||
!IsMediaProtocolSupported(MEDIA_TYPE_DATA, !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
data_answer->protocol(), secure); data_answer->protocol(), secure);
if (!AddTransportAnswer(media_description_options.mid, auto error = AddTransportAnswer(media_description_options.mid,
*(data_transport.get()), answer)) { *(data_transport.get()), answer);
return false; if (!error.ok()) {
return error;
} }
answer->AddContent(media_description_options.mid, offer_content->type, answer->AddContent(media_description_options.mid, offer_content->type,
rejected, std::move(data_answer)); rejected, std::move(data_answer));
return true; return RTCError::OK();
} }
bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer( RTCError MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -2972,7 +2978,9 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer(
current_description, bundle_transport != nullptr, current_description, bundle_transport != nullptr,
ice_credentials); ice_credentials);
if (!unsupported_transport) { if (!unsupported_transport) {
return false; LOG_AND_RETURN_ERROR(
RTCErrorType::INTERNAL_ERROR,
"Failed to create transport answer, unsupported transport is missing");
} }
RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_UNSUPPORTED)); RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_UNSUPPORTED));
@ -2983,13 +2991,15 @@ bool MediaSessionDescriptionFactory::AddUnsupportedContentForAnswer(
offer_unsupported_description->media_type()); offer_unsupported_description->media_type());
unsupported_answer->set_protocol(offer_unsupported_description->protocol()); unsupported_answer->set_protocol(offer_unsupported_description->protocol());
if (!AddTransportAnswer(media_description_options.mid, auto error = AddTransportAnswer(media_description_options.mid,
*(unsupported_transport.get()), answer)) { *(unsupported_transport.get()), answer);
return false; if (!error.ok()) {
return error;
} }
answer->AddContent(media_description_options.mid, offer_content->type, answer->AddContent(media_description_options.mid, offer_content->type,
/*rejected=*/true, std::move(unsupported_answer)); /*rejected=*/true, std::move(unsupported_answer));
return true; return RTCError::OK();
} }
void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() { void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {

View File

@ -177,10 +177,10 @@ class MediaSessionDescriptionFactory {
is_unified_plan_ = is_unified_plan; is_unified_plan_ = is_unified_plan;
} }
std::unique_ptr<SessionDescription> CreateOffer( webrtc::RTCErrorOr<std::unique_ptr<SessionDescription>> CreateOfferOrError(
const MediaSessionOptions& options, const MediaSessionOptions& options,
const SessionDescription* current_description) const; const SessionDescription* current_description) const;
std::unique_ptr<SessionDescription> CreateAnswer( webrtc::RTCErrorOr<std::unique_ptr<SessionDescription>> CreateAnswerOrError(
const SessionDescription* offer, const SessionDescription* offer,
const MediaSessionOptions& options, const MediaSessionOptions& options,
const SessionDescription* current_description) const; const SessionDescription* current_description) const;
@ -215,11 +215,12 @@ class MediaSessionDescriptionFactory {
bool extmap_allow_mixed, bool extmap_allow_mixed,
const std::vector<MediaDescriptionOptions>& media_description_options) const std::vector<MediaDescriptionOptions>& media_description_options)
const; const;
bool AddTransportOffer(const std::string& content_name, webrtc::RTCError AddTransportOffer(
const TransportOptions& transport_options, const std::string& content_name,
const SessionDescription* current_desc, const TransportOptions& transport_options,
SessionDescription* offer, const SessionDescription* current_desc,
IceCredentialsIterator* ice_credentials) const; SessionDescription* offer,
IceCredentialsIterator* ice_credentials) const;
std::unique_ptr<TransportDescription> CreateTransportAnswer( std::unique_ptr<TransportDescription> CreateTransportAnswer(
const std::string& content_name, const std::string& content_name,
@ -229,15 +230,16 @@ class MediaSessionDescriptionFactory {
bool require_transport_attributes, bool require_transport_attributes,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddTransportAnswer(const std::string& content_name, webrtc::RTCError AddTransportAnswer(
const TransportDescription& transport_desc, const std::string& content_name,
SessionDescription* answer_desc) const; const TransportDescription& transport_desc,
SessionDescription* answer_desc) const;
// Helpers for adding media contents to the SessionDescription. Returns true // Helpers for adding media contents to the SessionDescription. Returns true
// it succeeds or the media content is not needed, or false if there is any // it succeeds or the media content is not needed, or false if there is any
// error. // error.
bool AddAudioContentForOffer( webrtc::RTCError AddAudioContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -248,7 +250,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* desc, SessionDescription* desc,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddVideoContentForOffer( webrtc::RTCError AddVideoContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -259,7 +261,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* desc, SessionDescription* desc,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddDataContentForOffer( webrtc::RTCError AddDataContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -268,7 +270,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* desc, SessionDescription* desc,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddUnsupportedContentForOffer( webrtc::RTCError AddUnsupportedContentForOffer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* current_content, const ContentInfo* current_content,
@ -276,7 +278,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* desc, SessionDescription* desc,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddAudioContentForAnswer( webrtc::RTCError AddAudioContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -290,7 +292,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* answer, SessionDescription* answer,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddVideoContentForAnswer( webrtc::RTCError AddVideoContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -304,7 +306,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* answer, SessionDescription* answer,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddDataContentForAnswer( webrtc::RTCError AddDataContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,
@ -316,7 +318,7 @@ class MediaSessionDescriptionFactory {
SessionDescription* answer, SessionDescription* answer,
IceCredentialsIterator* ice_credentials) const; IceCredentialsIterator* ice_credentials) const;
bool AddUnsupportedContentForAnswer( webrtc::RTCError AddUnsupportedContentForAnswer(
const MediaDescriptionOptions& media_description_options, const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options, const MediaSessionOptions& session_options,
const ContentInfo* offer_content, const ContentInfo* offer_content,

File diff suppressed because it is too large Load Diff

View File

@ -280,17 +280,16 @@ void WebRtcSessionDescriptionFactory::InternalCreateOffer(
} }
} }
std::unique_ptr<cricket::SessionDescription> desc = auto result = session_desc_factory_.CreateOfferOrError(
session_desc_factory_.CreateOffer( request.options, sdp_info_->local_description()
request.options, sdp_info_->local_description() ? sdp_info_->local_description()->description()
? sdp_info_->local_description()->description() : nullptr);
: nullptr); if (!result.ok()) {
if (!desc) { PostCreateSessionDescriptionFailed(request.observer.get(), result.error());
PostCreateSessionDescriptionFailed(
request.observer.get(), RTCError(RTCErrorType::INTERNAL_ERROR,
"Failed to initialize the offer."));
return; return;
} }
std::unique_ptr<cricket::SessionDescription> desc = std::move(result.value());
RTC_CHECK(desc);
// RFC 3264 // RFC 3264
// When issuing an offer that modifies the session, // When issuing an offer that modifies the session,
@ -339,21 +338,20 @@ void WebRtcSessionDescriptionFactory::InternalCreateAnswer(
} }
} }
std::unique_ptr<cricket::SessionDescription> desc = auto result = session_desc_factory_.CreateAnswerOrError(
session_desc_factory_.CreateAnswer( sdp_info_->remote_description()
sdp_info_->remote_description() ? sdp_info_->remote_description()->description()
? sdp_info_->remote_description()->description() : nullptr,
: nullptr, request.options,
request.options, sdp_info_->local_description()
sdp_info_->local_description() ? sdp_info_->local_description()->description()
? sdp_info_->local_description()->description() : nullptr);
: nullptr); if (!result.ok()) {
if (!desc) { PostCreateSessionDescriptionFailed(request.observer.get(), result.error());
PostCreateSessionDescriptionFailed(
request.observer.get(), RTCError(RTCErrorType::INTERNAL_ERROR,
"Failed to initialize the answer."));
return; return;
} }
std::unique_ptr<cricket::SessionDescription> desc = std::move(result.value());
RTC_CHECK(desc);
// RFC 3264 // RFC 3264
// If the answer is different from the offer in any way (different IP // If the answer is different from the offer in any way (different IP

View File

@ -74,8 +74,6 @@ char kLSanDefaultSuppressions[] =
// peerconnection_unittests // peerconnection_unittests
// https://code.google.com/p/webrtc/issues/detail?id=2528 // https://code.google.com/p/webrtc/issues/detail?id=2528
"leak:cricket::FakeVideoMediaChannel::~FakeVideoMediaChannel\n" "leak:cricket::FakeVideoMediaChannel::~FakeVideoMediaChannel\n"
"leak:cricket::MediaSessionDescriptionFactory::CreateAnswer\n"
"leak:cricket::MediaSessionDescriptionFactory::CreateOffer\n"
"leak:DtmfSenderTest_InsertEmptyTonesToCancelPreviousTask_Test::TestBody\n" "leak:DtmfSenderTest_InsertEmptyTonesToCancelPreviousTask_Test::TestBody\n"
"leak:sigslot::_signal_base2*::~_signal_base2\n" "leak:sigslot::_signal_base2*::~_signal_base2\n"
"leak:testing::internal::CmpHelperEQ\n" "leak:testing::internal::CmpHelperEQ\n"
@ -83,8 +81,6 @@ char kLSanDefaultSuppressions[] =
"leak:webrtc::AudioDeviceLinuxALSA::InitSpeaker\n" "leak:webrtc::AudioDeviceLinuxALSA::InitSpeaker\n"
"leak:webrtc::CreateIceCandidate\n" "leak:webrtc::CreateIceCandidate\n"
"leak:webrtc::WebRtcIdentityRequestObserver::OnSuccess\n" "leak:webrtc::WebRtcIdentityRequestObserver::OnSuccess\n"
"leak:webrtc::WebRtcSessionDescriptionFactory::InternalCreateAnswer\n"
"leak:webrtc::WebRtcSessionDescriptionFactory::InternalCreateOffer\n"
"leak:PeerConnectionInterfaceTest_SsrcInOfferAnswer_Test::TestBody\n" "leak:PeerConnectionInterfaceTest_SsrcInOfferAnswer_Test::TestBody\n"
"leak:PeerConnectionInterfaceTest_CloseAndTestMethods_Test::TestBody\n" "leak:PeerConnectionInterfaceTest_CloseAndTestMethods_Test::TestBody\n"
"leak:WebRtcSdpTest::TestDeserializeRtcpFb\n" "leak:WebRtcSdpTest::TestDeserializeRtcpFb\n"