Bug 1534687: Implement RTCRtpParameters.codecs and RTCRtpReceiver.getParameters r=jib,webidl,smaug

We do not mark this field as required right now, because we still have users
that synthesize RTCRtpParameters instead of tweaking the return of
getParameters. The compat mode will ignore any attempt to modify .codecs,
otherwise this will result in the error specified in webrtc-pc.

Differential Revision: https://phabricator.services.mozilla.com/D209305
This commit is contained in:
Byron Campen 2024-06-03 23:24:51 +00:00
Родитель be4ccd11a1
Коммит f054723379
11 изменённых файлов: 197 добавлений и 43 удалений

Просмотреть файл

@ -2347,8 +2347,9 @@ void PeerConnectionImpl::GetCapabilities(
const bool redUlpfecEnabled =
Preferences::GetBool("media.navigator.video.red_ulpfec_enabled", false);
bool haveAddedRtx = false;
// Use the codecs for kind to fill out the RTCRtpCodecCapability
// Use the codecs for kind to fill out the RTCRtpCodec
for (const auto& codec : codecs) {
// To avoid misleading information on codec capabilities skip those
// not signaled for audio/video (webrtc-datachannel)
@ -2359,37 +2360,28 @@ void PeerConnectionImpl::GetCapabilities(
continue;
}
dom::RTCRtpCodecCapability capability;
capability.mMimeType = aKind + NS_ConvertASCIItoUTF16("/" + codec->mName);
capability.mClockRate = codec->mClock;
if (codec->mChannels) {
capability.mChannels.Construct(codec->mChannels);
}
UniquePtr<SdpFmtpAttributeList::Parameters> params;
codec->ApplyConfigToFmtp(params);
if (params != nullptr) {
std::ostringstream paramsString;
params->Serialize(paramsString);
nsTString<char16_t> fmtp;
fmtp.AssignASCII(paramsString.str());
capability.mSdpFmtpLine.Construct(fmtp);
}
dom::RTCRtpCodec capability;
RTCRtpTransceiver::ToDomRtpCodec(*codec, &capability);
if (!aResult.SetValue().mCodecs.AppendElement(capability, fallible)) {
mozalloc_handle_oom(0);
}
}
// We need to manually add rtx for video.
if (mediaType == JsepMediaType::kVideo) {
dom::RTCRtpCodecCapability capability;
capability.mMimeType = aKind + NS_ConvertASCIItoUTF16("/rtx");
capability.mClockRate = 90000;
if (!aResult.SetValue().mCodecs.AppendElement(capability, fallible)) {
mozalloc_handle_oom(0);
// We need to manually add rtx for video.
// Spec says: There will only be a single entry in codecs for
// retransmission via RTX, with sdpFmtpLine not present.
if (mediaType == JsepMediaType::kVideo && !haveAddedRtx) {
const JsepVideoCodecDescription& videoCodec =
static_cast<JsepVideoCodecDescription&>(*codec);
if (videoCodec.mRtxEnabled) {
dom::RTCRtpCodec rtx;
RTCRtpTransceiver::ToDomRtpCodecRtx(videoCodec, &rtx);
rtx.mSdpFmtpLine.Reset();
if (!aResult.SetValue().mCodecs.AppendElement(rtx, fallible)) {
mozalloc_handle_oom(0);
}
haveAddedRtx = true;
}
}
}

Просмотреть файл

@ -187,6 +187,8 @@ RTCRtpReceiver::RTCRtpReceiver(
mWatchManager.Watch(mReceiveTrackMute,
&RTCRtpReceiver::UpdateReceiveTrackMute);
mParameters.mCodecs.Construct();
}
#undef INIT_CANONICAL
@ -211,6 +213,10 @@ void RTCRtpReceiver::GetCapabilities(
PeerConnectionImpl::GetCapabilities(aKind, aResult, sdp::Direction::kRecv);
}
void RTCRtpReceiver::GetParameters(RTCRtpReceiveParameters& aParameters) const {
aParameters = mParameters;
}
already_AddRefed<Promise> RTCRtpReceiver::GetStats(ErrorResult& aError) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
RefPtr<Promise> promise = Promise::Create(global, aError);
@ -871,6 +877,29 @@ void RTCRtpReceiver::SyncFromJsep(const JsepTransceiver& aJsepTransceiver) {
return;
}
if (GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails()) {
const auto& details(
*GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails());
mParameters.mCodecs.Reset();
mParameters.mCodecs.Construct();
if (details.GetEncodingCount()) {
for (const auto& jsepCodec : details.GetEncoding(0).GetCodecs()) {
RTCRtpCodecParameters codec;
RTCRtpTransceiver::ToDomRtpCodecParameters(*jsepCodec, &codec);
Unused << mParameters.mCodecs.Value().AppendElement(codec, fallible);
if (jsepCodec->Type() == SdpMediaSection::kVideo) {
const JsepVideoCodecDescription& videoJsepCodec =
static_cast<JsepVideoCodecDescription&>(*jsepCodec);
if (videoJsepCodec.mRtxEnabled) {
RTCRtpCodecParameters rtx;
RTCRtpTransceiver::ToDomRtpCodecParametersRtx(videoJsepCodec, &rtx);
Unused << mParameters.mCodecs.Value().AppendElement(rtx, fallible);
}
}
}
}
}
// Spec says we set [[Receptive]] to true on sLD(sendrecv/recvonly), and to
// false on sRD(recvonly/inactive), sLD(sendonly/inactive), or when stop()
// is called.

Просмотреть файл

@ -14,6 +14,7 @@
#include "libwebrtcglue/RtpRtcpConfig.h"
#include "nsTArray.h"
#include "mozilla/dom/RTCRtpCapabilitiesBinding.h"
#include "mozilla/dom/RTCRtpParametersBinding.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#include "PerformanceRecorder.h"
#include "RTCStatsReport.h"
@ -63,6 +64,7 @@ class RTCRtpReceiver : public nsISupports,
RTCDtlsTransport* GetTransport() const;
static void GetCapabilities(const GlobalObject&, const nsAString& aKind,
Nullable<dom::RTCRtpCapabilities>& aResult);
void GetParameters(RTCRtpReceiveParameters& aParameters) const;
already_AddRefed<Promise> GetStats(ErrorResult& aError);
void GetContributingSources(
nsTArray<dom::RTCRtpContributingSource>& aSources);
@ -195,6 +197,8 @@ class RTCRtpReceiver : public nsISupports,
bool mReceptive = false;
// This is the [[JitterBufferTarget]] internal slot.
Maybe<DOMHighResTimeStamp> mJitterBufferTarget;
// Houses [[ReceiveCodecs]]
RTCRtpReceiveParameters mParameters;
MediaEventListener mRtcpByeListener;
MediaEventListener mRtcpTimeoutListener;

Просмотреть файл

@ -158,6 +158,8 @@ RTCRtpSender::RTCRtpSender(nsPIDOMWindowInner* aWindow, PeerConnectionImpl* aPc,
MaybeGetJsepRids();
}
mParameters.mCodecs.Construct();
if (mDtmf) {
mWatchManager.Watch(mTransmitting, &RTCRtpSender::UpdateDtmfSender);
}
@ -760,10 +762,18 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
paramsCopy.mEncodings = oldParams->mEncodings;
}
if (!(oldParams->mCodecs == paramsCopy.mCodecs)) {
nsCString error("RTCRtpParameters.codecs is a read-only parameter");
if (!mAllowOldSetParameters) {
p->MaybeRejectWithInvalidModificationError(error);
return p.forget();
}
WarnAboutBadSetParameters(error);
}
// TODO: Verify remaining read-only parameters
// headerExtensions (bug 1765851)
// rtcp (bug 1765852)
// codecs (bug 1534687)
// CheckAndRectifyEncodings handles the following steps:
// If transceiver kind is "audio", remove the scaleResolutionDownBy member
@ -822,7 +832,7 @@ already_AddRefed<Promise> RTCRtpSender::SetParameters(
// Set sender.[[LastReturnedParameters]] to null.
mLastReturnedParameters = Nothing();
// Set sender.[[SendEncodings]] to parameters.encodings.
mParameters = paramsCopy;
mParameters.mEncodings = paramsCopy.mEncodings;
UpdateRestorableEncodings(mParameters.mEncodings);
// Only clear mPendingParameters if it matches; there could have been
// back-to-back calls to setParameters, and we only want to clear this
@ -953,9 +963,6 @@ void RTCRtpSender::GetParameters(RTCRtpSendParameters& aParameters) {
// TODO(bug 1765851): We do not support this yet
// aParameters.mHeaderExtensions.Construct();
// codecs is set to the value of the [[SendCodecs]] internal slot
// TODO(bug 1534687): We do not support this yet
// rtcp.cname is set to the CNAME of the associated RTCPeerConnection.
// rtcp.reducedSize is set to true if reduced-size RTCP has been negotiated
// for sending, and false otherwise.
@ -964,7 +971,9 @@ void RTCRtpSender::GetParameters(RTCRtpSendParameters& aParameters) {
aParameters.mRtcp.Value().mCname.Construct();
aParameters.mRtcp.Value().mReducedSize.Construct(false);
aParameters.mHeaderExtensions.Construct();
aParameters.mCodecs.Construct();
if (mParameters.mCodecs.WasPassed()) {
aParameters.mCodecs.Construct(mParameters.mCodecs.Value());
}
// Set sender.[[LastReturnedParameters]] to result.
mLastReturnedParameters = Some(aParameters);
@ -1371,6 +1380,35 @@ void RTCRtpSender::MaybeUpdateConduit() {
}
}
void RTCRtpSender::UpdateParametersCodecs() {
mParameters.mCodecs.Reset();
mParameters.mCodecs.Construct();
if (GetJsepTransceiver().mSendTrack.GetNegotiatedDetails()) {
const JsepTrackNegotiatedDetails details(
*GetJsepTransceiver().mSendTrack.GetNegotiatedDetails());
if (details.GetEncodingCount()) {
for (const auto& jsepCodec : details.GetEncoding(0).GetCodecs()) {
RTCRtpCodecParameters codec;
RTCRtpTransceiver::ToDomRtpCodecParameters(*jsepCodec, &codec);
Unused << mParameters.mCodecs.Value().AppendElement(codec, fallible);
if (jsepCodec->Type() == SdpMediaSection::kVideo) {
const JsepVideoCodecDescription& videoJsepCodec =
static_cast<JsepVideoCodecDescription&>(*jsepCodec);
// In our JSEP implementation, RTX is an addon to an existing codec,
// not a codec object in its own right. webrtc-pc treats RTX as a
// separate codec, however.
if (videoJsepCodec.mRtxEnabled) {
RTCRtpCodecParameters rtx;
RTCRtpTransceiver::ToDomRtpCodecParametersRtx(videoJsepCodec, &rtx);
Unused << mParameters.mCodecs.Value().AppendElement(rtx, fallible);
}
}
}
}
}
}
void RTCRtpSender::SyncFromJsep(const JsepTransceiver& aJsepTransceiver) {
if (!mSimulcastEnvelopeSet) {
// JSEP is establishing the simulcast envelope for the first time, right now
@ -1396,6 +1434,7 @@ void RTCRtpSender::SyncFromJsep(const JsepTransceiver& aJsepTransceiver) {
MOZ_ASSERT(mParameters.mEncodings.Length());
}
}
UpdateParametersCodecs();
MaybeUpdateConduit();
}

Просмотреть файл

@ -167,6 +167,7 @@ class RTCRtpSender : public nsISupports,
RefPtr<PeerConnectionImpl> mPc;
RefPtr<dom::MediaStreamTrack> mSenderTrack;
bool mSenderTrackSetByAddTrack = false;
// Houses [[SendEncodings]] and [[SendCodecs]]
RTCRtpSendParameters mParameters;
Maybe<RTCRtpSendParameters> mPendingParameters;
uint32_t mNumSetParametersCalls = 0;
@ -257,6 +258,7 @@ class RTCRtpSender : public nsISupports,
void UpdateBaseConfig(BaseConfig* aConfig);
void ApplyVideoConfig(const VideoConfig& aConfig);
void ApplyAudioConfig(const AudioConfig& aConfig);
void UpdateParametersCodecs();
Canonical<Ssrcs> mSsrcs;
Canonical<Ssrcs> mVideoRtxSsrcs;

Просмотреть файл

@ -885,6 +885,74 @@ void RTCRtpTransceiver::NegotiatedDetailsToVideoCodecConfigs(
}
}
/* static */
void RTCRtpTransceiver::ToDomRtpCodec(const JsepCodecDescription& aCodec,
RTCRtpCodec* aDomCodec) {
MOZ_ASSERT(aCodec.Type() == SdpMediaSection::kAudio ||
aCodec.Type() == SdpMediaSection::kVideo);
if (aCodec.Type() == SdpMediaSection::kAudio) {
aDomCodec->mChannels.Construct(aCodec.mChannels);
}
aDomCodec->mClockRate = aCodec.mClock;
std::string mimeType =
aCodec.Type() == SdpMediaSection::kAudio ? "audio/" : "video/";
mimeType += aCodec.mName;
aDomCodec->mMimeType = NS_ConvertASCIItoUTF16(mimeType);
if (aCodec.mSdpFmtpLine) {
// The RTCRtpParameters.codecs case; just use what we parsed out of the SDP
if (!aCodec.mSdpFmtpLine->empty()) {
aDomCodec->mSdpFmtpLine.Construct(
NS_ConvertASCIItoUTF16(aCodec.mSdpFmtpLine->c_str()));
}
} else {
// The getCapabilities case; serialize what we would put in an offer.
UniquePtr<SdpFmtpAttributeList::Parameters> params;
aCodec.ApplyConfigToFmtp(params);
if (params != nullptr) {
std::ostringstream paramsString;
params->Serialize(paramsString);
nsTString<char16_t> fmtp;
fmtp.AssignASCII(paramsString.str());
aDomCodec->mSdpFmtpLine.Construct(fmtp);
}
}
}
/* static */
void RTCRtpTransceiver::ToDomRtpCodecParameters(
const JsepCodecDescription& aCodec,
RTCRtpCodecParameters* aDomCodecParameters) {
ToDomRtpCodec(aCodec, aDomCodecParameters);
uint16_t pt;
if (SdpHelper::GetPtAsInt(aCodec.mDefaultPt, &pt)) {
aDomCodecParameters->mPayloadType = pt;
}
}
/* static */
void RTCRtpTransceiver::ToDomRtpCodecRtx(
const JsepVideoCodecDescription& aCodec, RTCRtpCodec* aDomCodec) {
MOZ_ASSERT(aCodec.Type() == SdpMediaSection::kVideo);
aDomCodec->mClockRate = aCodec.mClock;
aDomCodec->mMimeType = NS_ConvertASCIItoUTF16("video/rtx");
std::ostringstream apt;
apt << "apt=" << aCodec.mDefaultPt;
aDomCodec->mSdpFmtpLine.Construct(NS_ConvertASCIItoUTF16(apt.str().c_str()));
}
/* static */
void RTCRtpTransceiver::ToDomRtpCodecParametersRtx(
const JsepVideoCodecDescription& aCodec,
RTCRtpCodecParameters* aDomCodecParameters) {
ToDomRtpCodecRtx(aCodec, aDomCodecParameters);
uint16_t pt;
if (SdpHelper::GetPtAsInt(aCodec.mRtxPayloadType, &pt)) {
aDomCodecParameters->mPayloadType = pt;
}
}
void RTCRtpTransceiver::Stop(ErrorResult& aRv) {
if (mPc->IsClosed()) {
aRv.ThrowInvalidStateError("Peer connection is closed");

Просмотреть файл

@ -171,6 +171,20 @@ class RTCRtpTransceiver : public nsISupports, public nsWrapperCache {
const JsepTrackNegotiatedDetails& aDetails,
std::vector<VideoCodecConfig>* aConfigs);
static void ToDomRtpCodec(const JsepCodecDescription& aCodec,
RTCRtpCodec* aDomCodec);
static void ToDomRtpCodecParameters(
const JsepCodecDescription& aCodec,
RTCRtpCodecParameters* aDomCodecParameters);
static void ToDomRtpCodecRtx(const JsepVideoCodecDescription& aCodec,
RTCRtpCodec* aDomCodec);
static void ToDomRtpCodecParametersRtx(
const JsepVideoCodecDescription& aCodec,
RTCRtpCodecParameters* aDomCodecParameters);
/* Returns a promise that will contain the stats in aStats, along with the
* codec stats (which is a PC-wide thing) */
void ChainToDomPromiseWithCodecStats(nsTArray<RefPtr<RTCStatsPromise>> aStats,

Просмотреть файл

@ -357,6 +357,11 @@ class JsepAudioCodecDescription : public JsepCodecDescription {
opusParams.maxFrameSizeMs = mMaxFrameSizeMs;
opusParams.useCbr = mCbrEnabled;
aFmtp.reset(opusParams.Clone());
} else if (mName == "telephone-event") {
if (!aFmtp) {
// We only use the default right now
aFmtp.reset(new SdpFmtpAttributeList::TelephoneEventParameters);
}
}
};

Просмотреть файл

@ -8,13 +8,11 @@
*/
dictionary RTCRtpCapabilities {
required sequence<RTCRtpCodecCapability> codecs;
required sequence<RTCRtpCodec> codecs;
required sequence<RTCRtpHeaderExtensionCapability> headerExtensions;
};
dictionary RTCRtpCodecCapability : RTCRtpCodec {
};
[GenerateEqualityOperator]
dictionary RTCRtpCodec {
required DOMString mimeType;
required unsigned long clockRate;

Просмотреть файл

@ -42,12 +42,9 @@ dictionary RTCRtcpParameters {
boolean reducedSize;
};
dictionary RTCRtpCodecParameters {
unsigned short payloadType;
DOMString mimeType;
unsigned long clockRate;
unsigned short channels = 1;
DOMString sdpFmtpLine;
[GenerateEqualityOperator]
dictionary RTCRtpCodecParameters : RTCRtpCodec {
required octet payloadType;
};
dictionary RTCRtpParameters {
@ -56,6 +53,8 @@ dictionary RTCRtpParameters {
// do with these in particular (see validateRtpParameters).
sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
RTCRtcpParameters rtcp;
// Don't make this required just yet; there are still implementations out
// there that build RTCRtpParameters themselves
sequence<RTCRtpCodecParameters> codecs;
};
@ -63,3 +62,6 @@ dictionary RTCRtpSendParameters : RTCRtpParameters {
DOMString transactionId;
required sequence<RTCRtpEncodingParameters> encodings;
};
dictionary RTCRtpReceiveParameters : RTCRtpParameters {
};

Просмотреть файл

@ -13,6 +13,7 @@ interface RTCRtpReceiver {
readonly attribute MediaStreamTrack track;
readonly attribute RTCDtlsTransport? transport;
static RTCRtpCapabilities? getCapabilities(DOMString kind);
RTCRtpReceiveParameters getParameters();
sequence<RTCRtpContributingSource> getContributingSources();
sequence<RTCRtpSynchronizationSource> getSynchronizationSources();
[NewObject]