NetEqImpl::GetDecoderFormat: Return RTP clockrate, not codec sample rate
Well, in fact we need to return both. But return codec sample rate separately and let the SdpAudioFormat contain the RTP clockrate, otherwise we're essentially lying to our callers. Bug: webrtc:11028 Change-Id: I40f36cb9db6b9824404ade6b0515a8312ff97009 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156307 Commit-Queue: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29444}
This commit is contained in:
@ -888,6 +888,9 @@ int ChannelReceive::GetRtpTimestampRateHz() const {
|
|||||||
// TODO(ossu): Zero clockrate can only happen if we've added an external
|
// TODO(ossu): Zero clockrate can only happen if we've added an external
|
||||||
// decoder for a format we don't support internally. Remove once that way of
|
// decoder for a format we don't support internally. Remove once that way of
|
||||||
// adding decoders is gone!
|
// adding decoders is gone!
|
||||||
|
// TODO(kwiberg): `decoder->second.clockrate_hz` is an RTP clockrate as it
|
||||||
|
// should, but `acm_receiver_.last_output_sample_rate_hz()` is a codec sample
|
||||||
|
// rate, which is not always the same thing.
|
||||||
return (decoder && decoder->second.clockrate_hz != 0)
|
return (decoder && decoder->second.clockrate_hz != 0)
|
||||||
? decoder->second.clockrate_hz
|
? decoder->second.clockrate_hz
|
||||||
: acm_receiver_.last_output_sample_rate_hz();
|
: acm_receiver_.last_output_sample_rate_hz();
|
||||||
|
@ -73,7 +73,7 @@ absl::optional<int> AcmReceiver::last_packet_sample_rate_hz() const {
|
|||||||
if (!last_decoder_) {
|
if (!last_decoder_) {
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
return last_decoder_->second.clockrate_hz;
|
return last_decoder_->sample_rate_hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AcmReceiver::last_output_sample_rate_hz() const {
|
int AcmReceiver::last_output_sample_rate_hz() const {
|
||||||
@ -89,7 +89,7 @@ int AcmReceiver::InsertPacket(const RTPHeader& rtp_header,
|
|||||||
|
|
||||||
int payload_type = rtp_header.payloadType;
|
int payload_type = rtp_header.payloadType;
|
||||||
auto format = neteq_->GetDecoderFormat(payload_type);
|
auto format = neteq_->GetDecoderFormat(payload_type);
|
||||||
if (format && absl::EqualsIgnoreCase(format->name, "red")) {
|
if (format && absl::EqualsIgnoreCase(format->sdp_format.name, "red")) {
|
||||||
// This is a RED packet. Get the format of the audio codec.
|
// This is a RED packet. Get the format of the audio codec.
|
||||||
payload_type = incoming_payload[0] & 0x7f;
|
payload_type = incoming_payload[0] & 0x7f;
|
||||||
format = neteq_->GetDecoderFormat(payload_type);
|
format = neteq_->GetDecoderFormat(payload_type);
|
||||||
@ -102,15 +102,17 @@ int AcmReceiver::InsertPacket(const RTPHeader& rtp_header,
|
|||||||
|
|
||||||
{
|
{
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
if (absl::EqualsIgnoreCase(format->name, "cn")) {
|
if (absl::EqualsIgnoreCase(format->sdp_format.name, "cn")) {
|
||||||
if (last_decoder_ && last_decoder_->second.num_channels > 1) {
|
if (last_decoder_ && last_decoder_->num_channels > 1) {
|
||||||
// This is a CNG and the audio codec is not mono, so skip pushing in
|
// This is a CNG and the audio codec is not mono, so skip pushing in
|
||||||
// packets into NetEq.
|
// packets into NetEq.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RTC_DCHECK(format);
|
last_decoder_ = DecoderInfo{/*payload_type=*/payload_type,
|
||||||
last_decoder_ = std::make_pair(payload_type, *format);
|
/*sample_rate_hz=*/format->sample_rate_hz,
|
||||||
|
/*num_channels=*/format->num_channels,
|
||||||
|
/*sdp_format=*/std::move(format->sdp_format)};
|
||||||
}
|
}
|
||||||
} // |crit_sect_| is released.
|
} // |crit_sect_| is released.
|
||||||
|
|
||||||
@ -221,8 +223,8 @@ absl::optional<std::pair<int, SdpAudioFormat>> AcmReceiver::LastDecoder()
|
|||||||
if (!last_decoder_) {
|
if (!last_decoder_) {
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
RTC_DCHECK_NE(-1, last_decoder_->first); // Payload type should be valid.
|
RTC_DCHECK_NE(-1, last_decoder_->payload_type);
|
||||||
return last_decoder_;
|
return std::make_pair(last_decoder_->payload_type, last_decoder_->sdp_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) const {
|
void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) const {
|
||||||
|
@ -203,11 +203,17 @@ class AcmReceiver {
|
|||||||
void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
|
void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct DecoderInfo {
|
||||||
|
int payload_type;
|
||||||
|
int sample_rate_hz;
|
||||||
|
int num_channels;
|
||||||
|
SdpAudioFormat sdp_format;
|
||||||
|
};
|
||||||
|
|
||||||
uint32_t NowInTimestamp(int decoder_sampling_rate) const;
|
uint32_t NowInTimestamp(int decoder_sampling_rate) const;
|
||||||
|
|
||||||
rtc::CriticalSection crit_sect_;
|
rtc::CriticalSection crit_sect_;
|
||||||
absl::optional<std::pair<int, SdpAudioFormat>> last_decoder_
|
absl::optional<DecoderInfo> last_decoder_ RTC_GUARDED_BY(crit_sect_);
|
||||||
RTC_GUARDED_BY(crit_sect_);
|
|
||||||
ACMResampler resampler_ RTC_GUARDED_BY(crit_sect_);
|
ACMResampler resampler_ RTC_GUARDED_BY(crit_sect_);
|
||||||
std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(crit_sect_);
|
std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(crit_sect_);
|
||||||
CallStatistics call_stats_ RTC_GUARDED_BY(crit_sect_);
|
CallStatistics call_stats_ RTC_GUARDED_BY(crit_sect_);
|
||||||
|
@ -143,6 +143,13 @@ class NetEq {
|
|||||||
|
|
||||||
enum ReturnCodes { kOK = 0, kFail = -1 };
|
enum ReturnCodes { kOK = 0, kFail = -1 };
|
||||||
|
|
||||||
|
// Return type for GetDecoderFormat.
|
||||||
|
struct DecoderFormat {
|
||||||
|
int sample_rate_hz;
|
||||||
|
int num_channels;
|
||||||
|
SdpAudioFormat sdp_format;
|
||||||
|
};
|
||||||
|
|
||||||
// Creates a new NetEq object, with parameters set in |config|. The |config|
|
// Creates a new NetEq object, with parameters set in |config|. The |config|
|
||||||
// object will only have to be valid for the duration of the call to this
|
// object will only have to be valid for the duration of the call to this
|
||||||
// method.
|
// method.
|
||||||
@ -265,7 +272,7 @@ class NetEq {
|
|||||||
|
|
||||||
// Returns the decoder info for the given payload type. Returns empty if no
|
// Returns the decoder info for the given payload type. Returns empty if no
|
||||||
// such payload type was registered.
|
// such payload type was registered.
|
||||||
virtual absl::optional<SdpAudioFormat> GetDecoderFormat(
|
virtual absl::optional<DecoderFormat> GetDecoderFormat(
|
||||||
int payload_type) const = 0;
|
int payload_type) const = 0;
|
||||||
|
|
||||||
// Flushes both the packet buffer and the sync buffer.
|
// Flushes both the packet buffer and the sync buffer.
|
||||||
|
@ -392,21 +392,23 @@ int NetEqImpl::last_output_sample_rate_hz() const {
|
|||||||
return last_output_sample_rate_hz_;
|
return last_output_sample_rate_hz_;
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<SdpAudioFormat> NetEqImpl::GetDecoderFormat(
|
absl::optional<NetEq::DecoderFormat> NetEqImpl::GetDecoderFormat(
|
||||||
int payload_type) const {
|
int payload_type) const {
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
const DecoderDatabase::DecoderInfo* const di =
|
const DecoderDatabase::DecoderInfo* const di =
|
||||||
decoder_database_->GetDecoderInfo(payload_type);
|
decoder_database_->GetDecoderInfo(payload_type);
|
||||||
if (!di) {
|
if (di) {
|
||||||
return absl::nullopt; // Payload type not registered.
|
|
||||||
}
|
|
||||||
|
|
||||||
SdpAudioFormat format = di->GetFormat();
|
|
||||||
// TODO(solenberg): This is legacy but messed up - mixing RTP rate and SR.
|
|
||||||
format.clockrate_hz = di->IsRed() ? 8000 : di->SampleRateHz();
|
|
||||||
const AudioDecoder* const decoder = di->GetDecoder();
|
const AudioDecoder* const decoder = di->GetDecoder();
|
||||||
format.num_channels = decoder ? decoder->Channels() : 1;
|
// TODO(kwiberg): Why the special case for RED?
|
||||||
return format;
|
return DecoderFormat{
|
||||||
|
/*sample_rate_hz=*/di->IsRed() ? 8000 : di->SampleRateHz(),
|
||||||
|
/*num_channels=*/
|
||||||
|
decoder ? rtc::dchecked_cast<int>(decoder->Channels()) : 1,
|
||||||
|
/*sdp_format=*/di->GetFormat()};
|
||||||
|
} else {
|
||||||
|
// Payload type not registered.
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetEqImpl::FlushBuffers() {
|
void NetEqImpl::FlushBuffers() {
|
||||||
|
@ -182,7 +182,7 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
|
|
||||||
int last_output_sample_rate_hz() const override;
|
int last_output_sample_rate_hz() const override;
|
||||||
|
|
||||||
absl::optional<SdpAudioFormat> GetDecoderFormat(
|
absl::optional<DecoderFormat> GetDecoderFormat(
|
||||||
int payload_type) const override;
|
int payload_type) const override;
|
||||||
|
|
||||||
// Flushes both the packet buffer and the sync buffer.
|
// Flushes both the packet buffer and the sync buffer.
|
||||||
|
Reference in New Issue
Block a user