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/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" 13 14 namespace ppapi { 15 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; 20 } 21 22 AudioCallbackCombined::AudioCallbackCombined() 23 : callback_1_0_(NULL), callback_(NULL) {} 24 25 AudioCallbackCombined::AudioCallbackCombined( 26 PPB_Audio_Callback_1_0 callback_1_0) 27 : callback_1_0_(callback_1_0), callback_(NULL) {} 28 29 AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback) 30 : callback_1_0_(NULL), callback_(callback) {} 31 32 AudioCallbackCombined::~AudioCallbackCombined() {} 33 34 bool AudioCallbackCombined::IsValid() const { 35 return callback_1_0_ || callback_; 36 } 37 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(); 48 } 49 } 50 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) { 59 } 60 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(); 66 } 67 68 void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback, 69 void* user_data) { 70 callback_ = callback; 71 user_data_ = user_data; 72 } 73 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(); 85 } 86 87 void PPB_Audio_Shared::SetStopPlaybackState() { 88 DCHECK(playing_); 89 StopThread(); 90 playing_ = false; 91 } 92 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; 106 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_]); 120 } 121 122 StartThread(); 123 } 124 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_); 136 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; 142 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(); 153 } 154 } 155 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; 169 } 170 } else { 171 if (audio_thread_.get()) { 172 CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join, 173 base::Unretained(audio_thread_.get()))); 174 audio_thread_.reset(); 175 } 176 } 177 } 178 179 // static 180 bool PPB_Audio_Shared::IsThreadFunctionReady() { 181 if (!g_nacl_mode) 182 return true; 183 184 return (g_thread_functions.thread_create != NULL && 185 g_thread_functions.thread_join != NULL); 186 } 187 188 // static 189 void PPB_Audio_Shared::SetNaClMode() { 190 g_nacl_mode = true; 191 } 192 193 // static 194 void PPB_Audio_Shared::SetThreadFunctions( 195 const struct PP_ThreadFunctions* functions) { 196 DCHECK(g_nacl_mode); 197 g_thread_functions = *functions; 198 } 199 200 // static 201 void PPB_Audio_Shared::CallRun(void* self) { 202 PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self); 203 audio->Run(); 204 } 205 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; 215 216 { 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_); 222 } 223 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); 228 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; 235 } 236 } 237 238 } // namespace ppapi 239