--- a/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
+++ b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h
@@ -125,24 +125,72 @@ class JsepAudioCodecDescription : public
uint32_t clock,
uint32_t channels,
uint32_t packetSize,
uint32_t bitRate,
bool enabled = true)
: JsepCodecDescription(mozilla::SdpMediaSection::kAudio, defaultPt, name,
clock, channels, enabled),
mPacketSize(packetSize),
- mBitrate(bitRate)
+ mBitrate(bitRate),
+ mMaxPlaybackRate(0)
{
}
JSEP_CODEC_CLONE(JsepAudioCodecDescription)
+ SdpFmtpAttributeList::OpusParameters
+ GetOpusParameters(const std::string& pt,
+ const SdpMediaSection& msection) const
+ {
+ // Will contain defaults if nothing else
+ SdpFmtpAttributeList::OpusParameters result;
+ auto* params = msection.FindFmtp(pt);
+
+ if (params && params->codec_type == SdpRtpmapAttributeList::kOpus) {
+ result =
+ static_cast<const SdpFmtpAttributeList::OpusParameters&>(*params);
+ }
+
+ return result;
+ }
+
+ void
+ AddParametersToMSection(SdpMediaSection& msection) const override
+ {
+ if (mDirection == sdp::kSend) {
+ return;
+ }
+
+ if (mName == "opus" && mMaxPlaybackRate) {
+ SdpFmtpAttributeList::OpusParameters opusParams(
+ GetOpusParameters(mDefaultPt, msection));
+ opusParams.maxplaybackrate = mMaxPlaybackRate;
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, opusParams));
+ }
+ }
+
+ bool
+ Negotiate(const std::string& pt,
+ const SdpMediaSection& remoteMsection) override
+ {
+ JsepCodecDescription::Negotiate(pt, remoteMsection);
+ if (mName == "opus" && mDirection == sdp::kSend) {
+ SdpFmtpAttributeList::OpusParameters opusParams(
+ GetOpusParameters(mDefaultPt, remoteMsection));
+
+ mMaxPlaybackRate = opusParams.maxplaybackrate;
+ }
+
+ return true;
+ }
+
uint32_t mPacketSize;
uint32_t mBitrate;
+ uint32_t mMaxPlaybackRate;
};
class JsepVideoCodecDescription : public JsepCodecDescription {
public:
JsepVideoCodecDescription(const std::string& defaultPt,
const std::string& name,
uint32_t clock,
bool enabled = true)
@@ -195,28 +243,26 @@ class JsepVideoCodecDescription : public
h264Params.profile_level_id = mProfileLevelId;
}
// Parameters that apply to both the send and recv directions
h264Params.packetization_mode = mPacketizationMode;
// Hard-coded, may need to change someday?
h264Params.level_asymmetry_allowed = true;
- msection.SetFmtp(
- SdpFmtpAttributeList::Fmtp(mDefaultPt, "", h264Params));
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, h264Params));
} else if (mName == "VP8" || mName == "VP9") {
if (mDirection == sdp::kRecv) {
// VP8 and VP9 share the same SDP parameters thus far
SdpFmtpAttributeList::VP8Parameters vp8Params(
GetVP8Parameters(mDefaultPt, msection));
vp8Params.max_fs = mConstraints.maxFs;
vp8Params.max_fr = mConstraints.maxFps;
- msection.SetFmtp(
- SdpFmtpAttributeList::Fmtp(mDefaultPt, "", vp8Params));
+ msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, vp8Params));
}
}
}
void
AddRtcpFbsToMSection(SdpMediaSection& msection) const
{
SdpRtcpFbAttributeList rtcpfbs(msection.GetRtcpFbs());
--- a/media/webrtc/signaling/src/jsep/JsepTrack.h
+++ b/media/webrtc/signaling/src/jsep/JsepTrack.h
@@ -136,24 +136,24 @@ public:
{
mSsrcs.push_back(ssrc);
}
virtual void PopulateCodecs(
const std::vector<JsepCodecDescription*>& prototype);
template <class UnaryFunction>
- void ForEachCodec(UnaryFunction& func)
+ void ForEachCodec(UnaryFunction func)
{
std::for_each(mPrototypeCodecs.values.begin(),
mPrototypeCodecs.values.end(), func);
}
template <class BinaryPredicate>
- void SortCodecs(BinaryPredicate& sorter)
+ void SortCodecs(BinaryPredicate sorter)
{
std::stable_sort(mPrototypeCodecs.values.begin(),
mPrototypeCodecs.values.end(), sorter);
}
virtual void AddToOffer(SdpMediaSection* offer) const;
virtual void AddToAnswer(const SdpMediaSection& offer,
SdpMediaSection* answer) const;
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -407,16 +407,26 @@ WebrtcAudioConduit::ConfigureSendMediaCo
CSFLogError(logTag, "%s Invalid Send Codec", __FUNCTION__);
return kMediaConduitInvalidSendCodec;
}
CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
mPtrVoEBase->LastError());
return kMediaConduitUnknownError;
}
+ if (codecConfig->mName == "opus" && codecConfig->mMaxPlaybackRate) {
+ if (mPtrVoECodec->SetOpusMaxPlaybackRate(
+ mChannel,
+ codecConfig->mMaxPlaybackRate) == -1) {
+ CSFLogError(logTag, "%s SetOpusMaxPlaybackRate Failed %d ", __FUNCTION__,
+ mPtrVoEBase->LastError());
+ return kMediaConduitUnknownError;
+ }
+ }
+
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
// TEMPORARY - see bug 694814 comment 2
nsresult rv;
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
if (branch) {
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -24,29 +24,32 @@ struct AudioCodecConfig
*/
int mType;
std::string mName;
int mFreq;
int mPacSize;
int mChannels;
int mRate;
+ // OPUS-specific
+ int mMaxPlaybackRate;
+
/* Default constructor is not provided since as a consumer, we
* can't decide the default configuration for the codec
*/
explicit AudioCodecConfig(int type, std::string name,
int freq,int pacSize,
int channels, int rate)
: mType(type),
mName(name),
mFreq(freq),
mPacSize(pacSize),
mChannels(channels),
- mRate(rate)
-
+ mRate(rate),
+ mMaxPlaybackRate(0)
{
}
};
/*
* Minimalistic video codec configuration
* More to be added later depending on the use-case
*/
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -69,16 +69,17 @@ JsepCodecDescToCodecConfig(const JsepCod
}
*aConfig = new AudioCodecConfig(pt,
desc.mName,
desc.mClock,
desc.mPacketSize,
desc.mChannels,
desc.mBitrate);
+ (*aConfig)->mMaxPlaybackRate = desc.mMaxPlaybackRate;
return NS_OK;
}
static std::vector<JsepCodecDescription*>
GetCodecs(const JsepTrackNegotiatedDetails& aDetails)
{
// We do not try to handle cases where a codec is not used on the primary
--- a/media/webrtc/signaling/src/sdp/SdpAttribute.cpp
+++ b/media/webrtc/signaling/src/sdp/SdpAttribute.cpp
@@ -108,23 +108,21 @@ SdpFingerprintAttributeList::ParseFinger
}
return fp;
}
void
SdpFmtpAttributeList::Serialize(std::ostream& os) const
{
for (auto i = mFmtps.begin(); i != mFmtps.end(); ++i) {
- os << "a=" << mType << ":" << i->format << " ";
if (i->parameters) {
+ os << "a=" << mType << ":" << i->format << " ";
i->parameters->Serialize(os);
- } else {
- os << i->parameters_string;
+ os << CRLF;
}
- os << CRLF;
}
}
void
SdpGroupAttributeList::Serialize(std::ostream& os) const
{
for (auto i = mGroups.begin(); i != mGroups.end(); ++i) {
os << "a=" << mType << ":" << i->semantics;
--- a/media/webrtc/signaling/src/sdp/SdpAttribute.h
+++ b/media/webrtc/signaling/src/sdp/SdpAttribute.h
@@ -1231,70 +1231,84 @@ public:
os << "max-fs=" << max_fs;
os << ";max-fr=" << max_fr;
}
unsigned int max_fs;
unsigned int max_fr;
};
+ class OpusParameters : public Parameters
+ {
+ public:
+ enum { kDefaultMaxPlaybackRate = 48000 };
+ OpusParameters() :
+ Parameters(SdpRtpmapAttributeList::kOpus),
+ maxplaybackrate(kDefaultMaxPlaybackRate)
+ {}
+
+ Parameters*
+ Clone() const override
+ {
+ return new OpusParameters(*this);
+ }
+
+ void
+ Serialize(std::ostream& os) const override
+ {
+ os << "maxplaybackrate=" << maxplaybackrate;
+ }
+
+ unsigned int maxplaybackrate;
+ };
+
class Fmtp
{
public:
- Fmtp(const std::string& aFormat, const std::string& aParametersString,
- UniquePtr<Parameters> aParameters)
+ Fmtp(const std::string& aFormat, UniquePtr<Parameters> aParameters)
: format(aFormat),
- parameters_string(aParametersString),
parameters(Move(aParameters))
{
}
- Fmtp(const std::string& aFormat, const std::string& aParametersString,
- const Parameters& aParameters)
+ Fmtp(const std::string& aFormat, const Parameters& aParameters)
: format(aFormat),
- parameters_string(aParametersString),
parameters(aParameters.Clone())
{
}
// TODO: Rip all of this out when we have move semantics in the stl.
Fmtp(const Fmtp& orig) { *this = orig; }
Fmtp& operator=(const Fmtp& rhs)
{
if (this != &rhs) {
format = rhs.format;
- parameters_string = rhs.parameters_string;
parameters.reset(rhs.parameters ? rhs.parameters->Clone() : nullptr);
}
return *this;
}
// The contract around these is as follows:
- // * |format| and |parameters_string| are always set
// * |parameters| is only set if we recognized the media type and had
// a subclass of Parameters to represent that type of parameters
// * |parameters| is a best-effort representation; it might be missing
// stuff
- // * if |parameters| is set, it determines the serialized form,
- // otherwise |parameters_string| is used
// * Parameters::codec_type tells you the concrete class, eg
// kH264 -> H264Parameters
std::string format;
- std::string parameters_string;
UniquePtr<Parameters> parameters;
};
virtual void Serialize(std::ostream& os) const override;
void
- PushEntry(const std::string& format, const std::string& parameters_string,
- UniquePtr<Parameters> parameters)
+ PushEntry(const std::string& format, UniquePtr<Parameters> parameters)
{
- mFmtps.push_back(Fmtp(format, parameters_string, Move(parameters)));
+ mFmtps.push_back(Fmtp(format, Move(parameters)));
}
std::vector<Fmtp> mFmtps;
};
///////////////////////////////////////////////////////////////////////////
// a=sctpmap, draft-ietf-mmusic-sctp-sdp-05
//-------------------------------------------------------------------------
--- a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
+++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
@@ -661,31 +661,16 @@ SipccSdpAttributeList::LoadFmtp(sdp_t* s
sdp_fmtp_t* fmtp = &(attr->attr.fmtp);
// Get the payload type
std::stringstream osPayloadType;
// payload_num is the number in the fmtp attribute, verbatim
osPayloadType << fmtp->payload_num;
- // Get the serialized form of the parameters
- flex_string fs;
- flex_string_init(&fs);
-
- // Very lame, but we need direct access so we can get the serialized form
- sdp_result_e sdpres = sdp_build_attr_fmtp_params(sdp, fmtp, &fs);
-
- if (sdpres != SDP_SUCCESS) {
- flex_string_free(&fs);
- continue;
- }
-
- std::string paramsString(fs.buffer);
- flex_string_free(&fs);
-
// Get parsed form of parameters, if supported
UniquePtr<SdpFmtpAttributeList::Parameters> parameters;
rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num);
switch (codec) {
case RTP_H264_P0:
case RTP_H264_P1: {
@@ -730,21 +715,27 @@ SipccSdpAttributeList::LoadFmtp(sdp_t* s
new SdpFmtpAttributeList::VP8Parameters(
SdpRtpmapAttributeList::kVP8));
vp8Parameters->max_fs = fmtp->max_fs;
vp8Parameters->max_fr = fmtp->max_fr;
parameters.reset(vp8Parameters);
} break;
+ case RTP_OPUS: {
+ SdpFmtpAttributeList::OpusParameters* opusParameters(
+ new SdpFmtpAttributeList::OpusParameters);
+ opusParameters->maxplaybackrate = fmtp->maxplaybackrate;
+ parameters.reset(opusParameters);
+ } break;
default: {
}
}
- fmtps->PushEntry(osPayloadType.str(), paramsString, Move(parameters));
+ fmtps->PushEntry(osPayloadType.str(), Move(parameters));
}
if (!fmtps->mFmtps.empty()) {
SetAttribute(fmtps.release());
}
}
void
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp.h
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp.h
@@ -408,16 +408,17 @@ typedef enum {
SDP_LEVEL_ASYMMETRY_ALLOWED,
SDP_MAX_AVERAGE_BIT_RATE,
SDP_USED_TX,
SDP_STEREO,
SDP_USE_IN_BAND_FEC,
SDP_MAX_CODED_AUDIO_BW,
SDP_CBR,
SDP_MAX_FR,
+ SDP_MAX_PLAYBACK_RATE,
SDP_MAX_FMTP_PARAM,
SDP_FMTP_PARAM_UNKNOWN
} sdp_fmtp_codec_param_e;
/* Fmtp attribute parameters values for
fmtp attribute parameters which convey codec
information */
@@ -636,16 +637,17 @@ typedef struct sdp_fmtp {
tinybool annexa_required;
tinybool annexa;
tinybool annexb;
uint32_t bitrate;
uint32_t mode;
/* some OPUS specific fmtp params */
+ uint32_t maxplaybackrate;
uint32_t maxaveragebitrate;
uint16_t usedtx;
uint16_t stereo;
uint16_t useinbandfec;
char maxcodedaudiobandwidth[SDP_MAX_STRING_LEN+1];
uint16_t cbr;
/* BEGIN - All Video related FMTP parameters */
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
@@ -1723,16 +1723,41 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t
strtoul_result > UINT_MAX) {
sdp_attr_fmtp_invalid_value(sdp_p, "max-fr", tok);
SDP_FREE(temp_ptr);
return SDP_INVALID_PARAMETER;
}
fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
fmtp_p->max_fr = (uint32_t) strtoul_result;
codec_info_found = TRUE;
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
+ sdp_fmtp_codec_param[50].strlen) == 0) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "maxplaybackrate");
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ tok = tmp;
+ tok++;
+ errno = 0;
+ strtoul_result = strtoul(tok, &strtoul_end, 10);
+
+ if (errno || tok == strtoul_end || strtoul_result == 0 || strtoul_result > UINT_MAX) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "maxplaybackrate", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
} else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
temp=PL_strtok_r(tmp, ";", &strtok_state);
if (temp) {
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
sdp_p->debug_str, fmtp_ptr, tmp);
}
while (temp != NULL) {
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c
@@ -425,17 +425,18 @@ const sdp_namearray_t sdp_fmtp_codec_par
{"mode", sizeof("mode")}, /* 41 */
{"level-asymmetry-allowed", sizeof("level-asymmetry-allowed")}, /* 42 */
{"maxaveragebitrate", sizeof("maxaveragebitrate")}, /* 43 */
{"usedtx", sizeof("usedtx")}, /* 44 */
{"stereo", sizeof("stereo")}, /* 45 */
{"useinbandfec", sizeof("useinbandfec")}, /* 46 */
{"maxcodedaudiobandwidth", sizeof("maxcodedaudiobandwidth")}, /* 47 */
{"cbr", sizeof("cbr")}, /* 48 */
- {"max-fr", sizeof("max-fr")} /* 49 */
+ {"max-fr", sizeof("max-fr")}, /* 49 */
+ {"maxplaybackrate", sizeof("maxplaybackrate")} /* 50 */
} ;
/* Note: These *must* be in the same order as the enum type. */
const sdp_namearray_t sdp_fmtp_codec_param_val[SDP_MAX_FMTP_PARAM_VAL] =
{
{"yes", sizeof("yes")},
{"no", sizeof("no")}
};
--- a/media/webrtc/signaling/test/jsep_track_unittest.cpp
+++ b/media/webrtc/signaling/test/jsep_track_unittest.cpp
@@ -460,16 +460,64 @@ TEST_F(JsepTrackTest, SimulcastAnswerer)
ASSERT_EQ("foo", mSendAns->GetNegotiatedDetails()->GetEncoding(0).mRid);
ASSERT_EQ(40000U,
mSendAns->GetNegotiatedDetails()->GetEncoding(0).mConstraints.maxBr);
ASSERT_EQ("bar", mSendAns->GetNegotiatedDetails()->GetEncoding(1).mRid);
ASSERT_EQ(10000U,
mSendAns->GetNegotiatedDetails()->GetEncoding(1).mConstraints.maxBr);
}
+#define VERIFY_OPUS_MAX_PLAYBACK_RATE(track, expectedRate) \
+{ \
+ JsepTrack& copy(track); \
+ ASSERT_TRUE(copy.GetNegotiatedDetails()); \
+ ASSERT_TRUE(copy.GetNegotiatedDetails()->GetEncodingCount()); \
+ for (auto codec : copy.GetNegotiatedDetails()->GetEncoding(0).GetCodecs()) {\
+ if (codec->mName == "opus") { \
+ JsepAudioCodecDescription* audioCodec = \
+ static_cast<JsepAudioCodecDescription*>(codec); \
+ ASSERT_EQ((expectedRate), audioCodec->mMaxPlaybackRate); \
+ } \
+ }; \
+}
+
+TEST_F(JsepTrackTest, DefaultOpusParameters)
+{
+ Init(SdpMediaSection::kAudio);
+ OfferAnswer();
+
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mSendOff,
+ SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mSendAns,
+ SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mRecvOff, 0U);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mRecvAns, 0U);
+}
+
+TEST_F(JsepTrackTest, NonDefaultOpusParameters)
+{
+ InitCodecs();
+ for (auto& codec : mAnsCodecs.values) {
+ if (codec->mName == "opus") {
+ JsepAudioCodecDescription* audioCodec =
+ static_cast<JsepAudioCodecDescription*>(codec);
+ audioCodec->mMaxPlaybackRate = 16000;
+ }
+ }
+ InitTracks(SdpMediaSection::kAudio);
+ InitSdp(SdpMediaSection::kAudio);
+ OfferAnswer();
+
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mSendOff, 16000U);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mSendAns,
+ SdpFmtpAttributeList::OpusParameters::kDefaultMaxPlaybackRate);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mRecvOff, 0U);
+ VERIFY_OPUS_MAX_PLAYBACK_RATE(*mRecvAns, 16000U);
+}
+
} // namespace mozilla
int
main(int argc, char** argv)
{
// Prevents some log spew
ScopedXPCOM xpcom("jsep_track_unittest");
--- a/media/webrtc/signaling/test/sdp_unittests.cpp
+++ b/media/webrtc/signaling/test/sdp_unittests.cpp
@@ -1136,16 +1136,17 @@ const std::string kBasicAudioVideoOffer
"a=identity:blahblahblah foo;bar" CRLF
"a=group:BUNDLE first second" CRLF
"a=group:BUNDLE third" CRLF
"a=group:LS first third" CRLF
"m=audio 9 RTP/SAVPF 109 9 0 8 101" CRLF
"c=IN IP4 0.0.0.0" CRLF
"a=mid:first" CRLF
"a=rtpmap:109 opus/48000/2" CRLF
+"a=fmtp:109 maxplaybackrate=32000" CRLF
"a=ptime:20" CRLF
"a=maxptime:20" CRLF
"a=rtpmap:9 G722/8000" CRLF
"a=rtpmap:0 PCMU/8000" CRLF
"a=rtpmap:8 PCMA/8000" CRLF
"a=rtpmap:101 telephone-event/8000" CRLF
"a=fmtp:101 0-15" CRLF
"a=ice-ufrag:00000000" CRLF
@@ -1497,17 +1498,17 @@ const std::string kH264AudioVideoOffer =
"a=mid:first" CRLF
"a=rtpmap:109 opus/48000/2" CRLF
"a=ptime:20" CRLF
"a=maxptime:20" CRLF
"a=rtpmap:9 G722/8000" CRLF
"a=rtpmap:0 PCMU/8000" CRLF
"a=rtpmap:8 PCMA/8000" CRLF
"a=rtpmap:101 telephone-event/8000" CRLF
-"a=fmtp:101 0-15" CRLF
+"a=fmtp:109 maxplaybackrate=32000" CRLF
"a=ice-ufrag:00000000" CRLF
"a=ice-pwd:0000000000000000000000000000000" CRLF
"a=sendonly" CRLF
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level" CRLF
"a=setup:actpass" CRLF
"a=rtcp-mux" CRLF
"a=msid:stream track" CRLF
"a=candidate:0 1 UDP 2130379007 10.0.0.36 62453 typ host" CRLF
@@ -1552,18 +1553,22 @@ TEST_P(NewSdpTest, CheckFormatParameters
ASSERT_EQ(3U, mSdp->GetMediaSectionCount())
<< "Wrong number of media sections";
ASSERT_TRUE(mSdp->GetMediaSection(0).GetAttributeList().HasAttribute(
SdpAttribute::kFmtpAttribute));
auto audio_format_params =
mSdp->GetMediaSection(0).GetAttributeList().GetFmtp().mFmtps;
ASSERT_EQ(1U, audio_format_params.size());
- ASSERT_EQ("101", audio_format_params[0].format);
- ASSERT_EQ("0-15", audio_format_params[0].parameters_string);
+ ASSERT_EQ("109", audio_format_params[0].format);
+ ASSERT_TRUE(!!audio_format_params[0].parameters);
+ const SdpFmtpAttributeList::OpusParameters* opus_parameters =
+ static_cast<SdpFmtpAttributeList::OpusParameters*>(
+ audio_format_params[0].parameters.get());
+ ASSERT_EQ(32000U, opus_parameters->maxplaybackrate);
ASSERT_TRUE(mSdp->GetMediaSection(1).GetAttributeList().HasAttribute(
SdpAttribute::kFmtpAttribute));
auto video_format_params =
mSdp->GetMediaSection(1).GetAttributeList().GetFmtp().mFmtps;
ASSERT_EQ(3U, video_format_params.size());
ASSERT_EQ("97", video_format_params[0].format);
ASSERT_TRUE(!!video_format_params[0].parameters);