Request the hotword audio stream when using always-on hotwording.
[chromium-blink-merge.git] / ppapi / shared_impl / ppb_audio_shared.cc
blob99af9d7e7e20bfece9fd2f2870c13a1d2d2f13d9
1 // Copyright (c) 2012 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.
5 #include "ppapi/shared_impl/ppb_audio_shared.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "ppapi/nacl_irt/public/irt_ppapi.h"
10 #include "ppapi/shared_impl/ppapi_globals.h"
11 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
12 #include "ppapi/shared_impl/proxy_lock.h"
14 namespace ppapi {
16 namespace {
17 bool g_nacl_mode = false;
18 // Because this is static, the function pointers will be NULL initially.
19 PP_ThreadFunctions g_thread_functions;
22 AudioCallbackCombined::AudioCallbackCombined()
23 : callback_1_0_(NULL), callback_(NULL) {}
25 AudioCallbackCombined::AudioCallbackCombined(
26 PPB_Audio_Callback_1_0 callback_1_0)
27 : callback_1_0_(callback_1_0), callback_(NULL) {}
29 AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback)
30 : callback_1_0_(NULL), callback_(callback) {}
32 AudioCallbackCombined::~AudioCallbackCombined() {}
34 bool AudioCallbackCombined::IsValid() const {
35 return callback_1_0_ || callback_;
38 void AudioCallbackCombined::Run(void* sample_buffer,
39 uint32_t buffer_size_in_bytes,
40 PP_TimeDelta latency,
41 void* user_data) const {
42 if (callback_) {
43 callback_(sample_buffer, buffer_size_in_bytes, latency, user_data);
44 } else if (callback_1_0_) {
45 callback_1_0_(sample_buffer, buffer_size_in_bytes, user_data);
46 } else {
47 NOTREACHED();
51 PPB_Audio_Shared::PPB_Audio_Shared()
52 : playing_(false),
53 shared_memory_size_(0),
54 nacl_thread_active_(false),
55 user_data_(NULL),
56 client_buffer_size_bytes_(0),
57 bytes_per_second_(0),
58 buffer_index_(0) {
61 PPB_Audio_Shared::~PPB_Audio_Shared() {
62 // Shut down the socket to escape any hanging |Receive|s.
63 if (socket_.get())
64 socket_->Shutdown();
65 StopThread();
68 void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback,
69 void* user_data) {
70 callback_ = callback;
71 user_data_ = user_data;
74 void PPB_Audio_Shared::SetStartPlaybackState() {
75 DCHECK(!playing_);
76 DCHECK(!audio_thread_.get());
77 DCHECK(!nacl_thread_active_);
78 // If the socket doesn't exist, that means that the plugin has started before
79 // the browser has had a chance to create all the shared memory info and
80 // notify us. This is a common case. In this case, we just set the playing_
81 // flag and the playback will automatically start when that data is available
82 // in SetStreamInfo.
83 playing_ = true;
84 StartThread();
87 void PPB_Audio_Shared::SetStopPlaybackState() {
88 DCHECK(playing_);
89 StopThread();
90 playing_ = false;
93 void PPB_Audio_Shared::SetStreamInfo(
94 PP_Instance instance,
95 base::SharedMemoryHandle shared_memory_handle,
96 size_t shared_memory_size,
97 base::SyncSocket::Handle socket_handle,
98 PP_AudioSampleRate sample_rate,
99 int sample_frame_count) {
100 socket_.reset(new base::CancelableSyncSocket(socket_handle));
101 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
102 shared_memory_size_ = shared_memory_size;
103 bytes_per_second_ =
104 kAudioOutputChannels * (kBitsPerAudioOutputSample / 8) * sample_rate;
105 buffer_index_ = 0;
107 if (!shared_memory_->Map(shared_memory_size_)) {
108 PpapiGlobals::Get()->LogWithSource(
109 instance,
110 PP_LOGLEVEL_WARNING,
111 std::string(),
112 "Failed to map shared memory for PPB_Audio_Shared.");
113 } else {
114 audio_bus_ = media::AudioBus::WrapMemory(
115 kAudioOutputChannels, sample_frame_count, shared_memory_->memory());
116 // Setup integer audio buffer for user audio data.
117 client_buffer_size_bytes_ = audio_bus_->frames() * audio_bus_->channels() *
118 kBitsPerAudioOutputSample / 8;
119 client_buffer_.reset(new uint8_t[client_buffer_size_bytes_]);
122 StartThread();
125 void PPB_Audio_Shared::StartThread() {
126 // Don't start the thread unless all our state is set up correctly.
127 if (!playing_ || !callback_.IsValid() || !socket_.get() ||
128 !shared_memory_->memory() || !audio_bus_.get() || !client_buffer_.get() ||
129 bytes_per_second_ == 0)
130 return;
131 // Clear contents of shm buffer before starting audio thread. This will
132 // prevent a burst of static if for some reason the audio thread doesn't
133 // start up quickly enough.
134 memset(shared_memory_->memory(), 0, shared_memory_size_);
135 memset(client_buffer_.get(), 0, client_buffer_size_bytes_);
137 if (g_nacl_mode) {
138 // Use NaCl's special API for IRT code that creates threads that call back
139 // into user code.
140 if (!IsThreadFunctionReady())
141 return;
143 DCHECK(!nacl_thread_active_);
144 int result =
145 g_thread_functions.thread_create(&nacl_thread_id_, CallRun, this);
146 DCHECK_EQ(0, result);
147 nacl_thread_active_ = true;
148 } else {
149 DCHECK(!audio_thread_.get());
150 audio_thread_.reset(
151 new base::DelegateSimpleThread(this, "plugin_audio_thread"));
152 audio_thread_->Start();
156 void PPB_Audio_Shared::StopThread() {
157 // In general, the audio thread should not do Pepper calls, but it might
158 // anyway (for example, our Audio test does CallOnMainThread). If it did a
159 // pepper call which acquires the lock (most of them do), and we try to shut
160 // down the thread and Join it while holding the lock, we would deadlock. So
161 // we give up the lock here so that the thread at least _can_ make Pepper
162 // calls without causing deadlock.
163 if (g_nacl_mode) {
164 if (nacl_thread_active_) {
165 int result =
166 CallWhileUnlocked(g_thread_functions.thread_join, nacl_thread_id_);
167 DCHECK_EQ(0, result);
168 nacl_thread_active_ = false;
170 } else {
171 if (audio_thread_.get()) {
172 CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join,
173 base::Unretained(audio_thread_.get())));
174 audio_thread_.reset();
179 // static
180 bool PPB_Audio_Shared::IsThreadFunctionReady() {
181 if (!g_nacl_mode)
182 return true;
184 return (g_thread_functions.thread_create != NULL &&
185 g_thread_functions.thread_join != NULL);
188 // static
189 void PPB_Audio_Shared::SetNaClMode() {
190 g_nacl_mode = true;
193 // static
194 void PPB_Audio_Shared::SetThreadFunctions(
195 const struct PP_ThreadFunctions* functions) {
196 DCHECK(g_nacl_mode);
197 g_thread_functions = *functions;
200 // static
201 void PPB_Audio_Shared::CallRun(void* self) {
202 PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self);
203 audio->Run();
206 void PPB_Audio_Shared::Run() {
207 int pending_data = 0;
208 while (sizeof(pending_data) ==
209 socket_->Receive(&pending_data, sizeof(pending_data))) {
210 // |buffer_index_| must track the number of Receive() calls. See the Send()
211 // call below for why this is important.
212 ++buffer_index_;
213 if (pending_data < 0)
214 break;
217 TRACE_EVENT0("audio", "PPB_Audio_Shared::FireRenderCallback");
218 PP_TimeDelta latency =
219 static_cast<double>(pending_data) / bytes_per_second_;
220 callback_.Run(
221 client_buffer_.get(), client_buffer_size_bytes_, latency, user_data_);
224 // Deinterleave the audio data into the shared memory as floats.
225 audio_bus_->FromInterleaved(client_buffer_.get(),
226 audio_bus_->frames(),
227 kBitsPerAudioOutputSample / 8);
229 // Let the other end know which buffer we just filled. The buffer index is
230 // used to ensure the other end is getting the buffer it expects. For more
231 // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
232 size_t bytes_sent = socket_->Send(&buffer_index_, sizeof(buffer_index_));
233 if (bytes_sent != sizeof(buffer_index_))
234 break;
238 } // namespace ppapi