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