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 } 35 36 PPB_Audio_Impl::~PPB_Audio_Impl() { 37 // Calling ShutDown() makes sure StreamCreated cannot be called anymore and 38 // releases the audio data associated with the pointer. Note however, that 39 // until ShutDown returns, StreamCreated may still be called. This will be 40 // OK since we'll just immediately clean up the data it stored later in this 41 // destructor. 42 if (audio_) { 43 audio_->ShutDown(); 44 audio_ = NULL; 45 } 46 } 47 48 // static 49 PP_Resource PPB_Audio_Impl::Create( 50 PP_Instance instance, 51 PP_Resource config, 52 const ppapi::AudioCallbackCombined& 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 const ppapi::AudioCallbackCombined& callback, 66 void* user_data) { 67 // Validate the config and keep a reference to it. 68 EnterResourceNoLock<PPB_AudioConfig_API> enter(config, true); 69 if (enter.failed()) 70 return false; 71 config_ = config; 72 73 if (!callback.IsValid()) 74 return false; 75 SetCallback(callback, user_data); 76 77 PepperPluginInstance* instance = PepperPluginInstance::Get(pp_instance()); 78 if (!instance) 79 return false; 80 81 // When the stream is created, we'll get called back on StreamCreated(). 82 CHECK(!audio_); 83 audio_ = PepperPlatformAudioOutput::Create( 84 static_cast<int>(enter.object()->GetSampleRate()), 85 static_cast<int>(enter.object()->GetSampleFrameCount()), 86 instance->GetRenderView()->GetRoutingID(), 87 this); 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 EnterResourceNoLock<PPB_AudioConfig_API> enter(config_, true); 162 SetStreamInfo(pp_instance(), shared_memory_handle, shared_memory_size, 163 socket_handle, enter.object()->GetSampleRate(), 164 enter.object()->GetSampleFrameCount()); 165 } 166 167 } // namespace content 168