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
126
127
128
129
130
131
132
133
134
media / audio / null_audio_sink.cc [blame]
// Copyright 2012 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/null_audio_sink.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "media/base/audio_glitch_info.h"
#include "media/base/audio_hash.h"
#include "media/base/fake_audio_worker.h"
namespace media {
NullAudioSink::NullAudioSink(
const scoped_refptr<base::SequencedTaskRunner>& task_runner)
: initialized_(false),
started_(false),
playing_(false),
callback_(nullptr),
task_runner_(task_runner) {}
NullAudioSink::~NullAudioSink() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void NullAudioSink::Initialize(const AudioParameters& params,
RenderCallback* callback) {
DCHECK(!started_);
fake_worker_ = std::make_unique<FakeAudioWorker>(task_runner_, params);
fixed_data_delay_ = FakeAudioWorker::ComputeFakeOutputDelay(params);
audio_bus_ = AudioBus::Create(params);
callback_ = callback;
initialized_ = true;
}
void NullAudioSink::Start() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(initialized_);
DCHECK(!started_);
started_ = true;
}
void NullAudioSink::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
started_ = false;
// Stop may be called at any time, so we have to check before stopping.
if (fake_worker_)
fake_worker_->Stop();
}
void NullAudioSink::Play() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(started_);
if (playing_)
return;
fake_worker_->Start(
base::BindRepeating(&NullAudioSink::CallRender, base::Unretained(this)));
playing_ = true;
}
void NullAudioSink::Pause() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(started_);
if (!playing_)
return;
fake_worker_->Stop();
playing_ = false;
}
void NullAudioSink::Flush() {}
bool NullAudioSink::SetVolume(double volume) {
// Audio is always muted.
return volume == 0.0;
}
OutputDeviceInfo NullAudioSink::GetOutputDeviceInfo() {
return OutputDeviceInfo(OUTPUT_DEVICE_STATUS_OK);
}
void NullAudioSink::GetOutputDeviceInfoAsync(OutputDeviceInfoCB info_cb) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(info_cb), GetOutputDeviceInfo()));
}
bool NullAudioSink::IsOptimizedForHardwareParameters() {
return false;
}
bool NullAudioSink::CurrentThreadIsRenderingThread() {
return task_runner_->RunsTasksInCurrentSequence();
}
void NullAudioSink::SwitchOutputDevice(const std::string& device_id,
OutputDeviceStatusCB callback) {
std::move(callback).Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
}
void NullAudioSink::CallRender(base::TimeTicks ideal_time,
base::TimeTicks now) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Since NullAudioSink is only used for cases where a real audio sink was not
// available, provide "idealized" delay-timing arguments. This will drive the
// smoothest playback (since video is sync'ed to audio). See
// content::AudioRendererImpl and media::AudioClock for further details.
int frames_received =
callback_->Render(fixed_data_delay_, ideal_time, {}, audio_bus_.get());
if (!audio_hash_ || frames_received <= 0)
return;
audio_hash_->Update(audio_bus_.get(), frames_received);
}
void NullAudioSink::StartAudioHashForTesting() {
DCHECK(!initialized_);
audio_hash_ = std::make_unique<AudioHash>();
}
const AudioHash& NullAudioSink::GetAudioHashForTesting() const {
return *audio_hash_;
}
} // namespace media