| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/shared_impl/ppb_audio_shared.h" | 5 #include "ppapi/shared_impl/ppb_audio_shared.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "ppapi/nacl_irt/public/irt_ppapi.h" |
| 8 #include "ppapi/shared_impl/ppapi_globals.h" | 9 #include "ppapi/shared_impl/ppapi_globals.h" |
| 9 #include "ppapi/shared_impl/ppb_audio_config_shared.h" | 10 #include "ppapi/shared_impl/ppb_audio_config_shared.h" |
| 10 #include "ppapi/shared_impl/proxy_lock.h" | 11 #include "ppapi/shared_impl/proxy_lock.h" |
| 11 | 12 |
| 12 namespace ppapi { | 13 namespace ppapi { |
| 13 | 14 |
| 14 #if defined(OS_NACL) | |
| 15 namespace { | 15 namespace { |
| 16 bool g_nacl_mode = false; |
| 16 // Because this is static, the function pointers will be NULL initially. | 17 // Because this is static, the function pointers will be NULL initially. |
| 17 PP_ThreadFunctions thread_functions; | 18 PP_ThreadFunctions g_thread_functions; |
| 18 } | 19 } |
| 19 #endif // defined(OS_NACL) | |
| 20 | 20 |
| 21 AudioCallbackCombined::AudioCallbackCombined() | 21 AudioCallbackCombined::AudioCallbackCombined() |
| 22 : callback_1_0_(NULL), callback_(NULL) {} | 22 : callback_1_0_(NULL), callback_(NULL) {} |
| 23 | 23 |
| 24 AudioCallbackCombined::AudioCallbackCombined( | 24 AudioCallbackCombined::AudioCallbackCombined( |
| 25 PPB_Audio_Callback_1_0 callback_1_0) | 25 PPB_Audio_Callback_1_0 callback_1_0) |
| 26 : callback_1_0_(callback_1_0), callback_(NULL) {} | 26 : callback_1_0_(callback_1_0), callback_(NULL) {} |
| 27 | 27 |
| 28 AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback) | 28 AudioCallbackCombined::AudioCallbackCombined(PPB_Audio_Callback callback) |
| 29 : callback_1_0_(NULL), callback_(callback) {} | 29 : callback_1_0_(NULL), callback_(callback) {} |
| (...skipping 13 matching lines...) Expand all Loading... |
| 43 } else if (callback_1_0_) { | 43 } else if (callback_1_0_) { |
| 44 callback_1_0_(sample_buffer, buffer_size_in_bytes, user_data); | 44 callback_1_0_(sample_buffer, buffer_size_in_bytes, user_data); |
| 45 } else { | 45 } else { |
| 46 NOTREACHED(); | 46 NOTREACHED(); |
| 47 } | 47 } |
| 48 } | 48 } |
| 49 | 49 |
| 50 PPB_Audio_Shared::PPB_Audio_Shared() | 50 PPB_Audio_Shared::PPB_Audio_Shared() |
| 51 : playing_(false), | 51 : playing_(false), |
| 52 shared_memory_size_(0), | 52 shared_memory_size_(0), |
| 53 #if defined(OS_NACL) | 53 nacl_thread_active_(false), |
| 54 thread_id_(0), | |
| 55 thread_active_(false), | |
| 56 #endif | |
| 57 user_data_(NULL), | 54 user_data_(NULL), |
| 58 client_buffer_size_bytes_(0), | 55 client_buffer_size_bytes_(0), |
| 59 bytes_per_second_(0), | 56 bytes_per_second_(0), |
| 60 buffer_index_(0) { | 57 buffer_index_(0) { |
| 61 } | 58 } |
| 62 | 59 |
| 63 PPB_Audio_Shared::~PPB_Audio_Shared() { | 60 PPB_Audio_Shared::~PPB_Audio_Shared() { |
| 64 // Shut down the socket to escape any hanging |Receive|s. | 61 // Shut down the socket to escape any hanging |Receive|s. |
| 65 if (socket_.get()) | 62 if (socket_.get()) |
| 66 socket_->Shutdown(); | 63 socket_->Shutdown(); |
| 67 StopThread(); | 64 StopThread(); |
| 68 } | 65 } |
| 69 | 66 |
| 70 void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback, | 67 void PPB_Audio_Shared::SetCallback(const AudioCallbackCombined& callback, |
| 71 void* user_data) { | 68 void* user_data) { |
| 72 callback_ = callback; | 69 callback_ = callback; |
| 73 user_data_ = user_data; | 70 user_data_ = user_data; |
| 74 } | 71 } |
| 75 | 72 |
| 76 void PPB_Audio_Shared::SetStartPlaybackState() { | 73 void PPB_Audio_Shared::SetStartPlaybackState() { |
| 77 DCHECK(!playing_); | 74 DCHECK(!playing_); |
| 78 #if !defined(OS_NACL) | |
| 79 DCHECK(!audio_thread_.get()); | 75 DCHECK(!audio_thread_.get()); |
| 80 #else | 76 DCHECK(!nacl_thread_active_); |
| 81 DCHECK(!thread_active_); | |
| 82 #endif | |
| 83 // If the socket doesn't exist, that means that the plugin has started before | 77 // 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 | 78 // 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_ | 79 // 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 | 80 // flag and the playback will automatically start when that data is available |
| 87 // in SetStreamInfo. | 81 // in SetStreamInfo. |
| 88 playing_ = true; | 82 playing_ = true; |
| 89 StartThread(); | 83 StartThread(); |
| 90 } | 84 } |
| 91 | 85 |
| 92 void PPB_Audio_Shared::SetStopPlaybackState() { | 86 void PPB_Audio_Shared::SetStopPlaybackState() { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 // Don't start the thread unless all our state is set up correctly. | 125 // Don't start the thread unless all our state is set up correctly. |
| 132 if (!playing_ || !callback_.IsValid() || !socket_.get() || | 126 if (!playing_ || !callback_.IsValid() || !socket_.get() || |
| 133 !shared_memory_->memory() || !audio_bus_.get() || !client_buffer_.get() || | 127 !shared_memory_->memory() || !audio_bus_.get() || !client_buffer_.get() || |
| 134 bytes_per_second_ == 0) | 128 bytes_per_second_ == 0) |
| 135 return; | 129 return; |
| 136 // Clear contents of shm buffer before starting audio thread. This will | 130 // Clear contents of shm buffer before starting audio thread. This will |
| 137 // prevent a burst of static if for some reason the audio thread doesn't | 131 // prevent a burst of static if for some reason the audio thread doesn't |
| 138 // start up quickly enough. | 132 // start up quickly enough. |
| 139 memset(shared_memory_->memory(), 0, shared_memory_size_); | 133 memset(shared_memory_->memory(), 0, shared_memory_size_); |
| 140 memset(client_buffer_.get(), 0, client_buffer_size_bytes_); | 134 memset(client_buffer_.get(), 0, client_buffer_size_bytes_); |
| 141 #if !defined(OS_NACL) | |
| 142 DCHECK(!audio_thread_.get()); | |
| 143 audio_thread_.reset( | |
| 144 new base::DelegateSimpleThread(this, "plugin_audio_thread")); | |
| 145 audio_thread_->Start(); | |
| 146 #else | |
| 147 // Use NaCl's special API for IRT code that creates threads that call back | |
| 148 // into user code. | |
| 149 if (!IsThreadFunctionReady()) | |
| 150 return; | |
| 151 | 135 |
| 152 DCHECK(!thread_active_); | 136 if (g_nacl_mode) { |
| 153 int result = thread_functions.thread_create(&thread_id_, CallRun, this); | 137 // Use NaCl's special API for IRT code that creates threads that call back |
| 154 DCHECK_EQ(result, 0); | 138 // into user code. |
| 155 thread_active_ = true; | 139 if (!IsThreadFunctionReady()) |
| 156 #endif | 140 return; |
| 141 |
| 142 DCHECK(!nacl_thread_active_); |
| 143 int result = |
| 144 g_thread_functions.thread_create(&nacl_thread_id_, CallRun, this); |
| 145 DCHECK_EQ(0, result); |
| 146 nacl_thread_active_ = true; |
| 147 } else { |
| 148 DCHECK(!audio_thread_.get()); |
| 149 audio_thread_.reset( |
| 150 new base::DelegateSimpleThread(this, "plugin_audio_thread")); |
| 151 audio_thread_->Start(); |
| 152 } |
| 157 } | 153 } |
| 158 | 154 |
| 159 void PPB_Audio_Shared::StopThread() { | 155 void PPB_Audio_Shared::StopThread() { |
| 160 #if !defined(OS_NACL) | 156 if (g_nacl_mode) { |
| 161 if (audio_thread_.get()) { | 157 if (nacl_thread_active_) { |
| 162 // In general, the audio thread should not do Pepper calls, but it might | 158 // In general, the audio thread should not do Pepper calls, but it |
| 163 // anyway (for example, our Audio test does CallOnMainThread). If it did | 159 // might anyway (for example, our Audio test does CallOnMainThread). If |
| 164 // a pepper call which acquires the lock (most of them do), and we try to | 160 // it did a pepper call which acquires the lock (most of them do), and |
| 165 // shut down the thread and Join it while holding the lock, we would | 161 // we try to shut down the thread and Join it while holding the lock, |
| 166 // deadlock. So we give up the lock here so that the thread at least _can_ | 162 // we would deadlock. So we give up the lock here so that the thread at |
| 167 // make Pepper calls without causing deadlock. | 163 // least _can_ make Pepper calls without causing deadlock. |
| 168 CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join, | 164 int result = |
| 169 base::Unretained(audio_thread_.get()))); | 165 CallWhileUnlocked(g_thread_functions.thread_join, nacl_thread_id_); |
| 170 audio_thread_.reset(); | 166 DCHECK_EQ(0, result); |
| 167 nacl_thread_active_ = false; |
| 168 } |
| 169 } else { |
| 170 if (audio_thread_.get()) { |
| 171 // See comment above about why we unlock here. |
| 172 CallWhileUnlocked(base::Bind(&base::DelegateSimpleThread::Join, |
| 173 base::Unretained(audio_thread_.get()))); |
| 174 audio_thread_.reset(); |
| 175 } |
| 171 } | 176 } |
| 172 #else | |
| 173 if (thread_active_) { | |
| 174 // See comment above about why we unlock here. | |
| 175 int result = CallWhileUnlocked(thread_functions.thread_join, thread_id_); | |
| 176 DCHECK_EQ(0, result); | |
| 177 thread_active_ = false; | |
| 178 } | |
| 179 #endif | |
| 180 } | 177 } |
| 181 | 178 |
| 182 // static | 179 // static |
| 183 bool PPB_Audio_Shared::IsThreadFunctionReady() { | 180 bool PPB_Audio_Shared::IsThreadFunctionReady() { |
| 184 #if defined(OS_NACL) | 181 if (!g_nacl_mode) |
| 185 if (thread_functions.thread_create == NULL || | 182 return true; |
| 186 thread_functions.thread_join == NULL) | 183 |
| 187 return false; | 184 return (g_thread_functions.thread_create != NULL && |
| 188 #endif | 185 g_thread_functions.thread_join != NULL); |
| 189 return true; | |
| 190 } | 186 } |
| 191 | 187 |
| 192 #if defined(OS_NACL) | 188 // static |
| 189 void PPB_Audio_Shared::SetNaClMode() { |
| 190 g_nacl_mode = true; |
| 191 } |
| 192 |
| 193 // static | 193 // static |
| 194 void PPB_Audio_Shared::SetThreadFunctions( | 194 void PPB_Audio_Shared::SetThreadFunctions( |
| 195 const struct PP_ThreadFunctions* functions) { | 195 const struct PP_ThreadFunctions* functions) { |
| 196 thread_functions = *functions; | 196 DCHECK(g_nacl_mode); |
| 197 g_thread_functions = *functions; |
| 197 } | 198 } |
| 198 | 199 |
| 199 // static | 200 // static |
| 200 void PPB_Audio_Shared::CallRun(void* self) { | 201 void PPB_Audio_Shared::CallRun(void* self) { |
| 201 PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self); | 202 PPB_Audio_Shared* audio = static_cast<PPB_Audio_Shared*>(self); |
| 202 audio->Run(); | 203 audio->Run(); |
| 203 } | 204 } |
| 204 #endif | |
| 205 | 205 |
| 206 void PPB_Audio_Shared::Run() { | 206 void PPB_Audio_Shared::Run() { |
| 207 int pending_data = 0; | 207 int pending_data = 0; |
| 208 while (sizeof(pending_data) == | 208 while (sizeof(pending_data) == |
| 209 socket_->Receive(&pending_data, sizeof(pending_data))) { | 209 socket_->Receive(&pending_data, sizeof(pending_data))) { |
| 210 // |buffer_index_| must track the number of Receive() calls. See the Send() | 210 // |buffer_index_| must track the number of Receive() calls. See the Send() |
| 211 // call below for why this is important. | 211 // call below for why this is important. |
| 212 ++buffer_index_; | 212 ++buffer_index_; |
| 213 if (pending_data < 0) | 213 if (pending_data < 0) |
| 214 break; | 214 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 226 // Let the other end know which buffer we just filled. The buffer index is | 226 // Let the other end know which buffer we just filled. The buffer index is |
| 227 // used to ensure the other end is getting the buffer it expects. For more | 227 // used to ensure the other end is getting the buffer it expects. For more |
| 228 // details on how this works see AudioSyncReader::WaitUntilDataIsReady(). | 228 // details on how this works see AudioSyncReader::WaitUntilDataIsReady(). |
| 229 size_t bytes_sent = socket_->Send(&buffer_index_, sizeof(buffer_index_)); | 229 size_t bytes_sent = socket_->Send(&buffer_index_, sizeof(buffer_index_)); |
| 230 if (bytes_sent != sizeof(buffer_index_)) | 230 if (bytes_sent != sizeof(buffer_index_)) |
| 231 break; | 231 break; |
| 232 } | 232 } |
| 233 } | 233 } |
| 234 | 234 |
| 235 } // namespace ppapi | 235 } // namespace ppapi |
| OLD | NEW |