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/media/media_stream_center.h" 6 7 #include <string> 8 9 #include "base/command_line.h" 10 #include "base/logging.h" 11 #include "content/common/media/media_stream_messages.h" 12 #include "content/public/common/content_switches.h" 13 #include "content/public/renderer/media_stream_audio_sink.h" 14 #include "content/public/renderer/render_thread.h" 15 #include "content/renderer/media/media_stream.h" 16 #include "content/renderer/media/media_stream_source.h" 17 #include "content/renderer/media/media_stream_video_source.h" 18 #include "content/renderer/media/media_stream_video_track.h" 19 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" 20 #include "content/renderer/media/webrtc_local_audio_source_provider.h" 21 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 22 #include "third_party/WebKit/public/platform/WebMediaStream.h" 23 #include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h" 24 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 25 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 26 #include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h" 27 #include "third_party/WebKit/public/platform/WebSourceInfo.h" 28 #include "third_party/WebKit/public/platform/WebVector.h" 29 #include "third_party/WebKit/public/web/WebFrame.h" 30 31 using blink::WebFrame; 32 using blink::WebView; 33 34 namespace content { 35 36 namespace { 37 38 void CreateNativeAudioMediaStreamTrack( 39 const blink::WebMediaStreamTrack& track, 40 PeerConnectionDependencyFactory* factory) { 41 DCHECK(!track.extraData()); 42 blink::WebMediaStreamSource source = track.source(); 43 DCHECK_EQ(source.type(), blink::WebMediaStreamSource::TypeAudio); 44 factory->CreateLocalAudioTrack(track); 45 } 46 47 void CreateNativeVideoMediaStreamTrack( 48 const blink::WebMediaStreamTrack& track) { 49 DCHECK(track.extraData() == NULL); 50 blink::WebMediaStreamSource source = track.source(); 51 DCHECK_EQ(source.type(), blink::WebMediaStreamSource::TypeVideo); 52 MediaStreamVideoSource* native_source = 53 MediaStreamVideoSource::GetVideoSource(source); 54 DCHECK(native_source); 55 blink::WebMediaStreamTrack writable_track(track); 56 // TODO(perkj): The constraints to use here should be passed from blink when 57 // a new track is created. For cloning, it should be the constraints of the 58 // cloned track and not the originating source. 59 // Also - source.constraints() returns an uninitialized constraint if the 60 // source is coming from a remote video track. See http://crbug/287805. 61 blink::WebMediaConstraints constraints = source.constraints(); 62 if (constraints.isNull()) 63 constraints.initialize(); 64 writable_track.setExtraData( 65 new MediaStreamVideoTrack(native_source, constraints, 66 MediaStreamVideoSource::ConstraintsCallback(), 67 track.isEnabled())); 68 } 69 70 void CreateNativeMediaStreamTrack(const blink::WebMediaStreamTrack& track, 71 PeerConnectionDependencyFactory* factory) { 72 DCHECK(!track.isNull() && !track.extraData()); 73 DCHECK(!track.source().isNull()); 74 75 switch (track.source().type()) { 76 case blink::WebMediaStreamSource::TypeAudio: 77 CreateNativeAudioMediaStreamTrack(track, factory); 78 break; 79 case blink::WebMediaStreamSource::TypeVideo: 80 CreateNativeVideoMediaStreamTrack(track); 81 break; 82 } 83 } 84 85 } // namespace 86 87 MediaStreamCenter::MediaStreamCenter(blink::WebMediaStreamCenterClient* client, 88 PeerConnectionDependencyFactory* factory) 89 : rtc_factory_(factory), next_request_id_(0) {} 90 91 MediaStreamCenter::~MediaStreamCenter() {} 92 93 bool MediaStreamCenter::getMediaStreamTrackSources( 94 const blink::WebMediaStreamTrackSourcesRequest& request) { 95 if (!CommandLine::ForCurrentProcess()->HasSwitch( 96 switches::kDisableDeviceEnumeration)) { 97 int request_id = next_request_id_++; 98 requests_.insert(std::make_pair(request_id, request)); 99 RenderThread::Get()->Send(new MediaStreamHostMsg_GetSources( 100 request_id, GURL(request.origin().utf8()))); 101 return true; 102 } 103 return false; 104 } 105 106 void MediaStreamCenter::didCreateMediaStreamTrack( 107 const blink::WebMediaStreamTrack& track) { 108 DVLOG(1) << "MediaStreamCenter::didCreateMediaStreamTrack"; 109 CreateNativeMediaStreamTrack(track, rtc_factory_); 110 } 111 112 void MediaStreamCenter::didEnableMediaStreamTrack( 113 const blink::WebMediaStreamTrack& track) { 114 MediaStreamTrack* native_track = 115 MediaStreamTrack::GetTrack(track); 116 if (native_track) 117 native_track->SetEnabled(true); 118 } 119 120 void MediaStreamCenter::didDisableMediaStreamTrack( 121 const blink::WebMediaStreamTrack& track) { 122 MediaStreamTrack* native_track = 123 MediaStreamTrack::GetTrack(track); 124 if (native_track) 125 native_track->SetEnabled(false); 126 } 127 128 bool MediaStreamCenter::didStopMediaStreamTrack( 129 const blink::WebMediaStreamTrack& track) { 130 DVLOG(1) << "MediaStreamCenter::didStopMediaStreamTrack"; 131 MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track); 132 native_track->Stop(); 133 return true; 134 } 135 136 blink::WebAudioSourceProvider* 137 MediaStreamCenter::createWebAudioSourceFromMediaStreamTrack( 138 const blink::WebMediaStreamTrack& track) { 139 DVLOG(1) << "MediaStreamCenter::createWebAudioSourceFromMediaStreamTrack"; 140 MediaStreamTrack* media_stream_track = 141 static_cast<MediaStreamTrack*>(track.extraData()); 142 // Only local audio track is supported now. 143 // TODO(xians): Support remote audio track. 144 if (!media_stream_track || !media_stream_track->is_local_track()) { 145 NOTIMPLEMENTED(); 146 return NULL; 147 } 148 149 blink::WebMediaStreamSource source = track.source(); 150 DCHECK_EQ(source.type(), blink::WebMediaStreamSource::TypeAudio); 151 WebRtcLocalAudioSourceProvider* source_provider = 152 new WebRtcLocalAudioSourceProvider(track); 153 return source_provider; 154 } 155 156 void MediaStreamCenter::didStopLocalMediaStream( 157 const blink::WebMediaStream& stream) { 158 DVLOG(1) << "MediaStreamCenter::didStopLocalMediaStream"; 159 MediaStream* native_stream = MediaStream::GetMediaStream(stream); 160 if (!native_stream) { 161 NOTREACHED(); 162 return; 163 } 164 165 // TODO(perkj): MediaStream::Stop is being deprecated. But for the moment we 166 // need to support both MediaStream::Stop and MediaStreamTrack::Stop. 167 blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; 168 stream.audioTracks(audio_tracks); 169 for (size_t i = 0; i < audio_tracks.size(); ++i) 170 didStopMediaStreamTrack(audio_tracks[i]); 171 172 blink::WebVector<blink::WebMediaStreamTrack> video_tracks; 173 stream.videoTracks(video_tracks); 174 for (size_t i = 0; i < video_tracks.size(); ++i) 175 didStopMediaStreamTrack(video_tracks[i]); 176 } 177 178 void MediaStreamCenter::didCreateMediaStream(blink::WebMediaStream& stream) { 179 DVLOG(1) << "MediaStreamCenter::didCreateMediaStream"; 180 blink::WebMediaStream writable_stream(stream); 181 MediaStream* native_stream( 182 new MediaStream(stream)); 183 writable_stream.setExtraData(native_stream); 184 185 blink::WebVector<blink::WebMediaStreamTrack> video_tracks; 186 stream.videoTracks(video_tracks); 187 for (size_t i = 0; i < video_tracks.size(); ++i) { 188 if (!MediaStreamTrack::GetTrack(video_tracks[i])) 189 CreateNativeMediaStreamTrack(video_tracks[i], rtc_factory_); 190 } 191 } 192 193 bool MediaStreamCenter::didAddMediaStreamTrack( 194 const blink::WebMediaStream& stream, 195 const blink::WebMediaStreamTrack& track) { 196 DVLOG(1) << "MediaStreamCenter::didAddMediaStreamTrack"; 197 MediaStream* native_stream = MediaStream::GetMediaStream(stream); 198 return native_stream->AddTrack(track); 199 } 200 201 bool MediaStreamCenter::didRemoveMediaStreamTrack( 202 const blink::WebMediaStream& stream, 203 const blink::WebMediaStreamTrack& track) { 204 DVLOG(1) << "MediaStreamCenter::didRemoveMediaStreamTrack"; 205 MediaStream* native_stream = MediaStream::GetMediaStream(stream); 206 return native_stream->RemoveTrack(track); 207 } 208 209 bool MediaStreamCenter::OnControlMessageReceived(const IPC::Message& message) { 210 bool handled = true; 211 IPC_BEGIN_MESSAGE_MAP(MediaStreamCenter, message) 212 IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK, 213 OnGetSourcesComplete) 214 IPC_MESSAGE_UNHANDLED(handled = false) 215 IPC_END_MESSAGE_MAP() 216 return handled; 217 } 218 219 void MediaStreamCenter::OnGetSourcesComplete( 220 int request_id, 221 const content::StreamDeviceInfoArray& devices) { 222 RequestMap::iterator request_it = requests_.find(request_id); 223 DCHECK(request_it != requests_.end()); 224 225 blink::WebVector<blink::WebSourceInfo> sourceInfos(devices.size()); 226 for (size_t i = 0; i < devices.size(); ++i) { 227 const MediaStreamDevice& device = devices[i].device; 228 DCHECK(device.type == MEDIA_DEVICE_AUDIO_CAPTURE || 229 device.type == MEDIA_DEVICE_VIDEO_CAPTURE); 230 blink::WebSourceInfo::VideoFacingMode video_facing; 231 switch (device.video_facing) { 232 case MEDIA_VIDEO_FACING_USER: 233 video_facing = blink::WebSourceInfo::VideoFacingModeUser; 234 break; 235 case MEDIA_VIDEO_FACING_ENVIRONMENT: 236 video_facing = blink::WebSourceInfo::VideoFacingModeEnvironment; 237 break; 238 default: 239 video_facing = blink::WebSourceInfo::VideoFacingModeNone; 240 } 241 242 sourceInfos[i] 243 .initialize(blink::WebString::fromUTF8(device.id), 244 device.type == MEDIA_DEVICE_AUDIO_CAPTURE 245 ? blink::WebSourceInfo::SourceKindAudio 246 : blink::WebSourceInfo::SourceKindVideo, 247 blink::WebString::fromUTF8(device.name), 248 video_facing); 249 } 250 request_it->second.requestSucceeded(sourceInfos); 251 } 252 253 } // namespace content 254