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