1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
media / audio / audio_output_device_thread_callback.cc [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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_glitch_info.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),
/*segment count*/ 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 that the shared memory is large enough. The memory allocated must be
// at least as large as expected.
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());
media::AudioOutputBuffer* buffer =
reinterpret_cast<media::AudioOutputBuffer*>(
shared_memory_mapping_.memory());
output_bus_ = media::AudioBus::WrapMemory(audio_parameters_, buffer->audio);
output_bus_->set_is_bitstream_format(audio_parameters_.IsBitstreamFormat());
}
// Called whenever we receive notifications about pending data.
void AudioOutputDeviceThreadCallback::Process(uint32_t control_signal) {
callback_num_++;
// Read and reset the glitch info.
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;
// When playback starts, we get an immediate callback to Process to make sure
// that we have some data, we'll get another one after the device is awake and
// ingesting data, which is what we want to track with this trace.
if (callback_num_ == 2) {
TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "StartingPlayback",
TRACE_ID_LOCAL(this));
if (first_play_start_time_) {
UmaHistogramTimes("Media.Audio.Render.OutputDeviceStartTime2",
base::TimeTicks::Now() - *first_play_start_time_);
}
}
// Update the audio-delay measurement, inform about the number of skipped
// frames, and ask client to render audio. Since |output_bus_| is wrapping
// the shared memory the Render() call is writing directly into the shared
// memory.
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_->GetBitstreamDataSize();
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_NESTABLE_ASYNC_BEGIN0("audio", "StartingPlayback",
TRACE_ID_LOCAL(this));
first_play_start_time_ = base::TimeTicks::Now();
}
} // namespace media