// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/renderer/pepper/pepper_media_device_manager.h" #include "base/location.h" #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" #include "content/renderer/media/media_stream_dispatcher.h" #include "content/renderer/render_frame_impl.h" #include "ppapi/shared_impl/ppb_device_ref_shared.h" namespace content { namespace { ppapi::DeviceRefData FromStreamDeviceInfo(const StreamDeviceInfo& info) { ppapi::DeviceRefData data; data.id = info.device.id; // Some Flash content can't handle an empty string, so stick a space in to // make them happy. See crbug.com/408404. data.name = info.device.name.empty() ? std::string(" ") : info.device.name; data.type = PepperMediaDeviceManager::FromMediaStreamType(info.device.type); return data; } } // namespace base::WeakPtr PepperMediaDeviceManager::GetForRenderFrame( RenderFrame* render_frame) { PepperMediaDeviceManager* handler = PepperMediaDeviceManager::Get(render_frame); if (!handler) handler = new PepperMediaDeviceManager(render_frame); return handler->AsWeakPtr(); } PepperMediaDeviceManager::PepperMediaDeviceManager(RenderFrame* render_frame) : RenderFrameObserver(render_frame), RenderFrameObserverTracker(render_frame), next_id_(1) {} PepperMediaDeviceManager::~PepperMediaDeviceManager() { DCHECK(enumerate_callbacks_.empty()); DCHECK(open_callbacks_.empty()); } int PepperMediaDeviceManager::EnumerateDevices( PP_DeviceType_Dev type, const GURL& document_url, const EnumerateDevicesCallback& callback) { enumerate_callbacks_[next_id_] = callback; int request_id = next_id_++; #if defined(ENABLE_WEBRTC) GetMediaStreamDispatcher()->EnumerateDevices( request_id, AsWeakPtr(), PepperMediaDeviceManager::FromPepperDeviceType(type), document_url.GetOrigin()); #else base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&PepperMediaDeviceManager::OnDevicesEnumerated, AsWeakPtr(), request_id, StreamDeviceInfoArray())); #endif return request_id; } void PepperMediaDeviceManager::StopEnumerateDevices(int request_id) { enumerate_callbacks_.erase(request_id); #if defined(ENABLE_WEBRTC) // Need to post task since this function might be called inside the callback // of EnumerateDevices. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PepperMediaDeviceManager::StopEnumerateDevicesDelayed, AsWeakPtr(), request_id)); #endif } void PepperMediaDeviceManager::StopEnumerateDevicesDelayed(int request_id) { #if defined(ENABLE_WEBRTC) // This method is being invoked by the message loop at some unknown // point-in-time after StopEnumerateDevices(). Therefore, check that // render_frame() is not NULL, in order to guarantee // GetMediaStreamDispatcher() won't return NULL. if (render_frame()) GetMediaStreamDispatcher()->StopEnumerateDevices(request_id, AsWeakPtr()); #endif } int PepperMediaDeviceManager::OpenDevice(PP_DeviceType_Dev type, const std::string& device_id, const GURL& document_url, const OpenDeviceCallback& callback) { open_callbacks_[next_id_] = callback; int request_id = next_id_++; #if defined(ENABLE_WEBRTC) GetMediaStreamDispatcher()->OpenDevice( request_id, AsWeakPtr(), device_id, PepperMediaDeviceManager::FromPepperDeviceType(type), document_url.GetOrigin()); #else base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&PepperMediaDeviceManager::OnDeviceOpenFailed, AsWeakPtr(), request_id)); #endif return request_id; } void PepperMediaDeviceManager::CancelOpenDevice(int request_id) { open_callbacks_.erase(request_id); #if defined(ENABLE_WEBRTC) GetMediaStreamDispatcher()->CancelOpenDevice(request_id, AsWeakPtr()); #endif } void PepperMediaDeviceManager::CloseDevice(const std::string& label) { #if defined(ENABLE_WEBRTC) GetMediaStreamDispatcher()->CloseDevice(label); #endif } int PepperMediaDeviceManager::GetSessionID(PP_DeviceType_Dev type, const std::string& label) { #if defined(ENABLE_WEBRTC) switch (type) { case PP_DEVICETYPE_DEV_AUDIOCAPTURE: return GetMediaStreamDispatcher()->audio_session_id(label, 0); case PP_DEVICETYPE_DEV_VIDEOCAPTURE: return GetMediaStreamDispatcher()->video_session_id(label, 0); default: NOTREACHED(); return 0; } #else return 0; #endif } void PepperMediaDeviceManager::OnStreamGenerated( int request_id, const std::string& label, const StreamDeviceInfoArray& audio_device_array, const StreamDeviceInfoArray& video_device_array) {} void PepperMediaDeviceManager::OnStreamGenerationFailed( int request_id, content::MediaStreamRequestResult result) {} void PepperMediaDeviceManager::OnDeviceStopped( const std::string& label, const StreamDeviceInfo& device_info) {} void PepperMediaDeviceManager::OnDevicesEnumerated( int request_id, const StreamDeviceInfoArray& device_array) { EnumerateCallbackMap::iterator iter = enumerate_callbacks_.find(request_id); if (iter == enumerate_callbacks_.end()) { // This might be enumerated result sent before StopEnumerateDevices is // called since EnumerateDevices is persistent request. return; } EnumerateDevicesCallback callback = iter->second; std::vector devices; devices.reserve(device_array.size()); for (StreamDeviceInfoArray::const_iterator info = device_array.begin(); info != device_array.end(); ++info) { devices.push_back(FromStreamDeviceInfo(*info)); } callback.Run(request_id, devices); } void PepperMediaDeviceManager::OnDeviceOpened( int request_id, const std::string& label, const StreamDeviceInfo& device_info) { NotifyDeviceOpened(request_id, true, label); } void PepperMediaDeviceManager::OnDeviceOpenFailed(int request_id) { NotifyDeviceOpened(request_id, false, std::string()); } // static MediaStreamType PepperMediaDeviceManager::FromPepperDeviceType( PP_DeviceType_Dev type) { switch (type) { case PP_DEVICETYPE_DEV_INVALID: return MEDIA_NO_SERVICE; case PP_DEVICETYPE_DEV_AUDIOCAPTURE: return MEDIA_DEVICE_AUDIO_CAPTURE; case PP_DEVICETYPE_DEV_VIDEOCAPTURE: return MEDIA_DEVICE_VIDEO_CAPTURE; default: NOTREACHED(); return MEDIA_NO_SERVICE; } } // static PP_DeviceType_Dev PepperMediaDeviceManager::FromMediaStreamType( MediaStreamType type) { switch (type) { case MEDIA_NO_SERVICE: return PP_DEVICETYPE_DEV_INVALID; case MEDIA_DEVICE_AUDIO_CAPTURE: return PP_DEVICETYPE_DEV_AUDIOCAPTURE; case MEDIA_DEVICE_VIDEO_CAPTURE: return PP_DEVICETYPE_DEV_VIDEOCAPTURE; default: NOTREACHED(); return PP_DEVICETYPE_DEV_INVALID; } } void PepperMediaDeviceManager::NotifyDeviceOpened(int request_id, bool succeeded, const std::string& label) { OpenCallbackMap::iterator iter = open_callbacks_.find(request_id); if (iter == open_callbacks_.end()) { // The callback may have been unregistered. return; } OpenDeviceCallback callback = iter->second; open_callbacks_.erase(iter); callback.Run(request_id, succeeded, label); } MediaStreamDispatcher* PepperMediaDeviceManager::GetMediaStreamDispatcher() const { DCHECK(render_frame()); MediaStreamDispatcher* const dispatcher = static_cast(render_frame())->GetMediaStreamDispatcher(); DCHECK(dispatcher); return dispatcher; } } // namespace content