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

Side by Side Diff: content/renderer/media/mojo_audio_output_ipc.cc

Issue 2821203005: Add a mojo implementation of AudioOutputIPC. (Closed)
Patch Set: Comments. SWITCH TO MACRO-BASED THREAD CHECKER. Created 3 years, 7 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 2017 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/renderer/media/mojo_audio_output_ipc.h"
6
7 #include <utility>
8
9 #include "media/audio/audio_device_description.h"
10 #include "mojo/public/cpp/system/platform_handle.h"
11
12 namespace content {
13
14 namespace {
15
16 void TrivialAuthorizedCallback(media::OutputDeviceStatus,
17 const media::AudioParameters&,
18 const std::string&) {}
19
20 } // namespace
21
22 // This class wraps a callback. If this class is destroyed without the callback
23 // being called, it will call it with an error. This is needed since the
24 // AudioOutputDevice could otherwise wait forever for device parameters in the
25 // case of a connection error.
26 class AuthorizationCallbackWrapper {
27 public:
28 using CallbackType = base::OnceCallback<void(media::OutputDeviceStatus,
29 const media::AudioParameters&,
30 const std::string&)>;
31
32 static CallbackType Wrap(CallbackType callback) {
33 return base::BindOnce(
34 AuthorizationCallbackWrapper::Call,
35 base::Passed(AuthorizationCallbackWrapper(std::move(callback))));
36 }
37
38 AuthorizationCallbackWrapper(AuthorizationCallbackWrapper&& other)
39 : callback_(std::move(other.callback_)) {
40 // It's not explicitly stated that moving from a OnceCallback resets the
41 // moved-from callback, so reset it here.
42 other.callback_ = CallbackType();
43 }
44
45 AuthorizationCallbackWrapper& operator=(
46 AuthorizationCallbackWrapper&& other) = delete;
47
48 ~AuthorizationCallbackWrapper() {
49 if (callback_) {
50 std::move(callback_).Run(
51 media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL,
52 media::AudioParameters::UnavailableDeviceParams(), std::string());
53 }
54 }
55
56 private:
57 explicit AuthorizationCallbackWrapper(CallbackType callback)
58 : callback_(std::move(callback)) {}
59
60 static void Call(AuthorizationCallbackWrapper callback_wrapper,
61 media::OutputDeviceStatus status,
62 const media::AudioParameters& params,
63 const std::string& device_id) {
64 if (callback_wrapper.callback_) {
65 std::move(callback_wrapper.callback_).Run(status, params, device_id);
66 // Make sure we don't call again in destructor:
67 callback_wrapper.callback_ = CallbackType();
68 }
69 }
70
71 CallbackType callback_;
72
73 DISALLOW_COPY_AND_ASSIGN(AuthorizationCallbackWrapper);
74 };
75
76 MojoAudioOutputIPC::MojoAudioOutputIPC(FactoryAccessor factory_accessor)
77 : factory_accessor_(std::move(factory_accessor)), weak_factory_(this) {
78 DETACH_FROM_THREAD(thread_checker_);
79 }
80
81 MojoAudioOutputIPC::~MojoAudioOutputIPC() {
82 // No thread check.
83 DCHECK(!AuthorizationRequested());
84 DCHECK(!StreamCreationRequested());
85 // Destructing |weak_factory_| on any thread is safe since it's not used after
86 // the final call to CloseStream, where its pointers are invalidated.
87 }
88
89 void MojoAudioOutputIPC::RequestDeviceAuthorization(
90 media::AudioOutputIPCDelegate* delegate,
91 int session_id,
92 const std::string& device_id,
93 const url::Origin& security_origin) {
94 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
95 DCHECK(delegate);
96 DCHECK(!AuthorizationRequested());
97 DCHECK(!StreamCreationRequested());
98 auto* factory = factory_accessor_.Run();
99 if (!factory) {
100 LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";
101 delegate->OnIPCClosed(); // deletes |this|.
102 return;
103 }
104
105 // We wrap the callback here so that we are sure to always get the
106 // authorization reply, even if the connection is closed.
107 factory->RequestDeviceAuthorization(
108 MakeProviderRequest(delegate), session_id, device_id,
109 AuthorizationCallbackWrapper::Wrap(
110 base::Bind(&MojoAudioOutputIPC::RecievedDeviceAuthorization,
111 weak_factory_.GetWeakPtr(), delegate)));
112 }
113
114 void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate,
115 const media::AudioParameters& params) {
116 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
117 DCHECK(delegate);
118 DCHECK(!StreamCreationRequested());
119 if (!AuthorizationRequested()) {
120 // No authorization requested yet. Request one for the default device.
121 auto* factory = factory_accessor_.Run();
122 if (!factory) {
123 LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";
124 delegate->OnIPCClosed(); // deletes |this|.
125 return;
126 }
127
128 // Since the delegate didn't explicitly request authorization, we shouldn't
129 // send a callback to it.
130 factory->RequestDeviceAuthorization(
131 MakeProviderRequest(delegate), 0,
132 media::AudioDeviceDescription::kDefaultDeviceId,
133 base::Bind(&TrivialAuthorizedCallback));
134 }
135
136 // Since the creation callback won't fire if the provider binding is gone,
137 // unretained is safe.
138 stream_provider_->Acquire(mojo::MakeRequest(&stream_), params,
139 base::Bind(&MojoAudioOutputIPC::StreamCreated,
140 base::Unretained(this), delegate));
141
142 // Unretained is safe because |delegate| must be valid until CloseStream is
143 // called, and |stream_| is reset in CloseStream.
144 stream_.set_connection_error_handler(base::Bind(
145 &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate)));
146 }
147
148 void MojoAudioOutputIPC::PlayStream() {
149 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
150 if (stream_.is_bound())
151 stream_->Play();
152 }
153
154 void MojoAudioOutputIPC::PauseStream() {
155 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
156 if (stream_.is_bound())
157 stream_->Pause();
158 }
159
160 void MojoAudioOutputIPC::CloseStream() {
161 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
162 stream_provider_.reset();
163 stream_.reset();
164
165 // Make sure we don't send an authorization callback for this stream to the
166 // delegate.
167 weak_factory_.InvalidateWeakPtrs();
168 }
169
170 void MojoAudioOutputIPC::SetVolume(double volume) {
171 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
172 if (stream_.is_bound())
173 stream_->SetVolume(volume);
174 }
175
176 bool MojoAudioOutputIPC::AuthorizationRequested() {
177 return stream_provider_.is_bound();
178 }
179
180 bool MojoAudioOutputIPC::StreamCreationRequested() {
181 return stream_.is_bound();
182 }
183
184 media::mojom::AudioOutputStreamProviderRequest
185 MojoAudioOutputIPC::MakeProviderRequest(
186 media::AudioOutputIPCDelegate* delegate) {
187 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
188 DCHECK(!AuthorizationRequested());
189 media::mojom::AudioOutputStreamProviderRequest request =
190 mojo::MakeRequest(&stream_provider_);
191
192 // Unretained is safe because |delegate| owns |this|.
o1ka 2017/05/15 13:27:08 l. 142 says "Unretained is safe because |delegate|
Max Morin 2017/05/16 15:51:35 Done.
193 stream_provider_.set_connection_error_handler(base::Bind(
194 &media::AudioOutputIPCDelegate::OnError, base::Unretained(delegate)));
195 return request;
196 }
197
198 void MojoAudioOutputIPC::RecievedDeviceAuthorization(
199 media::AudioOutputIPCDelegate* delegate,
200 media::OutputDeviceStatus status,
201 const media::AudioParameters& params,
202 const std::string& device_id) const {
203 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
204 delegate->OnDeviceAuthorized(status, params, device_id);
205 }
206
207 void MojoAudioOutputIPC::StreamCreated(
208 media::AudioOutputIPCDelegate* delegate,
209 mojo::ScopedSharedBufferHandle shared_memory,
210 mojo::ScopedHandle socket) {
211 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
212 DCHECK(socket.is_valid());
213 DCHECK(shared_memory.is_valid());
214
215 base::PlatformFile socket_handle;
216 mojo::UnwrapPlatformFile(std::move(socket), &socket_handle);
217
218 base::SharedMemoryHandle memory_handle;
219 bool read_only = false;
220 size_t memory_length = 0;
221 auto result = mojo::UnwrapSharedMemoryHandle(
222 std::move(shared_memory), &memory_handle, &memory_length, &read_only);
223 DCHECK_EQ(result, MOJO_RESULT_OK);
224 DCHECK(!read_only);
225
226 delegate->OnStreamCreated(memory_handle, socket_handle, memory_length);
227 }
228
229 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/mojo_audio_output_ipc.h ('k') | content/renderer/pepper/pepper_platform_audio_output.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698