Commit 27604226 authored by Ken MacKay's avatar Ken MacKay Committed by Commit Bot

[Chromecast] Replace AudioResampler with AudioClockSimulator

Merge-With: eureka-internal/348424
Change-Id: I3a3971c4e0130c80dc1016d3fddf9c1e9f726c92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1982704Reviewed-by: default avatarYuchen Liu <yucliu@chromium.org>
Commit-Queue: Kenneth MacKay <kmackay@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728076}
parent fe15aa04
...@@ -46,24 +46,6 @@ cast_source_set("processing") { ...@@ -46,24 +46,6 @@ cast_source_set("processing") {
cflags = [ "-ffast-math" ] cflags = [ "-ffast-math" ]
} }
cast_source_set("audio_resampler") {
sources = [
"audio_resampler.cc",
"audio_resampler.h",
]
deps = [
"//base",
"//chromecast/media/cma/base",
"//media",
]
# Use fastest possible float math.
configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_speed" ]
cflags = [ "-ffast-math" ]
}
cast_source_set("audio") { cast_source_set("audio") {
sources = [ sources = [
"cast_audio_input_stream.cc", "cast_audio_input_stream.cc",
......
...@@ -13,14 +13,6 @@ ...@@ -13,14 +13,6 @@
namespace chromecast { namespace chromecast {
namespace media { namespace media {
namespace {
int64_t FramesToTime(int64_t frames, int sample_rate) {
return frames * 1000000 / sample_rate;
}
} // namespace
constexpr int AudioClockSimulator::kInterpolateWindow; constexpr int AudioClockSimulator::kInterpolateWindow;
constexpr double AudioClockSimulator::kMaxRate; constexpr double AudioClockSimulator::kMaxRate;
constexpr double AudioClockSimulator::kMinRate; constexpr double AudioClockSimulator::kMinRate;
...@@ -53,9 +45,11 @@ int AudioClockSimulator::sample_rate() const { ...@@ -53,9 +45,11 @@ int AudioClockSimulator::sample_rate() const {
double AudioClockSimulator::SetRate(double rate) { double AudioClockSimulator::SetRate(double rate) {
rate = std::max(kMinRate, std::min(rate, kMaxRate)); rate = std::max(kMinRate, std::min(rate, kMaxRate));
clock_rate_ = rate; if (clock_rate_ != rate) {
input_frames_ = 0; clock_rate_ = rate;
output_frames_ = 0; input_frames_ = 0;
output_frames_ = 0;
}
return rate; return rate;
} }
...@@ -66,6 +60,14 @@ int AudioClockSimulator::DelayFrames() const { ...@@ -66,6 +60,14 @@ int AudioClockSimulator::DelayFrames() const {
return 0; return 0;
} }
void AudioClockSimulator::SetSampleRate(int sample_rate) {
sample_rate_ = sample_rate;
}
void AudioClockSimulator::SetPlaybackRate(double playback_rate) {
playback_rate_ = playback_rate;
}
int AudioClockSimulator::FillFrames(int num_frames, int AudioClockSimulator::FillFrames(int num_frames,
int64_t playout_timestamp, int64_t playout_timestamp,
float* const* channel_data) { float* const* channel_data) {
...@@ -107,7 +109,7 @@ int AudioClockSimulator::FillFrames(int num_frames, ...@@ -107,7 +109,7 @@ int AudioClockSimulator::FillFrames(int num_frames,
for (size_t c = 0; c < num_channels_; ++c) { for (size_t c = 0; c < num_channels_; ++c) {
channels[c] = channel_data[c] + filled; channels[c] = channel_data[c] + filled;
} }
int64_t timestamp = playout_timestamp + FramesToTime(filled, sample_rate_); int64_t timestamp = playout_timestamp + FramesToMicroseconds(filled);
int desired = std::min(num_frames - filled, kInterpolateWindow); int desired = std::min(num_frames - filled, kInterpolateWindow);
int provided = provider_->FillFrames(desired, timestamp, channels); int provided = provider_->FillFrames(desired, timestamp, channels);
input_frames_ += provided; input_frames_ += provided;
...@@ -148,7 +150,7 @@ AudioClockSimulator::FillResult AudioClockSimulator::FillDataLengthen( ...@@ -148,7 +150,7 @@ AudioClockSimulator::FillResult AudioClockSimulator::FillDataLengthen(
// index 1. // index 1.
channels[c] = scratch_buffer_->channel(c) + 1; channels[c] = scratch_buffer_->channel(c) + 1;
} }
int64_t timestamp = playout_timestamp + FramesToTime(offset, sample_rate_); int64_t timestamp = playout_timestamp + FramesToMicroseconds(offset);
int provided = provider_->FillFrames(desired_fill, timestamp, channels); int provided = provider_->FillFrames(desired_fill, timestamp, channels);
input_frames_ += provided; input_frames_ += provided;
InterpolateLonger(provided, channel_data, offset); InterpolateLonger(provided, channel_data, offset);
...@@ -213,7 +215,7 @@ AudioClockSimulator::FillResult AudioClockSimulator::FillDataShorten( ...@@ -213,7 +215,7 @@ AudioClockSimulator::FillResult AudioClockSimulator::FillDataShorten(
for (size_t c = 0; c < num_channels_; ++c) { for (size_t c = 0; c < num_channels_; ++c) {
channels[c] = scratch_buffer_->channel(c) + fill_offset; channels[c] = scratch_buffer_->channel(c) + fill_offset;
} }
int64_t timestamp = playout_timestamp + FramesToTime(offset, sample_rate_); int64_t timestamp = playout_timestamp + FramesToMicroseconds(offset);
int provided = provider_->FillFrames(desired_fill, timestamp, channels); int provided = provider_->FillFrames(desired_fill, timestamp, channels);
if (provided == 0) { if (provided == 0) {
return {false, 0}; return {false, 0};
...@@ -260,5 +262,9 @@ void AudioClockSimulator::InterpolateShorter(int num_frames, ...@@ -260,5 +262,9 @@ void AudioClockSimulator::InterpolateShorter(int num_frames,
} }
} }
int64_t AudioClockSimulator::FramesToMicroseconds(int64_t frames) {
return frames * 1000000 / (sample_rate_ * playback_rate_);
}
} // namespace media } // namespace media
} // namespace chromecast } // namespace chromecast
...@@ -53,6 +53,13 @@ class AudioClockSimulator : public AudioProvider { ...@@ -53,6 +53,13 @@ class AudioClockSimulator : public AudioProvider {
// internally. Will always return 0 or 1. // internally. Will always return 0 or 1.
int DelayFrames() const; int DelayFrames() const;
// Sets a new playback sample rate. Needed to calculate timestamps correctly.
void SetSampleRate(int sample_rate);
// Sets the playback rate (rate at which samples are played out relative to
// the sample rate). Needed to calculate timestamps correctly.
void SetPlaybackRate(double playback_rate);
// AudioProvider implementation: // AudioProvider implementation:
int FillFrames(int num_frames, int FillFrames(int num_frames,
int64_t playout_timestamp, int64_t playout_timestamp,
...@@ -87,9 +94,12 @@ class AudioClockSimulator : public AudioProvider { ...@@ -87,9 +94,12 @@ class AudioClockSimulator : public AudioProvider {
float* const* channel_data, float* const* channel_data,
int offset); int offset);
int64_t FramesToMicroseconds(int64_t frames);
AudioProvider* const provider_; AudioProvider* const provider_;
const int sample_rate_; int sample_rate_;
const size_t num_channels_; const size_t num_channels_;
double playback_rate_ = 1.0;
double clock_rate_ = 1.0; double clock_rate_ = 1.0;
int64_t input_frames_ = 0; int64_t input_frames_ = 0;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/audio/audio_resampler.h"
#include <algorithm>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
#include "media/base/decoder_buffer.h"
namespace chromecast {
namespace media {
namespace {
constexpr size_t kMaxChannels = 8;
} // namespace
AudioResampler::AudioResampler(size_t channel_count)
: channel_count_(channel_count) {
DCHECK_LE(channel_count_, kMaxChannels);
}
scoped_refptr<media::DecoderBufferBase> AudioResampler::ResampleBuffer(
scoped_refptr<media::DecoderBufferBase> buffer) {
DCHECK(buffer);
const int num_frames = buffer->data_size() / (channel_count_ * sizeof(float));
input_frames_for_clock_rate_ += num_frames;
int64_t expected_output_frames = output_frames_for_clock_rate_ + num_frames;
int64_t desired_output_frames =
input_frames_for_clock_rate_ / media_clock_rate_;
if (expected_output_frames > desired_output_frames) {
output_frames_for_clock_rate_ += num_frames - 1;
return ShortenBuffer(std::move(buffer));
} else if (expected_output_frames < desired_output_frames) {
output_frames_for_clock_rate_ += num_frames + 1;
return LengthenBuffer(std::move(buffer));
}
output_frames_for_clock_rate_ += num_frames;
return buffer;
}
double AudioResampler::SetMediaClockRate(double rate) {
// We are only allowed to deviate from 1.0x playback rate by this much,
// because we only add/remove 1 frame each buffer. The buffers are typically
// 1024 frames, and even if they're not, we limit to this rate anyway,
// because bigger changes may start being perceptible.
double max_deviation = 1.0 / 1024.0;
rate = std::min(rate, 1.0 + max_deviation);
rate = std::max(rate, 1.0 - max_deviation);
media_clock_rate_ = rate;
input_frames_for_clock_rate_ = 0;
output_frames_for_clock_rate_ = 0;
return rate;
}
scoped_refptr<media::DecoderBufferBase> AudioResampler::LengthenBuffer(
scoped_refptr<media::DecoderBufferBase> buffer) {
const int num_frames = buffer->data_size() / (channel_count_ * sizeof(float));
const int new_num_frames = num_frames + 1;
auto delayed_buffer = base::MakeRefCounted<::media::DecoderBuffer>(
new_num_frames * (channel_count_ * sizeof(float)));
delayed_buffer->set_timestamp(
base::TimeDelta::FromMicroseconds(buffer->timestamp()));
const float* old_channels[kMaxChannels];
float* new_channels[kMaxChannels];
for (size_t c = 0; c < channel_count_; ++c) {
old_channels[c] =
reinterpret_cast<const float*>(buffer->data()) + c * num_frames;
new_channels[c] =
reinterpret_cast<float*>(delayed_buffer->writable_data()) +
c * new_num_frames;
}
for (size_t c = 0; c < channel_count_; ++c) {
new_channels[c][0] = old_channels[c][0];
// Linearly interpolate between all n input samples to produce (n - 1)
// samples, plus the first and last sample = (n + 1) output samples.
for (int s = 1; s < num_frames; ++s) {
new_channels[c][s] =
(old_channels[c][s - 1] * s + old_channels[c][s] * (num_frames - s)) /
num_frames;
}
new_channels[c][num_frames] = old_channels[c][num_frames - 1];
}
return base::MakeRefCounted<media::DecoderBufferAdapter>(delayed_buffer);
}
scoped_refptr<media::DecoderBufferBase> AudioResampler::ShortenBuffer(
scoped_refptr<media::DecoderBufferBase> buffer) {
const int num_frames = buffer->data_size() / (channel_count_ * sizeof(float));
const int new_num_frames = num_frames - 1;
auto cut_buffer = base::MakeRefCounted<::media::DecoderBuffer>(
new_num_frames * (channel_count_ * sizeof(float)));
cut_buffer->set_timestamp(
base::TimeDelta::FromMicroseconds(buffer->timestamp()));
const float* old_channels[kMaxChannels];
float* new_channels[kMaxChannels];
for (size_t c = 0; c < channel_count_; ++c) {
old_channels[c] =
reinterpret_cast<const float*>(buffer->data()) + c * num_frames;
new_channels[c] = reinterpret_cast<float*>(cut_buffer->writable_data()) +
c * new_num_frames;
}
DCHECK_GE(num_frames, 2);
for (size_t c = 0; c < channel_count_; ++c) {
// Linearly interpolate between all n input samples to produce (n - 1)
// output samples.
for (int s = 0; s < new_num_frames; ++s) {
new_channels[c][s] = (old_channels[c][s] * (num_frames - (s + 1)) +
old_channels[c][s + 1] * (s + 1)) /
num_frames;
}
}
return base::MakeRefCounted<media::DecoderBufferAdapter>(cut_buffer);
}
} // namespace media
} // namespace chromecast
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_MEDIA_AUDIO_AUDIO_RESAMPLER_H_
#define CHROMECAST_MEDIA_AUDIO_AUDIO_RESAMPLER_H_
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace chromecast {
namespace media {
class DecoderBufferBase;
// The audio resampler allows us to apply small changes to the rate of audio
// playback via (supposedly) imperceptible changes.
//
// Note: only works for planar float data.
class AudioResampler {
public:
explicit AudioResampler(size_t channel_count);
// Sets the effective media clock rate.
double SetMediaClockRate(double rate);
// Resamples a buffer, adding or dropping frames as necessary to match the
// media clock rate.
scoped_refptr<media::DecoderBufferBase> ResampleBuffer(
scoped_refptr<media::DecoderBufferBase> buffer);
private:
// Adds a frame to a buffer.
scoped_refptr<media::DecoderBufferBase> LengthenBuffer(
scoped_refptr<media::DecoderBufferBase> buffer);
// Cuts a frame from a buffer.
scoped_refptr<media::DecoderBufferBase> ShortenBuffer(
scoped_refptr<media::DecoderBufferBase> buffer);
const size_t channel_count_;
double media_clock_rate_ = 1.0;
int64_t input_frames_for_clock_rate_ = 0;
int64_t output_frames_for_clock_rate_ = 0;
DISALLOW_COPY_AND_ASSIGN(AudioResampler);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_AUDIO_AUDIO_RESAMPLER_H_
...@@ -87,6 +87,12 @@ message SetPaused { ...@@ -87,6 +87,12 @@ message SetPaused {
optional bool paused = 1; optional bool paused = 1;
} }
// Sets (or simulates setting) the audio clock rate. If the provided rate is
// not supported, the rate will be clamped to the supported range.
message SetAudioClockRate {
optional double rate = 1;
}
// Indicates that previously pushed audio data has been queued for playback, // Indicates that previously pushed audio data has been queued for playback,
// and the next audio data that is pushed to the mixer will start playing at // and the next audio data that is pushed to the mixer will start playing at
// |next_playback_timestamp|. // |next_playback_timestamp|.
...@@ -225,4 +231,5 @@ message Generic { ...@@ -225,4 +231,5 @@ message Generic {
optional Error error = 20; optional Error error = 20;
optional NumOutputChannels set_num_output_channels = 21; optional NumOutputChannels set_num_output_channels = 21;
optional StreamInterruption stream_interruption = 22; optional StreamInterruption stream_interruption = 22;
optional SetAudioClockRate set_audio_clock_rate = 23;
} }
...@@ -113,6 +113,15 @@ void OutputStreamConnection::SetPlaybackRate(float playback_rate) { ...@@ -113,6 +113,15 @@ void OutputStreamConnection::SetPlaybackRate(float playback_rate) {
} }
} }
void OutputStreamConnection::SetAudioClockRate(double rate) {
audio_clock_rate_ = rate;
if (socket_) {
Generic message;
message.mutable_set_audio_clock_rate()->set_rate(rate);
socket_->SendProto(message);
}
}
void OutputStreamConnection::Pause() { void OutputStreamConnection::Pause() {
paused_ = true; paused_ = true;
if (socket_) { if (socket_) {
...@@ -145,6 +154,9 @@ void OutputStreamConnection::OnConnected(std::unique_ptr<MixerSocket> socket) { ...@@ -145,6 +154,9 @@ void OutputStreamConnection::OnConnected(std::unique_ptr<MixerSocket> socket) {
if (playback_rate_ != 1.0f) { if (playback_rate_ != 1.0f) {
message.mutable_set_playback_rate()->set_playback_rate(playback_rate_); message.mutable_set_playback_rate()->set_playback_rate(playback_rate_);
} }
if (audio_clock_rate_ != 1.0) {
message.mutable_set_audio_clock_rate()->set_rate(audio_clock_rate_);
}
if (volume_multiplier_ != 1.0f) { if (volume_multiplier_ != 1.0f) {
message.mutable_set_stream_volume()->set_volume(volume_multiplier_); message.mutable_set_stream_volume()->set_volume(volume_multiplier_);
} }
......
...@@ -90,6 +90,10 @@ class OutputStreamConnection : public MixerConnection, ...@@ -90,6 +90,10 @@ class OutputStreamConnection : public MixerConnection,
// 2.0 / sample_rate seconds. // 2.0 / sample_rate seconds.
void SetPlaybackRate(float playback_rate); void SetPlaybackRate(float playback_rate);
// Changes the audio output clock rate. If the provided |rate| is outside of
// the supported range, the rate will be clamped to the supported range.
void SetAudioClockRate(double rate);
// Pauses playback. // Pauses playback.
void Pause(); void Pause();
...@@ -120,6 +124,7 @@ class OutputStreamConnection : public MixerConnection, ...@@ -120,6 +124,7 @@ class OutputStreamConnection : public MixerConnection,
int64_t start_pts_ = INT64_MIN; int64_t start_pts_ = INT64_MIN;
float playback_rate_ = 1.0f; float playback_rate_ = 1.0f;
double audio_clock_rate_ = 1.0;
bool paused_ = false; bool paused_ = false;
bool sent_eos_ = false; bool sent_eos_ = false;
......
...@@ -166,7 +166,6 @@ cast_source_set("for_mixer_audio") { ...@@ -166,7 +166,6 @@ cast_source_set("for_mixer_audio") {
":volume_map", ":volume_map",
"//base", "//base",
"//chromecast/base", "//chromecast/base",
"//chromecast/media/audio:audio_resampler",
"//chromecast/media/audio:processing", "//chromecast/media/audio:processing",
"//chromecast/media/audio/mixer_service:common", "//chromecast/media/audio/mixer_service:common",
"//chromecast/media/audio/mixer_service:control_connection", "//chromecast/media/audio/mixer_service:control_connection",
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "chromecast/base/chromecast_switches.h" #include "chromecast/base/chromecast_switches.h"
#include "chromecast/base/task_runner_impl.h" #include "chromecast/base/task_runner_impl.h"
#include "chromecast/media/audio/audio_resampler.h" #include "chromecast/media/audio/audio_clock_simulator.h"
#include "chromecast/media/audio/mixer_service/conversions.h" #include "chromecast/media/audio/mixer_service/conversions.h"
#include "chromecast/media/audio/mixer_service/mixer_service.pb.h" #include "chromecast/media/audio/mixer_service/mixer_service.pb.h"
#include "chromecast/media/audio/mixer_service/mixer_socket.h" #include "chromecast/media/audio/mixer_service/mixer_socket.h"
...@@ -175,9 +175,6 @@ void AudioDecoderForMixer::CreateMixerInput(const AudioConfig& config, ...@@ -175,9 +175,6 @@ void AudioDecoderForMixer::CreateMixerInput(const AudioConfig& config,
CreateBufferPool(config, buffer_pool_frames_); CreateBufferPool(config, buffer_pool_frames_);
DCHECK_GT(buffer_pool_frames_, 0); DCHECK_GT(buffer_pool_frames_, 0);
audio_resampler_ = std::make_unique<AudioResampler>(config.channel_number);
audio_resampler_->SetMediaClockRate(av_sync_clock_rate_);
mixer_service::OutputStreamParams params; mixer_service::OutputStreamParams params;
params.set_stream_type( params.set_stream_type(
backend_->Primary() backend_->Primary()
...@@ -202,6 +199,7 @@ void AudioDecoderForMixer::CreateMixerInput(const AudioConfig& config, ...@@ -202,6 +199,7 @@ void AudioDecoderForMixer::CreateMixerInput(const AudioConfig& config,
std::make_unique<mixer_service::OutputStreamConnection>(this, params); std::make_unique<mixer_service::OutputStreamConnection>(this, params);
mixer_input_->Connect(); mixer_input_->Connect();
mixer_input_->SetVolumeMultiplier(volume_multiplier_); mixer_input_->SetVolumeMultiplier(volume_multiplier_);
mixer_input_->SetAudioClockRate(av_sync_clock_rate_);
} }
void AudioDecoderForMixer::StartPlaybackAt(int64_t playback_start_timestamp) { void AudioDecoderForMixer::StartPlaybackAt(int64_t playback_start_timestamp) {
...@@ -268,12 +266,12 @@ float AudioDecoderForMixer::SetPlaybackRate(float rate) { ...@@ -268,12 +266,12 @@ float AudioDecoderForMixer::SetPlaybackRate(float rate) {
return rate; return rate;
} }
float AudioDecoderForMixer::SetAvSyncPlaybackRate(float rate) { double AudioDecoderForMixer::SetAvSyncPlaybackRate(double rate) {
av_sync_clock_rate_ = rate; av_sync_clock_rate_ = std::max(AudioClockSimulator::kMinRate,
if (audio_resampler_) { std::min(rate, AudioClockSimulator::kMaxRate));
return audio_resampler_->SetMediaClockRate(rate); if (mixer_input_)
} mixer_input_->SetAudioClockRate(av_sync_clock_rate_);
return rate; return av_sync_clock_rate_;
} }
bool AudioDecoderForMixer::GetTimestampedPts(int64_t* timestamp, bool AudioDecoderForMixer::GetTimestampedPts(int64_t* timestamp,
...@@ -534,18 +532,7 @@ void AudioDecoderForMixer::WritePcm(scoped_refptr<DecoderBufferBase> buffer) { ...@@ -534,18 +532,7 @@ void AudioDecoderForMixer::WritePcm(scoped_refptr<DecoderBufferBase> buffer) {
return; return;
} }
// TODO(kmackay) This could be made more efficient by reducing memory const int frame_count = buffer->data_size() / frame_size;
// allocations and copies. For example we would resample (and maybe decode)
// directly into an IOBuffer.
DCHECK(audio_resampler_);
scoped_refptr<DecoderBufferBase> resampled =
(original_frame_count > 1
? audio_resampler_->ResampleBuffer(std::move(buffer))
: std::move(buffer));
const int frame_count = resampled->data_size() / frame_size;
// We only resample if there was more than 1 frame, and the resampler only
// subtracts at most 1 frame.
DCHECK_GT(frame_count, 0); DCHECK_GT(frame_count, 0);
if (frame_count > buffer_pool_frames_) { if (frame_count > buffer_pool_frames_) {
...@@ -553,12 +540,12 @@ void AudioDecoderForMixer::WritePcm(scoped_refptr<DecoderBufferBase> buffer) { ...@@ -553,12 +540,12 @@ void AudioDecoderForMixer::WritePcm(scoped_refptr<DecoderBufferBase> buffer) {
} }
auto io_buffer = buffer_pool_->GetBuffer(); auto io_buffer = buffer_pool_->GetBuffer();
memcpy(io_buffer->data() + kAudioMessageHeaderSize, resampled->data(), memcpy(io_buffer->data() + kAudioMessageHeaderSize, buffer->data(),
resampled->data_size()); buffer->data_size());
pending_buffer_complete_ = true; pending_buffer_complete_ = true;
mixer_input_->SendAudioBuffer(std::move(io_buffer), frame_count, mixer_input_->SendAudioBuffer(std::move(io_buffer), frame_count,
resampled->timestamp()); buffer->timestamp());
} }
void AudioDecoderForMixer::FillNextBuffer(void* buffer, void AudioDecoderForMixer::FillNextBuffer(void* buffer,
......
...@@ -26,7 +26,6 @@ namespace chromecast { ...@@ -26,7 +26,6 @@ namespace chromecast {
class IOBufferPool; class IOBufferPool;
namespace media { namespace media {
class AudioResampler;
class DecoderBufferBase; class DecoderBufferBase;
class MediaPipelineBackendForMixer; class MediaPipelineBackendForMixer;
...@@ -60,7 +59,7 @@ class AudioDecoderForMixer ...@@ -60,7 +59,7 @@ class AudioDecoderForMixer
// This allows for very small changes in the rate of audio playback that are // This allows for very small changes in the rate of audio playback that are
// (supposedly) imperceptible. // (supposedly) imperceptible.
float SetAvSyncPlaybackRate(float rate); double SetAvSyncPlaybackRate(double rate);
void RestartPlaybackAt(int64_t pts, int64_t timestamp); void RestartPlaybackAt(int64_t pts, int64_t timestamp);
RenderingDelay GetMixerRenderingDelay(); RenderingDelay GetMixerRenderingDelay();
...@@ -110,8 +109,7 @@ class AudioDecoderForMixer ...@@ -110,8 +109,7 @@ class AudioDecoderForMixer
AudioConfig config_; AudioConfig config_;
std::unique_ptr<CastAudioDecoder> decoder_; std::unique_ptr<CastAudioDecoder> decoder_;
std::unique_ptr<AudioResampler> audio_resampler_; double av_sync_clock_rate_ = 1.0;
float av_sync_clock_rate_ = 1.0f;
std::unique_ptr<mixer_service::OutputStreamConnection> mixer_input_; std::unique_ptr<mixer_service::OutputStreamConnection> mixer_input_;
......
...@@ -179,6 +179,7 @@ MixerInputConnection::MixerInputConnection( ...@@ -179,6 +179,7 @@ MixerInputConnection::MixerInputConnection(
kDefaultFadeTime, kDefaultFadeTime,
input_samples_per_second_), input_samples_per_second_),
1.0 /* playback_rate */), 1.0 /* playback_rate */),
audio_clock_simulator_(&fader_),
use_start_timestamp_(params.use_start_timestamp()), use_start_timestamp_(params.use_start_timestamp()),
playback_start_timestamp_(use_start_timestamp_ ? INT64_MAX : INT64_MIN), playback_start_timestamp_(use_start_timestamp_ ? INT64_MAX : INT64_MIN),
audio_buffer_pool_( audio_buffer_pool_(
...@@ -254,6 +255,9 @@ bool MixerInputConnection::HandleMetadata( ...@@ -254,6 +255,9 @@ bool MixerInputConnection::HandleMetadata(
if (message.has_set_playback_rate()) { if (message.has_set_playback_rate()) {
SetMediaPlaybackRate(message.set_playback_rate().playback_rate()); SetMediaPlaybackRate(message.set_playback_rate().playback_rate());
} }
if (message.has_set_audio_clock_rate()) {
SetAudioClockRate(message.set_audio_clock_rate().rate());
}
if (message.has_set_paused()) { if (message.has_set_paused()) {
SetPaused(message.set_paused().paused()); SetPaused(message.set_paused().paused());
} }
...@@ -448,6 +452,13 @@ void MixerInputConnection::SetMediaPlaybackRate(double rate) { ...@@ -448,6 +452,13 @@ void MixerInputConnection::SetMediaPlaybackRate(double rate) {
} }
} }
void MixerInputConnection::SetAudioClockRate(double rate) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
base::AutoLock lock(lock_);
audio_clock_simulator_.SetRate(rate);
}
void MixerInputConnection::SetPaused(bool paused) { void MixerInputConnection::SetPaused(bool paused) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
LOG(INFO) << (paused ? "Pausing " : "Unpausing ") << this; LOG(INFO) << (paused ? "Pausing " : "Unpausing ") << this;
...@@ -573,8 +584,9 @@ int64_t MixerInputConnection::QueueData(scoped_refptr<net::IOBuffer> data) { ...@@ -573,8 +584,9 @@ int64_t MixerInputConnection::QueueData(scoped_refptr<net::IOBuffer> data) {
// |extra_delay_frames_|). // |extra_delay_frames_|).
// * Queued data in |queue_|. // * Queued data in |queue_|.
// * Data in the rate shifter, if any. // * Data in the rate shifter, if any.
double extra_delay_frames = double extra_delay_frames = extra_delay_frames_ +
extra_delay_frames_ + queued_frames_ / playback_rate_; queued_frames_ / playback_rate_ +
audio_clock_simulator_.DelayFrames();
if (rate_shifter_) { if (rate_shifter_) {
double rate_shifter_delay = double rate_shifter_delay =
static_cast<double>(rate_shifter_input_frames_) / playback_rate_ - static_cast<double>(rate_shifter_input_frames_) / playback_rate_ -
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/thread_annotations.h" #include "base/thread_annotations.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chromecast/media/audio/audio_clock_simulator.h"
#include "chromecast/media/audio/audio_fader.h" #include "chromecast/media/audio/audio_fader.h"
#include "chromecast/media/audio/audio_provider.h" #include "chromecast/media/audio/audio_provider.h"
#include "chromecast/media/audio/mixer_service/mixer_service.pb.h" #include "chromecast/media/audio/mixer_service/mixer_service.pb.h"
...@@ -90,6 +91,7 @@ class MixerInputConnection : public mixer_service::MixerSocket::Delegate, ...@@ -90,6 +91,7 @@ class MixerInputConnection : public mixer_service::MixerSocket::Delegate,
void OnInactivityTimeout(); void OnInactivityTimeout();
void RestartPlaybackAt(int64_t timestamp, int64_t pts); void RestartPlaybackAt(int64_t timestamp, int64_t pts);
void SetMediaPlaybackRate(double rate); void SetMediaPlaybackRate(double rate);
void SetAudioClockRate(double rate);
void SetPaused(bool paused); void SetPaused(bool paused);
// MixerInput::Source implementation: // MixerInput::Source implementation:
...@@ -175,6 +177,7 @@ class MixerInputConnection : public mixer_service::MixerSocket::Delegate, ...@@ -175,6 +177,7 @@ class MixerInputConnection : public mixer_service::MixerSocket::Delegate,
int extra_delay_frames_ GUARDED_BY(lock_) = 0; int extra_delay_frames_ GUARDED_BY(lock_) = 0;
int current_buffer_offset_ GUARDED_BY(lock_) = 0; int current_buffer_offset_ GUARDED_BY(lock_) = 0;
AudioFader fader_ GUARDED_BY(lock_); AudioFader fader_ GUARDED_BY(lock_);
AudioClockSimulator audio_clock_simulator_ GUARDED_BY(lock_);
bool zero_fader_frames_ GUARDED_BY(lock_) = false; bool zero_fader_frames_ GUARDED_BY(lock_) = false;
bool started_ GUARDED_BY(lock_) = false; bool started_ GUARDED_BY(lock_) = false;
double playback_rate_ GUARDED_BY(lock_) = 1.0; double playback_rate_ GUARDED_BY(lock_) = 1.0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment