Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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/peer_connection_handler.h" | |
| 6 | |
| 7 #include <stdlib.h> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/string_number_conversions.h" | |
| 13 #include "base/utf_string_conversions.h" | |
| 14 #include "content/renderer/media/media_stream_dependency_factory.h" | |
| 15 #include "content/renderer/media/media_stream_impl.h" | |
| 16 #include "third_party/libjingle/source/talk/base/thread.h" | |
| 17 #include "third_party/libjingle/source/talk/p2p/client/httpportallocator.h" | |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamDescrip tor.h" | |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamSource. h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPeerConnectionHand lerClient.h" | |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" | |
| 22 | |
| 23 PeerConnectionHandler::PeerConnectionHandler( | |
| 24 WebKit::WebPeerConnectionHandlerClient* client, | |
| 25 MediaStreamImpl* msi, | |
| 26 MediaStreamDependencyFactory* dependency_factory, | |
| 27 talk_base::Thread* signaling_thread, | |
| 28 cricket::HttpPortAllocator* port_allocator) | |
| 29 : client_(client), | |
| 30 media_stream_impl_(msi), | |
| 31 dependency_factory_(dependency_factory), | |
| 32 message_loop_proxy_(base::MessageLoopProxy::current()), | |
| 33 signaling_thread_(signaling_thread), | |
| 34 port_allocator_(port_allocator), | |
| 35 call_state_(NOT_STARTED) { | |
| 36 } | |
| 37 | |
| 38 PeerConnectionHandler::~PeerConnectionHandler() { | |
| 39 if (native_peer_connection_.get()) { | |
| 40 native_peer_connection_->RegisterObserver(NULL); | |
| 41 native_peer_connection_->Close(); | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 bool PeerConnectionHandler::SetVideoRenderer( | |
| 46 const std::string& stream_label, | |
| 47 cricket::VideoRenderer* renderer) { | |
| 48 return native_peer_connection_->SetVideoRenderer(stream_label, renderer); | |
| 49 } | |
| 50 | |
| 51 void PeerConnectionHandler::initialize( | |
| 52 const WebKit::WebString& server_configuration, | |
| 53 const WebKit::WebSecurityOrigin& security_origin) { | |
| 54 // We support the following server configuration format: | |
| 55 // "STUN <address>:<port>". We only support STUN at the moment. | |
| 56 | |
| 57 // Strip "STUN ". | |
| 58 std::string strip_string = "STUN "; | |
| 59 std::string config = UTF16ToUTF8(server_configuration); | |
| 60 size_t pos = config.find(strip_string); | |
| 61 DCHECK_EQ(pos, 0u); | |
|
scherkus (not reviewing)
2011/11/23 22:52:04
are these strings passed in from WebKit via JS/HTM
Henrik Grunell
2011/11/24 11:32:59
Yes.
| |
| 62 if (pos != 0) { | |
| 63 VLOG(1) << "Invalid configuration string."; | |
|
scherkus (not reviewing)
2011/11/23 22:52:04
DVLOG?
Henrik Grunell
2011/11/24 11:32:59
Sure, fixed.
| |
| 64 return; | |
| 65 } | |
| 66 config = config.substr(strip_string.length()); | |
| 67 // Parse out port. | |
| 68 pos = config.find(':'); | |
| 69 DCHECK(pos != std::string::npos); | |
|
scherkus (not reviewing)
2011/11/23 22:52:04
ditto for this + other DCHECKs
Henrik Grunell
2011/11/24 11:32:59
Done.
| |
| 70 if (pos == std::string::npos) { | |
| 71 VLOG(1) << "Invalid configuration string."; | |
| 72 return; | |
| 73 } | |
| 74 int port = 0; | |
| 75 bool success = base::StringToInt(config.substr(pos+1), &port); | |
| 76 DCHECK(success && (port != 0)); | |
| 77 if (!success || (port == 0)) { | |
| 78 VLOG(1) << "Invalid configuration string."; | |
| 79 return; | |
| 80 } | |
| 81 // Get address. | |
| 82 std::string address = config.substr(0, pos); | |
| 83 | |
| 84 std::vector<talk_base::SocketAddress> stun_hosts; | |
| 85 stun_hosts.push_back(talk_base::SocketAddress(address, port)); | |
| 86 port_allocator_->SetStunHosts(stun_hosts); | |
| 87 | |
| 88 native_peer_connection_.reset(dependency_factory_->CreatePeerConnection( | |
| 89 signaling_thread_)); | |
| 90 native_peer_connection_->RegisterObserver(this); | |
| 91 } | |
| 92 | |
| 93 void PeerConnectionHandler::produceInitialOffer( | |
| 94 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | |
| 95 pending_add_streams) { | |
| 96 // We currently don't support creating an initial offer without a stream. | |
| 97 // Native PeerConnection will anyway create the initial offer when the first | |
| 98 // (and only) stream is added, so it will be done when processPendingStreams | |
| 99 // is called if not here. | |
| 100 if (pending_add_streams.isEmpty()) { | |
| 101 DVLOG(1) << "Can't produce initial offer with no stream."; | |
| 102 return; | |
| 103 } | |
| 104 // TODO(grunell): Support several streams. | |
| 105 DCHECK_EQ(pending_add_streams.size(), 1u); | |
| 106 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; | |
| 107 pending_add_streams[0].sources(source_vector); | |
| 108 DCHECK_GT(source_vector.size(), 0u); | |
| 109 std::string label = UTF16ToUTF8(source_vector[0].id()); | |
| 110 AddStream(label); | |
| 111 } | |
| 112 | |
| 113 void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { | |
| 114 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | |
| 115 } | |
| 116 | |
| 117 void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { | |
| 118 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | |
| 119 } | |
| 120 | |
| 121 void PeerConnectionHandler::processPendingStreams( | |
| 122 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | |
| 123 pending_add_streams, | |
| 124 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | |
| 125 pending_remove_streams) { | |
| 126 // TODO(grunell): Support several streams. | |
| 127 if (!pending_add_streams.isEmpty()) { | |
| 128 DCHECK_EQ(pending_add_streams.size(), 1u); | |
| 129 AddStream(UTF16ToUTF8(pending_add_streams[0].label())); | |
| 130 } | |
| 131 // Currently we ignore remove stream, no support in native PeerConnection. | |
| 132 } | |
| 133 | |
| 134 void PeerConnectionHandler::sendDataStreamMessage( | |
| 135 const char* data, | |
| 136 size_t length) { | |
| 137 // TODO(grunell): Implement. Not supported in native PeerConnection. | |
| 138 NOTIMPLEMENTED(); | |
| 139 } | |
| 140 | |
| 141 void PeerConnectionHandler::stop() { | |
| 142 if (native_peer_connection_.get()) | |
| 143 native_peer_connection_->RegisterObserver(NULL); | |
| 144 native_peer_connection_.reset(); | |
| 145 // The close function will delete us. | |
| 146 media_stream_impl_->ClosePeerConnection(); | |
| 147 } | |
| 148 | |
| 149 void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { | |
| 150 if (!message_loop_proxy_->BelongsToCurrentThread()) { | |
| 151 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 152 &PeerConnectionHandler::OnSignalingMessage, | |
| 153 base::Unretained(this), | |
| 154 msg)); | |
| 155 return; | |
| 156 } | |
| 157 client_->didGenerateSDP(UTF8ToUTF16(msg)); | |
| 158 } | |
| 159 | |
| 160 void PeerConnectionHandler::OnAddStream(const std::string& stream_id, | |
| 161 bool video) { | |
| 162 if (!video) | |
| 163 return; | |
| 164 | |
| 165 if (!message_loop_proxy_->BelongsToCurrentThread()) { | |
| 166 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 167 &PeerConnectionHandler::OnAddStreamCallback, | |
| 168 base::Unretained(this), | |
| 169 stream_id)); | |
| 170 } else { | |
| 171 OnAddStreamCallback(stream_id); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 void PeerConnectionHandler::OnRemoveStream( | |
| 176 const std::string& stream_id, | |
| 177 bool video) { | |
| 178 if (!video) | |
| 179 return; | |
| 180 | |
| 181 if (!message_loop_proxy_->BelongsToCurrentThread()) { | |
| 182 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
| 183 &PeerConnectionHandler::OnRemoveStreamCallback, | |
| 184 base::Unretained(this), | |
| 185 remote_label_)); | |
| 186 } else { | |
| 187 OnRemoveStreamCallback(remote_label_); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 void PeerConnectionHandler::AddStream(const std::string label) { | |
| 192 // TODO(grunell): Fix code in this function after a new native PeerConnection | |
| 193 // version has been rolled out. | |
| 194 if (call_state_ == NOT_STARTED) { | |
| 195 // TODO(grunell): Add audio and/or video depending on what's enabled | |
| 196 // in the stream. | |
| 197 std::string audio_label = label; | |
| 198 audio_label.append("-audio"); | |
| 199 native_peer_connection_->AddStream(audio_label, false); // Audio | |
| 200 native_peer_connection_->AddStream(label, true); // Video | |
| 201 call_state_ = INITIATING; | |
| 202 } | |
| 203 if (call_state_ == INITIATING || call_state_ == RECEIVING) { | |
| 204 local_label_ = label; | |
| 205 if (media_stream_impl_->SetVideoCaptureModule(label)) | |
| 206 native_peer_connection_->SetVideoCapture(""); | |
| 207 if (call_state_ == INITIATING) | |
| 208 native_peer_connection_->Connect(); | |
| 209 else if (call_state_ == RECEIVING) | |
| 210 call_state_ = SENDING_AND_RECEIVING; | |
| 211 } else { | |
| 212 DLOG(ERROR) << "Multiple streams not supported"; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 void PeerConnectionHandler::OnAddStreamCallback( | |
| 217 const std::string& stream_label) { | |
| 218 // TODO(grunell): Fix code in this function after a new native PeerConnection | |
| 219 // version has been rolled out. | |
| 220 if (call_state_ == NOT_STARTED) { | |
| 221 remote_label_ = stream_label; | |
| 222 call_state_ = RECEIVING; | |
| 223 } else if (call_state_ == INITIATING) { | |
| 224 remote_label_ = local_label_; | |
| 225 remote_label_ += "-remote"; | |
| 226 call_state_ = SENDING_AND_RECEIVING; | |
| 227 } | |
| 228 | |
| 229 // TODO(grunell): Support several tracks. | |
| 230 WebKit::WebVector<WebKit::WebMediaStreamSource> | |
| 231 source_vector(static_cast<size_t>(2)); | |
| 232 source_vector[0].initialize(WebKit::WebString::fromUTF8(remote_label_), | |
| 233 WebKit::WebMediaStreamSource::TypeVideo, | |
| 234 WebKit::WebString::fromUTF8("RemoteVideo")); | |
| 235 source_vector[1].initialize(WebKit::WebString::fromUTF8(remote_label_), | |
| 236 WebKit::WebMediaStreamSource::TypeAudio, | |
| 237 WebKit::WebString::fromUTF8("RemoteAudio")); | |
| 238 WebKit::WebMediaStreamDescriptor descriptor; | |
| 239 descriptor.initialize(UTF8ToUTF16(remote_label_), source_vector); | |
| 240 client_->didAddRemoteStream(descriptor); | |
| 241 } | |
| 242 | |
| 243 void PeerConnectionHandler::OnRemoveStreamCallback( | |
| 244 const std::string& stream_label) { | |
| 245 // TODO(grunell): Support several tracks. | |
| 246 WebKit::WebVector<WebKit::WebMediaStreamSource> | |
| 247 source_vector(static_cast<size_t>(2)); | |
| 248 source_vector[0].initialize(WebKit::WebString::fromUTF8(stream_label), | |
| 249 WebKit::WebMediaStreamSource::TypeVideo, | |
| 250 WebKit::WebString::fromUTF8("RemoteVideo")); | |
| 251 source_vector[1].initialize(WebKit::WebString::fromUTF8(stream_label), | |
| 252 WebKit::WebMediaStreamSource::TypeAudio, | |
| 253 WebKit::WebString::fromUTF8("RemoteAudio")); | |
| 254 WebKit::WebMediaStreamDescriptor descriptor; | |
| 255 descriptor.initialize(UTF8ToUTF16(stream_label), source_vector); | |
| 256 client_->didRemoveRemoteStream(descriptor); | |
| 257 } | |
| OLD | NEW |