Index: content/renderer/media/media_stream_impl.cc |
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc |
index 52e9ec2eaaed9f442477afabad0ce93110abc9d5..246a32057fd32329a628cd24e18ff46a7734a7f7 100644 |
--- a/content/renderer/media/media_stream_impl.cc |
+++ b/content/renderer/media/media_stream_impl.cc |
@@ -4,12 +4,40 @@ |
#include "content/renderer/media/media_stream_impl.h" |
-#include "base/string_util.h" |
+#include <vector> |
+ |
+#include "base/logging.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "base/utf_string_conversions.h" |
+#include "content/common/media/media_stream_options.h" |
#include "content/renderer/media/capture_video_decoder.h" |
+#include "content/renderer/media/media_stream_dependency_factory.h" |
+#include "content/renderer/media/media_stream_dispatcher.h" |
+#include "content/renderer/media/rtc_video_decoder.h" |
#include "content/renderer/media/video_capture_impl_manager.h" |
-#include "googleurl/src/gurl.h" |
+#include "content/renderer/media/video_capture_module_impl.h" |
+#include "content/renderer/media/webrtc_audio_device_impl.h" |
+#include "content/renderer/p2p/ipc_network_manager.h" |
+#include "content/renderer/p2p/ipc_socket_factory.h" |
+#include "content/renderer/p2p/socket_dispatcher.h" |
+#include "jingle/glue/thread_wrapper.h" |
#include "media/base/message_loop_factory.h" |
-#include "media/base/pipeline.h" |
+#include "third_party/libjingle/source/talk/p2p/client/httpportallocator.h" |
+#include "third_party/libjingle/source/talk/session/phone/dummydevicemanager.h" |
+#include "third_party/libjingle/source/talk/session/phone/webrtcmediaengine.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebLocalMediaStream.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStream.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamController.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistry.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamTrack.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamTrackList.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" |
+ |
+// TODO(grunell): Replace NewRunnableMethod with base::Bind throughout this |
+// class. |
namespace { |
@@ -17,24 +45,300 @@ static const int kVideoCaptureWidth = 352; |
static const int kVideoCaptureHeight = 288; |
static const int kVideoCaptureFramePerSecond = 30; |
-static const int kStartOpenSessionId = 1; |
+} // namespace |
-// TODO(wjia): remove this string when full media stream code is checked in. |
-static const char kRawMediaScheme[] = "mediastream"; |
+MediaStreamImpl::MediaStreamImpl( |
+ MediaStreamDispatcher* media_stream_dispatcher, |
+ content::P2PSocketDispatcher* p2p_socket_dispatcher, |
+ VideoCaptureImplManager* vc_manager, |
+ MediaStreamDependencyFactory* dependency_factory) |
+ : dependency_factory_(dependency_factory), |
+ media_stream_dispatcher_(media_stream_dispatcher), |
+ media_engine_(NULL), |
+ p2p_socket_dispatcher_(p2p_socket_dispatcher), |
+ vc_manager_(vc_manager), |
+ signaling_thread_(NULL), |
+ worker_thread_(NULL), |
+ chrome_worker_thread_("Chrome_libJingle_WorkerThread"), |
+ call_state_(NOT_STARTED), |
+ vcm_created_(false) { |
+ message_loop_proxy_ = base::MessageLoopProxy::current(); |
+} |
-} // namespace |
+MediaStreamImpl::~MediaStreamImpl() { |
+ if (native_peer_connection_.get()) { |
+ native_peer_connection_->RegisterObserver(NULL); |
+ native_peer_connection_->Close(); |
+ } |
+ dependency_factory_->DeletePeerConnectionFactory(); |
+} |
+ |
+void MediaStreamImpl::setController( |
+ WebKit::WebMediaStreamController* controller) { |
+ controller_.reset(controller); |
+} |
+ |
+void MediaStreamImpl::shutdown() { |
+ controller_.reset(); |
+} |
+ |
+void MediaStreamImpl::generateStream( |
+ int request_id, |
+ WebKit::WebGenerateStreamOptionFlags flags, |
+ const WebKit::WebSecurityOrigin& web_security_origin) { |
+ bool audio = (flags & WebKit::WebGenerateStreamRequestAudio) != 0; |
+ media_stream::StreamOptions::VideoOption video_option = |
+ media_stream::StreamOptions::kNoCamera; |
+ if ((flags & WebKit::WebGenerateStreamRequestVideoFacingUser) && |
+ (flags & WebKit::WebGenerateStreamRequestVideoFacingEnvironment)) { |
+ video_option = media_stream::StreamOptions::kFacingBoth; |
+ } else { |
+ if (flags & WebKit::WebGenerateStreamRequestVideoFacingEnvironment) |
+ video_option = media_stream::StreamOptions::kFacingEnvironment; |
+ if (flags & WebKit::WebGenerateStreamRequestVideoFacingUser) |
+ video_option = media_stream::StreamOptions::kFacingUser; |
+ } |
+ DLOG(INFO) << "MediaStreamImpl::generateStream(" |
+ << request_id << ", [ " |
+ << (audio ? "audio " : "") |
+ << ((flags & WebKit::WebGenerateStreamRequestVideoFacingUser) ? |
+ "video_facing_user " : "") |
+ << ((flags & |
+ WebKit::WebGenerateStreamRequestVideoFacingEnvironment) ? |
+ "video_facing_environment " : "") |
+ << "], " |
+ << static_cast<string16>(web_security_origin.toString()) << ")"; |
+ |
+ media_stream_dispatcher_->GenerateStream(request_id, this, |
+ media_stream::StreamOptions(audio, video_option), |
+ UTF16ToUTF8(web_security_origin.toString())); |
+} |
+ |
+void MediaStreamImpl::stopGeneratedStream( |
+ const WebKit::WebLocalMediaStream& stream) { |
+ std::string label = UTF16ToUTF8(stream.label()); |
+ media_stream_dispatcher_->StopStream(label); |
+} |
+ |
+void MediaStreamImpl::recordStream( |
+ const WebKit::WebMediaStreamRecorder& recorder) { |
+ // TODO(grunell): Implement. |
+} |
+ |
+void MediaStreamImpl::getRecordedData( |
+ const WebKit::WebMediaStreamRecorder& recorder, |
+ int request_id) { |
+ // TODO(grunell): Implement. |
+} |
+ |
+void MediaStreamImpl::disposeRecordedData( |
+ const WebKit::WebMediaStreamRecorder& recorder) { |
+ // TODO(grunell): Implement. |
+} |
+ |
+void MediaStreamImpl::setMediaStreamTrackEnabled( |
+ const WebKit::WebMediaStreamTrack& track) { |
+ // TODO(grunell): Implement. |
+} |
+ |
+void MediaStreamImpl::processSignalingMessage( |
+ const WebKit::WebPeerConnection& web_peer_connection, |
+ const WebKit::WebString& message) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ DCHECK(native_peer_connection_.get()); |
+ native_peer_connection_->SignalingMessage(UTF16ToUTF8(message)); |
+} |
+ |
+void MediaStreamImpl::message( |
+ const WebKit::WebPeerConnection& web_peer_connection, |
+ const WebKit::WebString& message) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
tommi (sloooow) - chröme
2011/10/25 09:58:34
NOTREACHED() instead of DLOG(ERROR)?
(same for oth
Henrik Grunell
2011/10/25 12:14:32
Agree, changed.
|
+ return; |
+ } |
+ // TODO(grunell): Implement. |
+} |
-MediaStreamImpl::MediaStreamImpl(VideoCaptureImplManager* vc_manager) |
- : vc_manager_(vc_manager) { |
+void MediaStreamImpl::addStream( |
+ const WebKit::WebPeerConnection& web_peer_connection, |
+ const WebKit::WebMediaStream& stream) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ // TODO(grunell): Fix code in this function after a new native PeerConnection |
+ // version has been rolled out. |
+ std::string label = UTF16ToUTF8(stream.label()); |
+ if (call_state_ == NOT_STARTED) { |
+ DCHECK(native_peer_connection_.get()); |
+ // TODO(grunell): Add audio and/or video depending on what's enabled |
+ // in the stream. |
+ std::string audioLabel = label; |
+ audioLabel.append("-audio"); |
+ native_peer_connection_->AddStream(audioLabel, false); // Audio |
+ native_peer_connection_->AddStream(label, true); // Video |
+ call_state_ = INITIATING; |
+ } |
+ if (call_state_ == INITIATING || call_state_ == RECEIVING) { |
+ local_label_ = label; |
+ if (!vcm_created_) { |
+ // Set the capture device |
+ // TODO(grunell): Instead of using the first track, the selected track |
+ // should be used. |
+ int id = media_stream_dispatcher_->video_session_id(local_label_, 0); |
+ if (id != media_stream::StreamDeviceInfo::kNoId) { |
+ webrtc::VideoCaptureModule* vcm = |
+ new VideoCaptureModuleImpl(id, vc_manager_.get()); |
+ vcm_created_ = true; |
+ media_engine_->SetVideoCaptureModule(vcm); |
+ native_peer_connection_->SetVideoCapture(""); |
+ } |
+ } |
+ if (call_state_ == INITIATING) |
+ native_peer_connection_->Connect(); |
+ else if (call_state_ == RECEIVING) |
+ call_state_ = SENDING_AND_RECEIVING; |
+ } else { |
+ DLOG(ERROR) << __FUNCTION__ << ": Multiple calls not supported"; |
+ return; |
tommi (sloooow) - chröme
2011/10/25 09:58:34
no need for this return
Henrik Grunell
2011/10/25 12:14:32
Done.
|
+ } |
} |
-MediaStreamImpl::~MediaStreamImpl() {} |
+void MediaStreamImpl::newPeerConnection( |
+ const WebKit::WebPeerConnection& web_peer_connection, |
+ const WebKit::WebString& configuration) { |
+ if (native_peer_connection_.get()) { |
+ LOG(WARNING) << __FUNCTION__ << ": A PeerConnection already exists"; |
+ return; |
+ } |
+ |
+ if (!media_engine_) { |
+ media_engine_ = dependency_factory_->CreateWebRtcMediaEngine(); |
+ } |
+ |
+ if (!signaling_thread_) { |
+ jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); |
+ jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); |
+ signaling_thread_ = jingle_glue::JingleThreadWrapper::current(); |
+ } |
+ |
+ if (!worker_thread_) { |
+ if (!chrome_worker_thread_.IsRunning()) { |
+ if (!chrome_worker_thread_.Start()) { |
+ LOG(ERROR) << __FUNCTION__ << ": Could not start worker thread"; |
+ return; |
+ } |
+ } |
+ base::WaitableEvent event(true, false); |
+ chrome_worker_thread_.message_loop()->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, |
+ &MediaStreamImpl::InitializeWorkerThread, |
+ &worker_thread_, |
+ &event)); |
+ event.Wait(); |
+ DCHECK(worker_thread_); |
+ } |
+ |
+ if (!dependency_factory_->PeerConnectionFactoryCreated()) { |
+ ipc_network_manager_.reset( |
+ new content::IpcNetworkManager(p2p_socket_dispatcher_)); |
+ ipc_socket_factory_.reset( |
+ new content::IpcPacketSocketFactory(p2p_socket_dispatcher_)); |
+ cricket::HttpPortAllocator* port_allocator = |
+ new cricket::HttpPortAllocator(ipc_network_manager_.get(), |
+ ipc_socket_factory_.get(), |
+ "PeerConnection"); |
+ // TODO(mallinath): The following flags were added to solve a crash in |
+ // HttpClient, we should probably remove them after that issue has been |
+ // investigated. |
+ port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | |
+ cricket::PORTALLOCATOR_DISABLE_RELAY); |
+ |
+ // TODO(mallinath): PeerConnectionFactory constructor changed in latest |
+ // code and it no more accepts config string. Config string must be parsed |
+ // here and set in HttpPortAllocator. Now using standard google STUN server |
+ // address. |
+ std::vector<talk_base::SocketAddress> stun_hosts; |
+ stun_hosts.push_back(talk_base::SocketAddress("stun.l.google.com", 19302)); |
+ port_allocator->SetStunHosts(stun_hosts); |
+ |
+ if (!dependency_factory_->CreatePeerConnectionFactory( |
+ port_allocator, |
+ media_engine_, |
+ worker_thread_)) { |
+ LOG(ERROR) << __FUNCTION__ |
+ << ": Could not initialize PeerConnection factory"; |
+ return; |
tommi (sloooow) - chröme
2011/10/25 09:58:34
no need for this return statement
Henrik Grunell
2011/10/25 12:14:32
Kept, code below should not be executed.
|
+ } |
+ } |
+ |
+ native_peer_connection_.reset(dependency_factory_->CreatePeerConnection( |
+ signaling_thread_)); |
+ DCHECK(native_peer_connection_.get()); |
+ web_peer_connection_ = web_peer_connection; |
+ native_peer_connection_->RegisterObserver(this); |
+} |
+ |
+void MediaStreamImpl::closePeerConnection( |
+ const WebKit::WebPeerConnection& web_peer_connection) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ if (native_peer_connection_.get()) |
tommi (sloooow) - chröme
2011/10/25 09:58:34
did you forget {}?
Henrik Grunell
2011/10/25 12:14:32
No {}. Decreased indent below.
|
+ native_peer_connection_->RegisterObserver(NULL); |
+ native_peer_connection_.reset(); |
+ web_peer_connection_.reset(); |
+ rtc_video_decoder_ = NULL; |
+ media_engine_->SetVideoCaptureModule(NULL); |
+ vcm_created_ = false; |
+ call_state_ = NOT_STARTED; |
+} |
+ |
+void MediaStreamImpl::startNegotiation( |
+ const WebKit::WebPeerConnection& web_peer_connection) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ // TODO(grunell): Implement. Currently not supported in native PeerConnection. |
+} |
+ |
+void MediaStreamImpl::removeStream( |
+ const WebKit::WebPeerConnection& web_peer_connection, |
+ const WebKit::WebMediaStream& stream) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ // TODO(grunell): Implement. Currently not supported in native PeerConnection. |
+} |
+ |
+void MediaStreamImpl::commitStreamChanges( |
+ const WebKit::WebPeerConnection& web_peer_connection) { |
+ if (web_peer_connection != web_peer_connection_) { |
+ DLOG(ERROR) << __FUNCTION__ << ": PeerConnection is not valid"; |
+ return; |
+ } |
+ // TODO(grunell): Implement. Currently not supported in native PeerConnection. |
+} |
scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder( |
- const GURL& url, media::MessageLoopFactory* message_loop_factory) { |
- bool raw_media = (url.spec().find(kRawMediaScheme) == 0); |
- media::VideoDecoder* decoder = NULL; |
- if (raw_media) { |
+ const GURL& url, |
+ media::MessageLoopFactory* message_loop_factory) { |
+ std::string label = |
+ UTF16ToUTF8(WebKit::WebMediaStreamRegistry::mediaStreamLabel(url)); |
+ if (label.empty()) |
+ return NULL; // This is not a valid stream. |
+ |
+ scoped_refptr<media::VideoDecoder> decoder; |
+ if (media_stream_dispatcher_->IsStream(label)) { |
+ // It's a local stream. |
+ int video_session_id = media_stream_dispatcher_->video_session_id(label, 0); |
media::VideoCapture::VideoCaptureCapability capability; |
capability.width = kVideoCaptureWidth; |
capability.height = kVideoCaptureHeight; |
@@ -43,10 +347,174 @@ scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder( |
capability.raw_type = media::VideoFrame::I420; |
capability.interlaced = false; |
capability.resolution_fixed = false; |
- |
decoder = new CaptureVideoDecoder( |
- message_loop_factory->GetMessageLoopProxy("CaptureVideoDecoder").get(), |
- kStartOpenSessionId, vc_manager_.get(), capability); |
+ message_loop_factory->GetMessageLoopProxy("CaptureVideoDecoderThread"), |
+ video_session_id, |
+ vc_manager_.get(), |
+ capability); |
+ } else { |
+ // It's a remote stream. |
+ size_t found = label.rfind("-remote"); |
+ if (found != std::string::npos) |
+ label = label.substr(0, found); |
+ if (rtc_video_decoder_.get()) { |
+ // The renderer is used by PeerConnection, release it first. |
+ if (native_peer_connection_.get()) |
+ native_peer_connection_->SetVideoRenderer(label, NULL); |
+ } |
+ rtc_video_decoder_ = new RTCVideoDecoder( |
+ message_loop_factory->GetMessageLoop("RtcVideoDecoderThread"), |
+ url.spec()); |
+ decoder = rtc_video_decoder_; |
+ if (native_peer_connection_.get()) |
+ native_peer_connection_->SetVideoRenderer(label, rtc_video_decoder_); |
} |
return decoder; |
} |
+ |
+void MediaStreamImpl::OnStreamGenerated( |
+ int request_id, |
+ const std::string& label, |
+ const media_stream::StreamDeviceInfoArray& audio_array, |
+ const media_stream::StreamDeviceInfoArray& video_array) { |
+ DCHECK(controller_.get()); |
+ |
+ WebKit::WebVector<WebKit::WebMediaStreamTrack> web_track_vector( |
+ audio_array.size() + video_array.size()); |
+ |
+ WebKit::WebString track_id(WebKit::WebString::fromUTF8("")); |
+ WebKit::WebString track_kind(WebKit::WebString::fromUTF8("main")); |
+ WebKit::WebString track_label_audio( |
+ WebKit::WebString::fromUTF8("AudioDevice")); |
+ WebKit::WebString track_label_video( |
+ WebKit::WebString::fromUTF8("VideoCapture")); |
+ unsigned int track_num = web_track_vector.size(); |
tommi (sloooow) - chröme
2011/10/25 09:58:34
size_t?
Henrik Grunell
2011/10/25 12:14:32
Done.
|
+ while (track_num--) { |
+ if (track_num < audio_array.size()) { |
+ web_track_vector[track_num].initialize(track_id, |
+ track_kind, |
+ track_label_audio); |
+ } else { |
+ web_track_vector[track_num].initialize(track_id, |
+ track_kind, |
+ track_label_video); |
+ } |
+ } |
+ |
+ WebKit::WebMediaStreamTrackList web_track_list; |
+ web_track_list.initialize(web_track_vector); |
+ |
+ WebKit::WebLocalMediaStream web_local_media_stream; |
+ web_local_media_stream.initialize(UTF8ToUTF16(label), web_track_list); |
+ |
+ controller_->streamGenerated(request_id, web_local_media_stream); |
+} |
+ |
+void MediaStreamImpl::OnStreamGenerationFailed(int request_id) { |
+ VLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed(" |
+ << request_id << ")"; |
+ DCHECK(controller_.get()); |
+ controller_->streamGenerationFailed( |
+ request_id, |
+ WebKit::WebMediaStreamController::ErrorPermissionDenied); |
+} |
+ |
+void MediaStreamImpl::OnVideoDeviceFailed(const std::string& label, |
+ int index) { |
+ VLOG(1) << "MediaStreamImpl::OnVideoDeviceFailed(" |
+ << label << ", " << index << ")"; |
+ DCHECK(controller_.get()); |
+ controller_->streamFailed(UTF8ToUTF16(label)); |
+} |
+ |
+void MediaStreamImpl::OnAudioDeviceFailed(const std::string& label, |
+ int index) { |
+ VLOG(1) << "MediaStreamImpl::OnAudioDeviceFailed(" |
+ << label << ", " << index << ")"; |
+ DCHECK(controller_.get()); |
+ controller_->streamFailed(UTF8ToUTF16(label)); |
+} |
+ |
+void MediaStreamImpl::OnSignalingMessage(const std::string& msg) { |
+ if (!message_loop_proxy_->BelongsToCurrentThread()) { |
+ message_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, &MediaStreamImpl::OnSignalingMessage, msg)); |
+ return; |
+ } |
+ |
+ DCHECK(controller_.get()); |
+ controller_->onSignalingMessage(web_peer_connection_, UTF8ToUTF16(msg)); |
+} |
+ |
+void MediaStreamImpl::OnAddStream(const std::string& stream_id, bool video) { |
+ // TODO(grunell): Fix code in this function after a new native PeerConnection |
+ // version has been rolled out. |
+ if (video) { |
+ if (call_state_ == NOT_STARTED) { |
+ remote_label_ = stream_id; |
+ call_state_ = RECEIVING; |
+ } else if (call_state_ == INITIATING) { |
+ remote_label_ = local_label_; |
+ remote_label_ += "-remote"; |
+ call_state_ = SENDING_AND_RECEIVING; |
+ } |
+ |
+ if (!message_loop_proxy_->BelongsToCurrentThread()) { |
+ message_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, |
+ &MediaStreamImpl::OnAddStreamCallback, |
+ remote_label_)); |
+ return; |
tommi (sloooow) - chröme
2011/10/25 09:58:34
no need for return
Henrik Grunell
2011/10/25 12:14:32
Done.
|
+ } else { |
+ OnAddStreamCallback(remote_label_); |
+ } |
+ } |
+} |
+ |
+void MediaStreamImpl::OnRemoveStream(const std::string& stream_id, bool video) { |
+ if (video) { |
+ if (!message_loop_proxy_->BelongsToCurrentThread()) { |
+ message_loop_proxy_->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, |
+ &MediaStreamImpl::OnRemoveStreamCallback, |
+ remote_label_)); |
+ return; |
tommi (sloooow) - chröme
2011/10/25 09:58:34
no need for return
Henrik Grunell
2011/10/25 12:14:32
Done.
|
+ } else { |
+ OnRemoveStreamCallback(remote_label_); |
+ } |
+ } |
+} |
+ |
+void MediaStreamImpl::OnAddStreamCallback(const std::string& stream_label) { |
+ DCHECK(controller_.get()); |
+ |
+ // Currently only support for one track |
+ size_t size = 1; |
+ WebKit::WebVector<WebKit::WebMediaStreamTrack> web_track_vector(size); |
+ web_track_vector[0].initialize(WebKit::WebString::fromUTF8(""), |
+ WebKit::WebString::fromUTF8("main"), |
+ WebKit::WebString::fromUTF8(stream_label)); |
+ WebKit::WebMediaStreamTrackList web_track_list; |
+ web_track_list.initialize(web_track_vector); |
+ |
+ WebKit::WebMediaStream web_media_stream; |
+ web_media_stream.initialize(UTF8ToUTF16(stream_label), web_track_list); |
+ |
+ controller_->onAddStream(web_peer_connection_, web_media_stream); |
+} |
+ |
+void MediaStreamImpl::OnRemoveStreamCallback(const std::string& stream_label) { |
+ DCHECK(controller_.get()); |
+ controller_->onRemoveStream(web_peer_connection_, UTF8ToUTF16(stream_label)); |
+} |
+ |
+void MediaStreamImpl::InitializeWorkerThread(talk_base::Thread** thread, |
+ base::WaitableEvent* event) { |
+ jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); |
+ jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); |
+ *thread = jingle_glue::JingleThreadWrapper::current(); |
+ event->Signal(); |
+} |