blob: abe68a24c666b6d28e4e300d7700fff40c593205 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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_impl.h"
6
7#include <utility>
8
9#include "base/logging.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010010#include "base/strings/string_number_conversions.h"
11#include "base/strings/stringprintf.h"
12#include "base/strings/utf_string_conversions.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010013#include "content/renderer/media/media_stream_audio_renderer.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000014#include "content/renderer/media/media_stream_dependency_factory.h"
15#include "content/renderer/media/media_stream_dispatcher.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000016#include "content/renderer/media/media_stream_extra_data.h"
17#include "content/renderer/media/media_stream_source_extra_data.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018#include "content/renderer/media/rtc_video_renderer.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000019#include "content/renderer/media/webrtc_audio_capturer.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000020#include "content/renderer/media/webrtc_audio_renderer.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000021#include "content/renderer/media/webrtc_local_audio_renderer.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000022#include "content/renderer/media/webrtc_uma_histograms.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010023#include "third_party/WebKit/public/platform/WebMediaConstraints.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/WebVector.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010027#include "third_party/WebKit/public/web/WebDocument.h"
28#include "third_party/WebKit/public/web/WebFrame.h"
29#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000030
31namespace content {
32namespace {
33
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010034std::string GetStreamConstraint(
35 const WebKit::WebMediaConstraints& constraints, const std::string& key,
36 bool is_mandatory) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000037 if (constraints.isNull())
38 return std::string();
39
40 WebKit::WebString value;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010041 if (is_mandatory) {
42 constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value);
43 } else {
44 constraints.getOptionalConstraintValue(UTF8ToUTF16(key), value);
45 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000046 return UTF16ToUTF8(value);
47}
48
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000049void UpdateRequestOptions(
Torne (Richard Coles)58218062012-11-14 11:43:16 +000050 const WebKit::WebUserMediaRequest& user_media_request,
51 StreamOptions* options) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000052 if (options->audio_type != content::MEDIA_NO_SERVICE) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010053 std::string audio_stream_source = GetStreamConstraint(
54 user_media_request.audioConstraints(), kMediaStreamSource, true);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000055 if (audio_stream_source == kMediaStreamSourceTab) {
56 options->audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010057 options->audio_device_id = GetStreamConstraint(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000058 user_media_request.audioConstraints(),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010059 kMediaStreamSourceId, true);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010060 } else if (audio_stream_source == kMediaStreamSourceSystem) {
61 options->audio_type = content::MEDIA_SYSTEM_AUDIO_CAPTURE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000062 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000063 }
64
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000065 if (options->video_type != content::MEDIA_NO_SERVICE) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010066 std::string video_stream_source = GetStreamConstraint(
67 user_media_request.videoConstraints(), kMediaStreamSource, true);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000068 if (video_stream_source == kMediaStreamSourceTab) {
69 options->video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010070 options->video_device_id = GetStreamConstraint(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000071 user_media_request.videoConstraints(),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010072 kMediaStreamSourceId, true);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000073 } else if (video_stream_source == kMediaStreamSourceScreen) {
74 options->video_type = content::MEDIA_SCREEN_VIDEO_CAPTURE;
75 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000076 }
77}
78
79static int g_next_request_id = 0;
80
81// Creates a WebKit representation of a stream sources based on
82// |devices| from the MediaStreamDispatcher.
83void CreateWebKitSourceVector(
84 const std::string& label,
85 const StreamDeviceInfoArray& devices,
86 WebKit::WebMediaStreamSource::Type type,
87 WebKit::WebVector<WebKit::WebMediaStreamSource>& webkit_sources) {
88 CHECK_EQ(devices.size(), webkit_sources.size());
89 for (size_t i = 0; i < devices.size(); ++i) {
90 const char* track_type =
91 (type == WebKit::WebMediaStreamSource::TypeAudio) ? "a" : "v";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000092 std::string source_id = base::StringPrintf("%s%s%u", label.c_str(),
93 track_type,
94 static_cast<unsigned int>(i));
Torne (Richard Coles)58218062012-11-14 11:43:16 +000095 webkit_sources[i].initialize(
96 UTF8ToUTF16(source_id),
97 type,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000098 UTF8ToUTF16(devices[i].device.name));
Torne (Richard Coles)58218062012-11-14 11:43:16 +000099 webkit_sources[i].setExtraData(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100100 new content::MediaStreamSourceExtraData(devices[i], webkit_sources[i]));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100101 webkit_sources[i].setDeviceId(UTF8ToUTF16(
102 base::IntToString(devices[i].session_id)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000103 }
104}
105
106webrtc::MediaStreamInterface* GetNativeMediaStream(
Ben Murdochbbcdd452013-07-25 10:06:34 +0100107 const WebKit::WebMediaStream& web_stream) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000108 content::MediaStreamExtraData* extra_data =
Ben Murdochbbcdd452013-07-25 10:06:34 +0100109 static_cast<content::MediaStreamExtraData*>(web_stream.extraData());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000110 if (!extra_data)
111 return NULL;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100112 return extra_data->stream().get();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000113}
114
115} // namespace
116
117MediaStreamImpl::MediaStreamImpl(
118 RenderView* render_view,
119 MediaStreamDispatcher* media_stream_dispatcher,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000120 MediaStreamDependencyFactory* dependency_factory)
121 : RenderViewObserver(render_view),
122 dependency_factory_(dependency_factory),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100123 media_stream_dispatcher_(media_stream_dispatcher) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000124}
125
126MediaStreamImpl::~MediaStreamImpl() {
127}
128
129void MediaStreamImpl::OnLocalMediaStreamStop(
130 const std::string& label) {
131 DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop(" << label << ")";
132
133 UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label);
134 if (user_media_request) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100135 StopLocalAudioTrack(user_media_request->web_stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000136 media_stream_dispatcher_->StopStream(label);
137 DeleteUserMediaRequestInfo(user_media_request);
138 } else {
139 DVLOG(1) << "MediaStreamImpl::OnLocalMediaStreamStop: the stream has "
140 << "already been stopped.";
141 }
142}
143
144void MediaStreamImpl::requestUserMedia(
Ben Murdocheb525c52013-07-10 11:40:50 +0100145 const WebKit::WebUserMediaRequest& user_media_request) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000146 // Save histogram data so we can see how much GetUserMedia is used.
147 // The histogram counts the number of calls to the JS API
148 // webGetUserMedia.
149 UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA);
150 DCHECK(CalledOnValidThread());
151 int request_id = g_next_request_id++;
152 StreamOptions options(MEDIA_NO_SERVICE, MEDIA_NO_SERVICE);
153 WebKit::WebFrame* frame = NULL;
154 GURL security_origin;
155
156 // |user_media_request| can't be mocked. So in order to test at all we check
157 // if it isNull.
158 if (user_media_request.isNull()) {
159 // We are in a test.
Ben Murdocheb525c52013-07-10 11:40:50 +0100160 options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
161 options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000162 } else {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100163 if (user_media_request.audio()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000164 options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100165 options.audio_device_id = GetStreamConstraint(
166 user_media_request.audioConstraints(),
167 kMediaStreamSourceInfoId, false);
168 }
169 if (user_media_request.video()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000170 options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100171 options.video_device_id = GetStreamConstraint(
172 user_media_request.videoConstraints(),
173 kMediaStreamSourceInfoId, false);
174 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000175
176 security_origin = GURL(user_media_request.securityOrigin().toString());
177 // Get the WebFrame that requested a MediaStream.
178 // The frame is needed to tell the MediaStreamDispatcher when a stream goes
179 // out of scope.
180 frame = user_media_request.ownerDocument().frame();
181 DCHECK(frame);
182
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000183 UpdateRequestOptions(user_media_request, &options);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000184 }
185
186 DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ "
187 << "audio=" << (options.audio_type)
188 << ", video=" << (options.video_type) << " ], "
189 << security_origin.spec() << ")";
190
191 user_media_requests_.push_back(
192 new UserMediaRequestInfo(request_id, frame, user_media_request));
193
194 media_stream_dispatcher_->GenerateStream(
195 request_id,
196 AsWeakPtr(),
197 options,
198 security_origin);
199}
200
201void MediaStreamImpl::cancelUserMediaRequest(
202 const WebKit::WebUserMediaRequest& user_media_request) {
203 DCHECK(CalledOnValidThread());
204 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request);
205 if (request) {
206 // We can't abort the stream generation process.
207 // Instead, erase the request. Once the stream is generated we will stop the
208 // stream if the request does not exist.
209 DeleteUserMediaRequestInfo(request);
210 }
211}
212
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000213WebKit::WebMediaStream MediaStreamImpl::GetMediaStream(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000214 const GURL& url) {
215 return WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
216}
217
218bool MediaStreamImpl::IsMediaStream(const GURL& url) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100219 WebKit::WebMediaStream web_stream(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000220 WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
221
Ben Murdochbbcdd452013-07-25 10:06:34 +0100222 if (web_stream.isNull() || !web_stream.extraData())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000223 return false; // This is not a valid stream.
224
Ben Murdochbbcdd452013-07-25 10:06:34 +0100225 webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000226 return (stream &&
227 (!stream->GetVideoTracks().empty() || !stream->GetAudioTracks().empty()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000228}
229
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100230scoped_refptr<VideoFrameProvider>
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000231MediaStreamImpl::GetVideoFrameProvider(
232 const GURL& url,
233 const base::Closure& error_cb,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100234 const VideoFrameProvider::RepaintCB& repaint_cb) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000235 DCHECK(CalledOnValidThread());
Ben Murdochbbcdd452013-07-25 10:06:34 +0100236 WebKit::WebMediaStream web_stream(GetMediaStream(url));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000237
Ben Murdochbbcdd452013-07-25 10:06:34 +0100238 if (web_stream.isNull() || !web_stream.extraData())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000239 return NULL; // This is not a valid stream.
240
241 DVLOG(1) << "MediaStreamImpl::GetVideoFrameProvider stream:"
Ben Murdochbbcdd452013-07-25 10:06:34 +0100242 << UTF16ToUTF8(web_stream.id());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000243
Ben Murdochbbcdd452013-07-25 10:06:34 +0100244 webrtc::MediaStreamInterface* stream = GetNativeMediaStream(web_stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000245 if (stream)
246 return CreateVideoFrameProvider(stream, error_cb, repaint_cb);
247 NOTREACHED();
248 return NULL;
249}
250
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100251scoped_refptr<MediaStreamAudioRenderer>
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000252MediaStreamImpl::GetAudioRenderer(const GURL& url) {
253 DCHECK(CalledOnValidThread());
Ben Murdochbbcdd452013-07-25 10:06:34 +0100254 WebKit::WebMediaStream web_stream(GetMediaStream(url));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000255
Ben Murdochbbcdd452013-07-25 10:06:34 +0100256 if (web_stream.isNull() || !web_stream.extraData())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000257 return NULL; // This is not a valid stream.
258
259 DVLOG(1) << "MediaStreamImpl::GetAudioRenderer stream:"
Ben Murdochbbcdd452013-07-25 10:06:34 +0100260 << UTF16ToUTF8(web_stream.id());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000261
262 MediaStreamExtraData* extra_data =
Ben Murdochbbcdd452013-07-25 10:06:34 +0100263 static_cast<MediaStreamExtraData*>(web_stream.extraData());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000264
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000265 if (extra_data->is_local()) {
266 // Create the local audio renderer if the stream contains audio tracks.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100267 return CreateLocalAudioRenderer(extra_data->stream().get());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000268 }
269
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100270 webrtc::MediaStreamInterface* stream = extra_data->stream().get();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000271 if (!stream || stream->GetAudioTracks().empty())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000272 return NULL;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000273
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000274 // This is a remote media stream.
275 WebRtcAudioDeviceImpl* audio_device =
276 dependency_factory_->GetWebRtcAudioDevice();
277
278 // Share the existing renderer if any, otherwise create a new one.
279 scoped_refptr<WebRtcAudioRenderer> renderer(audio_device->renderer());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100280 if (!renderer.get()) {
281 renderer = CreateRemoteAudioRenderer(extra_data->stream().get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000282
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100283 if (renderer.get() && !audio_device->SetAudioRenderer(renderer.get()))
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000284 renderer = NULL;
285 }
286 return renderer;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000287}
288
289// Callback from MediaStreamDispatcher.
290// The requested stream have been generated by the MediaStreamDispatcher.
291void MediaStreamImpl::OnStreamGenerated(
292 int request_id,
293 const std::string& label,
294 const StreamDeviceInfoArray& audio_array,
295 const StreamDeviceInfoArray& video_array) {
296 DCHECK(CalledOnValidThread());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000297 DVLOG(1) << "MediaStreamImpl::OnStreamGenerated stream:" << label;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000298
299 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
300 if (!request_info) {
301 // This can happen if the request is canceled or the frame reloads while
302 // MediaStreamDispatcher is processing the request.
303 // We need to tell the dispatcher to stop the stream.
304 media_stream_dispatcher_->StopStream(label);
305 DVLOG(1) << "Request ID not found";
306 return;
307 }
308 request_info->generated = true;
309
310 WebKit::WebVector<WebKit::WebMediaStreamSource> audio_source_vector(
311 audio_array.size());
312 CreateWebKitSourceVector(label, audio_array,
313 WebKit::WebMediaStreamSource::TypeAudio,
314 audio_source_vector);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100315 request_info->audio_sources.assign(audio_source_vector);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000316 WebKit::WebVector<WebKit::WebMediaStreamSource> video_source_vector(
317 video_array.size());
318 CreateWebKitSourceVector(label, video_array,
319 WebKit::WebMediaStreamSource::TypeVideo,
320 video_source_vector);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100321 request_info->video_sources.assign(video_source_vector);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000322
323 WebKit::WebUserMediaRequest* request = &(request_info->request);
Ben Murdochbbcdd452013-07-25 10:06:34 +0100324 WebKit::WebString webkit_id = UTF8ToUTF16(label);
325 WebKit::WebMediaStream* web_stream = &(request_info->web_stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000326
Ben Murdochbbcdd452013-07-25 10:06:34 +0100327 WebKit::WebVector<WebKit::WebMediaStreamTrack> audio_track_vector(
328 audio_array.size());
329 for (size_t i = 0; i < audio_track_vector.size(); ++i) {
330 audio_track_vector[i].initialize(audio_source_vector[i].id(),
331 audio_source_vector[i]);
332 }
333
334 WebKit::WebVector<WebKit::WebMediaStreamTrack> video_track_vector(
335 video_array.size());
336 for (size_t i = 0; i < video_track_vector.size(); ++i) {
337 video_track_vector[i].initialize(video_source_vector[i].id(),
338 video_source_vector[i]);
339 }
340
341 web_stream->initialize(webkit_id, audio_track_vector,
342 video_track_vector);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000343
344 // WebUserMediaRequest don't have an implementation in unit tests.
345 // Therefore we need to check for isNull here.
346 WebKit::WebMediaConstraints audio_constraints = request->isNull() ?
347 WebKit::WebMediaConstraints() : request->audioConstraints();
348 WebKit::WebMediaConstraints video_constraints = request->isNull() ?
349 WebKit::WebMediaConstraints() : request->videoConstraints();
350
351 dependency_factory_->CreateNativeMediaSources(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100352 RenderViewObserver::routing_id(),
Ben Murdochbbcdd452013-07-25 10:06:34 +0100353 audio_constraints, video_constraints, web_stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000354 base::Bind(&MediaStreamImpl::OnCreateNativeSourcesComplete, AsWeakPtr()));
355}
356
357// Callback from MediaStreamDispatcher.
358// The requested stream failed to be generated.
359void MediaStreamImpl::OnStreamGenerationFailed(int request_id) {
360 DCHECK(CalledOnValidThread());
361 DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed("
362 << request_id << ")";
363 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(request_id);
364 if (!request_info) {
365 // This can happen if the request is canceled or the frame reloads while
366 // MediaStreamDispatcher is processing the request.
367 DVLOG(1) << "Request ID not found";
368 return;
369 }
Ben Murdochbbcdd452013-07-25 10:06:34 +0100370 CompleteGetUserMediaRequest(request_info->web_stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000371 &request_info->request,
372 false);
373 DeleteUserMediaRequestInfo(request_info);
374}
375
Ben Murdochbbcdd452013-07-25 10:06:34 +0100376// Callback from MediaStreamDependencyFactory when the sources in |web_stream|
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000377// have been generated.
378void MediaStreamImpl::OnCreateNativeSourcesComplete(
Ben Murdochbbcdd452013-07-25 10:06:34 +0100379 WebKit::WebMediaStream* web_stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000380 bool request_succeeded) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100381 UserMediaRequestInfo* request_info = FindUserMediaRequestInfo(web_stream);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000382 if (!request_info) {
383 // This can happen if the request is canceled or the frame reloads while
384 // MediaStreamDependencyFactory is creating the sources.
385 DVLOG(1) << "Request ID not found";
386 return;
387 }
388
389 // Create a native representation of the stream.
390 if (request_succeeded) {
391 dependency_factory_->CreateNativeLocalMediaStream(
Ben Murdochbbcdd452013-07-25 10:06:34 +0100392 web_stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000393 base::Bind(&MediaStreamImpl::OnLocalMediaStreamStop, AsWeakPtr()));
394 }
Ben Murdochbbcdd452013-07-25 10:06:34 +0100395 CompleteGetUserMediaRequest(request_info->web_stream, &request_info->request,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000396 request_succeeded);
397 if (!request_succeeded) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100398 OnLocalMediaStreamStop(UTF16ToUTF8(web_stream->id()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000399 }
400}
401
402void MediaStreamImpl::OnDevicesEnumerated(
403 int request_id,
404 const StreamDeviceInfoArray& device_array) {
405 DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerated("
406 << request_id << ")";
407 NOTIMPLEMENTED();
408}
409
410void MediaStreamImpl::OnDevicesEnumerationFailed(int request_id) {
411 DVLOG(1) << "MediaStreamImpl::OnDevicesEnumerationFailed("
412 << request_id << ")";
413 NOTIMPLEMENTED();
414}
415
416void MediaStreamImpl::OnDeviceOpened(
417 int request_id,
418 const std::string& label,
419 const StreamDeviceInfo& video_device) {
420 DVLOG(1) << "MediaStreamImpl::OnDeviceOpened("
421 << request_id << ", " << label << ")";
422 NOTIMPLEMENTED();
423}
424
425void MediaStreamImpl::OnDeviceOpenFailed(int request_id) {
426 DVLOG(1) << "MediaStreamImpl::VideoDeviceOpenFailed("
427 << request_id << ")";
428 NOTIMPLEMENTED();
429}
430
431void MediaStreamImpl::CompleteGetUserMediaRequest(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000432 const WebKit::WebMediaStream& stream,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000433 WebKit::WebUserMediaRequest* request_info,
434 bool request_succeeded) {
435 if (request_succeeded) {
436 request_info->requestSucceeded(stream);
437 } else {
438 request_info->requestFailed();
439 }
440}
441
442MediaStreamImpl::UserMediaRequestInfo*
443MediaStreamImpl::FindUserMediaRequestInfo(int request_id) {
444 UserMediaRequests::iterator it = user_media_requests_.begin();
445 for (; it != user_media_requests_.end(); ++it) {
446 if ((*it)->request_id == request_id)
447 return (*it);
448 }
449 return NULL;
450}
451
452MediaStreamImpl::UserMediaRequestInfo*
453MediaStreamImpl::FindUserMediaRequestInfo(
454 const WebKit::WebUserMediaRequest& request) {
455 UserMediaRequests::iterator it = user_media_requests_.begin();
456 for (; it != user_media_requests_.end(); ++it) {
457 if ((*it)->request == request)
458 return (*it);
459 }
460 return NULL;
461}
462
463MediaStreamImpl::UserMediaRequestInfo*
464MediaStreamImpl::FindUserMediaRequestInfo(const std::string& label) {
465 UserMediaRequests::iterator it = user_media_requests_.begin();
466 for (; it != user_media_requests_.end(); ++it) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100467 if ((*it)->generated && (*it)->web_stream.id() == UTF8ToUTF16(label))
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000468 return (*it);
469 }
470 return NULL;
471}
472
473MediaStreamImpl::UserMediaRequestInfo*
474MediaStreamImpl::FindUserMediaRequestInfo(
Ben Murdochbbcdd452013-07-25 10:06:34 +0100475 WebKit::WebMediaStream* web_stream) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000476 UserMediaRequests::iterator it = user_media_requests_.begin();
477 for (; it != user_media_requests_.end(); ++it) {
Ben Murdochbbcdd452013-07-25 10:06:34 +0100478 if (&((*it)->web_stream) == web_stream)
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000479 return (*it);
480 }
481 return NULL;
482}
483
484void MediaStreamImpl::DeleteUserMediaRequestInfo(
485 UserMediaRequestInfo* request) {
486 UserMediaRequests::iterator it = user_media_requests_.begin();
487 for (; it != user_media_requests_.end(); ++it) {
488 if ((*it) == request) {
489 user_media_requests_.erase(it);
490 return;
491 }
492 }
493 NOTREACHED();
494}
495
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100496void MediaStreamImpl::FrameDetached(WebKit::WebFrame* frame) {
497 // Do same thing as FrameWillClose.
498 FrameWillClose(frame);
499}
500
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000501void MediaStreamImpl::FrameWillClose(WebKit::WebFrame* frame) {
502 // Loop through all UserMediaRequests and find the requests that belong to the
503 // frame that is being closed.
504 UserMediaRequests::iterator request_it = user_media_requests_.begin();
505
506 while (request_it != user_media_requests_.end()) {
507 if ((*request_it)->frame == frame) {
508 DVLOG(1) << "MediaStreamImpl::FrameWillClose: "
509 << "Cancel user media request " << (*request_it)->request_id;
510 // If the request is generated, it means that the MediaStreamDispatcher
511 // has generated a stream for us and we need to let the
512 // MediaStreamDispatcher know that the stream is no longer wanted.
513 // If not, we cancel the request and delete the request object.
514 if ((*request_it)->generated) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000515 // Stop the local audio track before closing the device in the browser.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100516 StopLocalAudioTrack((*request_it)->web_stream);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000517
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000518 media_stream_dispatcher_->StopStream(
Ben Murdochbbcdd452013-07-25 10:06:34 +0100519 UTF16ToUTF8((*request_it)->web_stream.id()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000520 } else {
521 media_stream_dispatcher_->CancelGenerateStream(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100522 (*request_it)->request_id, AsWeakPtr());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000523 }
524 request_it = user_media_requests_.erase(request_it);
525 } else {
526 ++request_it;
527 }
528 }
529}
530
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100531scoped_refptr<VideoFrameProvider>
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000532MediaStreamImpl::CreateVideoFrameProvider(
533 webrtc::MediaStreamInterface* stream,
534 const base::Closure& error_cb,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100535 const VideoFrameProvider::RepaintCB& repaint_cb) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000536 if (stream->GetVideoTracks().empty())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000537 return NULL;
538
539 DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoFrameProvider label:"
540 << stream->label();
541
542 return new RTCVideoRenderer(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000543 stream->GetVideoTracks()[0],
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000544 error_cb,
545 repaint_cb);
546}
547
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000548scoped_refptr<WebRtcAudioRenderer> MediaStreamImpl::CreateRemoteAudioRenderer(
549 webrtc::MediaStreamInterface* stream) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000550 if (stream->GetAudioTracks().empty())
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000551 return NULL;
552
553 DVLOG(1) << "MediaStreamImpl::CreateRemoteAudioRenderer label:"
554 << stream->label();
555
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000556 return new WebRtcAudioRenderer(RenderViewObserver::routing_id());
557}
558
559scoped_refptr<WebRtcLocalAudioRenderer>
560MediaStreamImpl::CreateLocalAudioRenderer(
561 webrtc::MediaStreamInterface* stream) {
562 if (stream->GetAudioTracks().empty())
563 return NULL;
564
565 DVLOG(1) << "MediaStreamImpl::CreateLocalAudioRenderer label:"
566 << stream->label();
567
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000568 webrtc::AudioTrackVector audio_tracks = stream->GetAudioTracks();
569 DCHECK_EQ(audio_tracks.size(), 1u);
570 webrtc::AudioTrackInterface* audio_track = audio_tracks[0];
571 DVLOG(1) << "audio_track.kind : " << audio_track->kind()
572 << "audio_track.id : " << audio_track->id()
573 << "audio_track.enabled: " << audio_track->enabled();
574
575 // Create a new WebRtcLocalAudioRenderer instance and connect it to the
576 // existing WebRtcAudioCapturer so that the renderer can use it as source.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100577 return new WebRtcLocalAudioRenderer(
578 static_cast<WebRtcLocalAudioTrack*>(audio_track),
579 RenderViewObserver::routing_id());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000580}
581
Ben Murdochbb1529c2013-08-08 10:24:53 +0100582void MediaStreamImpl::StopLocalAudioTrack(
583 const WebKit::WebMediaStream& web_stream) {
584 MediaStreamExtraData* extra_data = static_cast<MediaStreamExtraData*>(
585 web_stream.extraData());
586 if (extra_data && extra_data->is_local() && extra_data->stream().get() &&
587 !extra_data->stream()->GetAudioTracks().empty()) {
588 webrtc::AudioTrackVector audio_tracks =
589 extra_data->stream()->GetAudioTracks();
590 for (size_t i = 0; i < audio_tracks.size(); ++i) {
591 WebRtcLocalAudioTrack* audio_track = static_cast<WebRtcLocalAudioTrack*>(
592 audio_tracks[i].get());
593 // Remove the WebRtcAudioDevice as the sink to the local audio track.
594 audio_track->RemoveSink(dependency_factory_->GetWebRtcAudioDevice());
595 // Stop the audio track. This will unhook the audio track from the
596 // capturer and will shutdown the source of the capturer if it is the
597 // last audio track connecting to the capturer.
598 audio_track->Stop();
599 }
600 }
601}
602
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000603MediaStreamSourceExtraData::MediaStreamSourceExtraData(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100604 const StreamDeviceInfo& device_info,
605 const WebKit::WebMediaStreamSource& webkit_source)
606 : device_info_(device_info),
607 webkit_source_(webkit_source) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000608}
609
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000610MediaStreamSourceExtraData::MediaStreamSourceExtraData(
611 media::AudioCapturerSource* source)
612 : audio_source_(source) {
613}
614
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000615MediaStreamSourceExtraData::~MediaStreamSourceExtraData() {}
616
617MediaStreamExtraData::MediaStreamExtraData(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000618 webrtc::MediaStreamInterface* stream, bool is_local)
619 : stream_(stream),
620 is_local_(is_local) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000621}
622
623MediaStreamExtraData::~MediaStreamExtraData() {
624}
625
626void MediaStreamExtraData::SetLocalStreamStopCallback(
627 const StreamStopCallback& stop_callback) {
628 stream_stop_callback_ = stop_callback;
629}
630
631void MediaStreamExtraData::OnLocalStreamStop() {
632 if (!stream_stop_callback_.is_null())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000633 stream_stop_callback_.Run(stream_->label());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000634}
635
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100636MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo()
637 : request_id(0), generated(false), frame(NULL), request() {
638}
639
640MediaStreamImpl::UserMediaRequestInfo::UserMediaRequestInfo(
641 int request_id,
642 WebKit::WebFrame* frame,
643 const WebKit::WebUserMediaRequest& request)
644 : request_id(request_id), generated(false), frame(frame),
645 request(request) {
646}
647
648MediaStreamImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
649 // Release the extra data field of all sources created by
650 // MediaStreamImpl for this request. This breaks the circular reference to
651 // WebKit::MediaStreamSource.
652 // TODO(tommyw): Remove this once WebKit::MediaStreamSource::Owner has been
653 // implemented to fully avoid a circular dependency.
654 for (size_t i = 0; i < audio_sources.size(); ++i) {
655 audio_sources[i].setReadyState(
656 WebKit::WebMediaStreamSource::ReadyStateEnded);
657 audio_sources[i].setExtraData(NULL);
658 }
659
660 for (size_t i = 0; i < video_sources.size(); ++i) {
661 video_sources[i].setReadyState(
662 WebKit::WebMediaStreamSource::ReadyStateEnded);
663 video_sources[i].setExtraData(NULL);
664 }
665}
666
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000667} // namespace content