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 "content/renderer/pepper/ppb_audio_impl.h" 6 7 #include "base/logging.h" 8 #include "content/renderer/pepper/common.h" 9 #include "content/renderer/pepper/pepper_platform_audio_output.h" 10 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 11 #include "content/renderer/render_view_impl.h" 12 #include "media/audio/audio_output_controller.h" 13 #include "ppapi/c/pp_completion_callback.h" 14 #include "ppapi/c/ppb_audio.h" 15 #include "ppapi/c/ppb_audio_config.h" 16 #include "ppapi/shared_impl/resource_tracker.h" 17 #include "ppapi/thunk/enter.h" 18 #include "ppapi/thunk/ppb_audio_config_api.h" 19 #include "ppapi/thunk/thunk.h" 20 21 using ppapi::PpapiGlobals; 22 using ppapi::thunk::EnterResourceNoLock; 23 using ppapi::thunk::PPB_Audio_API; 24 using ppapi::thunk::PPB_AudioConfig_API; 25 using ppapi::TrackedCallback; 26 27 namespace content { 28 29 // PPB_Audio_Impl -------------------------------------------------------------- 30 31 PPB_Audio_Impl::PPB_Audio_Impl(PP_Instance instance) 32 : Resource(ppapi::OBJECT_IS_IMPL, instance), 33 audio_(NULL), 34 sample_frame_count_(0) { 35 } 36 37 PPB_Audio_Impl::~PPB_Audio_Impl() { 38 // Calling ShutDown() makes sure StreamCreated cannot be called anymore and 39 // releases the audio data associated with the pointer. Note however, that 40 // until ShutDown returns, StreamCreated may still be called. This will be 41 // OK since we'll just immediately clean up the data it stored later in this 42 // destructor. 43 if (audio_) { 44 audio_->ShutDown(); 45 audio_ = NULL; 46 } 47 } 48 49 // static 50 PP_Resource PPB_Audio_Impl::Create(PP_Instance instance, 51 PP_Resource config, 52 PPB_Audio_Callback audio_callback, 53 void* user_data) { 54 scoped_refptr<PPB_Audio_Impl> audio(new PPB_Audio_Impl(instance)); 55 if (!audio->Init(config, audio_callback, user_data)) 56 return 0; 57 return audio->GetReference(); 58 } 59 60 PPB_Audio_API* PPB_Audio_Impl::AsPPB_Audio_API() { 61 return this; 62 } 63 64 bool PPB_Audio_Impl::Init(PP_Resource config, 65 PPB_Audio_Callback callback, void* user_data) { 66 // Validate the config and keep a reference to it. 67 EnterResourceNoLock<PPB_AudioConfig_API> enter(config, true); 68 if (enter.failed()) 69 return false; 70 config_ = config; 71 72 if (!callback) 73 return false; 74 SetCallback(callback, user_data); 75 76 PepperPluginInstance* instance = PepperPluginInstance::Get(pp_instance()); 77 if (!instance) 78 return false; 79 80 // When the stream is created, we'll get called back on StreamCreated(). 81 CHECK(!audio_); 82 audio_ = PepperPlatformAudioOutput::Create( 83 static_cast<int>(enter.object()->GetSampleRate()), 84 static_cast<int>(enter.object()->GetSampleFrameCount()), 85 instance->GetRenderView()->GetRoutingID(), 86 this); 87 sample_frame_count_ = enter.object()->GetSampleFrameCount(); 88 return audio_ != NULL; 89 } 90 91 PP_Resource PPB_Audio_Impl::GetCurrentConfig() { 92 // AddRef on behalf of caller, while keeping a ref for ourselves. 93 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(config_); 94 return config_; 95 } 96 97 PP_Bool PPB_Audio_Impl::StartPlayback() { 98 if (!audio_) 99 return PP_FALSE; 100 if (playing()) 101 return PP_TRUE; 102 SetStartPlaybackState(); 103 return BoolToPPBool(audio_->StartPlayback()); 104 } 105 106 PP_Bool PPB_Audio_Impl::StopPlayback() { 107 if (!audio_) 108 return PP_FALSE; 109 if (!playing()) 110 return PP_TRUE; 111 if (!audio_->StopPlayback()) 112 return PP_FALSE; 113 SetStopPlaybackState(); 114 return PP_TRUE; 115 } 116 117 int32_t PPB_Audio_Impl::Open( 118 PP_Resource config, 119 scoped_refptr<TrackedCallback> create_callback) { 120 // Validate the config and keep a reference to it. 121 EnterResourceNoLock<PPB_AudioConfig_API> enter(config, true); 122 if (enter.failed()) 123 return PP_ERROR_FAILED; 124 config_ = config; 125 126 PepperPluginInstance* instance = PepperPluginInstance::Get(pp_instance()); 127 if (!instance) 128 return PP_ERROR_FAILED; 129 130 // When the stream is created, we'll get called back on StreamCreated(). 131 DCHECK(!audio_); 132 audio_ = PepperPlatformAudioOutput::Create( 133 static_cast<int>(enter.object()->GetSampleRate()), 134 static_cast<int>(enter.object()->GetSampleFrameCount()), 135 instance->GetRenderView()->GetRoutingID(), 136 this); 137 if (!audio_) 138 return PP_ERROR_FAILED; 139 140 // At this point, we are guaranteeing ownership of the completion 141 // callback. Audio promises to fire the completion callback 142 // once and only once. 143 SetCreateCallback(create_callback); 144 145 return PP_OK_COMPLETIONPENDING; 146 } 147 148 int32_t PPB_Audio_Impl::GetSyncSocket(int* sync_socket) { 149 return GetSyncSocketImpl(sync_socket); 150 } 151 152 int32_t PPB_Audio_Impl::GetSharedMemory(int* shm_handle, 153 uint32_t* shm_size) { 154 return GetSharedMemoryImpl(shm_handle, shm_size); 155 } 156 157 void PPB_Audio_Impl::OnSetStreamInfo( 158 base::SharedMemoryHandle shared_memory_handle, 159 size_t shared_memory_size, 160 base::SyncSocket::Handle socket_handle) { 161 SetStreamInfo(pp_instance(), shared_memory_handle, shared_memory_size, 162 socket_handle, sample_frame_count_); 163 } 164 165 } // namespace content 166