Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: content/browser/renderer_host/media/audio_output_impl.cc

Issue 2319493002: Add mojo interface for audio rendering. (Closed)
Patch Set: format Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/media/audio_output_impl.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "base/memory/shared_memory.h"
13 #include "content/browser/media/capture/audio_mirroring_manager.h"
14 #include "mojo/public/cpp/system/platform_handle.h"
15
16 namespace content {
17
18 // static
19 AudioOutputImpl::UniquePtr AudioOutputImpl::Create(
20 base::SingleThreadTaskRunner* task_runner,
21 Host* host,
22 int32_t id,
23 int render_frame_id,
24 int render_process_id,
25 const std::string& output_device_id) {
26 return UniquePtr(new AudioOutputImpl(task_runner, host, id, render_frame_id,
27 render_process_id, output_device_id),
28 Deleter());
29 }
30
31 AudioOutputImpl::~AudioOutputImpl() {
32 DCHECK(task_runner_->BelongsToCurrentThread());
33 }
34
35 void AudioOutputImpl::Bind(media::mojom::AudioOutputRequest request) {
36 DCHECK(task_runner_->BelongsToCurrentThread());
37 binding_.Bind(std::move(request));
38 binding_.set_connection_error_handler(
39 base::Bind(&AudioOutputImpl::OnError, base::Unretained(this)));
40 }
41
42 void AudioOutputImpl::Close() {
43 // Since AudioOutputController is closed asynchronously, we need to take
44 // extra care when AudioOutputImpl is deleted. We use a custom deleter for
45 // our unique_ptrs to make this extra trouble transparent to the owner.
46 // The entire termination sequence is like this:
47 // 1. Close is called and we unbind ourselves, if bound.
48 // 2. We ask the AudioOutputService to remove us.
49 // 3. AudioOutputService removes its reference, causing Deleter::operator()
50 // to run.
51 // 4. a. Deleter closes controller_, which then deletes us by callback.
52 // b. There is no controller, so Deleter just deletes us.
53 DCHECK(task_runner_->BelongsToCurrentThread());
54 if (is_closing)
55 return;
56 is_closing = true;
57 binding_.Close();
58 if (IsStarted())
59 host_->NotifyStreamClosed(id_);
60 host_->Remove(id_);
61 }
62
63 void AudioOutputImpl::Start(const media::AudioParameters& params,
64 const StartCallback& callback) {
65 DCHECK(task_runner_->BelongsToCurrentThread());
66 DCHECK(!is_closing);
67 if (IsStarted()) {
68 Close();
69 return;
70 }
71 Init(params);
72 if (!IsStarted()) {
73 Close();
74 return;
75 }
76
77 host_->NotifyStreamCreated(id_, controller_.get(), render_frame_id_);
78 // We add the controller to AudioMirroringManager in this class since we
79 // have to remove it in this class.
80 content::AudioMirroringManager::GetInstance()->AddDiverter(
81 render_process_id_, render_frame_id_, controller_.get());
82
83 controller_->Play();
84 start_callback_ = std::move(callback);
85 }
86
87 void AudioOutputImpl::Play() {
88 DCHECK(!is_closing);
89 DCHECK(task_runner_->BelongsToCurrentThread());
90 if (!IsStarted())
91 Close();
o1ka 2016/09/28 10:24:06 Here and in other places: what is the purpose of C
Max Morin 2016/09/28 12:47:33 Ok, in this case the client might call Play() befo
92 else
93 controller_->Play();
94 }
95
96 void AudioOutputImpl::Pause() {
97 DCHECK(!is_closing);
98 DCHECK(task_runner_->BelongsToCurrentThread());
99 if (!IsStarted())
100 Close();
101 else
102 controller_->Pause();
103 }
104
105 void AudioOutputImpl::SetVolume(double volume) {
106 DCHECK(!is_closing);
107 DCHECK(task_runner_->BelongsToCurrentThread());
108 if (!IsStarted() || volume < 0.0 || volume > 1.0)
o1ka 2016/09/28 10:24:07 Where these volume limits come from? And what if t
Max Morin 2016/09/28 12:47:33 Good question. Needs better comments.
109 Close();
110 else
111 controller_->SetVolume(volume);
112 }
113
114 void AudioOutputImpl::OnCreated() {
115 task_runner_->PostTask(
116 FROM_HERE,
117 base::Bind(&AudioOutputImpl::DoCompleteCreation, base::Unretained(this)));
o1ka 2016/09/28 10:24:07 "this" won't survive
118 }
119
120 void AudioOutputImpl::OnPlaying() {
o1ka 2016/09/28 10:24:07 Thread check? and what if it is called after Clos
121 host_->NotifyStreamStateChanged(id_, true);
122 }
123 void AudioOutputImpl::OnPaused() {
124 host_->NotifyStreamStateChanged(id_, false);
o1ka 2016/09/28 10:24:06 Same as above
125 }
126 void AudioOutputImpl::OnError() {
127 task_runner_->PostTask(
128 FROM_HERE, base::Bind(&AudioOutputImpl::Close, base::Unretained(this)));
o1ka 2016/09/28 10:24:06 What is the guarantee that "this" will survive unt
Max Morin 2016/09/28 12:47:33 Ok, so we should maybe have weak pointers to *this
129 }
130
131 AudioOutputImpl::AudioOutputImpl(base::SingleThreadTaskRunner* task_runner,
132 Host* host,
133 int32_t id,
134 int render_frame_id,
135 int render_process_id,
136 const std::string& output_device_id)
137 : task_runner_(task_runner),
138 host_(host),
139 id_(id),
140 render_frame_id_(render_frame_id),
141 render_process_id_(render_process_id),
142 output_device_id_(output_device_id),
143 binding_(this) {
144 DCHECK(task_runner_->BelongsToCurrentThread());
o1ka 2016/09/28 10:24:07 Do you really need it to be constructed on this th
145 }
146
147 void AudioOutputImpl::DoCompleteCreation() {
148 DCHECK(task_runner_->BelongsToCurrentThread());
149 if (is_closing)
o1ka 2016/09/28 10:24:06 is it actually "closing" or "closed"?
Max Morin 2016/09/28 12:47:33 I'll rework this bit.
150 return;
151 DCHECK(reader_);
152 DCHECK(binding_.is_bound());
153
154 // Now construction is done and we are ready to send the shared memory and the
155 // sync socket to the renderer.
156 base::SharedMemory* shared_memory = reader_->shared_memory();
157 base::CancelableSyncSocket* foreign_socket = reader_->foreign_socket();
158 DCHECK(shared_memory);
159 DCHECK(foreign_socket);
160
161 // Wrap the shared memory for sending:
162 base::SharedMemoryHandle foreign_memory_handle =
163 base::SharedMemory::DuplicateHandle(shared_memory->handle());
164 // TODO: When does this fail?
165 DCHECK(base::SharedMemory::IsHandleValid(foreign_memory_handle))
166 << "Invalid memory handle.";
167 mojo::ScopedSharedBufferHandle shared_buffer_handle =
168 mojo::WrapSharedMemoryHandle(foreign_memory_handle,
169 shared_memory->requested_size(), false);
170
171 // TODO: When does this fail?
172 DCHECK(shared_buffer_handle.is_valid());
173
174 // TODO: take ownership of sync socket handle, crbug.com/647659
175 start_callback_.Run(std::move(shared_buffer_handle),
176 mojo::WrapPlatformFile(foreign_socket->handle()));
177 }
178
179 void AudioOutputImpl::Init(const media::AudioParameters& params) {
180 DCHECK(!is_closing);
181 DCHECK(task_runner_->BelongsToCurrentThread());
182 reader_ = AudioSyncReader::Create(params);
183 if (!reader_)
184 return;
o1ka 2016/09/28 10:24:06 Is it a normal situation? If not - DCHECK? (we can
Max Morin 2016/09/28 12:47:33 Should probably be a DCHECK, it happens if we can'
185 controller_ = media::AudioOutputController::Create(
186 media::AudioManager::Get(), this, params, output_device_id_,
187 reader_.get());
188 DCHECK(controller_);
189 }
190
191 bool AudioOutputImpl::IsStarted() const {
192 DCHECK(task_runner_->BelongsToCurrentThread());
193 return controller_ != nullptr;
194 }
195
196 void AudioOutputImpl::Deleter::operator()(AudioOutputImpl* output) {
197 DCHECK(output->task_runner_->BelongsToCurrentThread());
198 DCHECK(output->is_closing);
199 if (output->controller_)
200 output->controller_->Close(base::Bind(&AudioOutputImpl::DeleteAndUnregister,
201 base::Unretained(output)));
202 else
203 delete output;
204 }
205
206 // static
207 void AudioOutputImpl::DeleteAndUnregister(AudioOutputImpl* output) {
208 // This must be done after controller finished closing, see
209 // http://crbug.com/474432.
210 AudioMirroringManager::GetInstance()->RemoveDiverter(
211 output->controller_.get());
212 output->task_runner_->DeleteSoon(FROM_HERE, output);
o1ka 2016/09/28 10:24:06 This deletion is a lot of fun, but can we probably
213 }
214
215 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698