| 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..e9aa8231f9a55e4c70f65122556507a2c3fdc4a7 100644
|
| --- a/content/renderer/media/media_stream_impl.cc
|
| +++ b/content/renderer/media/media_stream_impl.cc
|
| @@ -4,12 +4,38 @@
|
|
|
| #include "content/renderer/media/media_stream_impl.h"
|
|
|
| -#include "base/string_util.h"
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#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"
|
|
|
| namespace {
|
|
|
| @@ -17,24 +43,303 @@ 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),
|
| + message_loop_proxy_(base::MessageLoopProxy::current()),
|
| + signaling_thread_(NULL),
|
| + worker_thread_(NULL),
|
| + chrome_worker_thread_("Chrome_libJingle_WorkerThread"),
|
| + call_state_(NOT_STARTED),
|
| + vcm_created_(false) {
|
| +}
|
|
|
| -} // 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;
|
| + }
|
| + DVLOG(1) << "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.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::getRecordedData(
|
| + const WebKit::WebMediaStreamRecorder& recorder,
|
| + int request_id) {
|
| + // TODO(grunell): Implement.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::disposeRecordedData(
|
| + const WebKit::WebMediaStreamRecorder& recorder) {
|
| + // TODO(grunell): Implement.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::setMediaStreamTrackEnabled(
|
| + const WebKit::WebMediaStreamTrack& track) {
|
| + // TODO(grunell): Implement.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::processSignalingMessage(
|
| + const WebKit::WebPeerConnection& web_peer_connection,
|
| + const WebKit::WebString& message) {
|
| + if (web_peer_connection != web_peer_connection_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + 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_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + // TODO(grunell): Implement.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::addStream(
|
| + const WebKit::WebPeerConnection& web_peer_connection,
|
| + const WebKit::WebMediaStream& stream) {
|
| + if (web_peer_connection != web_peer_connection_) {
|
| + NOTREACHED();
|
| + 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) {
|
| + // TODO(grunell): Add audio and/or video depending on what's enabled
|
| + // in the stream.
|
| + std::string audio_label = label;
|
| + audio_label.append("-audio");
|
| + native_peer_connection_->AddStream(audio_label, 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) << "Multiple calls not supported";
|
| + }
|
| +}
|
| +
|
| +void MediaStreamImpl::newPeerConnection(
|
| + const WebKit::WebPeerConnection& web_peer_connection,
|
| + const WebKit::WebString& configuration) {
|
| + if (native_peer_connection_.get()) {
|
| + LOG(WARNING) << "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) << "Could not start worker thread";
|
| + return;
|
| + }
|
| + }
|
| + base::WaitableEvent event(true, false);
|
| + chrome_worker_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
|
| + &MediaStreamImpl::InitializeWorkerThread,
|
| + this,
|
| + &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;
|
| + }
|
| + }
|
|
|
| -MediaStreamImpl::MediaStreamImpl(VideoCaptureImplManager* vc_manager)
|
| - : vc_manager_(vc_manager) {
|
| + native_peer_connection_.reset(dependency_factory_->CreatePeerConnection(
|
| + signaling_thread_));
|
| + web_peer_connection_ = web_peer_connection;
|
| + native_peer_connection_->RegisterObserver(this);
|
| }
|
|
|
| -MediaStreamImpl::~MediaStreamImpl() {}
|
| +void MediaStreamImpl::closePeerConnection(
|
| + const WebKit::WebPeerConnection& web_peer_connection) {
|
| + if (web_peer_connection != web_peer_connection_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + if (native_peer_connection_.get())
|
| + 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_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + // TODO(grunell): Implement. Currently not supported in native PeerConnection.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::removeStream(
|
| + const WebKit::WebPeerConnection& web_peer_connection,
|
| + const WebKit::WebMediaStream& stream) {
|
| + if (web_peer_connection != web_peer_connection_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + // TODO(grunell): Implement. Currently not supported in native PeerConnection.
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void MediaStreamImpl::commitStreamChanges(
|
| + const WebKit::WebPeerConnection& web_peer_connection) {
|
| + if (web_peer_connection != web_peer_connection_) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + // TODO(grunell): Implement. Currently not supported in native PeerConnection.
|
| + NOTIMPLEMENTED();
|
| +}
|
|
|
| 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 +348,162 @@ 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) {
|
| + 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"));
|
| + size_t track_num = web_track_vector.size();
|
| + 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) {
|
| + DVLOG(1) << "MediaStreamImpl::OnStreamGenerationFailed("
|
| + << request_id << ")";
|
| + controller_->streamGenerationFailed(
|
| + request_id,
|
| + WebKit::WebMediaStreamController::ErrorPermissionDenied);
|
| +}
|
| +
|
| +void MediaStreamImpl::OnVideoDeviceFailed(const std::string& label,
|
| + int index) {
|
| + DVLOG(1) << "MediaStreamImpl::OnVideoDeviceFailed("
|
| + << label << ", " << index << ")";
|
| + controller_->streamFailed(UTF8ToUTF16(label));
|
| +}
|
| +
|
| +void MediaStreamImpl::OnAudioDeviceFailed(const std::string& label,
|
| + int index) {
|
| + DVLOG(1) << "MediaStreamImpl::OnAudioDeviceFailed("
|
| + << label << ", " << index << ")";
|
| + controller_->streamFailed(UTF8ToUTF16(label));
|
| +}
|
| +
|
| +void MediaStreamImpl::OnSignalingMessage(const std::string& msg) {
|
| + if (!message_loop_proxy_->BelongsToCurrentThread()) {
|
| + message_loop_proxy_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&MediaStreamImpl::OnSignalingMessage, this, msg));
|
| + return;
|
| + }
|
| + controller_->onSignalingMessage(web_peer_connection_, UTF8ToUTF16(msg));
|
| +}
|
| +
|
| +void MediaStreamImpl::OnAddStream(const std::string& stream_id, bool video) {
|
| + if (!video)
|
| + return;
|
| +
|
| + if (!message_loop_proxy_->BelongsToCurrentThread()) {
|
| + message_loop_proxy_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&MediaStreamImpl::OnAddStreamCallback, this, stream_id));
|
| + } else {
|
| + OnAddStreamCallback(stream_id);
|
| + }
|
| +}
|
| +
|
| +void MediaStreamImpl::OnRemoveStream(const std::string& stream_id, bool video) {
|
| + if (!video)
|
| + return;
|
| +
|
| + if (!message_loop_proxy_->BelongsToCurrentThread()) {
|
| + message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
|
| + &MediaStreamImpl::OnRemoveStreamCallback,
|
| + this,
|
| + remote_label_));
|
| + } else {
|
| + OnRemoveStreamCallback(remote_label_);
|
| + }
|
| +}
|
| +
|
| +void MediaStreamImpl::OnAddStreamCallback(const std::string& stream_label) {
|
| + // TODO(grunell): Fix code in this function after a new native PeerConnection
|
| + // version has been rolled out.
|
| + if (call_state_ == NOT_STARTED) {
|
| + remote_label_ = stream_label;
|
| + call_state_ = RECEIVING;
|
| + } else if (call_state_ == INITIATING) {
|
| + remote_label_ = local_label_;
|
| + remote_label_ += "-remote";
|
| + call_state_ = SENDING_AND_RECEIVING;
|
| + }
|
| +
|
| + // TODO(grunell): Currently only support for one track. Add support for
|
| + // several tracks.
|
| + WebKit::WebVector<WebKit::WebMediaStreamTrack> web_track_vector(
|
| + static_cast<size_t>(1));
|
| + web_track_vector[0].initialize(WebKit::WebString::fromUTF8(""),
|
| + WebKit::WebString::fromUTF8("main"),
|
| + WebKit::WebString::fromUTF8(remote_label_));
|
| + WebKit::WebMediaStreamTrackList web_track_list;
|
| + web_track_list.initialize(web_track_vector);
|
| +
|
| + WebKit::WebMediaStream web_media_stream;
|
| + web_media_stream.initialize(UTF8ToUTF16(remote_label_), web_track_list);
|
| +
|
| + controller_->onAddStream(web_peer_connection_, web_media_stream);
|
| +}
|
| +
|
| +void MediaStreamImpl::OnRemoveStreamCallback(const std::string& stream_label) {
|
| + 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();
|
| +}
|
|
|