зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1275360 - Add sdp handling for video FEC (red/ulpfec). r=drno
MozReview-Commit-ID: BIt7SkSEquj --HG-- extra : transplant_source : %A9%27%7B%D7%AA%FBI%94%9D%EC%9E%A2%2C%ED%3D%06%2C%90f%DB
This commit is contained in:
Родитель
82187afe2d
Коммит
089e002c9b
|
@ -50,6 +50,7 @@ class JsepCodecDescription {
|
|||
virtual bool
|
||||
Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const
|
||||
{
|
||||
// note: fmt here is remote fmt (to go with remoteMsection)
|
||||
if (mType != remoteMsection.GetMediaType()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -214,6 +215,7 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
clock, 0, enabled),
|
||||
mTmmbrEnabled(false),
|
||||
mRembEnabled(false),
|
||||
mFECEnabled(false),
|
||||
mPacketizationMode(0)
|
||||
{
|
||||
// Add supported rtcp-fb types
|
||||
|
@ -242,6 +244,16 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
EnableFec() {
|
||||
// Enabling FEC for video works a little differently than enabling
|
||||
// REMB or TMMBR. Support for FEC is indicated by the presence of
|
||||
// particular codes (red and ulpfec) instead of using rtcpfb
|
||||
// attributes on a given codec. There is no rtcpfb to push for FEC
|
||||
// as can be seen above when REMB or TMMBR are enabled.
|
||||
mFECEnabled = true;
|
||||
}
|
||||
|
||||
void
|
||||
AddParametersToMSection(SdpMediaSection& msection) const override
|
||||
{
|
||||
|
@ -282,6 +294,11 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
h264Params.level_asymmetry_allowed = true;
|
||||
|
||||
msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, h264Params));
|
||||
} else if (mName == "red") {
|
||||
SdpFmtpAttributeList::RedParameters redParams(
|
||||
GetRedParameters(mDefaultPt, msection));
|
||||
redParams.encodings = mRedundantEncodings;
|
||||
msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, redParams));
|
||||
} else if (mName == "VP8" || mName == "VP9") {
|
||||
if (mDirection == sdp::kRecv) {
|
||||
// VP8 and VP9 share the same SDP parameters thus far
|
||||
|
@ -338,6 +355,21 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
return result;
|
||||
}
|
||||
|
||||
SdpFmtpAttributeList::RedParameters
|
||||
GetRedParameters(const std::string& pt,
|
||||
const SdpMediaSection& msection) const
|
||||
{
|
||||
SdpFmtpAttributeList::RedParameters result;
|
||||
auto* params = msection.FindFmtp(pt);
|
||||
|
||||
if (params && params->codec_type == SdpRtpmapAttributeList::kRed) {
|
||||
result =
|
||||
static_cast<const SdpFmtpAttributeList::RedParameters&>(*params);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SdpFmtpAttributeList::VP8Parameters
|
||||
GetVP8Parameters(const std::string& pt,
|
||||
const SdpMediaSection& msection) const
|
||||
|
@ -427,7 +459,10 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
} else {
|
||||
// TODO(bug 1143709): max-recv-level support
|
||||
}
|
||||
|
||||
} else if (mName == "red") {
|
||||
SdpFmtpAttributeList::RedParameters redParams(
|
||||
GetRedParameters(mDefaultPt, remoteMsection));
|
||||
mRedundantEncodings = redParams.encodings;
|
||||
} else if (mName == "VP8" || mName == "VP9") {
|
||||
if (mDirection == sdp::kSend) {
|
||||
SdpFmtpAttributeList::VP8Parameters vp8Params(
|
||||
|
@ -649,6 +684,24 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual void
|
||||
UpdateRedundantEncodings(std::vector<JsepCodecDescription*> codecs)
|
||||
{
|
||||
for (const auto codec : codecs) {
|
||||
if (codec->mType == SdpMediaSection::kVideo &&
|
||||
codec->mEnabled &&
|
||||
codec->mName != "red") {
|
||||
uint8_t pt = (uint8_t)strtoul(codec->mDefaultPt.c_str(), nullptr, 10);
|
||||
// returns 0 if failed to convert, and since zero could
|
||||
// be valid, check the defaultPt for 0
|
||||
if (pt == 0 && codec->mDefaultPt != "0") {
|
||||
continue;
|
||||
}
|
||||
mRedundantEncodings.push_back(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSEP_CODEC_CLONE(JsepVideoCodecDescription)
|
||||
|
||||
std::vector<std::string> mAckFbTypes;
|
||||
|
@ -657,6 +710,8 @@ class JsepVideoCodecDescription : public JsepCodecDescription {
|
|||
std::vector<SdpRtcpFbAttributeList::Feedback> mOtherFbTypes;
|
||||
bool mTmmbrEnabled;
|
||||
bool mRembEnabled;
|
||||
bool mFECEnabled;
|
||||
std::vector<uint8_t> mRedundantEncodings;
|
||||
|
||||
// H264-specific stuff
|
||||
uint32_t mProfileLevelId;
|
||||
|
|
|
@ -2182,11 +2182,29 @@ JsepSessionImpl::SetupDefaultCodecs()
|
|||
h264_0->mProfileLevelId = 0x42E00D;
|
||||
mSupportedCodecs.values.push_back(h264_0);
|
||||
|
||||
JsepVideoCodecDescription* red = new JsepVideoCodecDescription(
|
||||
"122", // payload type
|
||||
"red", // codec name
|
||||
90000 // clock rate (match other video codecs)
|
||||
);
|
||||
mSupportedCodecs.values.push_back(red);
|
||||
|
||||
JsepVideoCodecDescription* ulpfec = new JsepVideoCodecDescription(
|
||||
"123", // payload type
|
||||
"ulpfec", // codec name
|
||||
90000 // clock rate (match other video codecs)
|
||||
);
|
||||
mSupportedCodecs.values.push_back(ulpfec);
|
||||
|
||||
mSupportedCodecs.values.push_back(new JsepApplicationCodecDescription(
|
||||
"5000",
|
||||
"webrtc-datachannel",
|
||||
WEBRTC_DATACHANNEL_STREAMS_DEFAULT
|
||||
));
|
||||
|
||||
// Update the redundant encodings for the RED codec with the supported
|
||||
// codecs. Note: only uses the video codecs.
|
||||
red->UpdateRedundantEncodings(mSupportedCodecs.values);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -344,13 +344,58 @@ JsepTrack::NegotiateCodecs(
|
|||
}
|
||||
}
|
||||
|
||||
// Find the (potential) red codec and ulpfec codec
|
||||
JsepVideoCodecDescription* red = nullptr;
|
||||
JsepVideoCodecDescription* ulpfec = nullptr;
|
||||
for (auto codec : *codecs) {
|
||||
if (codec->mName == "red") {
|
||||
red = static_cast<JsepVideoCodecDescription*>(codec);
|
||||
break;
|
||||
}
|
||||
if (codec->mName == "ulpfec") {
|
||||
ulpfec = static_cast<JsepVideoCodecDescription*>(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if we have a red codec remove redundant encodings that don't exist
|
||||
if (red) {
|
||||
// Since we could have an externally specified redundant endcodings
|
||||
// list, we shouldn't simply rebuild the redundant encodings list
|
||||
// based on the current list of codecs.
|
||||
std::vector<uint8_t> unnegotiatedEncodings;
|
||||
std::swap(unnegotiatedEncodings, red->mRedundantEncodings);
|
||||
for (auto redundantPt : unnegotiatedEncodings) {
|
||||
std::string pt = std::to_string(redundantPt);
|
||||
for (auto codec : *codecs) {
|
||||
if (pt == codec->mDefaultPt) {
|
||||
red->mRedundantEncodings.push_back(redundantPt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Video FEC is indicated by the existence of the red and ulpfec
|
||||
// codecs and not an attribute on the particular video codec (like in
|
||||
// a rtcpfb attr). If we see both red and ulpfec codecs, we enable FEC
|
||||
// on all the other codecs.
|
||||
if (red && ulpfec) {
|
||||
for (auto codec : *codecs) {
|
||||
if (codec->mName != "red" && codec->mName != "ulpfec") {
|
||||
JsepVideoCodecDescription* videoCodec =
|
||||
static_cast<JsepVideoCodecDescription*>(codec);
|
||||
videoCodec->EnableFec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure strongly preferred codecs are up front, overriding the remote
|
||||
// side's preference.
|
||||
std::stable_sort(codecs->begin(), codecs->end(), CompareCodec);
|
||||
|
||||
// TODO(bug 814227): Remove this once we're ready to put multiple codecs in an
|
||||
// answer
|
||||
if (!codecs->empty()) {
|
||||
// answer. For now, remove all but the first codec unless the red codec
|
||||
// exists, and then we include the others per RFC 5109, section 14.2.
|
||||
if (!codecs->empty() && !red) {
|
||||
for (size_t i = 1; i < codecs->size(); ++i) {
|
||||
delete (*codecs)[i];
|
||||
(*codecs)[i] = nullptr;
|
||||
|
|
|
@ -149,6 +149,7 @@ JsepCodecDescToCodecConfig(const JsepCodecDescription& aCodec,
|
|||
configRaw->mNackFbTypes = desc.mNackFbTypes;
|
||||
configRaw->mCcmFbTypes = desc.mCcmFbTypes;
|
||||
configRaw->mRembFbSet = desc.RtcpFbRembIsSet();
|
||||
configRaw->mFECFbSet = desc.mFECEnabled;
|
||||
|
||||
*aConfig = configRaw;
|
||||
return NS_OK;
|
||||
|
|
|
@ -886,7 +886,8 @@ class ConfigureCodec {
|
|||
mVP8MaxFr(0),
|
||||
mUseTmmbr(false),
|
||||
mUseRemb(false),
|
||||
mUseAudioFec(false)
|
||||
mUseAudioFec(false),
|
||||
mRedUlpfecEnabled(false)
|
||||
{
|
||||
#ifdef MOZ_WEBRTC_OMX
|
||||
// Check to see if what HW codecs are available (not in use) at this moment.
|
||||
|
@ -957,6 +958,9 @@ class ConfigureCodec {
|
|||
branch->GetBoolPref("media.navigator.video.use_remb", &mUseRemb);
|
||||
|
||||
branch->GetBoolPref("media.navigator.audio.use_fec", &mUseAudioFec);
|
||||
|
||||
branch->GetBoolPref("media.navigator.video.red_ulpfec_enabled",
|
||||
&mRedUlpfecEnabled);
|
||||
}
|
||||
|
||||
void operator()(JsepCodecDescription* codec) const
|
||||
|
@ -997,6 +1001,10 @@ class ConfigureCodec {
|
|||
if (mHardwareH264Supported) {
|
||||
videoCodec.mStronglyPreferred = true;
|
||||
}
|
||||
} else if (videoCodec.mName == "red") {
|
||||
videoCodec.mEnabled = mRedUlpfecEnabled;
|
||||
} else if (videoCodec.mName == "ulpfec") {
|
||||
videoCodec.mEnabled = mRedUlpfecEnabled;
|
||||
} else if (videoCodec.mName == "VP8" || videoCodec.mName == "VP9") {
|
||||
if (videoCodec.mName == "VP9" && !mVP9Enabled) {
|
||||
videoCodec.mEnabled = false;
|
||||
|
@ -1035,6 +1043,41 @@ class ConfigureCodec {
|
|||
bool mUseTmmbr;
|
||||
bool mUseRemb;
|
||||
bool mUseAudioFec;
|
||||
bool mRedUlpfecEnabled;
|
||||
};
|
||||
|
||||
class ConfigureRedCodec {
|
||||
public:
|
||||
explicit ConfigureRedCodec(nsCOMPtr<nsIPrefBranch>& branch,
|
||||
std::vector<uint8_t>* redundantEncodings) :
|
||||
mRedundantEncodings(redundantEncodings)
|
||||
{
|
||||
// if we wanted to override or modify which encodings are considered
|
||||
// for redundant encodings, we'd probably want to handle it here by
|
||||
// checking prefs modifying the operator() code below
|
||||
}
|
||||
|
||||
void operator()(JsepCodecDescription* codec) const
|
||||
{
|
||||
if (codec->mType == SdpMediaSection::kVideo &&
|
||||
codec->mEnabled == false) {
|
||||
uint8_t pt = (uint8_t)strtoul(codec->mDefaultPt.c_str(), nullptr, 10);
|
||||
// don't search for the codec payload type unless we have a valid
|
||||
// conversion (non-zero)
|
||||
if (pt != 0) {
|
||||
std::vector<uint8_t>::iterator it =
|
||||
std::find(mRedundantEncodings->begin(),
|
||||
mRedundantEncodings->end(),
|
||||
pt);
|
||||
if (it != mRedundantEncodings->end()) {
|
||||
mRedundantEncodings->erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t>* mRedundantEncodings;
|
||||
};
|
||||
|
||||
nsresult
|
||||
|
@ -1059,6 +1102,23 @@ PeerConnectionImpl::ConfigureJsepSessionCodecs() {
|
|||
ConfigureCodec configurer(branch);
|
||||
mJsepSession->ForEachCodec(configurer);
|
||||
|
||||
// first find the red codec description
|
||||
std::vector<JsepCodecDescription*>& codecs = mJsepSession->Codecs();
|
||||
JsepVideoCodecDescription* redCodec = nullptr;
|
||||
for (auto codec : codecs) {
|
||||
// we only really care about finding the RED codec if it is
|
||||
// enabled
|
||||
if (codec->mName == "red" && codec->mEnabled) {
|
||||
redCodec = static_cast<JsepVideoCodecDescription*>(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if red codec was found, configure it for the other enabled codecs
|
||||
if (redCodec) {
|
||||
ConfigureRedCodec configureRed(branch, &(redCodec->mRedundantEncodings));
|
||||
mJsepSession->ForEachCodec(configureRed);
|
||||
}
|
||||
|
||||
// We use this to sort the list of codecs once everything is configured
|
||||
CompareCodecPriority comparator;
|
||||
|
||||
|
|
|
@ -1102,6 +1102,8 @@ ShouldSerializeChannels(SdpRtpmapAttributeList::CodecType type)
|
|||
case SdpRtpmapAttributeList::kiLBC:
|
||||
case SdpRtpmapAttributeList::kiSAC:
|
||||
case SdpRtpmapAttributeList::kH264:
|
||||
case SdpRtpmapAttributeList::kRed:
|
||||
case SdpRtpmapAttributeList::kUlpfec:
|
||||
return false;
|
||||
case SdpRtpmapAttributeList::kOtherCodec:
|
||||
return true;
|
||||
|
|
|
@ -1023,6 +1023,8 @@ public:
|
|||
kiLBC,
|
||||
kiSAC,
|
||||
kH264,
|
||||
kRed,
|
||||
kUlpfec,
|
||||
kOtherCodec
|
||||
};
|
||||
|
||||
|
@ -1102,6 +1104,12 @@ inline std::ostream& operator<<(std::ostream& os,
|
|||
case SdpRtpmapAttributeList::kH264:
|
||||
os << "H264";
|
||||
break;
|
||||
case SdpRtpmapAttributeList::kRed:
|
||||
os << "red";
|
||||
break;
|
||||
case SdpRtpmapAttributeList::kUlpfec:
|
||||
os << "ulpfec";
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
os << "?";
|
||||
|
@ -1135,6 +1143,32 @@ public:
|
|||
SdpRtpmapAttributeList::CodecType codec_type;
|
||||
};
|
||||
|
||||
class RedParameters : public Parameters
|
||||
{
|
||||
public:
|
||||
RedParameters()
|
||||
: Parameters(SdpRtpmapAttributeList::kRed)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Parameters*
|
||||
Clone() const override
|
||||
{
|
||||
return new RedParameters(*this);
|
||||
}
|
||||
|
||||
virtual void
|
||||
Serialize(std::ostream& os) const override
|
||||
{
|
||||
for(size_t i = 0; i < encodings.size(); ++i) {
|
||||
os << (i != 0 ? "/" : "")
|
||||
<< std::to_string(encodings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> encodings;
|
||||
};
|
||||
|
||||
class H264Parameters : public Parameters
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -359,6 +359,10 @@ SipccSdpAttributeList::GetCodecType(rtp_ptype type)
|
|||
return SdpRtpmapAttributeList::kVP8;
|
||||
case RTP_VP9:
|
||||
return SdpRtpmapAttributeList::kVP9;
|
||||
case RTP_RED:
|
||||
return SdpRtpmapAttributeList::kRed;
|
||||
case RTP_ULPFEC:
|
||||
return SdpRtpmapAttributeList::kUlpfec;
|
||||
case RTP_NONE:
|
||||
// Happens when sipcc doesn't know how to translate to the enum
|
||||
case RTP_CELP:
|
||||
|
@ -721,6 +725,17 @@ SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level)
|
|||
|
||||
parameters.reset(vp8Parameters);
|
||||
} break;
|
||||
case RTP_RED: {
|
||||
SdpFmtpAttributeList::RedParameters* redParameters(
|
||||
new SdpFmtpAttributeList::RedParameters);
|
||||
for (int i = 0;
|
||||
i < SDP_FMTP_MAX_REDUNDANT_ENCODINGS && fmtp->redundant_encodings[i];
|
||||
++i) {
|
||||
redParameters->encodings.push_back(fmtp->redundant_encodings[i]);
|
||||
}
|
||||
|
||||
parameters.reset(redParameters);
|
||||
} break;
|
||||
case RTP_OPUS: {
|
||||
SdpFmtpAttributeList::OpusParameters* opusParameters(
|
||||
new SdpFmtpAttributeList::OpusParameters);
|
||||
|
|
|
@ -40,6 +40,8 @@ typedef enum rtp_ptype_
|
|||
RTP_OPUS = 109,
|
||||
RTP_VP8 = 120,
|
||||
RTP_VP9 = 121,
|
||||
RTP_RED = 122,
|
||||
RTP_ULPFEC = 123,
|
||||
RTP_I420 = 124,
|
||||
RTP_ISAC = 124
|
||||
} rtp_ptype;
|
||||
|
|
|
@ -49,6 +49,9 @@
|
|||
#define SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN 0
|
||||
#define SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN 0
|
||||
|
||||
/* Max number of fmtp redundant encodings */
|
||||
#define SDP_FMTP_MAX_REDUNDANT_ENCODINGS 128
|
||||
|
||||
/*
|
||||
* SRTP_CONTEXT_SET_*
|
||||
* Set a SRTP Context field flag
|
||||
|
@ -710,6 +713,9 @@ typedef struct sdp_fmtp {
|
|||
uint16_t annex_k_val;
|
||||
uint16_t annex_n_val;
|
||||
|
||||
/* RFC 5109 Section 4.2 for specifying redundant encodings */
|
||||
uint8_t redundant_encodings[SDP_FMTP_MAX_REDUNDANT_ENCODINGS];
|
||||
|
||||
/* Annex P can take one or more values in the range 1-4 . e.g P=1,3 */
|
||||
uint16_t annex_p_val_picture_resize; /* 1 = four; 2 = sixteenth */
|
||||
uint16_t annex_p_val_warp; /* 3 = half; 4=sixteenth */
|
||||
|
|
|
@ -29,6 +29,8 @@ static const char* logTag = "sdp_access";
|
|||
#define SIPSDP_ATTR_ENCNAME_L16_256K "L16"
|
||||
#define SIPSDP_ATTR_ENCNAME_ISAC "ISAC"
|
||||
#define SIPSDP_ATTR_ENCNAME_OPUS "opus"
|
||||
#define SIPSDP_ATTR_ENCNAME_RED "red"
|
||||
#define SIPSDP_ATTR_ENCNAME_ULPFEC "ulpfec"
|
||||
|
||||
/* Function: sdp_find_media_level
|
||||
* Description: Find and return a pointer to the specified media level,
|
||||
|
@ -1377,6 +1379,12 @@ rtp_ptype sdp_get_known_payload_type(sdp_t *sdp_p,
|
|||
if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP9) == 0) {
|
||||
return (RTP_VP9);
|
||||
}
|
||||
if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_RED) == 0) {
|
||||
return (RTP_RED);
|
||||
}
|
||||
if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ULPFEC) == 0) {
|
||||
return (RTP_ULPFEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1509,7 +1509,7 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
|
|||
fmtp_p->annex_p_val_picture_resize = 0;
|
||||
fmtp_p->annex_p_val_warp = 0;
|
||||
tok = tmp;
|
||||
tok++; temp=PL_strtok_r(tok, ",", &strtok_state);
|
||||
tok++; temp = PL_strtok_r(tok, ",", &strtok_state);
|
||||
if (temp) {
|
||||
iter=1;
|
||||
while (temp != NULL) {
|
||||
|
@ -1525,7 +1525,7 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
|
|||
else if (iter == 2)
|
||||
fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;
|
||||
|
||||
temp=PL_strtok_r(NULL, ",", &strtok_state);
|
||||
temp = PL_strtok_r(NULL, ",", &strtok_state);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
@ -1780,6 +1780,27 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
|
|||
}
|
||||
} /* if (temp) */
|
||||
done = TRUE;
|
||||
} else if (strchr(tmp, '/')) {
|
||||
// XXX Note that because RFC 5109 so conveniently specified
|
||||
// this fmtp with no param names, we hope that nothing else
|
||||
// has a slash in the string because otherwise we won't know
|
||||
// how to differentiate.
|
||||
temp=PL_strtok_r(tmp, "/", &strtok_state);
|
||||
if (temp) {
|
||||
iter = 0;
|
||||
while (temp != NULL) {
|
||||
errno = 0;
|
||||
strtoul_result = strtoul(temp, &strtoul_end, 10);
|
||||
|
||||
if (errno ||
|
||||
temp == strtoul_end || strtoul_result > USHRT_MAX) {
|
||||
continue;
|
||||
}
|
||||
fmtp_p->redundant_encodings[iter++] =
|
||||
(uint8_t)strtoul_result;
|
||||
temp=PL_strtok_r(NULL, "/", &strtok_state);
|
||||
}
|
||||
} /* if (temp) */
|
||||
} else {
|
||||
// XXX Note that DTMF fmtp will fall into here:
|
||||
// a=fmtp:101 0-15 (or 0-15,NN,NN etc)
|
||||
|
|
|
@ -2742,11 +2742,13 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
|
|||
auto& video_attrs = video_section.GetAttributeList();
|
||||
ASSERT_EQ(SdpDirectionAttribute::kSendrecv, video_attrs.GetDirection());
|
||||
|
||||
ASSERT_EQ(4U, video_section.GetFormats().size());
|
||||
ASSERT_EQ(6U, video_section.GetFormats().size());
|
||||
ASSERT_EQ("121", video_section.GetFormats()[0]);
|
||||
ASSERT_EQ("120", video_section.GetFormats()[1]);
|
||||
ASSERT_EQ("126", video_section.GetFormats()[2]);
|
||||
ASSERT_EQ("97", video_section.GetFormats()[3]);
|
||||
ASSERT_EQ("122", video_section.GetFormats()[4]);
|
||||
ASSERT_EQ("123", video_section.GetFormats()[5]);
|
||||
|
||||
// Validate rtpmap
|
||||
ASSERT_TRUE(video_attrs.HasAttribute(SdpAttribute::kRtpmapAttribute));
|
||||
|
@ -2755,22 +2757,28 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
|
|||
ASSERT_TRUE(rtpmaps.HasEntry("121"));
|
||||
ASSERT_TRUE(rtpmaps.HasEntry("126"));
|
||||
ASSERT_TRUE(rtpmaps.HasEntry("97"));
|
||||
ASSERT_TRUE(rtpmaps.HasEntry("122"));
|
||||
ASSERT_TRUE(rtpmaps.HasEntry("123"));
|
||||
|
||||
auto& vp8_entry = rtpmaps.GetEntry("120");
|
||||
auto& vp9_entry = rtpmaps.GetEntry("121");
|
||||
auto& h264_1_entry = rtpmaps.GetEntry("126");
|
||||
auto& h264_0_entry = rtpmaps.GetEntry("97");
|
||||
auto& red_0_entry = rtpmaps.GetEntry("122");
|
||||
auto& ulpfec_0_entry = rtpmaps.GetEntry("123");
|
||||
|
||||
ASSERT_EQ("VP8", vp8_entry.name);
|
||||
ASSERT_EQ("VP9", vp9_entry.name);
|
||||
ASSERT_EQ("H264", h264_1_entry.name);
|
||||
ASSERT_EQ("H264", h264_0_entry.name);
|
||||
ASSERT_EQ("red", red_0_entry.name);
|
||||
ASSERT_EQ("ulpfec", ulpfec_0_entry.name);
|
||||
|
||||
// Validate fmtps
|
||||
ASSERT_TRUE(video_attrs.HasAttribute(SdpAttribute::kFmtpAttribute));
|
||||
auto& fmtps = video_attrs.GetFmtp().mFmtps;
|
||||
|
||||
ASSERT_EQ(4U, fmtps.size());
|
||||
ASSERT_EQ(5U, fmtps.size());
|
||||
|
||||
// VP8
|
||||
const SdpFmtpAttributeList::Parameters* vp8_params =
|
||||
|
@ -2821,11 +2829,30 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
|
|||
ASSERT_EQ((uint32_t)0x42e00d, parsed_h264_0_params.profile_level_id);
|
||||
ASSERT_TRUE(parsed_h264_0_params.level_asymmetry_allowed);
|
||||
ASSERT_EQ(0U, parsed_h264_0_params.packetization_mode);
|
||||
|
||||
// red
|
||||
const SdpFmtpAttributeList::Parameters* red_params =
|
||||
video_section.FindFmtp("122");
|
||||
ASSERT_TRUE(red_params);
|
||||
ASSERT_EQ(SdpRtpmapAttributeList::kRed, red_params->codec_type);
|
||||
|
||||
auto& parsed_red_params =
|
||||
*static_cast<const SdpFmtpAttributeList::RedParameters*>(red_params);
|
||||
ASSERT_EQ(5U, parsed_red_params.encodings.size());
|
||||
ASSERT_EQ(121, parsed_red_params.encodings[0]);
|
||||
ASSERT_EQ(120, parsed_red_params.encodings[1]);
|
||||
ASSERT_EQ(126, parsed_red_params.encodings[2]);
|
||||
ASSERT_EQ(97, parsed_red_params.encodings[3]);
|
||||
ASSERT_EQ(123, parsed_red_params.encodings[4]);
|
||||
}
|
||||
|
||||
TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
|
||||
{
|
||||
|
||||
// TODO(bug 1099351): Once fixed, we can allow red in this offer,
|
||||
// which will also cause multiple codecs in answer. For now,
|
||||
// red/ulpfec for video are behind a pref to mitigate potential for
|
||||
// errors.
|
||||
SetCodecEnabled(mSessionOff, "red", false);
|
||||
for (auto i = mSessionAns.Codecs().begin(); i != mSessionAns.Codecs().end();
|
||||
++i) {
|
||||
auto* codec = *i;
|
||||
|
|
|
@ -32,7 +32,7 @@ class JsepTrackTest : public ::testing::Test
|
|||
JsepTrackTest() {}
|
||||
|
||||
std::vector<JsepCodecDescription*>
|
||||
MakeCodecs() const
|
||||
MakeCodecs(bool addFecCodecs = false, bool preferRed = false) const
|
||||
{
|
||||
std::vector<JsepCodecDescription*> results;
|
||||
results.push_back(
|
||||
|
@ -40,6 +40,16 @@ class JsepTrackTest : public ::testing::Test
|
|||
results.push_back(
|
||||
new JsepAudioCodecDescription("9", "G722", 8000, 1, 320, 64000));
|
||||
|
||||
JsepVideoCodecDescription* red = nullptr;
|
||||
if (addFecCodecs && preferRed) {
|
||||
red = new JsepVideoCodecDescription(
|
||||
"122",
|
||||
"red",
|
||||
90000
|
||||
);
|
||||
results.push_back(red);
|
||||
}
|
||||
|
||||
JsepVideoCodecDescription* vp8 =
|
||||
new JsepVideoCodecDescription("120", "VP8", 90000);
|
||||
vp8->mConstraints.maxFs = 12288;
|
||||
|
@ -52,6 +62,23 @@ class JsepTrackTest : public ::testing::Test
|
|||
h264->mProfileLevelId = 0x42E00D;
|
||||
results.push_back(h264);
|
||||
|
||||
if (addFecCodecs) {
|
||||
if (!preferRed) {
|
||||
red = new JsepVideoCodecDescription(
|
||||
"122",
|
||||
"red",
|
||||
90000
|
||||
);
|
||||
results.push_back(red);
|
||||
}
|
||||
JsepVideoCodecDescription* ulpfec = new JsepVideoCodecDescription(
|
||||
"123",
|
||||
"ulpfec",
|
||||
90000
|
||||
);
|
||||
results.push_back(ulpfec);
|
||||
}
|
||||
|
||||
results.push_back(
|
||||
new JsepApplicationCodecDescription(
|
||||
"5000",
|
||||
|
@ -59,6 +86,12 @@ class JsepTrackTest : public ::testing::Test
|
|||
16
|
||||
));
|
||||
|
||||
// if we're doing something with red, it needs
|
||||
// to update the redundant encodings list
|
||||
if (red) {
|
||||
red->UpdateRedundantEncodings(results);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -211,7 +244,9 @@ class JsepTrackTest : public ::testing::Test
|
|||
}
|
||||
|
||||
const JsepVideoCodecDescription*
|
||||
GetVideoCodec(const JsepTrack& track) const
|
||||
GetVideoCodec(const JsepTrack& track,
|
||||
size_t expectedSize = 1,
|
||||
size_t codecIndex = 0) const
|
||||
{
|
||||
if (!track.GetNegotiatedDetails() ||
|
||||
track.GetNegotiatedDetails()->GetEncodingCount() != 1U) {
|
||||
|
@ -219,8 +254,8 @@ class JsepTrackTest : public ::testing::Test
|
|||
}
|
||||
const std::vector<JsepCodecDescription*>& codecs =
|
||||
track.GetNegotiatedDetails()->GetEncoding(0).GetCodecs();
|
||||
if (codecs.size() != 1U ||
|
||||
codecs[0]->mType != SdpMediaSection::kVideo) {
|
||||
if (codecs.size() != expectedSize ||
|
||||
codecs[codecIndex]->mType != SdpMediaSection::kVideo) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<const JsepVideoCodecDescription*>(codecs[0]);
|
||||
|
@ -366,6 +401,200 @@ TEST_F(JsepTrackTest, VideoNegotiation)
|
|||
CheckAnsEncodingCount(1);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotationOffererFEC)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(true);
|
||||
mAnsCodecs.values = MakeCodecs(false);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=fmtp:122"), std::string::npos);
|
||||
|
||||
const JsepVideoCodecDescription* track = nullptr;
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendOff)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvOff)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendAns)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvAns)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotationAnswererFEC)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(false);
|
||||
mAnsCodecs.values = MakeCodecs(true);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_EQ(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_EQ(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_EQ(mOffer->ToString().find("a=fmtp:122"), std::string::npos);
|
||||
ASSERT_EQ(mAnswer->ToString().find("a=fmtp:122"), std::string::npos);
|
||||
|
||||
const JsepVideoCodecDescription* track = nullptr;
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendOff)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvOff)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendAns)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvAns)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFEC)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(true);
|
||||
mAnsCodecs.values = MakeCodecs(true);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
|
||||
const JsepVideoCodecDescription* track = nullptr;
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendOff, 4)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvOff, 4)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendAns, 4)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvAns, 4)));
|
||||
ASSERT_EQ("120", track->mDefaultPt);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECPreferred)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(true, true);
|
||||
mAnsCodecs.values = MakeCodecs(true);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
|
||||
const JsepVideoCodecDescription* track = nullptr;
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendOff, 4)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvOff, 4)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendAns, 4)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvAns, 4)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
}
|
||||
|
||||
// Make sure we only put the right things in the fmtp:122 120/.... line
|
||||
TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECMismatch)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(true, true);
|
||||
mAnsCodecs.values = MakeCodecs(true);
|
||||
// remove h264 from answer codecs
|
||||
ASSERT_EQ("H264", mAnsCodecs.values[3]->mName);
|
||||
mAnsCodecs.values.erase(mAnsCodecs.values.begin()+3);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=fmtp:122 120/126/123"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=fmtp:122 120/123"), std::string::npos);
|
||||
|
||||
const JsepVideoCodecDescription* track = nullptr;
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendOff, 3)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvOff, 3)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mSendAns, 3)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
ASSERT_TRUE((track = GetVideoCodec(*mRecvAns, 3)));
|
||||
ASSERT_EQ("122", track->mDefaultPt);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotationOffererAnswererFECZeroVP9Codec)
|
||||
{
|
||||
mOffCodecs.values = MakeCodecs(true);
|
||||
JsepVideoCodecDescription* vp9 =
|
||||
new JsepVideoCodecDescription("0", "VP9", 90000);
|
||||
vp9->mConstraints.maxFs = 12288;
|
||||
vp9->mConstraints.maxFps = 60;
|
||||
mOffCodecs.values.push_back(vp9);
|
||||
|
||||
ASSERT_EQ(8U, mOffCodecs.values.size());
|
||||
JsepVideoCodecDescription* red =
|
||||
static_cast<JsepVideoCodecDescription*>(mOffCodecs.values[4]);
|
||||
ASSERT_EQ("red", red->mName);
|
||||
// rebuild the redundant encodings with our newly added "wacky" VP9
|
||||
red->mRedundantEncodings.clear();
|
||||
red->UpdateRedundantEncodings(mOffCodecs.values);
|
||||
|
||||
mAnsCodecs.values = MakeCodecs(true);
|
||||
|
||||
InitTracks(SdpMediaSection::kVideo);
|
||||
InitSdp(SdpMediaSection::kVideo);
|
||||
OfferAnswer();
|
||||
|
||||
CheckOffEncodingCount(1);
|
||||
CheckAnsEncodingCount(1);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mOffer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:122 red"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=rtpmap:123 ulpfec"), std::string::npos);
|
||||
|
||||
ASSERT_NE(mOffer->ToString().find("a=fmtp:122 120/126/123/0"), std::string::npos);
|
||||
ASSERT_NE(mAnswer->ToString().find("a=fmtp:122 120/126/123\r\n"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(JsepTrackTest, VideoNegotiationOfferRemb)
|
||||
{
|
||||
InitCodecs();
|
||||
|
|
|
@ -1225,7 +1225,7 @@ const std::string kBasicAudioVideoOffer =
|
|||
"a=rtcp:62454 IN IP4 162.222.183.171" CRLF
|
||||
"a=end-of-candidates" CRLF
|
||||
"a=ssrc:5150" CRLF
|
||||
"m=video 9 RTP/SAVPF 120 121" CRLF
|
||||
"m=video 9 RTP/SAVPF 120 121 122 123" CRLF
|
||||
"c=IN IP6 ::1" CRLF
|
||||
"a=fingerprint:sha-1 DF:FA:FB:08:3B:3C:54:1D:D7:D4:05:77:A0:72:9B:14:08:6D:0F:4C:2E:AC:8A:FD:0A:8E:99:BF:5D:E8:3C:E7" CRLF
|
||||
"a=mid:second" CRLF
|
||||
|
@ -1233,6 +1233,8 @@ const std::string kBasicAudioVideoOffer =
|
|||
"a=fmtp:120 max-fs=3600;max-fr=30" CRLF
|
||||
"a=rtpmap:121 VP9/90000" CRLF
|
||||
"a=fmtp:121 max-fs=3600;max-fr=30" CRLF
|
||||
"a=rtpmap:122 red/90000" CRLF
|
||||
"a=rtpmap:123 ulpfec/90000" CRLF
|
||||
"a=recvonly" CRLF
|
||||
"a=rtcp-fb:120 nack" CRLF
|
||||
"a=rtcp-fb:120 nack pli" CRLF
|
||||
|
@ -1418,9 +1420,11 @@ TEST_P(NewSdpTest, CheckMlines) {
|
|||
mSdp->GetMediaSection(1).GetProtocol())
|
||||
<< "Wrong protocol for video";
|
||||
auto video_formats = mSdp->GetMediaSection(1).GetFormats();
|
||||
ASSERT_EQ(2U, video_formats.size()) << "Wrong number of formats for video";
|
||||
ASSERT_EQ(4U, video_formats.size()) << "Wrong number of formats for video";
|
||||
ASSERT_EQ("120", video_formats[0]);
|
||||
ASSERT_EQ("121", video_formats[1]);
|
||||
ASSERT_EQ("122", video_formats[2]);
|
||||
ASSERT_EQ("123", video_formats[3]);
|
||||
|
||||
ASSERT_EQ(SdpMediaSection::kAudio, mSdp->GetMediaSection(2).GetMediaType())
|
||||
<< "Wrong type for third media section";
|
||||
|
@ -1518,23 +1522,128 @@ TEST_P(NewSdpTest, CheckRtpmap) {
|
|||
audiosec.GetFormats()[4],
|
||||
rtpmap);
|
||||
|
||||
const SdpMediaSection& videosec1 = mSdp->GetMediaSection(1);
|
||||
const SdpMediaSection& videosec = mSdp->GetMediaSection(1);
|
||||
const SdpRtpmapAttributeList videoRtpmap =
|
||||
videosec.GetAttributeList().GetRtpmap();
|
||||
ASSERT_EQ(4U, videoRtpmap.mRtpmaps.size())
|
||||
<< "Wrong number of rtpmap attributes for video";
|
||||
|
||||
CheckRtpmap("120",
|
||||
SdpRtpmapAttributeList::kVP8,
|
||||
"VP8",
|
||||
90000,
|
||||
0,
|
||||
videosec1.GetFormats()[0],
|
||||
videosec1.GetAttributeList().GetRtpmap());
|
||||
videosec.GetFormats()[0],
|
||||
videoRtpmap);
|
||||
|
||||
const SdpMediaSection& videosec2 = mSdp->GetMediaSection(1);
|
||||
CheckRtpmap("121",
|
||||
SdpRtpmapAttributeList::kVP9,
|
||||
"VP9",
|
||||
90000,
|
||||
0,
|
||||
videosec2.GetFormats()[1],
|
||||
videosec2.GetAttributeList().GetRtpmap());
|
||||
videosec.GetFormats()[1],
|
||||
videoRtpmap);
|
||||
|
||||
CheckRtpmap("122",
|
||||
SdpRtpmapAttributeList::kRed,
|
||||
"red",
|
||||
90000,
|
||||
0,
|
||||
videosec.GetFormats()[2],
|
||||
videoRtpmap);
|
||||
|
||||
CheckRtpmap("123",
|
||||
SdpRtpmapAttributeList::kUlpfec,
|
||||
"ulpfec",
|
||||
90000,
|
||||
0,
|
||||
videosec.GetFormats()[3],
|
||||
videoRtpmap);
|
||||
}
|
||||
|
||||
static const std::string kVideoWithRedAndUlpfecSdp =
|
||||
"v=0" CRLF
|
||||
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
|
||||
"s=SIP Call" CRLF
|
||||
"c=IN IP4 198.51.100.7" CRLF
|
||||
"t=0 0" CRLF
|
||||
"m=video 9 RTP/SAVPF 97 120 121 122 123" CRLF
|
||||
"c=IN IP6 ::1" CRLF
|
||||
"a=fingerprint:sha-1 DF:FA:FB:08:3B:3C:54:1D:D7:D4:05:77:A0:72:9B:14:08:6D:0F:4C:2E:AC:8A:FD:0A:8E:99:BF:5D:E8:3C:E7" CRLF
|
||||
"a=rtpmap:97 H264/90000" CRLF
|
||||
"a=fmtp:97 profile-level-id=42a01e" CRLF
|
||||
"a=rtpmap:120 VP8/90000" CRLF
|
||||
"a=fmtp:120 max-fs=3600;max-fr=30" CRLF
|
||||
"a=rtpmap:121 VP9/90000" CRLF
|
||||
"a=fmtp:121 max-fs=3600;max-fr=30" CRLF
|
||||
"a=rtpmap:122 red/90000" CRLF
|
||||
"a=rtpmap:123 ulpfec/90000" CRLF;
|
||||
|
||||
TEST_P(NewSdpTest, CheckRedNoFmtp) {
|
||||
ParseSdp(kVideoWithRedAndUlpfecSdp);
|
||||
ASSERT_TRUE(!!mSdp) << "Parse failed: " << GetParseErrors();
|
||||
ASSERT_EQ(1U, mSdp->GetMediaSectionCount())
|
||||
<< "Wrong number of media sections";
|
||||
|
||||
ASSERT_TRUE(mSdp->GetMediaSection(0).GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kFmtpAttribute));
|
||||
auto video_format_params =
|
||||
mSdp->GetMediaSection(0).GetAttributeList().GetFmtp().mFmtps;
|
||||
ASSERT_EQ(3U, video_format_params.size());
|
||||
|
||||
// make sure we don't get a fmtp for codec 122
|
||||
for (size_t i = 0; i < video_format_params.size(); ++i) {
|
||||
ASSERT_NE("122", video_format_params[i].format);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(NewSdpTest, CheckRedFmtpWith2Codecs) {
|
||||
ParseSdp(kVideoWithRedAndUlpfecSdp + "a=fmtp:122 120/121" CRLF);
|
||||
ASSERT_TRUE(!!mSdp) << "Parse failed: " << GetParseErrors();
|
||||
ASSERT_EQ(1U, mSdp->GetMediaSectionCount())
|
||||
<< "Wrong number of media sections";
|
||||
|
||||
ASSERT_TRUE(mSdp->GetMediaSection(0).GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kFmtpAttribute));
|
||||
auto video_format_params =
|
||||
mSdp->GetMediaSection(0).GetAttributeList().GetFmtp().mFmtps;
|
||||
ASSERT_EQ(4U, video_format_params.size());
|
||||
|
||||
ASSERT_EQ("122", video_format_params[3].format);
|
||||
ASSERT_TRUE(!!video_format_params[3].parameters);
|
||||
ASSERT_EQ(SdpRtpmapAttributeList::kRed,
|
||||
video_format_params[3].parameters->codec_type);
|
||||
const SdpFmtpAttributeList::RedParameters* red_parameters(
|
||||
static_cast<SdpFmtpAttributeList::RedParameters*>(
|
||||
video_format_params[3].parameters.get()));
|
||||
ASSERT_EQ(2U, red_parameters->encodings.size());
|
||||
ASSERT_EQ(120U, red_parameters->encodings[0]);
|
||||
ASSERT_EQ(121U, red_parameters->encodings[1]);
|
||||
}
|
||||
|
||||
TEST_P(NewSdpTest, CheckRedFmtpWith3Codecs) {
|
||||
ParseSdp(kVideoWithRedAndUlpfecSdp + "a=fmtp:122 120/121/123" CRLF);
|
||||
ASSERT_TRUE(!!mSdp) << "Parse failed: " << GetParseErrors();
|
||||
ASSERT_EQ(1U, mSdp->GetMediaSectionCount())
|
||||
<< "Wrong number of media sections";
|
||||
|
||||
ASSERT_TRUE(mSdp->GetMediaSection(0).GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kFmtpAttribute));
|
||||
auto video_format_params =
|
||||
mSdp->GetMediaSection(0).GetAttributeList().GetFmtp().mFmtps;
|
||||
ASSERT_EQ(4U, video_format_params.size());
|
||||
|
||||
ASSERT_EQ("122", video_format_params[3].format);
|
||||
ASSERT_TRUE(!!video_format_params[3].parameters);
|
||||
ASSERT_EQ(SdpRtpmapAttributeList::kRed,
|
||||
video_format_params[3].parameters->codec_type);
|
||||
const SdpFmtpAttributeList::RedParameters* red_parameters(
|
||||
static_cast<SdpFmtpAttributeList::RedParameters*>(
|
||||
video_format_params[3].parameters.get()));
|
||||
ASSERT_EQ(3U, red_parameters->encodings.size());
|
||||
ASSERT_EQ(120U, red_parameters->encodings[0]);
|
||||
ASSERT_EQ(121U, red_parameters->encodings[1]);
|
||||
ASSERT_EQ(123U, red_parameters->encodings[2]);
|
||||
}
|
||||
|
||||
const std::string kH264AudioVideoOffer =
|
||||
|
|
|
@ -403,6 +403,7 @@ pref("media.navigator.video.default_minfps",10);
|
|||
pref("media.navigator.video.use_remb", true);
|
||||
pref("media.navigator.video.use_tmmbr", false);
|
||||
pref("media.navigator.audio.use_fec", true);
|
||||
pref("media.navigator.video.red_ulpfec_enabled", false);
|
||||
|
||||
pref("media.webrtc.debug.trace_mask", 0);
|
||||
pref("media.webrtc.debug.multi_log", false);
|
||||
|
|
Загрузка…
Ссылка в новой задаче