diff --git a/webrtc/api/rtpparameters.h b/webrtc/api/rtpparameters.h index 13704dc15b..f506c4031c 100644 --- a/webrtc/api/rtpparameters.h +++ b/webrtc/api/rtpparameters.h @@ -12,22 +12,297 @@ #define WEBRTC_API_RTPPARAMETERS_H_ #include +#include #include +#include "webrtc/api/mediatypes.h" #include "webrtc/base/optional.h" namespace webrtc { -// These structures are defined as part of the RtpSender interface. -// See http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface for details. -struct RtpEncodingParameters { +// These structures are intended to mirror those defined by: +// http://draft.ortc.org/#rtcrtpdictionaries* +// Contains everything specified as of 2017 Jan 24. +// +// They are used when retrieving or modifying the parameters of an +// RtpSender/RtpReceiver, or retrieving capabilities. +// +// Note on conventions: Where ORTC may use "octet", "short" and "unsigned" +// types, we typically use "int", in keeping with our style guidelines. The +// parameter's actual valid range will be enforced when the parameters are set, +// rather than when the parameters struct is built. An exception is made for +// SSRCs, since they use the full unsigned 32-bit range, and aren't expected to +// be used for any numeric comparisons/operations. +// +// Additionally, where ORTC uses strings, we may use enums for things that have +// a fixed number of supported values. However, for things that can be extended +// (such as codecs, by providing an external encoder factory), a string +// identifier is used. + +enum class FecMechanism { + RED, + RED_AND_ULPFEC, + FLEXFEC, +}; + +// Used in RtcpFeedback struct. +enum class RtcpFeedbackType { + ACK, + CCM, + NACK, + REMB, // "goog-remb" + TRANSPORT_CC, +}; + +// Used in RtcpFeedback struct when type is ACK, NACK or CCM. +enum class RtcpFeedbackMessageType { + // Equivalent to {type: "nack", parameter: undefined} in ORTC. + GENERIC_NACK, + PLI, // Usable with NACK. + FIR, // Usable with CCM. +}; + +enum class DtxStatus { + DISABLED, + ENABLED, +}; + +enum class DegradationPreference { + MAINTAIN_FRAMERATE, + MAINTAIN_RESOLUTION, + BALANCED, +}; + +enum class PriorityType { VERY_LOW, LOW, MEDIUM, HIGH }; + +struct RtcpFeedback { + RtcpFeedbackType type = RtcpFeedbackType::ACK; + + // Equivalent to ORTC "parameter" field with slight differences: + // 1. It's an enum instead of a string. + // 2. Generic NACK feedback is represented by a GENERIC_NACK message type, + // rather than an unset "parameter" value. + rtc::Optional message_type; + + bool operator==(const RtcpFeedback& o) const { + return type == o.type && message_type == o.message_type; + } + bool operator!=(const RtcpFeedback& o) const { return !(*this == o); } +}; + +// RtpCodecCapability is to RtpCodecParameters as RtpCapabilities is to +// RtpParameters. This represents the static capabilities of an endpoint's +// implementation of a codec. +struct RtpCodecCapability { + // Build MIME "type/subtype" string from |name| and |kind|. + std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; } + + // Used to identify the codec. Equivalent to MIME subtype. + std::string name; + + // The media type of this codec. Equivalent to MIME top-level type. + cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO; + + // Clock rate in Hertz. If unset, the codec is applicable to any clock rate. + rtc::Optional clock_rate; + + // Default payload type for this codec. Mainly needed for codecs that use + // that have statically assigned payload types. + rtc::Optional preferred_payload_type; + + // Maximum packetization time supported by an RtpReceiver for this codec. + // TODO(deadbeef): Not implemented. + rtc::Optional max_ptime; + + // Preferred packetization time for an RtpReceiver or RtpSender of this + // codec. + // TODO(deadbeef): Not implemented. + rtc::Optional ptime; + + // The number of audio channels supported. Unused for video codecs. + rtc::Optional num_channels; + + // Feedback mechanisms supported for this codec. + std::vector rtcp_feedback; + + // Codec-specific parameters that must be signaled to the remote party. + // Corresponds to "a=fmtp" parameters in SDP. + std::unordered_map parameters; + + // Codec-specific parameters that may optionally be signaled to the remote + // party. + // TODO(deadbeef): Not implemented. + std::unordered_map options; + + // Maximum number of temporal layer extensions supported by this codec. + // For example, a value of 1 indicates that 2 total layers are supported. + // TODO(deadbeef): Not implemented. + int max_temporal_layer_extensions = 0; + + // Maximum number of spatial layer extensions supported by this codec. + // For example, a value of 1 indicates that 2 total layers are supported. + // TODO(deadbeef): Not implemented. + int max_spatial_layer_extensions = 0; + + // Whether the implementation can send/receive SVC layers with distinct + // SSRCs. Always false for audio codecs. True for video codecs that support + // scalable video coding with MRST. + // TODO(deadbeef): Not implemented. + bool svc_multi_stream_support = false; + + bool operator==(const RtpCodecCapability& o) const { + return name == o.name && kind == o.kind && clock_rate == o.clock_rate && + preferred_payload_type == o.preferred_payload_type && + max_ptime == o.max_ptime && ptime == o.ptime && + num_channels == o.num_channels && rtcp_feedback == o.rtcp_feedback && + parameters == o.parameters && options == o.options && + max_temporal_layer_extensions == o.max_temporal_layer_extensions && + max_spatial_layer_extensions == o.max_spatial_layer_extensions && + svc_multi_stream_support == o.svc_multi_stream_support; + } + bool operator!=(const RtpCodecCapability& o) const { return !(*this == o); } +}; + +// Used in RtpCapabilities; represents the capabilities/preferences of an +// implementation for a header extension. +// +// Just called "RtpHeaderExtension" in ORTC, but the "Capability" suffix was +// added here for consistency and to avoid confusion with +// RtpHeaderExtensionParameters. +// +// Note that ORTC includes a "kind" field, but we omit this because it's +// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)", +// you know you're getting audio capabilities. +struct RtpHeaderExtensionCapability { + // URI of this extension, as defined in RFC5285. + std::string uri; + + // Preferred value of ID that goes in the packet. + rtc::Optional preferred_id; + + // If true, it's preferred that the value in the header is encrypted. + // TODO(deadbeef): Not implemented. + bool preferred_encrypt = false; + + bool operator==(const RtpHeaderExtensionCapability& o) const { + return uri == o.uri && preferred_id == o.preferred_id && + preferred_encrypt == o.preferred_encrypt; + } + bool operator!=(const RtpHeaderExtensionCapability& o) const { + return !(*this == o); + } +}; + +// Used in RtpParameters; represents a specific configuration of a header +// extension. +struct RtpHeaderExtensionParameters { + // URI of this extension, as defined in RFC5285. + std::string uri; + + // ID value that goes in the packet. + int id = 0; + + // If true, the value in the header is encrypted. + // TODO(deadbeef): Not implemented. + bool encrypt = false; + + bool operator==(const RtpHeaderExtensionParameters& o) const { + return uri == o.uri && id == o.id && encrypt == o.encrypt; + } + bool operator!=(const RtpHeaderExtensionParameters& o) const { + return !(*this == o); + } +}; + +struct RtpFecParameters { + // If unset, a value is chosen by the implementation. rtc::Optional ssrc; + + FecMechanism mechanism = FecMechanism::RED; + + bool operator==(const RtpFecParameters& o) const { + return ssrc == o.ssrc && mechanism == o.mechanism; + } + bool operator!=(const RtpFecParameters& o) const { return !(*this == o); } +}; + +struct RtpRtxParameters { + // If unset, a value is chosen by the implementation. + rtc::Optional ssrc; + + bool operator==(const RtpRtxParameters& o) const { return ssrc == o.ssrc; } + bool operator!=(const RtpRtxParameters& o) const { return !(*this == o); } +}; + +struct RtpEncodingParameters { + // If unset, a value is chosen by the implementation. + rtc::Optional ssrc; + + // Can be used to reference a codec in the |codecs| member of the + // RtpParameters that contains this RtpEncodingParameters. If unset, the + // implementation will choose the first possible codec. + // TODO(deadbeef): Not implemented. + rtc::Optional codec_payload_type; + + // Specifies the FEC mechanism, if set. + // TODO(deadbeef): Not implemented. + rtc::Optional fec; + + // Specifies the RTX parameters, if set. + // TODO(deadbeef): Not implemented. + rtc::Optional rtx; + + // Only used for audio. If set, determines whether or not discontinuous + // transmission will be used, if an available codec supports it. If not + // set, the implementation default setting will be used. + rtc::Optional dtx; + + // The relative priority of this encoding. + // TODO(deadbeef): Not implemented. + rtc::Optional priority; + + // If set, this represents the Transport Independent Application Specific + // maximum bandwidth defined in RFC3890. If unset, there is no maximum + // bitrate. + // Just called "maxBitrate" in ORTC spec. + rtc::Optional max_bitrate_bps; + + // TODO(deadbeef): Not implemented. + rtc::Optional max_framerate; + + // For video, scale the resolution down by this factor. + // TODO(deadbeef): Not implemented. + double scale_resolution_down_by = 1.0; + + // Scale the framerate down by this factor. + // TODO(deadbeef): Not implemented. + double scale_framerate_down_by = 1.0; + + // For an RtpSender, set to true to cause this encoding to be sent, and false + // for it not to be sent. For an RtpReceiver, set to true to cause the + // encoding to be decoded, and false for it to be ignored. + // TODO(deadbeef): RtpReceiver part is not implemented. bool active = true; - int max_bitrate_bps = -1; + + // Value to use for RID RTP header extension. + // Called "encodingId" in ORTC. + // TODO(deadbeef): Not implemented. + std::string rid; + + // RIDs of encodings on which this layer depends. + // Called "dependencyEncodingIds" in ORTC spec. + // TODO(deadbeef): Not implemented. + std::vector dependency_rids; bool operator==(const RtpEncodingParameters& o) const { - return ssrc == o.ssrc && active == o.active && - max_bitrate_bps == o.max_bitrate_bps; + return ssrc == o.ssrc && codec_payload_type == o.codec_payload_type && + fec == o.fec && rtx == o.rtx && dtx == o.dtx && + priority == o.priority && max_bitrate_bps == o.max_bitrate_bps && + max_framerate == o.max_framerate && + scale_resolution_down_by == o.scale_resolution_down_by && + scale_framerate_down_by == o.scale_framerate_down_by && + active == o.active && rid == o.rid && + dependency_rids == o.dependency_rids; } bool operator!=(const RtpEncodingParameters& o) const { return !(*this == o); @@ -35,25 +310,107 @@ struct RtpEncodingParameters { }; struct RtpCodecParameters { - int payload_type; - std::string mime_type; - int clock_rate; - int channels = 1; - // TODO(deadbeef): Add sdpFmtpLine field. + // Build MIME "type/subtype" string from |name| and |kind|. + std::string mime_type() const { return MediaTypeToString(kind) + "/" + name; } + + // Used to identify the codec. Equivalent to MIME subtype. + std::string name; + + // The media type of this codec. Equivalent to MIME top-level type. + cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO; + + // Payload type used to identify this codec in RTP packets. + // This MUST always be present, and must be unique across all codecs using + // the same transport. + int payload_type = 0; + + // If unset, the implementation default is used. + rtc::Optional clock_rate; + + // The number of audio channels used. Unset for video codecs. If unset for + // audio, the implementation default is used. + // TODO(deadbeef): The "implementation default" part is unimplemented. + rtc::Optional num_channels; + + // The maximum packetization time to be used by an RtpSender. + // If |ptime| is also set, this will be ignored. + // TODO(deadbeef): Not implemented. + rtc::Optional max_ptime; + + // The packetization time to be used by an RtpSender. + // If unset, will use any time up to max_ptime. + // TODO(deadbeef): Not implemented. + rtc::Optional ptime; + + // Feedback mechanisms to be used for this codec. + // TODO(deadbeef): Not implemented. + std::vector rtcp_feedback; + + // Codec-specific parameters that must be signaled to the remote party. + // Corresponds to "a=fmtp" parameters in SDP. + // TODO(deadbeef): Not implemented. + std::unordered_map parameters; bool operator==(const RtpCodecParameters& o) const { - return payload_type == o.payload_type && mime_type == o.mime_type && - clock_rate == o.clock_rate && channels == o.channels; + return name == o.name && kind == o.kind && payload_type == o.payload_type && + clock_rate == o.clock_rate && num_channels == o.num_channels && + max_ptime == o.max_ptime && ptime == o.ptime && + rtcp_feedback == o.rtcp_feedback && parameters == o.parameters; } bool operator!=(const RtpCodecParameters& o) const { return !(*this == o); } }; +// RtpCapabilities is used to represent the static capabilities of an +// endpoint. An application can use these capabilities to construct an +// RtpParameters. +struct RtpCapabilities { + // Supported codecs. + std::vector codecs; + + // Supported RTP header extensions. + std::vector header_extensions; + + // Supported Forward Error Correction (FEC) mechanisms. + std::vector fec; + + bool operator==(const RtpCapabilities& o) const { + return codecs == o.codecs && header_extensions == o.header_extensions && + fec == o.fec; + } + bool operator!=(const RtpCapabilities& o) const { return !(*this == o); } +}; + +// Note that unlike in ORTC, an RtcpParameters is not included in +// RtpParameters, because our API will include an additional "RtpTransport" +// abstraction on which RTCP parameters are set. struct RtpParameters { - std::vector encodings; + // Used when calling getParameters/setParameters with a PeerConnection + // RtpSender, to ensure that outdated parameters are not unintentionally + // applied successfully. + // TODO(deadbeef): Not implemented. + std::string transaction_id; + + // Value to use for MID RTP header extension. + // Called "muxId" in ORTC. + // TODO(deadbeef): Not implemented. + std::string mid; + std::vector codecs; + // TODO(deadbeef): Not implemented. + std::vector header_extensions; + + std::vector encodings; + + // TODO(deadbeef): Not implemented. + DegradationPreference degradation_preference = + DegradationPreference::BALANCED; + bool operator==(const RtpParameters& o) const { - return encodings == o.encodings && codecs == o.codecs; + return mid == o.mid && codecs == o.codecs && + header_extensions == o.header_extensions && + encodings == o.encodings && + degradation_preference == o.degradation_preference; } bool operator!=(const RtpParameters& o) const { return !(*this == o); } }; diff --git a/webrtc/media/base/codec.cc b/webrtc/media/base/codec.cc index 75e5a7bf71..1e305a60b7 100644 --- a/webrtc/media/base/codec.cc +++ b/webrtc/media/base/codec.cc @@ -149,8 +149,8 @@ void Codec::IntersectFeedbackParams(const Codec& other) { webrtc::RtpCodecParameters Codec::ToCodecParameters() const { webrtc::RtpCodecParameters codec_params; codec_params.payload_type = id; - codec_params.mime_type = name; - codec_params.clock_rate = clockrate; + codec_params.name = name; + codec_params.clock_rate = rtc::Optional(clockrate); return codec_params; } @@ -190,12 +190,6 @@ bool AudioCodec::Matches(const AudioCodec& codec) const { ((codec.channels < 2 && channels < 2) || channels == codec.channels); } -webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const { - webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters(); - codec_params.channels = static_cast(channels); - return codec_params; -} - std::string AudioCodec::ToString() const { std::ostringstream os; os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate @@ -203,12 +197,25 @@ std::string AudioCodec::ToString() const { return os.str(); } +webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const { + webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters(); + codec_params.num_channels = rtc::Optional(static_cast(channels)); + codec_params.kind = MEDIA_TYPE_AUDIO; + return codec_params; +} + std::string VideoCodec::ToString() const { std::ostringstream os; os << "VideoCodec[" << id << ":" << name << "]"; return os.str(); } +webrtc::RtpCodecParameters VideoCodec::ToCodecParameters() const { + webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters(); + codec_params.kind = MEDIA_TYPE_VIDEO; + return codec_params; +} + VideoCodec::VideoCodec(int id, const std::string& name) : Codec(id, name, kVideoCodecClockrate) { SetDefaultParameters(); diff --git a/webrtc/media/base/codec.h b/webrtc/media/base/codec.h index ac85d1fef4..7dd8889671 100644 --- a/webrtc/media/base/codec.h +++ b/webrtc/media/base/codec.h @@ -162,6 +162,8 @@ struct VideoCodec : public Codec { std::string ToString() const; + webrtc::RtpCodecParameters ToCodecParameters() const override; + VideoCodec& operator=(const VideoCodec& c); VideoCodec& operator=(VideoCodec&& c); diff --git a/webrtc/media/base/codec_unittest.cc b/webrtc/media/base/codec_unittest.cc index 77c1fd015f..5a375fcc83 100644 --- a/webrtc/media/base/codec_unittest.cc +++ b/webrtc/media/base/codec_unittest.cc @@ -311,14 +311,17 @@ TEST(CodecTest, TestToCodecParameters) { const VideoCodec v(96, "V"); webrtc::RtpCodecParameters codec_params_1 = v.ToCodecParameters(); EXPECT_EQ(96, codec_params_1.payload_type); - EXPECT_EQ("V", codec_params_1.mime_type); - EXPECT_EQ(cricket::kVideoCodecClockrate, codec_params_1.clock_rate); - EXPECT_EQ(1, codec_params_1.channels); + EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, codec_params_1.kind); + EXPECT_EQ("V", codec_params_1.name); + EXPECT_EQ(rtc::Optional(cricket::kVideoCodecClockrate), + codec_params_1.clock_rate); + EXPECT_EQ(rtc::Optional(), codec_params_1.num_channels); const AudioCodec a(97, "A", 44100, 20000, 2); webrtc::RtpCodecParameters codec_params_2 = a.ToCodecParameters(); EXPECT_EQ(97, codec_params_2.payload_type); - EXPECT_EQ("A", codec_params_2.mime_type); - EXPECT_EQ(44100, codec_params_2.clock_rate); - EXPECT_EQ(2, codec_params_2.channels); + EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, codec_params_2.kind); + EXPECT_EQ("A", codec_params_2.name); + EXPECT_EQ(rtc::Optional(44100), codec_params_2.clock_rate); + EXPECT_EQ(rtc::Optional(2), codec_params_2.num_channels); } diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc index c6c522a99e..955560a680 100644 --- a/webrtc/media/engine/webrtcvideoengine2.cc +++ b/webrtc/media/engine/webrtcvideoengine2.cc @@ -1861,9 +1861,12 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig( encoder_config.number_of_streams = 1; } - int stream_max_bitrate = - MinPositive(rtp_parameters_.encodings[0].max_bitrate_bps, - parameters_.max_bitrate_bps); + int stream_max_bitrate = parameters_.max_bitrate_bps; + if (rtp_parameters_.encodings[0].max_bitrate_bps) { + stream_max_bitrate = + MinPositive(*(rtp_parameters_.encodings[0].max_bitrate_bps), + parameters_.max_bitrate_bps); + } int codec_max_bitrate_kbps; if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps)) { diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc index f7bfeb1ed6..4b73faa92a 100644 --- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc +++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc @@ -1177,12 +1177,13 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_); EXPECT_EQ(1UL, parameters.encodings.size()); - parameters.encodings[0].max_bitrate_bps = stream_max; + parameters.encodings[0].max_bitrate_bps = rtc::Optional(stream_max); EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters)); // Read back the parameteres and verify they have the correct value parameters = channel_->GetRtpSendParameters(last_ssrc_); EXPECT_EQ(1UL, parameters.encodings.size()); - EXPECT_EQ(stream_max, parameters.encodings[0].max_bitrate_bps); + EXPECT_EQ(rtc::Optional(stream_max), + parameters.encodings[0].max_bitrate_bps); // Verify that the new value propagated down to the encoder EXPECT_EQ(expected_encoder_bitrate, GetMaxEncoderBitrate()); } diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index 65a238f3db..7029e5b1f5 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -520,10 +520,16 @@ const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[14] = { {kDtmfCodecName, 8000, 1, 126, false, {}} }; +// |max_send_bitrate_bps| is the bitrate from "b=" in SDP. +// |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters. rtc::Optional ComputeSendBitrate(int max_send_bitrate_bps, - int rtp_max_bitrate_bps, + rtc::Optional rtp_max_bitrate_bps, const webrtc::CodecInst& codec_inst) { - const int bps = MinPositive(max_send_bitrate_bps, rtp_max_bitrate_bps); + // If application-configured bitrate is set, take minimum of that and SDP + // bitrate. + const int bps = rtp_max_bitrate_bps + ? MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps) + : max_send_bitrate_bps; const int codec_rate = codec_inst.rate; if (bps <= 0) { diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc index 526f7cc3ab..a7ea8c2c92 100644 --- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc +++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc @@ -289,7 +289,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test { webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(ssrc); EXPECT_EQ(1UL, parameters.encodings.size()); - parameters.encodings[0].max_bitrate_bps = bitrate; + parameters.encodings[0].max_bitrate_bps = rtc::Optional(bitrate); return channel_->SetRtpSendParameters(ssrc, parameters); } diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc index 57e7afb179..a64fc34b31 100644 --- a/webrtc/pc/channel_unittest.cc +++ b/webrtc/pc/channel_unittest.cc @@ -1956,7 +1956,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { return channel1_->SetRemoteContent(&content, CA_OFFER, NULL); } - webrtc::RtpParameters BitrateLimitedParameters(int limit) { + webrtc::RtpParameters BitrateLimitedParameters(rtc::Optional limit) { webrtc::RtpParameters parameters; webrtc::RtpEncodingParameters encoding; encoding.max_bitrate_bps = limit; @@ -1965,7 +1965,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { } void VerifyMaxBitrate(const webrtc::RtpParameters& parameters, - int expected_bitrate) { + rtc::Optional expected_bitrate) { EXPECT_EQ(1UL, parameters.encodings.size()); EXPECT_EQ(expected_bitrate, parameters.encodings[0].max_bitrate_bps); } @@ -1975,7 +1975,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE( channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL)); EXPECT_EQ(media_channel1_->max_bps(), -1); - VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), -1); + VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), + rtc::Optional()); } void CanChangeMaxBitrate() { @@ -1984,15 +1985,19 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL)); EXPECT_TRUE(channel1_->SetRtpSendParameters( - kSsrc1, BitrateLimitedParameters(1000))); - VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), 1000); - VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), 1000); + kSsrc1, BitrateLimitedParameters(rtc::Optional(1000)))); + VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), + rtc::Optional(1000)); + VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), + rtc::Optional(1000)); EXPECT_EQ(-1, media_channel1_->max_bps()); - EXPECT_TRUE( - channel1_->SetRtpSendParameters(kSsrc1, BitrateLimitedParameters(-1))); - VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), -1); - VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), -1); + EXPECT_TRUE(channel1_->SetRtpSendParameters( + kSsrc1, BitrateLimitedParameters(rtc::Optional()))); + VerifyMaxBitrate(channel1_->GetRtpSendParameters(kSsrc1), + rtc::Optional()); + VerifyMaxBitrate(media_channel1_->GetRtpSendParameters(kSsrc1), + rtc::Optional()); EXPECT_EQ(-1, media_channel1_->max_bps()); } diff --git a/webrtc/pc/rtcstatscollector.cc b/webrtc/pc/rtcstatscollector.cc index 6344d87c10..435cf8e6c6 100644 --- a/webrtc/pc/rtcstatscollector.cc +++ b/webrtc/pc/rtcstatscollector.cc @@ -170,13 +170,16 @@ std::unique_ptr CodecStatsFromRtpCodecParameters( const RtpCodecParameters& codec_params) { RTC_DCHECK_GE(codec_params.payload_type, 0); RTC_DCHECK_LE(codec_params.payload_type, 127); + RTC_DCHECK(codec_params.clock_rate); uint32_t payload_type = static_cast(codec_params.payload_type); std::unique_ptr codec_stats(new RTCCodecStats( RTCCodecStatsIDFromDirectionMediaAndPayload(inbound, audio, payload_type), timestamp_us)); codec_stats->payload_type = payload_type; - codec_stats->codec = (audio ? "audio/" : "video/") + codec_params.mime_type; - codec_stats->clock_rate = static_cast(codec_params.clock_rate); + codec_stats->codec = codec_params.mime_type(); + if (codec_params.clock_rate) { + codec_stats->clock_rate = static_cast(*codec_params.clock_rate); + } return codec_stats; } diff --git a/webrtc/pc/rtcstatscollector_unittest.cc b/webrtc/pc/rtcstatscollector_unittest.cc index 6d1595e0c3..178deee761 100644 --- a/webrtc/pc/rtcstatscollector_unittest.cc +++ b/webrtc/pc/rtcstatscollector_unittest.cc @@ -765,15 +765,17 @@ TEST_F(RTCStatsCollectorTest, CollectRTCCodecStats) { RtpCodecParameters inbound_audio_codec; inbound_audio_codec.payload_type = 1; - inbound_audio_codec.mime_type = "opus"; - inbound_audio_codec.clock_rate = 1337; + inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO; + inbound_audio_codec.name = "opus"; + inbound_audio_codec.clock_rate = rtc::Optional(1337); voice_media_info.receive_codecs.insert( std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec)); RtpCodecParameters outbound_audio_codec; outbound_audio_codec.payload_type = 2; - outbound_audio_codec.mime_type = "isac"; - outbound_audio_codec.clock_rate = 1338; + outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO; + outbound_audio_codec.name = "isac"; + outbound_audio_codec.clock_rate = rtc::Optional(1338); voice_media_info.send_codecs.insert( std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec)); @@ -785,15 +787,17 @@ TEST_F(RTCStatsCollectorTest, CollectRTCCodecStats) { RtpCodecParameters inbound_video_codec; inbound_video_codec.payload_type = 3; - inbound_video_codec.mime_type = "H264"; - inbound_video_codec.clock_rate = 1339; + inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO; + inbound_video_codec.name = "H264"; + inbound_video_codec.clock_rate = rtc::Optional(1339); video_media_info.receive_codecs.insert( std::make_pair(inbound_video_codec.payload_type, inbound_video_codec)); RtpCodecParameters outbound_video_codec; outbound_video_codec.payload_type = 4; - outbound_video_codec.mime_type = "VP8"; - outbound_video_codec.clock_rate = 1340; + outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO; + outbound_video_codec.name = "VP8"; + outbound_video_codec.clock_rate = rtc::Optional(1340); video_media_info.send_codecs.insert( std::make_pair(outbound_video_codec.payload_type, outbound_video_codec)); @@ -1687,8 +1691,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) { RtpCodecParameters codec_parameters; codec_parameters.payload_type = 42; - codec_parameters.mime_type = "dummy"; - codec_parameters.clock_rate = 0; + codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO; + codec_parameters.name = "dummy"; + codec_parameters.clock_rate = rtc::Optional(0); voice_media_info.receive_codecs.insert( std::make_pair(codec_parameters.payload_type, codec_parameters)); @@ -1769,8 +1774,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) { RtpCodecParameters codec_parameters; codec_parameters.payload_type = 42; - codec_parameters.mime_type = "dummy"; - codec_parameters.clock_rate = 0; + codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO; + codec_parameters.name = "dummy"; + codec_parameters.clock_rate = rtc::Optional(0); video_media_info.receive_codecs.insert( std::make_pair(codec_parameters.payload_type, codec_parameters)); @@ -1848,8 +1854,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) { RtpCodecParameters codec_parameters; codec_parameters.payload_type = 42; - codec_parameters.mime_type = "dummy"; - codec_parameters.clock_rate = 0; + codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO; + codec_parameters.name = "dummy"; + codec_parameters.clock_rate = rtc::Optional(0); voice_media_info.send_codecs.insert( std::make_pair(codec_parameters.payload_type, codec_parameters)); @@ -1927,8 +1934,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) { RtpCodecParameters codec_parameters; codec_parameters.payload_type = 42; - codec_parameters.mime_type = "dummy"; - codec_parameters.clock_rate = 0; + codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO; + codec_parameters.name = "dummy"; + codec_parameters.clock_rate = rtc::Optional(0); video_media_info.send_codecs.insert( std::make_pair(codec_parameters.payload_type, codec_parameters)); diff --git a/webrtc/pc/rtpsenderreceiver_unittest.cc b/webrtc/pc/rtpsenderreceiver_unittest.cc index 508a417733..c02da587b0 100644 --- a/webrtc/pc/rtpsenderreceiver_unittest.cc +++ b/webrtc/pc/rtpsenderreceiver_unittest.cc @@ -575,19 +575,19 @@ TEST_F(RtpSenderReceiverTest, SetAudioMaxSendBitrate) { EXPECT_EQ(-1, voice_media_channel_->max_bps()); webrtc::RtpParameters params = audio_rtp_sender_->GetParameters(); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(-1, params.encodings[0].max_bitrate_bps); - params.encodings[0].max_bitrate_bps = 1000; + EXPECT_FALSE(params.encodings[0].max_bitrate_bps); + params.encodings[0].max_bitrate_bps = rtc::Optional(1000); EXPECT_TRUE(audio_rtp_sender_->SetParameters(params)); // Read back the parameters and verify they have been changed. params = audio_rtp_sender_->GetParameters(); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); + EXPECT_EQ(rtc::Optional(1000), params.encodings[0].max_bitrate_bps); // Verify that the audio channel received the new parameters. params = voice_media_channel_->GetRtpSendParameters(kAudioSsrc); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); + EXPECT_EQ(rtc::Optional(1000), params.encodings[0].max_bitrate_bps); // Verify that the global bitrate limit has not been changed. EXPECT_EQ(-1, voice_media_channel_->max_bps()); @@ -611,19 +611,19 @@ TEST_F(RtpSenderReceiverTest, SetVideoMaxSendBitrate) { EXPECT_EQ(-1, video_media_channel_->max_bps()); webrtc::RtpParameters params = video_rtp_sender_->GetParameters(); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(-1, params.encodings[0].max_bitrate_bps); - params.encodings[0].max_bitrate_bps = 1000; + EXPECT_FALSE(params.encodings[0].max_bitrate_bps); + params.encodings[0].max_bitrate_bps = rtc::Optional(1000); EXPECT_TRUE(video_rtp_sender_->SetParameters(params)); // Read back the parameters and verify they have been changed. params = video_rtp_sender_->GetParameters(); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); + EXPECT_EQ(rtc::Optional(1000), params.encodings[0].max_bitrate_bps); // Verify that the video channel received the new parameters. params = video_media_channel_->GetRtpSendParameters(kVideoSsrc); EXPECT_EQ(1, params.encodings.size()); - EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); + EXPECT_EQ(rtc::Optional(1000), params.encodings[0].max_bitrate_bps); // Verify that the global bitrate limit has not been changed. EXPECT_EQ(-1, video_media_channel_->max_bps()); diff --git a/webrtc/sdk/android/api/org/webrtc/RtpParameters.java b/webrtc/sdk/android/api/org/webrtc/RtpParameters.java index a50cf550f5..fde2b35502 100644 --- a/webrtc/sdk/android/api/org/webrtc/RtpParameters.java +++ b/webrtc/sdk/android/api/org/webrtc/RtpParameters.java @@ -15,23 +15,43 @@ import java.util.LinkedList; /** * The parameters for an {@code RtpSender}, as defined in * http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface. + * + * Note: These structures use nullable Integer/etc. types because in the + * future, they may be used to construct ORTC RtpSender/RtpReceivers, in + * which case "null" will be used to represent "choose the implementation + * default value". */ public class RtpParameters { public static class Encoding { + // Set to true to cause this encoding to be sent, and false for it not to + // be sent. public boolean active = true; - // A null value means "no maximum bitrate". + // If non-null, this represents the Transport Independent Application + // Specific maximum bandwidth defined in RFC3890. If null, there is no + // maximum bitrate. public Integer maxBitrateBps; + // SSRC to be used by this encoding. + // Can't be changed between getParameters/setParameters. public Long ssrc; } public static class Codec { - int payloadType; - String mimeType; - int clockRate; - int channels = 1; + // Payload type used to identify this codec in RTP packets. + public int payloadType; + // Name used to identify the codec. Equivalent to MIME subtype. + public String name; + // The media type of this codec. Equivalent to MIME top-level type. + MediaStreamTrack.MediaType kind; + // Clock rate in Hertz. + public Integer clockRate; + // The number of audio channels used. Set to null for video codecs. + public Integer numChannels; } public final LinkedList encodings; + // Codec parameters can't currently be changed between getParameters and + // setParameters. Though in the future it will be possible to reorder them or + // remove them. public final LinkedList codecs; public RtpParameters() { diff --git a/webrtc/sdk/android/src/jni/peerconnection_jni.cc b/webrtc/sdk/android/src/jni/peerconnection_jni.cc index 6a6ba25c96..d3f23445d6 100644 --- a/webrtc/sdk/android/src/jni/peerconnection_jni.cc +++ b/webrtc/sdk/android/src/jni/peerconnection_jni.cc @@ -158,6 +158,47 @@ static DataChannelInit JavaDataChannelInitToNative( return init; } +static cricket::MediaType JavaMediaTypeToJsepMediaType(JNIEnv* jni, + jobject j_media_type) { + jclass j_media_type_class = + FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType"); + jmethodID j_name_id = + GetMethodID(jni, j_media_type_class, "name", "()Ljava/lang/String;"); + jstring j_type_string = + (jstring)jni->CallObjectMethod(j_media_type, j_name_id); + CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; + std::string type_string = JavaToStdString(jni, j_type_string); + + RTC_DCHECK(type_string == "MEDIA_TYPE_AUDIO" || + type_string == "MEDIA_TYPE_VIDEO") + << "Media type: " << type_string; + return type_string == "MEDIA_TYPE_AUDIO" ? cricket::MEDIA_TYPE_AUDIO + : cricket::MEDIA_TYPE_VIDEO; +} + +static jobject JsepMediaTypeToJavaMediaType(JNIEnv* jni, + cricket::MediaType media_type) { + jclass j_media_type_class = + FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType"); + + const char* media_type_str = nullptr; + switch (media_type) { + case cricket::MEDIA_TYPE_AUDIO: + media_type_str = "MEDIA_TYPE_AUDIO"; + break; + case cricket::MEDIA_TYPE_VIDEO: + media_type_str = "MEDIA_TYPE_VIDEO"; + break; + case cricket::MEDIA_TYPE_DATA: + RTC_NOTREACHED(); + break; + } + jfieldID j_media_type_fid = + GetStaticFieldID(jni, j_media_type_class, media_type_str, + "Lorg/webrtc/MediaStreamTrack$MediaType;"); + return GetStaticObjectField(jni, j_media_type_class, j_media_type_fid); +} + class ConstraintsWrapper; // Adapter between the C++ PeerConnectionObserver interface and the Java @@ -917,20 +958,7 @@ class RtpReceiverObserver : public RtpReceiverObserverInterface { jni, GetObjectClass(jni, *j_observer_global_), "onFirstPacketReceived", "(Lorg/webrtc/MediaStreamTrack$MediaType;)V"); // Get the Java version of media type. - jclass j_media_type_class = - FindClass(jni, "org/webrtc/MediaStreamTrack$MediaType"); - - RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || - media_type == cricket::MEDIA_TYPE_VIDEO) - << "Media type: " << media_type; - const char* media_type_str = media_type == cricket::MEDIA_TYPE_AUDIO - ? "MEDIA_TYPE_AUDIO" - : "MEDIA_TYPE_VIDEO"; - jfieldID j_media_type_fid = - GetStaticFieldID(jni, j_media_type_class, media_type_str, - "Lorg/webrtc/MediaStreamTrack$MediaType;"); - jobject JavaMediaType = - GetStaticObjectField(jni, j_media_type_class, j_media_type_fid); + jobject JavaMediaType = JsepMediaTypeToJavaMediaType(jni, media_type); // Trigger the callback function. jni->CallVoidMethod(*j_observer_global_, j_on_first_packet_received_mid, JavaMediaType); @@ -2400,7 +2428,6 @@ static void JavaRtpParametersToJsepRtpParameters( // Convert encodings. jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id); - const int kBitrateUnlimited = -1; jclass j_encoding_parameters_class = jni->FindClass("org/webrtc/RtpParameters$Encoding"); jfieldID active_id = @@ -2422,9 +2449,7 @@ static void JavaRtpParametersToJsepRtpParameters( if (!IsNull(jni, j_bitrate)) { int bitrate_value = jni->CallIntMethod(j_bitrate, int_value_id); CHECK_EXCEPTION(jni) << "error during CallIntMethod"; - encoding.max_bitrate_bps = bitrate_value; - } else { - encoding.max_bitrate_bps = kBitrateUnlimited; + encoding.max_bitrate_bps = rtc::Optional(bitrate_value); } jobject j_ssrc = GetNullableObjectField(jni, j_encoding_parameters, ssrc_id); @@ -2440,18 +2465,33 @@ static void JavaRtpParametersToJsepRtpParameters( jobject j_codecs = GetObjectField(jni, j_parameters, codecs_id); jclass codec_class = jni->FindClass("org/webrtc/RtpParameters$Codec"); jfieldID payload_type_id = GetFieldID(jni, codec_class, "payloadType", "I"); - jfieldID mime_type_id = - GetFieldID(jni, codec_class, "mimeType", "Ljava/lang/String;"); - jfieldID clock_rate_id = GetFieldID(jni, codec_class, "clockRate", "I"); - jfieldID channels_id = GetFieldID(jni, codec_class, "channels", "I"); + jfieldID name_id = GetFieldID(jni, codec_class, "name", "Ljava/lang/String;"); + jfieldID kind_id = GetFieldID(jni, codec_class, "kind", + "Lorg/webrtc/MediaStreamTrack$MediaType;"); + jfieldID clock_rate_id = + GetFieldID(jni, codec_class, "clockRate", "Ljava/lang/Integer;"); + jfieldID num_channels_id = + GetFieldID(jni, codec_class, "numChannels", "Ljava/lang/Integer;"); for (jobject j_codec : Iterable(jni, j_codecs)) { webrtc::RtpCodecParameters codec; codec.payload_type = GetIntField(jni, j_codec, payload_type_id); - codec.mime_type = - JavaToStdString(jni, GetStringField(jni, j_codec, mime_type_id)); - codec.clock_rate = GetIntField(jni, j_codec, clock_rate_id); - codec.channels = GetIntField(jni, j_codec, channels_id); + codec.name = JavaToStdString(jni, GetStringField(jni, j_codec, name_id)); + codec.kind = JavaMediaTypeToJsepMediaType( + jni, GetObjectField(jni, j_codec, kind_id)); + jobject j_clock_rate = GetNullableObjectField(jni, j_codec, clock_rate_id); + if (!IsNull(jni, j_clock_rate)) { + int clock_rate_value = jni->CallIntMethod(j_clock_rate, int_value_id); + CHECK_EXCEPTION(jni) << "error during CallIntMethod"; + codec.clock_rate = rtc::Optional(clock_rate_value); + } + jobject j_num_channels = + GetNullableObjectField(jni, j_codec, num_channels_id); + if (!IsNull(jni, j_num_channels)) { + int num_channels_value = jni->CallIntMethod(j_num_channels, int_value_id); + CHECK_EXCEPTION(jni) << "error during CallIntMethod"; + codec.num_channels = rtc::Optional(num_channels_value); + } parameters->codecs.push_back(codec); } } @@ -2473,8 +2513,7 @@ static jobject JsepRtpParametersToJavaRtpParameters( jobject j_encodings = GetObjectField(jni, j_parameters, encodings_id); jmethodID encodings_add = GetMethodID(jni, GetObjectClass(jni, j_encodings), "add", "(Ljava/lang/Object;)Z"); - jfieldID active_id = - GetFieldID(jni, encoding_class, "active", "Z"); + jfieldID active_id = GetFieldID(jni, encoding_class, "active", "Z"); jfieldID bitrate_id = GetFieldID(jni, encoding_class, "maxBitrateBps", "Ljava/lang/Integer;"); jfieldID ssrc_id = @@ -2491,9 +2530,9 @@ static jobject JsepRtpParametersToJavaRtpParameters( CHECK_EXCEPTION(jni) << "error during NewObject"; jni->SetBooleanField(j_encoding_parameters, active_id, encoding.active); CHECK_EXCEPTION(jni) << "error during SetBooleanField"; - if (encoding.max_bitrate_bps > 0) { - jobject j_bitrate_value = - jni->NewObject(integer_class, integer_ctor, encoding.max_bitrate_bps); + if (encoding.max_bitrate_bps) { + jobject j_bitrate_value = jni->NewObject(integer_class, integer_ctor, + *(encoding.max_bitrate_bps)); CHECK_EXCEPTION(jni) << "error during NewObject"; jni->SetObjectField(j_encoding_parameters, bitrate_id, j_bitrate_value); CHECK_EXCEPTION(jni) << "error during SetObjectField"; @@ -2517,26 +2556,42 @@ static jobject JsepRtpParametersToJavaRtpParameters( jfieldID codecs_id = GetFieldID(jni, parameters_class, "codecs", "Ljava/util/LinkedList;"); jobject j_codecs = GetObjectField(jni, j_parameters, codecs_id); - jmethodID codecs_add = GetMethodID(jni, GetObjectClass(jni, j_codecs), - "add", "(Ljava/lang/Object;)Z"); + jmethodID codecs_add = GetMethodID(jni, GetObjectClass(jni, j_codecs), "add", + "(Ljava/lang/Object;)Z"); jfieldID payload_type_id = GetFieldID(jni, codec_class, "payloadType", "I"); - jfieldID mime_type_id = - GetFieldID(jni, codec_class, "mimeType", "Ljava/lang/String;"); - jfieldID clock_rate_id = GetFieldID(jni, codec_class, "clockRate", "I"); - jfieldID channels_id = GetFieldID(jni, codec_class, "channels", "I"); + jfieldID name_id = GetFieldID(jni, codec_class, "name", "Ljava/lang/String;"); + jfieldID kind_id = GetFieldID(jni, codec_class, "kind", + "Lorg/webrtc/MediaStreamTrack$MediaType;"); + jfieldID clock_rate_id = + GetFieldID(jni, codec_class, "clockRate", "Ljava/lang/Integer;"); + jfieldID num_channels_id = + GetFieldID(jni, codec_class, "numChannels", "Ljava/lang/Integer;"); for (const webrtc::RtpCodecParameters& codec : parameters.codecs) { jobject j_codec = jni->NewObject(codec_class, codec_ctor); CHECK_EXCEPTION(jni) << "error during NewObject"; jni->SetIntField(j_codec, payload_type_id, codec.payload_type); CHECK_EXCEPTION(jni) << "error during SetIntField"; - jni->SetObjectField(j_codec, mime_type_id, - JavaStringFromStdString(jni, codec.mime_type)); + jni->SetObjectField(j_codec, name_id, + JavaStringFromStdString(jni, codec.name)); CHECK_EXCEPTION(jni) << "error during SetObjectField"; - jni->SetIntField(j_codec, clock_rate_id, codec.clock_rate); - CHECK_EXCEPTION(jni) << "error during SetIntField"; - jni->SetIntField(j_codec, channels_id, codec.channels); - CHECK_EXCEPTION(jni) << "error during SetIntField"; + jni->SetObjectField(j_codec, kind_id, + JsepMediaTypeToJavaMediaType(jni, codec.kind)); + CHECK_EXCEPTION(jni) << "error during SetObjectField"; + if (codec.clock_rate) { + jobject j_clock_rate_value = + jni->NewObject(integer_class, integer_ctor, *(codec.clock_rate)); + CHECK_EXCEPTION(jni) << "error during NewObject"; + jni->SetObjectField(j_codec, clock_rate_id, j_clock_rate_value); + CHECK_EXCEPTION(jni) << "error during SetObjectField"; + } + if (codec.num_channels) { + jobject j_num_channels_value = + jni->NewObject(integer_class, integer_ctor, *(codec.num_channels)); + CHECK_EXCEPTION(jni) << "error during NewObject"; + jni->SetObjectField(j_codec, num_channels_id, j_num_channels_value); + CHECK_EXCEPTION(jni) << "error during SetObjectField"; + } jboolean added = jni->CallBooleanMethod(j_codecs, codecs_add, j_codec); CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; RTC_CHECK(added); diff --git a/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm b/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm index 40f4f251bf..90529c8636 100644 --- a/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm +++ b/webrtc/sdk/objc/Framework/Classes/RTCRtpCodecParameters.mm @@ -11,33 +11,36 @@ #import "RTCRtpCodecParameters+Private.h" #import "NSString+StdString.h" +#import "WebRTC/RTCMediaStreamTrack.h" // For "kind" strings. +#include "webrtc/base/checks.h" #include "webrtc/media/base/mediaconstants.h" -const NSString * const kRTCRtxCodecMimeType = @(cricket::kRtxCodecName); -const NSString * const kRTCRedCodecMimeType = @(cricket::kRedCodecName); -const NSString * const kRTCUlpfecCodecMimeType = @(cricket::kUlpfecCodecName); -const NSString * const kRTCFlexfecCodecMimeType = @(cricket::kFlexfecCodecName); -const NSString * const kRTCOpusCodecMimeType = @(cricket::kOpusCodecName); -const NSString * const kRTCIsacCodecMimeType = @(cricket::kIsacCodecName); -const NSString * const kRTCL16CodecMimeType = @(cricket::kL16CodecName); -const NSString * const kRTCG722CodecMimeType = @(cricket::kG722CodecName); -const NSString * const kRTCIlbcCodecMimeType = @(cricket::kIlbcCodecName); -const NSString * const kRTCPcmuCodecMimeType = @(cricket::kPcmuCodecName); -const NSString * const kRTCPcmaCodecMimeType = @(cricket::kPcmaCodecName); -const NSString * const kRTCDtmfCodecMimeType = @(cricket::kDtmfCodecName); -const NSString * const kRTCComfortNoiseCodecMimeType = +const NSString * const kRTCRtxCodecName = @(cricket::kRtxCodecName); +const NSString * const kRTCRedCodecName = @(cricket::kRedCodecName); +const NSString * const kRTCUlpfecCodecName = @(cricket::kUlpfecCodecName); +const NSString * const kRTCFlexfecCodecName = @(cricket::kFlexfecCodecName); +const NSString * const kRTCOpusCodecName = @(cricket::kOpusCodecName); +const NSString * const kRTCIsacCodecName = @(cricket::kIsacCodecName); +const NSString * const kRTCL16CodecName = @(cricket::kL16CodecName); +const NSString * const kRTCG722CodecName = @(cricket::kG722CodecName); +const NSString * const kRTCIlbcCodecName = @(cricket::kIlbcCodecName); +const NSString * const kRTCPcmuCodecName = @(cricket::kPcmuCodecName); +const NSString * const kRTCPcmaCodecName = @(cricket::kPcmaCodecName); +const NSString * const kRTCDtmfCodecName = @(cricket::kDtmfCodecName); +const NSString * const kRTCComfortNoiseCodecName = @(cricket::kComfortNoiseCodecName); -const NSString * const kVp8CodecMimeType = @(cricket::kVp8CodecName); -const NSString * const kVp9CodecMimeType = @(cricket::kVp9CodecName); -const NSString * const kH264CodecMimeType = @(cricket::kH264CodecName); +const NSString * const kVp8CodecName = @(cricket::kVp8CodecName); +const NSString * const kVp9CodecName = @(cricket::kVp9CodecName); +const NSString * const kH264CodecName = @(cricket::kH264CodecName); @implementation RTCRtpCodecParameters @synthesize payloadType = _payloadType; -@synthesize mimeType = _mimeType; +@synthesize name = _name; +@synthesize kind = _kind; @synthesize clockRate = _clockRate; -@synthesize channels = _channels; +@synthesize numChannels = _numChannels; - (instancetype)init { return [super init]; @@ -47,9 +50,24 @@ const NSString * const kH264CodecMimeType = @(cricket::kH264CodecName); (const webrtc::RtpCodecParameters &)nativeParameters { if (self = [self init]) { _payloadType = nativeParameters.payload_type; - _mimeType = [NSString stringForStdString:nativeParameters.mime_type]; - _clockRate = nativeParameters.clock_rate; - _channels = nativeParameters.channels; + _name = [NSString stringForStdString:nativeParameters.name]; + switch (nativeParameters.kind) { + case cricket::MEDIA_TYPE_AUDIO: + _kind = kRTCMediaStreamTrackKindAudio; + break; + case cricket::MEDIA_TYPE_VIDEO: + _kind = kRTCMediaStreamTrackKindVideo; + break; + case cricket::MEDIA_TYPE_DATA: + RTC_NOTREACHED(); + break; + } + if (nativeParameters.clock_rate) { + _clockRate = [NSNumber numberWithInt:*nativeParameters.clock_rate]; + } + if (nativeParameters.num_channels) { + _numChannels = [NSNumber numberWithInt:*nativeParameters.num_channels]; + } } return self; } @@ -57,9 +75,22 @@ const NSString * const kH264CodecMimeType = @(cricket::kH264CodecName); - (webrtc::RtpCodecParameters)nativeParameters { webrtc::RtpCodecParameters parameters; parameters.payload_type = _payloadType; - parameters.mime_type = [NSString stdStringForString:_mimeType]; - parameters.clock_rate = _clockRate; - parameters.channels = _channels; + parameters.name = [NSString stdStringForString:_name]; + // NSString pointer comparison is safe here since "kind" is readonly and only + // populated above. + if (_kind == kRTCMediaStreamTrackKindAudio) { + parameters.kind = cricket::MEDIA_TYPE_AUDIO; + } else if (_kind == kRTCMediaStreamTrackKindVideo) { + parameters.kind = cricket::MEDIA_TYPE_VIDEO; + } else { + RTC_NOTREACHED(); + } + if (_clockRate != nil) { + parameters.clock_rate = rtc::Optional(_clockRate.intValue); + } + if (_numChannels != nil) { + parameters.num_channels = rtc::Optional(_numChannels.intValue); + } return parameters; } diff --git a/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm b/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm index be47894a8f..8e72d18fca 100644 --- a/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm +++ b/webrtc/sdk/objc/Framework/Classes/RTCRtpEncodingParameters.mm @@ -16,8 +16,6 @@ @synthesize maxBitrateBps = _maxBitrateBps; @synthesize ssrc = _ssrc; -static const int kBitrateUnlimited = -1; - - (instancetype)init { return [super init]; } @@ -26,10 +24,9 @@ static const int kBitrateUnlimited = -1; (const webrtc::RtpEncodingParameters &)nativeParameters { if (self = [self init]) { _isActive = nativeParameters.active; - // TODO(skvlad): Replace with rtc::Optional once the C++ code is updated. - if (nativeParameters.max_bitrate_bps != kBitrateUnlimited) { + if (nativeParameters.max_bitrate_bps) { _maxBitrateBps = - [NSNumber numberWithInt:nativeParameters.max_bitrate_bps]; + [NSNumber numberWithInt:*nativeParameters.max_bitrate_bps]; } if (nativeParameters.ssrc) { _ssrc = [NSNumber numberWithUnsignedLong:*nativeParameters.ssrc]; @@ -42,7 +39,7 @@ static const int kBitrateUnlimited = -1; webrtc::RtpEncodingParameters parameters; parameters.active = _isActive; if (_maxBitrateBps != nil) { - parameters.max_bitrate_bps = _maxBitrateBps.intValue; + parameters.max_bitrate_bps = rtc::Optional(_maxBitrateBps.intValue); } if (_ssrc != nil) { parameters.ssrc = rtc::Optional(_ssrc.unsignedLongValue); diff --git a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h index a3156bb9cd..c7ca2f59c0 100644 --- a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h +++ b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCRtpCodecParameters.h @@ -14,22 +14,22 @@ NS_ASSUME_NONNULL_BEGIN -RTC_EXTERN const NSString * const kRTCRtxCodecMimeType; -RTC_EXTERN const NSString * const kRTCRedCodecMimeType; -RTC_EXTERN const NSString * const kRTCUlpfecCodecMimeType; -RTC_EXTERN const NSString * const kRTCFlexfecCodecMimeType; -RTC_EXTERN const NSString * const kRTCOpusCodecMimeType; -RTC_EXTERN const NSString * const kRTCIsacCodecMimeType; -RTC_EXTERN const NSString * const kRTCL16CodecMimeType; -RTC_EXTERN const NSString * const kRTCG722CodecMimeType; -RTC_EXTERN const NSString * const kRTCIlbcCodecMimeType; -RTC_EXTERN const NSString * const kRTCPcmuCodecMimeType; -RTC_EXTERN const NSString * const kRTCPcmaCodecMimeType; -RTC_EXTERN const NSString * const kRTCDtmfCodecMimeType; -RTC_EXTERN const NSString * const kRTCComfortNoiseCodecMimeType; -RTC_EXTERN const NSString * const kRTCVp8CodecMimeType; -RTC_EXTERN const NSString * const kRTCVp9CodecMimeType; -RTC_EXTERN const NSString * const kRTCH264CodecMimeType; +RTC_EXTERN const NSString * const kRTCRtxCodecName; +RTC_EXTERN const NSString * const kRTCRedCodecName; +RTC_EXTERN const NSString * const kRTCUlpfecCodecName; +RTC_EXTERN const NSString * const kRTCFlexfecCodecName; +RTC_EXTERN const NSString * const kRTCOpusCodecName; +RTC_EXTERN const NSString * const kRTCIsacCodecName; +RTC_EXTERN const NSString * const kRTCL16CodecName; +RTC_EXTERN const NSString * const kRTCG722CodecName; +RTC_EXTERN const NSString * const kRTCIlbcCodecName; +RTC_EXTERN const NSString * const kRTCPcmuCodecName; +RTC_EXTERN const NSString * const kRTCPcmaCodecName; +RTC_EXTERN const NSString * const kRTCDtmfCodecName; +RTC_EXTERN const NSString * const kRTCComfortNoiseCodecName; +RTC_EXTERN const NSString * const kRTCVp8CodecName; +RTC_EXTERN const NSString * const kRTCVp9CodecName; +RTC_EXTERN const NSString * const kRTCH264CodecName; /** Defined in http://w3c.github.io/webrtc-pc/#idl-def-RTCRtpCodecParameters */ RTC_EXPORT @@ -39,18 +39,29 @@ RTC_EXPORT @property(nonatomic, assign) int payloadType; /** - * The codec MIME type. Valid types are listed in: + * The codec MIME subtype. Valid types are listed in: * http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-2 * * Several supported types are represented by the constants above. */ -@property(nonatomic, nonnull) NSString *mimeType; +@property(nonatomic, readonly, nonnull) NSString *name; + +/** + * The media type of this codec. Equivalent to MIME top-level type. + * + * Valid values are kRTCMediaStreamTrackKindAudio and + * kRTCMediaStreamTrackKindVideo. + */ +@property(nonatomic, readonly, nonnull) NSString *kind; /** The codec clock rate expressed in Hertz. */ -@property(nonatomic, assign) int clockRate; +@property(nonatomic, readonly, nullable) NSNumber *clockRate; -/** The number of channels (mono=1, stereo=2). */ -@property(nonatomic, assign) int channels; +/** + * The number of channels (mono=1, stereo=2). + * Set to null for video codecs. + **/ +@property(nonatomic, readonly, nullable) NSNumber *numChannels; - (instancetype)init NS_DESIGNATED_INITIALIZER;