blob: 241d6ecd23aba50939d9df78d167d3177194ab1a [file] [log] [blame]
[email protected]028b90f62012-04-05 01:44:131// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]5d84d012010-12-02 17:17:212// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]9a578392011-12-07 18:59:275#include "ppapi/shared_impl/ppb_audio_shared.h"
[email protected]5d84d012010-12-02 17:17:216
dchengd2b9f612015-12-18 19:08:517#include <utility>
8
Sebastien Marchand6d0558fd2019-01-25 16:49:379#include "base/bind.h"
[email protected]d1bbf6fd2011-07-15 22:09:2810#include "base/logging.h"
primiano3ca22962015-01-30 17:08:3711#include "base/trace_event/trace_event.h"
jrummell37a54c02016-04-22 19:54:2712#include "media/base/audio_parameters.h"
[email protected]d40ece12014-04-23 16:11:3913#include "ppapi/nacl_irt/public/irt_ppapi.h"
[email protected]96724682012-04-26 20:53:3714#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]6b1511262013-09-06 21:46:3415#include "ppapi/shared_impl/ppb_audio_config_shared.h"
[email protected]17a17b02013-07-25 21:07:3916#include "ppapi/shared_impl/proxy_lock.h"
[email protected]d1bbf6fd2011-07-15 22:09:2817
[email protected]55cdf6052011-05-13 19:22:5318namespace ppapi {
[email protected]5d84d012010-12-02 17:17:2119
[email protected]420ade42012-07-25 21:47:3120namespace {
[email protected]d40ece12014-04-23 16:11:3921bool g_nacl_mode = false;
[email protected]420ade42012-07-25 21:47:3122// Because this is static, the function pointers will be NULL initially.
[email protected]d40ece12014-04-23 16:11:3923PP_ThreadFunctions g_thread_functions;
[email protected]420ade42012-07-25 21:47:3124}
[email protected]420ade42012-07-25 21:47:3125
[email protected]665b5c542014-02-22 08:06:2626AudioCallbackCombined::AudioCallbackCombined()
27 : callback_1_0_(NULL), callback_(NULL) {}
[email protected]6b1511262013-09-06 21:46:3428
29AudioCallbackCombined::AudioCallbackCombined(
30 PPB_Audio_Callback_1_0 callback_1_0)
[email protected]665b5c542014-02-22 08:06:2631 : callback_1_0_(callback_1_0), callback_(NULL) {}
[email protected]6b1511262013-09-06 21:46:3432
33AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback)
[email protected]665b5c542014-02-22 08:06:2634 : callback_1_0_(NULL), callback_(callback) {}
[email protected]6b1511262013-09-06 21:46:3435
[email protected]665b5c542014-02-22 08:06:2636AudioCallbackCombined::~AudioCallbackCombined() {}
[email protected]6b1511262013-09-06 21:46:3437
38bool AudioCallbackCombined::IsValid() const {
39 return callback_1_0_ || callback_;
40}
41
42void AudioCallbackCombined::Run(void* sample_buffer,
43 uint32_t buffer_size_in_bytes,
44 PP_TimeDelta latency,
45 void* user_data) const {
46 if (callback_) {
47 callback_(sample_buffer, buffer_size_in_bytes, latency, user_data);
48 } else if (callback_1_0_) {
49 callback_1_0_(sample_buffer, buffer_size_in_bytes, user_data);
50 } else {
51 NOTREACHED();
52 }
53}
54
[email protected]9a578392011-12-07 18:59:2755PPB_Audio_Shared::PPB_Audio_Shared()
[email protected]5d84d012010-12-02 17:17:2156 : playing_(false),
57 shared_memory_size_(0),
tommycli43d8cc42015-03-20 17:48:1958 nacl_thread_id_(0),
[email protected]d40ece12014-04-23 16:11:3959 nacl_thread_active_(false),
[email protected]dfc48e4c2012-09-05 13:39:2160 user_data_(NULL),
[email protected]6b1511262013-09-06 21:46:3461 client_buffer_size_bytes_(0),
[email protected]1caf0aa2013-10-31 07:58:0262 bytes_per_second_(0),
63 buffer_index_(0) {
[email protected]5d84d012010-12-02 17:17:2164}
65
[email protected]9a578392011-12-07 18:59:2766PPB_Audio_Shared::~PPB_Audio_Shared() {
[email protected]7b388d12012-08-25 00:22:5267 // Shut down the socket to escape any hanging |Receive|s.
68 if (socket_.get())
69 socket_->Shutdown();
[email protected]0e8d17b12012-05-15 21:32:2570 StopThread();
[email protected]5d84d012010-12-02 17:17:2171}
72
[email protected]6b1511262013-09-06 21:46:3473void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback,
[email protected]9a578392011-12-07 18:59:2774 void* user_data) {
[email protected]5d84d012010-12-02 17:17:2175 callback_ = callback;
76 user_data_ = user_data;
77}
78
[email protected]9a578392011-12-07 18:59:2779void PPB_Audio_Shared::SetStartPlaybackState() {
[email protected]5d84d012010-12-02 17:17:2180 DCHECK(!playing_);
81 DCHECK(!audio_thread_.get());
[email protected]d40ece12014-04-23 16:11:3982 DCHECK(!nacl_thread_active_);
[email protected]5d84d012010-12-02 17:17:2183 // If the socket doesn't exist, that means that the plugin has started before
84 // the browser has had a chance to create all the shared memory info and
85 // notify us. This is a common case. In this case, we just set the playing_
86 // flag and the playback will automatically start when that data is available
87 // in SetStreamInfo.
[email protected]5d84d012010-12-02 17:17:2188 playing_ = true;
[email protected]96724682012-04-26 20:53:3789 StartThread();
[email protected]5d84d012010-12-02 17:17:2190}
91
[email protected]9a578392011-12-07 18:59:2792void PPB_Audio_Shared::SetStopPlaybackState() {
[email protected]5d84d012010-12-02 17:17:2193 DCHECK(playing_);
[email protected]0e8d17b12012-05-15 21:32:2594 StopThread();
[email protected]5d84d012010-12-02 17:17:2195 playing_ = false;
96}
97
[email protected]9a578392011-12-07 18:59:2798void PPB_Audio_Shared::SetStreamInfo(
[email protected]96724682012-04-26 20:53:3799 PP_Instance instance,
Alexandr Ilin20f2841c2018-06-01 11:56:18100 base::UnsafeSharedMemoryRegion shared_memory_region,
[email protected]dfc48e4c2012-09-05 13:39:21101 base::SyncSocket::Handle socket_handle,
[email protected]6b1511262013-09-06 21:46:34102 PP_AudioSampleRate sample_rate,
[email protected]dfc48e4c2012-09-05 13:39:21103 int sample_frame_count) {
[email protected]0e8d17b12012-05-15 21:32:25104 socket_.reset(new base::CancelableSyncSocket(socket_handle));
Max Morin30996fb2017-09-01 13:28:35105 shared_memory_size_ = media::ComputeAudioOutputBufferSize(
106 kAudioOutputChannels, sample_frame_count);
Alexandr Ilin20f2841c2018-06-01 11:56:18107 DCHECK_GE(shared_memory_region.GetSize(), shared_memory_size_);
[email protected]665b5c542014-02-22 08:06:26108 bytes_per_second_ =
109 kAudioOutputChannels * (kBitsPerAudioOutputSample / 8) * sample_rate;
[email protected]1caf0aa2013-10-31 07:58:02110 buffer_index_ = 0;
[email protected]5d84d012010-12-02 17:17:21111
Alexandr Ilin20f2841c2018-06-01 11:56:18112 shared_memory_ = shared_memory_region.MapAt(0, shared_memory_size_);
113 if (!shared_memory_.IsValid()) {
[email protected]007b3f82013-04-09 08:46:45114 PpapiGlobals::Get()->LogWithSource(
115 instance,
116 PP_LOGLEVEL_WARNING,
117 std::string(),
118 "Failed to map shared memory for PPB_Audio_Shared.");
[email protected]dfc48e4c2012-09-05 13:39:21119 } else {
grunell09a6d7932015-12-18 11:28:21120 media::AudioOutputBuffer* buffer =
Alexandr Ilin20f2841c2018-06-01 11:56:18121 reinterpret_cast<media::AudioOutputBuffer*>(shared_memory_.memory());
grunell09a6d7932015-12-18 11:28:21122 audio_bus_ = media::AudioBus::WrapMemory(kAudioOutputChannels,
123 sample_frame_count, buffer->audio);
[email protected]dfc48e4c2012-09-05 13:39:21124 // Setup integer audio buffer for user audio data.
[email protected]665b5c542014-02-22 08:06:26125 client_buffer_size_bytes_ = audio_bus_->frames() * audio_bus_->channels() *
126 kBitsPerAudioOutputSample / 8;
[email protected]dfc48e4c2012-09-05 13:39:21127 client_buffer_.reset(new uint8_t[client_buffer_size_bytes_]);
[email protected]5d84d012010-12-02 17:17:21128 }
[email protected]96724682012-04-26 20:53:37129
130 StartThread();
[email protected]5d84d012010-12-02 17:17:21131}
132
[email protected]9a578392011-12-07 18:59:27133void PPB_Audio_Shared::StartThread() {
[email protected]96724682012-04-26 20:53:37134 // Don't start the thread unless all our state is set up correctly.
[email protected]6b1511262013-09-06 21:46:34135 if (!playing_ || !callback_.IsValid() || !socket_.get() ||
Alexandr Ilin20f2841c2018-06-01 11:56:18136 !shared_memory_.memory() || !audio_bus_.get() || !client_buffer_.get() ||
[email protected]6b1511262013-09-06 21:46:34137 bytes_per_second_ == 0)
[email protected]96724682012-04-26 20:53:37138 return;
[email protected]420ade42012-07-25 21:47:31139 // Clear contents of shm buffer before starting audio thread. This will
140 // prevent a burst of static if for some reason the audio thread doesn't
141 // start up quickly enough.
Alexandr Ilin20f2841c2018-06-01 11:56:18142 memset(shared_memory_.memory(), 0, shared_memory_size_);
[email protected]dfc48e4c2012-09-05 13:39:21143 memset(client_buffer_.get(), 0, client_buffer_size_bytes_);
[email protected]420ade42012-07-25 21:47:31144
[email protected]d40ece12014-04-23 16:11:39145 if (g_nacl_mode) {
146 // Use NaCl's special API for IRT code that creates threads that call back
147 // into user code.
148 if (!IsThreadFunctionReady())
149 return;
150
151 DCHECK(!nacl_thread_active_);
152 int result =
153 g_thread_functions.thread_create(&nacl_thread_id_, CallRun, this);
154 DCHECK_EQ(0, result);
155 nacl_thread_active_ = true;
156 } else {
157 DCHECK(!audio_thread_.get());
158 audio_thread_.reset(
159 new base::DelegateSimpleThread(this, "plugin_audio_thread"));
160 audio_thread_->Start();
161 }
[email protected]5d84d012010-12-02 17:17:21162}
163
[email protected]0e8d17b12012-05-15 21:32:25164void PPB_Audio_Shared::StopThread() {
[email protected]d40ece12014-04-23 16:11:39165 // In general, the audio thread should not do Pepper calls, but it might
166 // anyway (for example, our Audio test does CallOnMainThread). If it did a
167 // pepper call which acquires the lock (most of them do), and we try to shut
168 // down the thread and Join it while holding the lock, we would deadlock. So
169 // we give up the lock here so that the thread at least _can_ make Pepper
170 // calls without causing deadlock.
bbudge338f9692015-09-10 00:58:15171 // IMPORTANT: This instance's thread state should be reset to uninitialized
172 // before we release the proxy lock, so any calls from the plugin while we're
173 // unlocked can't access the joined thread.
[email protected]d40ece12014-04-23 16:11:39174 if (g_nacl_mode) {
175 if (nacl_thread_active_) {
bbudge338f9692015-09-10 00:58:15176 nacl_thread_active_ = false;
[email protected]d40ece12014-04-23 16:11:39177 int result =
178 CallWhileUnlocked(g_thread_functions.thread_join, nacl_thread_id_);
179 DCHECK_EQ(0, result);
[email protected]d40ece12014-04-23 16:11:39180 }
181 } else {
182 if (audio_thread_.get()) {
dchengd2b9f612015-12-18 19:08:51183 auto local_audio_thread(std::move(audio_thread_));
[email protected]d40ece12014-04-23 16:11:39184 CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join,
bbudge338f9692015-09-10 00:58:15185 base::Unretained(local_audio_thread.get())));
[email protected]d40ece12014-04-23 16:11:39186 }
[email protected]0e8d17b12012-05-15 21:32:25187 }
188}
189
[email protected]a4a01e42014-04-21 10:36:21190// static
191bool PPB_Audio_Shared::IsThreadFunctionReady() {
[email protected]d40ece12014-04-23 16:11:39192 if (!g_nacl_mode)
193 return true;
194
195 return (g_thread_functions.thread_create != NULL &&
196 g_thread_functions.thread_join != NULL);
[email protected]a4a01e42014-04-21 10:36:21197}
198
[email protected]d40ece12014-04-23 16:11:39199// static
200void PPB_Audio_Shared::SetNaClMode() {
201 g_nacl_mode = true;
202}
203
[email protected]420ade42012-07-25 21:47:31204// static
205void PPB_Audio_Shared::SetThreadFunctions(
206 const struct PP_ThreadFunctions* functions) {
[email protected]d40ece12014-04-23 16:11:39207 DCHECK(g_nacl_mode);
208 g_thread_functions = *functions;
[email protected]420ade42012-07-25 21:47:31209}
210
211// static
212void PPB_Audio_Shared::CallRun(void* self) {
213 PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
214 audio->Run();
215}
[email protected]420ade42012-07-25 21:47:31216
[email protected]9a578392011-12-07 18:59:27217void PPB_Audio_Shared::Run() {
mikhail.pozdnyakova6a331a2016-12-01 12:40:54218 int control_signal = 0;
219 while (sizeof(control_signal) ==
220 socket_->Receive(&control_signal, sizeof(control_signal))) {
[email protected]1caf0aa2013-10-31 07:58:02221 // |buffer_index_| must track the number of Receive() calls. See the Send()
222 // call below for why this is important.
223 ++buffer_index_;
mikhail.pozdnyakova6a331a2016-12-01 12:40:54224 if (control_signal < 0)
[email protected]1caf0aa2013-10-31 07:58:02225 break;
226
[email protected]386778b62014-06-03 01:05:09227 {
228 TRACE_EVENT0("audio", "PPB_Audio_Shared::FireRenderCallback");
mikhail.pozdnyakova6a331a2016-12-01 12:40:54229 media::AudioOutputBuffer* buffer =
Alexandr Ilin20f2841c2018-06-01 11:56:18230 reinterpret_cast<media::AudioOutputBuffer*>(shared_memory_.memory());
mikhail.pozdnyakova6a331a2016-12-01 12:40:54231 base::TimeDelta delay =
Lizhi Fan058bf2f2018-03-26 14:56:42232 base::TimeDelta::FromMicroseconds(buffer->params.delay_us);
mikhail.pozdnyakova6a331a2016-12-01 12:40:54233
234 callback_.Run(client_buffer_.get(), client_buffer_size_bytes_,
235 delay.InSecondsF(), user_data_);
[email protected]386778b62014-06-03 01:05:09236 }
[email protected]dfc48e4c2012-09-05 13:39:21237
[email protected]1caf0aa2013-10-31 07:58:02238 // Deinterleave the audio data into the shared memory as floats.
Raul Tambreb1da2442019-04-07 18:18:03239 static_assert(kBitsPerAudioOutputSample == 16,
240 "FromInterleaved expects 2 bytes.");
241 audio_bus_->FromInterleaved<media::SignedInt16SampleTypeTraits>(
242 reinterpret_cast<int16_t*>(client_buffer_.get()), audio_bus_->frames());
[email protected]3e3715e2012-04-18 05:50:15243
[email protected]1caf0aa2013-10-31 07:58:02244 // Let the other end know which buffer we just filled. The buffer index is
245 // used to ensure the other end is getting the buffer it expects. For more
246 // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
247 size_t bytes_sent = socket_->Send(&buffer_index_, sizeof(buffer_index_));
248 if (bytes_sent != sizeof(buffer_index_))
[email protected]078c07bd2013-10-23 21:33:46249 break;
[email protected]5d84d012010-12-02 17:17:21250 }
251}
252
[email protected]55cdf6052011-05-13 19:22:53253} // namespace ppapi