#include "media/audio/audio_output_device_thread_callback.h"
#include <utility>
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "media/audio/audio_device_stats_reporter.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_glitch_info.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
namespace media {
AudioOutputDeviceThreadCallback::AudioOutputDeviceThreadCallback(
const media::AudioParameters& audio_parameters,
base::UnsafeSharedMemoryRegion shared_memory_region,
media::AudioRendererSink::RenderCallback* render_callback)
: media::AudioDeviceThread::Callback(
audio_parameters,
ComputeAudioOutputBufferSize(audio_parameters),
1),
shared_memory_region_(std::move(shared_memory_region)),
render_callback_(render_callback),
create_time_(base::TimeTicks::Now()),
stats_reporter_(audio_parameters,
AudioDeviceStatsReporter::Type::kOutput) {
CHECK(memory_length_ <= shared_memory_region_.GetSize());
}
AudioOutputDeviceThreadCallback::~AudioOutputDeviceThreadCallback() {
UmaHistogramLongTimes("Media.Audio.Render.OutputStreamDuration2",
base::TimeTicks::Now() - create_time_);
}
void AudioOutputDeviceThreadCallback::MapSharedMemory() {
CHECK_EQ(total_segments_, 1u);
shared_memory_mapping_ = shared_memory_region_.MapAt(0, memory_length_);
CHECK(shared_memory_mapping_.IsValid());
base::span<uint8_t> data = shared_memory_mapping_.GetMemoryAsSpan<uint8_t>();
base::span<uint8_t> audio_data_span =
data.subspan<sizeof(media::AudioOutputBufferParameters)>();
const media::AudioOutputBuffer* buffer =
shared_memory_mapping_.GetMemoryAs<media::AudioOutputBuffer>();
CHECK_EQ(audio_data_span.data(), buffer->audio);
output_bus_ = media::AudioBus::WrapMemory(audio_parameters_, audio_data_span);
output_bus_->set_is_bitstream_format(audio_parameters_.IsBitstreamFormat());
}
void AudioOutputDeviceThreadCallback::Process(uint32_t control_signal) {
callback_num_++;
media::AudioOutputBuffer* buffer =
reinterpret_cast<media::AudioOutputBuffer*>(
shared_memory_mapping_.memory());
media::AudioGlitchInfo glitch_info{
.duration = base::Microseconds(buffer->params.glitch_duration_us),
.count = buffer->params.glitch_count};
buffer->params.glitch_duration_us = {};
buffer->params.glitch_count = 0;
base::TimeDelta delay = base::Microseconds(buffer->params.delay_us);
base::TimeTicks delay_timestamp =
base::TimeTicks() + base::Microseconds(buffer->params.delay_timestamp_us);
TRACE_EVENT("audio", "AudioOutputDevice::FireRenderCallback", "callback_num",
callback_num_, "delay_timestamp (ms)",
(delay_timestamp - base::TimeTicks()).InMillisecondsF(),
"playout_delay (ms)", delay.InMillisecondsF());
glitch_info.MaybeAddTraceEvent();
DVLOG(4) << __func__ << " delay:" << delay << " delay_timestamp:" << delay;
if (callback_num_ == 2) {
TRACE_EVENT_END("audio", perfetto::Track::FromPointer(this));
if (first_play_start_time_) {
UmaHistogramTimes("Media.Audio.Render.OutputDeviceStartTime2",
base::TimeTicks::Now() - *first_play_start_time_);
}
}
render_callback_->Render(delay, delay_timestamp, glitch_info,
output_bus_.get());
stats_reporter_.ReportCallback(delay, glitch_info);
if (audio_parameters_.IsBitstreamFormat()) {
buffer->params.bitstream_data_size = output_bus_->bitstream_data().size();
buffer->params.bitstream_frames = output_bus_->GetBitstreamFrames();
}
}
void AudioOutputDeviceThreadCallback::OnSocketError() {
render_callback_->OnRenderError();
}
bool AudioOutputDeviceThreadCallback::CurrentThreadIsAudioDeviceThread() {
return thread_checker_.CalledOnValidThread();
}
void AudioOutputDeviceThreadCallback::InitializePlayStartTime() {
if (first_play_start_time_)
return;
DCHECK(!callback_num_);
TRACE_EVENT_BEGIN("audio", "StartingPlayback",
perfetto::Track::FromPointer(this));
first_play_start_time_ = base::TimeTicks::Now();
}
}