Chromium Code Reviews| Index: webrtc/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc |
| diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..45bb6efe4dbdb5db504052eed5b2a39a3e2118b5 |
| --- /dev/null |
| +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc |
| @@ -0,0 +1,166 @@ |
| +/* |
| + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| + |
| +#include "webrtc/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h" |
| + |
| +#include <algorithm> |
| +#include <limits> |
| +#include <utility> |
| + |
| +namespace webrtc { |
| +namespace test { |
| + |
| +void NetEqDelayAnalyzer::AfterInsertPacket( |
| + const test::NetEqInput::PacketData& packet, |
| + NetEq* neteq) { |
| + data_.insert( |
| + std::make_pair(packet.header.timestamp, |
| + TimingData(packet.header.sequenceNumber, packet.time_ms))); |
| +} |
| + |
| +void NetEqDelayAnalyzer::BeforeGetAudio(NetEq* neteq) { |
| + last_sync_buffer_ms_ = neteq->SyncBufferSizeMs(); |
| +} |
| + |
| +void NetEqDelayAnalyzer::AfterGetAudio(int64_t time_now_ms, |
| + const AudioFrame& audio_frame, |
| + bool muted, |
|
ivoc
2017/05/16 13:25:50
Since this is not used you can comment out the nam
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + NetEq* neteq) { |
| + get_audio_time_ms_.push_back(time_now_ms); |
| + // Check what timestamps were decoded in the last GetAudio call. |
| + std::vector<uint32_t> dec_ts = neteq->LastDecodedTimestamps(); |
| + // Find those timestamps in data_, insert their decoding time and sync |
| + // delay. |
| + for (uint32_t ts : dec_ts) { |
| + auto it = data_.find(ts); |
| + if (it == data_.end()) { |
| + // This is a packet that was split out from another packet. Skip it. |
| + continue; |
| + } |
| + RTC_CHECK(!it->second.decode_get_audio_count) |
|
ivoc
2017/05/16 13:25:50
I think this code block would be easier to read wi
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + << "Decode time already written"; |
| + it->second.decode_get_audio_count = |
| + rtc::Optional<int64_t>(get_audio_count_); |
| + RTC_CHECK(!it->second.sync_delay_ms) << "Decode time already written"; |
| + it->second.sync_delay_ms = rtc::Optional<int64_t>(last_sync_buffer_ms_); |
| + it->second.target_delay_ms = rtc::Optional<int>(neteq->TargetDelayMs()); |
| + it->second.current_delay_ms = |
| + rtc::Optional<int>(neteq->FilteredCurrentDelayMs()); |
| + } |
| + last_sample_rate_hz_ = audio_frame.sample_rate_hz_; |
| + ++get_audio_count_; |
| +} |
| + |
| +void NetEqDelayAnalyzer::CreateGraphs( |
|
ivoc
2017/05/16 13:25:50
This function is pretty long, so you can consider
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + std::vector<float>* send_time_s, |
| + std::vector<float>* arrival_delay_ms, |
| + std::vector<float>* corrected_arrival_delay_ms, |
| + std::vector<rtc::Optional<float>>* playout_delay_ms, |
| + std::vector<rtc::Optional<float>>* target_delay_ms) const { |
| + // Create nominal_get_audio_time_ms, a vector starting at |
| + // get_audio_time_ms_[0] and increasing by 10 for each element. |
| + std::vector<int64_t> nominal_get_audio_time_ms(get_audio_time_ms_.size()); |
| + nominal_get_audio_time_ms[0] = get_audio_time_ms_[0]; |
| + std::transform( |
| + nominal_get_audio_time_ms.begin(), nominal_get_audio_time_ms.end() - 1, |
|
ivoc
2017/05/16 13:25:50
Will this crash if nominal_get_audio_time_ms is em
hlundin-webrtc
2017/05/30 14:56:06
Presumably, but we already set the first element o
ivoc
2017/05/30 16:29:45
Acknowledged.
|
| + nominal_get_audio_time_ms.begin() + 1, [](int64_t& x) { return x + 10; }); |
| + RTC_DCHECK( |
| + std::is_sorted(get_audio_time_ms_.begin(), get_audio_time_ms_.end())); |
| + |
| + std::vector<double> rtp_timestamps_ms; |
| + std::vector<double> arrival_time_ms; |
| + std::vector<double> corrected_arrival_time_ms; |
| + std::vector<int64_t> decode_get_audio_count; |
| + std::vector<int64_t> sync_delay_ms; |
| + std::vector<int> raw_target_delay_ms; |
| + std::vector<int> filtered_delay_ms; |
| + double offset = std::numeric_limits<double>::max(); |
| + |
| + TimestampUnwrapper unwrapper; |
| + for (auto& d : data_) { |
|
ivoc
2017/05/16 13:25:50
Please add a comment to explain what this loop doe
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + rtp_timestamps_ms.push_back(unwrapper.Unwrap(d.first) / |
| + (last_sample_rate_hz_ / 1000.f)); |
| + arrival_time_ms.push_back(d.second.arrival_time_ms); |
|
ivoc
2017/05/16 13:25:50
Also here I would suggest to introduce an intermed
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + offset = |
| + std::min(offset, arrival_time_ms.back() - rtp_timestamps_ms.back()); |
| + // Interpolate arrival times. |
| + double x = d.second.arrival_time_ms; |
| + // Find first element which is larger than x. |
| + auto it = std::find_if(get_audio_time_ms_.begin(), get_audio_time_ms_.end(), |
| + [x](int64_t v) -> bool { return v > x; }); |
| + if (it == get_audio_time_ms_.end()) { |
| + --it; |
| + } |
| + const size_t upper_ix = it - get_audio_time_ms_.begin(); |
| + |
| + size_t lower_ix; |
| + if (upper_ix == 0 || get_audio_time_ms_[upper_ix] <= x) { |
| + lower_ix = upper_ix; |
| + } else { |
| + lower_ix = upper_ix - 1; |
| + } |
| + double y; |
|
ivoc
2017/05/16 13:25:50
The variable names are a bit cryptic in this funct
hlundin-webrtc
2017/05/30 14:56:06
I broke this part out to a generalized interpolati
|
| + if (lower_ix == upper_ix) { |
| + y = nominal_get_audio_time_ms[lower_ix]; |
| + } else { |
| + RTC_DCHECK_NE(get_audio_time_ms_[lower_ix], get_audio_time_ms_[upper_ix]); |
| + y = (x - get_audio_time_ms_[lower_ix]) * |
| + (nominal_get_audio_time_ms[upper_ix] - |
| + nominal_get_audio_time_ms[lower_ix]) / |
| + (get_audio_time_ms_[upper_ix] - get_audio_time_ms_[lower_ix]) + |
| + nominal_get_audio_time_ms[lower_ix]; |
| + } |
| + corrected_arrival_time_ms.push_back(y); |
| + |
| + decode_get_audio_count.push_back( |
| + d.second.decode_get_audio_count.value_or(-1)); |
| + sync_delay_ms.push_back(d.second.sync_delay_ms.value_or(-1)); |
| + raw_target_delay_ms.push_back(d.second.target_delay_ms.value_or(-1)); |
| + filtered_delay_ms.push_back(d.second.current_delay_ms.value_or(-1)); |
| + } |
| + send_time_s->resize(rtp_timestamps_ms.size()); |
| + std::transform(rtp_timestamps_ms.begin(), rtp_timestamps_ms.end(), |
| + send_time_s->begin(), [rtp_timestamps_ms](double x) { |
| + return (x - rtp_timestamps_ms[0]) / 1000.f; |
| + }); |
| + |
| + RTC_DCHECK_EQ(send_time_s->size(), corrected_arrival_time_ms.size()); |
| + RTC_DCHECK_EQ(send_time_s->size(), rtp_timestamps_ms.size()); |
| + RTC_DCHECK_EQ(send_time_s->size(), decode_get_audio_count.size()); |
| + for (size_t i = 0; i < send_time_s->size(); ++i) { |
|
ivoc
2017/05/16 13:25:50
Please add a comment to explain what this for loop
hlundin-webrtc
2017/05/30 14:56:06
Done.
|
| + const double y = |
| + corrected_arrival_time_ms[i] - (rtp_timestamps_ms[i] + offset); |
| + corrected_arrival_delay_ms->emplace_back(y); |
|
ivoc
2017/05/16 13:25:50
This is exactly the same as push_back for a vector
hlundin-webrtc
2017/05/30 14:56:06
You are right. This is over-kill. I changed them a
|
| + const double z = arrival_time_ms[i] - (rtp_timestamps_ms[i] + offset); |
| + arrival_delay_ms->emplace_back(z); |
| + |
| + if (decode_get_audio_count[i] > -1) { |
| + RTC_DCHECK_NE(sync_delay_ms[i], -1); |
| + const float playout_ms = decode_get_audio_count[i] * 10 + |
| + get_audio_time_ms_[0] + sync_delay_ms[i] - |
| + (rtp_timestamps_ms[i] + offset); |
| + playout_delay_ms->emplace_back(rtc::Optional<float>(playout_ms)); |
| + RTC_DCHECK_GT(raw_target_delay_ms[i], -1); |
| + RTC_DCHECK_GT(filtered_delay_ms[i], -1); |
| + const float target = |
| + playout_ms - filtered_delay_ms[i] + raw_target_delay_ms[i]; |
| + target_delay_ms->emplace_back(rtc::Optional<float>(target)); |
| + } else { |
| + playout_delay_ms->emplace_back(rtc::Optional<float>()); |
| + target_delay_ms->emplace_back(rtc::Optional<float>()); |
| + } |
| + } |
| + RTC_DCHECK_EQ(send_time_s->size(), corrected_arrival_delay_ms->size()); |
| + RTC_DCHECK_EQ(send_time_s->size(), playout_delay_ms->size()); |
| + RTC_DCHECK_EQ(send_time_s->size(), target_delay_ms->size()); |
| +} |
| + |
| +} // namespace test |
| +} // namespace webrtc |