| OLD | NEW |
| 1 // Copyright (c) 2011 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_input_shared.h" | 5 #include "ppapi/shared_impl/ppb_audio_input_shared.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "ppapi/c/pp_errors.h" |
| 9 #include "ppapi/shared_impl/ppapi_globals.h" |
| 10 #include "ppapi/shared_impl/ppb_device_ref_shared.h" |
| 11 #include "ppapi/shared_impl/resource_tracker.h" |
| 12 #include "ppapi/thunk/enter.h" |
| 13 #include "ppapi/thunk/ppb_audio_config_api.h" |
| 8 | 14 |
| 9 namespace ppapi { | 15 namespace ppapi { |
| 10 | 16 |
| 11 PPB_AudioInput_Shared::PPB_AudioInput_Shared() | 17 namespace { |
| 12 : capturing_(false), | 18 |
| 19 void IgnoredCompletionCallback(void* user_data, int32_t result) { |
| 20 // Do nothing. |
| 21 } |
| 22 |
| 23 } // namespace |
| 24 |
| 25 PPB_AudioInput_Shared::PPB_AudioInput_Shared(const HostResource& audio_input) |
| 26 : Resource(OBJECT_IS_PROXY, audio_input), |
| 27 open_state_(BEFORE_OPEN), |
| 28 capturing_(false), |
| 13 shared_memory_size_(0), | 29 shared_memory_size_(0), |
| 14 callback_(NULL), | 30 audio_input_callback_(NULL), |
| 15 user_data_(NULL) { | 31 user_data_(NULL), |
| 32 devices_(NULL), |
| 33 resource_object_type_(OBJECT_IS_PROXY) { |
| 34 } |
| 35 |
| 36 PPB_AudioInput_Shared::PPB_AudioInput_Shared(PP_Instance instance) |
| 37 : Resource(OBJECT_IS_IMPL, instance), |
| 38 open_state_(BEFORE_OPEN), |
| 39 capturing_(false), |
| 40 shared_memory_size_(0), |
| 41 audio_input_callback_(NULL), |
| 42 user_data_(NULL), |
| 43 devices_(NULL), |
| 44 resource_object_type_(OBJECT_IS_IMPL) { |
| 16 } | 45 } |
| 17 | 46 |
| 18 PPB_AudioInput_Shared::~PPB_AudioInput_Shared() { | 47 PPB_AudioInput_Shared::~PPB_AudioInput_Shared() { |
| 48 DCHECK(open_state_ == CLOSED); |
| 49 } |
| 50 |
| 51 thunk::PPB_AudioInput_API* PPB_AudioInput_Shared::AsPPB_AudioInput_API() { |
| 52 return this; |
| 53 } |
| 54 |
| 55 int32_t PPB_AudioInput_Shared::EnumerateDevices( |
| 56 PP_Resource* devices, |
| 57 PP_CompletionCallback callback) { |
| 58 if (!callback.func) |
| 59 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 60 if (TrackedCallback::IsPending(enumerate_devices_callback_)) |
| 61 return PP_ERROR_INPROGRESS; |
| 62 |
| 63 return InternalEnumerateDevices(devices, callback); |
| 64 } |
| 65 |
| 66 int32_t PPB_AudioInput_Shared::Open( |
| 67 const std::string& device_id, |
| 68 PP_Resource config, |
| 69 PPB_AudioInput_Callback audio_input_callback, |
| 70 void* user_data, |
| 71 PP_CompletionCallback callback) { |
| 72 if (!audio_input_callback) |
| 73 return PP_ERROR_BADARGUMENT; |
| 74 |
| 75 return CommonOpen(device_id, config, audio_input_callback, user_data, |
| 76 callback); |
| 77 } |
| 78 |
| 79 PP_Resource PPB_AudioInput_Shared::GetCurrentConfig() { |
| 80 // AddRef for the caller. |
| 81 if (config_.get()) |
| 82 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_); |
| 83 return config_; |
| 84 } |
| 85 |
| 86 PP_Bool PPB_AudioInput_Shared::StartCapture() { |
| 87 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN && |
| 88 !TrackedCallback::IsPending(open_callback_))) { |
| 89 return PP_FALSE; |
| 90 } |
| 91 if (capturing_) |
| 92 return PP_TRUE; |
| 93 |
| 94 return InternalStartCapture(); |
| 95 } |
| 96 |
| 97 PP_Bool PPB_AudioInput_Shared::StopCapture() { |
| 98 if (open_state_ == CLOSED || (open_state_ == BEFORE_OPEN && |
| 99 !TrackedCallback::IsPending(open_callback_))) { |
| 100 return PP_FALSE; |
| 101 } |
| 102 if (!capturing_) |
| 103 return PP_TRUE; |
| 104 |
| 105 return InternalStopCapture(); |
| 106 } |
| 107 |
| 108 void PPB_AudioInput_Shared::Close() { |
| 109 if (open_state_ == CLOSED) |
| 110 return; |
| 111 |
| 112 open_state_ = CLOSED; |
| 113 InternalClose(); |
| 114 |
| 19 // Closing the socket causes the thread to exit - wait for it. | 115 // Closing the socket causes the thread to exit - wait for it. |
| 20 if (socket_.get()) | 116 if (socket_.get()) |
| 21 socket_->Close(); | 117 socket_->Close(); |
| 22 if (audio_input_thread_.get()) { | 118 if (audio_input_thread_.get()) { |
| 23 audio_input_thread_->Join(); | 119 audio_input_thread_->Join(); |
| 24 audio_input_thread_.reset(); | 120 audio_input_thread_.reset(); |
| 25 } | 121 } |
| 122 |
| 123 if (TrackedCallback::IsPending(open_callback_)) |
| 124 open_callback_->PostAbort(); |
| 26 } | 125 } |
| 27 | 126 |
| 28 void PPB_AudioInput_Shared::SetCallback(PPB_AudioInput_Callback callback, | 127 void PPB_AudioInput_Shared::OnEnumerateDevicesComplete( |
| 29 void* user_data) { | 128 int32_t result, |
| 30 callback_ = callback; | 129 const std::vector<DeviceRefData>& devices) { |
| 31 user_data_ = user_data; | 130 DCHECK(TrackedCallback::IsPending(enumerate_devices_callback_)); |
| 131 |
| 132 if (result == PP_OK && devices_) { |
| 133 *devices_ = PPB_DeviceRef_Shared::CreateResourceArray( |
| 134 resource_object_type_, pp_instance(), devices); |
| 135 } |
| 136 devices_ = NULL; |
| 137 |
| 138 TrackedCallback::ClearAndRun(&enumerate_devices_callback_, result); |
| 139 } |
| 140 |
| 141 void PPB_AudioInput_Shared::OnOpenComplete( |
| 142 int32_t result, |
| 143 base::SharedMemoryHandle shared_memory_handle, |
| 144 size_t shared_memory_size, |
| 145 base::SyncSocket::Handle socket_handle) { |
| 146 if (open_state_ == BEFORE_OPEN && result == PP_OK) { |
| 147 open_state_ = OPENED; |
| 148 SetStreamInfo(shared_memory_handle, shared_memory_size, socket_handle); |
| 149 } else { |
| 150 // Clean up the handles. |
| 151 base::SyncSocket temp_socket(socket_handle); |
| 152 base::SharedMemory temp_mem(shared_memory_handle, false); |
| 153 } |
| 154 |
| 155 // The callback may have been aborted by Close(). |
| 156 if (TrackedCallback::IsPending(open_callback_)) |
| 157 TrackedCallback::ClearAndRun(&open_callback_, result); |
| 158 } |
| 159 |
| 160 // static |
| 161 PP_CompletionCallback PPB_AudioInput_Shared::MakeIgnoredCompletionCallback() { |
| 162 return PP_MakeCompletionCallback(&IgnoredCompletionCallback, NULL); |
| 32 } | 163 } |
| 33 | 164 |
| 34 void PPB_AudioInput_Shared::SetStartCaptureState() { | 165 void PPB_AudioInput_Shared::SetStartCaptureState() { |
| 35 DCHECK(!capturing_); | 166 DCHECK(!capturing_); |
| 36 DCHECK(!audio_input_thread_.get()); | 167 DCHECK(!audio_input_thread_.get()); |
| 37 | 168 |
| 38 // If the socket doesn't exist, that means that the plugin has started before | 169 // If the socket doesn't exist, that means that the plugin has started before |
| 39 // the browser has had a chance to create all the shared memory info and | 170 // the browser has had a chance to create all the shared memory info and |
| 40 // notify us. This is a common case. In this case, we just set the playing_ | 171 // notify us. This is a common case. In this case, we just set the capturing_ |
| 41 // flag and the capture will automatically start when that data is available | 172 // flag and the capture will automatically start when that data is available |
| 42 // in SetStreamInfo. | 173 // in SetStreamInfo. |
| 43 if (socket_.get()) | 174 if (audio_input_callback_ && socket_.get()) |
| 44 StartThread(); | 175 StartThread(); |
| 45 capturing_ = true; | 176 capturing_ = true; |
| 46 } | 177 } |
| 47 | 178 |
| 48 void PPB_AudioInput_Shared::SetStopCaptureState() { | 179 void PPB_AudioInput_Shared::SetStopCaptureState() { |
| 49 DCHECK(capturing_); | 180 DCHECK(capturing_); |
| 50 | 181 |
| 51 if (audio_input_thread_.get()) { | 182 if (audio_input_thread_.get()) { |
| 52 audio_input_thread_->Join(); | 183 audio_input_thread_->Join(); |
| 53 audio_input_thread_.reset(); | 184 audio_input_thread_.reset(); |
| 54 } | 185 } |
| 55 capturing_ = false; | 186 capturing_ = false; |
| 56 } | 187 } |
| 57 | 188 |
| 58 void PPB_AudioInput_Shared::SetStreamInfo( | 189 void PPB_AudioInput_Shared::SetStreamInfo( |
| 59 base::SharedMemoryHandle shared_memory_handle, | 190 base::SharedMemoryHandle shared_memory_handle, |
| 60 size_t shared_memory_size, | 191 size_t shared_memory_size, |
| 61 base::SyncSocket::Handle socket_handle) { | 192 base::SyncSocket::Handle socket_handle) { |
| 62 socket_.reset(new base::SyncSocket(socket_handle)); | 193 socket_.reset(new base::SyncSocket(socket_handle)); |
| 63 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); | 194 shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false)); |
| 64 shared_memory_size_ = shared_memory_size; | 195 shared_memory_size_ = shared_memory_size; |
| 65 | 196 |
| 66 if (callback_) { | 197 if (audio_input_callback_) { |
| 67 shared_memory_->Map(shared_memory_size_); | 198 shared_memory_->Map(shared_memory_size_); |
| 68 | 199 |
| 69 // In common case StartCapture() was called before StreamCreated(). | 200 // StartCapture() may be called before SetSreamInfo(). |
| 70 if (capturing_) | 201 if (capturing_) |
| 71 StartThread(); | 202 StartThread(); |
| 72 } | 203 } |
| 73 } | 204 } |
| 74 | 205 |
| 75 void PPB_AudioInput_Shared::StartThread() { | 206 void PPB_AudioInput_Shared::StartThread() { |
| 76 DCHECK(callback_); | 207 DCHECK(audio_input_callback_); |
| 77 DCHECK(!audio_input_thread_.get()); | 208 DCHECK(!audio_input_thread_.get()); |
| 78 audio_input_thread_.reset(new base::DelegateSimpleThread( | 209 audio_input_thread_.reset(new base::DelegateSimpleThread( |
| 79 this, "plugin_audio_input_thread")); | 210 this, "plugin_audio_input_thread")); |
| 80 audio_input_thread_->Start(); | 211 audio_input_thread_->Start(); |
| 81 } | 212 } |
| 82 | 213 |
| 83 void PPB_AudioInput_Shared::Run() { | 214 void PPB_AudioInput_Shared::Run() { |
| 84 int pending_data; | 215 int pending_data; |
| 85 void* buffer = shared_memory_->memory(); | 216 void* buffer = shared_memory_->memory(); |
| 86 | 217 |
| 87 while (sizeof(pending_data) == socket_->Receive(&pending_data, | 218 while (sizeof(pending_data) == socket_->Receive(&pending_data, |
| 88 sizeof(pending_data)) && | 219 sizeof(pending_data)) && |
| 89 pending_data >= 0) { | 220 pending_data >= 0) { |
| 90 callback_(buffer, shared_memory_size_, user_data_); | 221 audio_input_callback_(buffer, shared_memory_size_, user_data_); |
| 91 } | 222 } |
| 92 } | 223 } |
| 93 | 224 |
| 225 int32_t PPB_AudioInput_Shared::CommonOpen( |
| 226 const std::string& device_id, |
| 227 PP_Resource config, |
| 228 PPB_AudioInput_Callback audio_input_callback, |
| 229 void* user_data, |
| 230 PP_CompletionCallback callback) { |
| 231 if (open_state_ != BEFORE_OPEN) |
| 232 return PP_ERROR_FAILED; |
| 233 |
| 234 thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config, |
| 235 true); |
| 236 if (enter_config.failed()) |
| 237 return PP_ERROR_BADARGUMENT; |
| 238 |
| 239 if (!callback.func) |
| 240 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 241 |
| 242 if (TrackedCallback::IsPending(open_callback_)) |
| 243 return PP_ERROR_INPROGRESS; |
| 244 |
| 245 config_ = config; |
| 246 audio_input_callback_ = audio_input_callback; |
| 247 user_data_ = user_data; |
| 248 |
| 249 return InternalOpen(device_id, enter_config.object()->GetSampleRate(), |
| 250 enter_config.object()->GetSampleFrameCount(), callback); |
| 251 } |
| 252 |
| 94 } // namespace ppapi | 253 } // namespace ppapi |
| OLD | NEW |