OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/peer_connection_handler.h" | 5 #include "content/renderer/media/peer_connection_handler.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <utility> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/string_number_conversions.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" | 13 #include "base/utf_string_conversions.h" |
16 #include "content/renderer/media/media_stream_dependency_factory.h" | 14 #include "content/renderer/media/media_stream_dependency_factory.h" |
17 #include "content/renderer/media/media_stream_impl.h" | 15 #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" | 16 #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" | 17 #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" | 18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPeerConne
ctionHandlerClient.h" |
25 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" | 19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" |
26 | 20 |
27 PeerConnectionHandler::PeerConnectionHandler( | 21 PeerConnectionHandler::PeerConnectionHandler( |
28 WebKit::WebPeerConnectionHandlerClient* client, | 22 WebKit::WebPeerConnectionHandlerClient* client, |
29 MediaStreamImpl* msi, | 23 MediaStreamImpl* msi, |
30 MediaStreamDependencyFactory* dependency_factory, | 24 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), | 25 : client_(client), |
36 media_stream_impl_(msi), | 26 media_stream_impl_(msi), |
37 dependency_factory_(dependency_factory), | 27 dependency_factory_(dependency_factory), |
38 message_loop_proxy_(base::MessageLoopProxy::current()), | 28 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 } | 29 } |
45 | 30 |
46 PeerConnectionHandler::~PeerConnectionHandler() { | 31 PeerConnectionHandler::~PeerConnectionHandler() { |
47 if (native_peer_connection_.get()) { | |
48 native_peer_connection_->RegisterObserver(NULL); | |
49 native_peer_connection_->Close(); | |
50 } | |
51 } | 32 } |
52 | 33 |
53 bool PeerConnectionHandler::SetVideoRenderer( | 34 void PeerConnectionHandler::SetVideoRenderer( |
54 const std::string& stream_label, | 35 const std::string& stream_label, |
55 cricket::VideoRenderer* renderer) { | 36 webrtc::VideoRendererWrapperInterface* renderer) { |
56 return native_peer_connection_->SetVideoRenderer(stream_label, renderer); | 37 webrtc::MediaStreamInterface* stream = |
| 38 native_peer_connection_->remote_streams()->find(stream_label); |
| 39 webrtc::VideoTracks* video_tracks = stream->video_tracks(); |
| 40 // We assume there is only one enabled video track. |
| 41 for(size_t i = 0; i < video_tracks->count(); ++i) { |
| 42 webrtc::VideoTrackInterface* video_track = video_tracks->at(i); |
| 43 if (video_track->enabled()) { |
| 44 video_track->SetRenderer(renderer); |
| 45 return; |
| 46 } |
| 47 } |
| 48 DVLOG(1) << "No enabled video track."; |
57 } | 49 } |
58 | 50 |
59 void PeerConnectionHandler::initialize( | 51 void PeerConnectionHandler::initialize( |
60 const WebKit::WebString& server_configuration, | 52 const WebKit::WebString& server_configuration, |
61 const WebKit::WebSecurityOrigin& security_origin) { | 53 const WebKit::WebSecurityOrigin& security_origin) { |
62 // We support the following server configuration format: | 54 native_peer_connection_ = dependency_factory_->CreatePeerConnection( |
63 // "STUN <address>:<port>". We only support STUN at the moment. | 55 UTF16ToUTF8(server_configuration), |
64 // TODO(grunell): Support TURN. | 56 this); |
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 } | 57 } |
105 | 58 |
106 void PeerConnectionHandler::produceInitialOffer( | 59 void PeerConnectionHandler::produceInitialOffer( |
107 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 60 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
108 pending_add_streams) { | 61 pending_add_streams) { |
109 // We currently don't support creating an initial offer without a stream. | 62 AddStreams(pending_add_streams); |
110 // Native PeerConnection will anyway create the initial offer when the first | 63 native_peer_connection_->CommitStreamChanges(); |
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 } | 64 } |
125 | 65 |
126 void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { | 66 void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { |
127 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | 67 native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); |
128 } | 68 } |
129 | 69 |
130 void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { | 70 void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { |
131 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | 71 native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); |
132 } | 72 } |
133 | 73 |
134 void PeerConnectionHandler::processPendingStreams( | 74 void PeerConnectionHandler::processPendingStreams( |
135 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 75 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
136 pending_add_streams, | 76 pending_add_streams, |
137 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 77 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
138 pending_remove_streams) { | 78 pending_remove_streams) { |
139 // TODO(grunell): Support several streams. | 79 AddStreams(pending_add_streams); |
140 if (!pending_add_streams.isEmpty()) { | 80 RemoveStreams(pending_remove_streams); |
141 DCHECK_EQ(pending_add_streams.size(), 1u); | 81 native_peer_connection_->CommitStreamChanges(); |
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 } | 82 } |
150 | 83 |
151 void PeerConnectionHandler::sendDataStreamMessage( | 84 void PeerConnectionHandler::sendDataStreamMessage( |
152 const char* data, | 85 const char* data, |
153 size_t length) { | 86 size_t length) { |
154 // TODO(grunell): Implement. Not supported in native PeerConnection. | 87 // TODO(grunell): Implement. |
155 NOTIMPLEMENTED(); | 88 NOTIMPLEMENTED(); |
156 } | 89 } |
157 | 90 |
158 void PeerConnectionHandler::stop() { | 91 void PeerConnectionHandler::stop() { |
159 if (native_peer_connection_.get()) | 92 // TODO(ronghuawu): There's an issue with signaling messages being sent during |
160 native_peer_connection_->RegisterObserver(NULL); | 93 // close. We need to investigate further. Not calling Close() on native |
161 native_peer_connection_.reset(); | 94 // PeerConnection is OK for now. |
162 // The close function will delete us. | 95 native_peer_connection_ = NULL; |
163 media_stream_impl_->ClosePeerConnection(); | 96 media_stream_impl_->ClosePeerConnection(); |
164 } | 97 } |
165 | 98 |
| 99 void PeerConnectionHandler::OnError() { |
| 100 // TODO(grunell): Implement. |
| 101 NOTIMPLEMENTED(); |
| 102 } |
| 103 |
| 104 void PeerConnectionHandler::OnMessage(const std::string& msg) { |
| 105 // TODO(grunell): Implement. |
| 106 NOTIMPLEMENTED(); |
| 107 } |
| 108 |
166 void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { | 109 void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { |
167 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 110 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
168 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 111 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
169 &PeerConnectionHandler::OnSignalingMessage, | 112 &PeerConnectionHandler::OnSignalingMessage, |
170 base::Unretained(this), | 113 base::Unretained(this), |
171 msg)); | 114 msg)); |
172 return; | 115 return; |
173 } | 116 } |
174 client_->didGenerateSDP(UTF8ToUTF16(msg)); | 117 client_->didGenerateSDP(UTF8ToUTF16(msg)); |
175 } | 118 } |
176 | 119 |
177 void PeerConnectionHandler::OnAddStream(const std::string& stream_id, | 120 void PeerConnectionHandler::OnStateChange(StateType state_changed) { |
178 bool video) { | 121 // TODO(grunell): Implement. |
179 if (!video) | 122 NOTIMPLEMENTED(); |
| 123 } |
| 124 |
| 125 void PeerConnectionHandler::OnAddStream(webrtc::MediaStreamInterface* stream) { |
| 126 if (!stream) |
180 return; | 127 return; |
181 | 128 |
182 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 129 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
183 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 130 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
184 &PeerConnectionHandler::OnAddStreamCallback, | 131 &PeerConnectionHandler::OnAddStreamCallback, |
185 base::Unretained(this), | 132 base::Unretained(this), |
186 stream_id)); | 133 stream)); |
187 } else { | 134 } else { |
188 OnAddStreamCallback(stream_id); | 135 OnAddStreamCallback(stream); |
189 } | 136 } |
190 } | 137 } |
191 | 138 |
192 void PeerConnectionHandler::OnRemoveStream( | 139 void PeerConnectionHandler::OnRemoveStream( |
193 const std::string& stream_id, | 140 webrtc::MediaStreamInterface* stream) { |
194 bool video) { | 141 if (!stream) |
195 if (!video) | |
196 return; | 142 return; |
197 | 143 |
198 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 144 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
199 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 145 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
200 &PeerConnectionHandler::OnRemoveStreamCallback, | 146 &PeerConnectionHandler::OnRemoveStreamCallback, |
201 base::Unretained(this), | 147 base::Unretained(this), |
202 remote_label_)); | 148 stream)); |
203 } else { | 149 } else { |
204 OnRemoveStreamCallback(remote_label_); | 150 OnRemoveStreamCallback(stream); |
205 } | 151 } |
206 } | 152 } |
207 | 153 |
208 void PeerConnectionHandler::AddStream(const std::string label) { | 154 void PeerConnectionHandler::AddStreams( |
209 // TODO(grunell): Fix code in this function after a new native PeerConnection | 155 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams) { |
210 // version has been rolled out. | 156 for (size_t i = 0; i < streams.size(); ++i) { |
211 if (call_state_ == NOT_STARTED) { | 157 talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream = |
212 // TODO(grunell): Add audio and/or video depending on what's enabled | 158 dependency_factory_->CreateLocalMediaStream( |
213 // in the stream. | 159 UTF16ToUTF8(streams[i].label())); |
214 std::string audio_label = label; | 160 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; |
215 audio_label.append("-audio"); | 161 streams[i].sources(source_vector); |
216 native_peer_connection_->AddStream(audio_label, false); // Audio | 162 |
217 native_peer_connection_->AddStream(label, true); // Video | 163 // Get and add all tracks. |
218 call_state_ = INITIATING; | 164 for (size_t j = 0; j < source_vector.size(); ++j) { |
| 165 webrtc::MediaStreamTrackInterface* track = |
| 166 media_stream_impl_->GetLocalMediaStreamTrack( |
| 167 UTF16ToUTF8(source_vector[j].id())); |
| 168 DCHECK(track); |
| 169 if (source_vector[j].type() == WebKit::WebMediaStreamSource::TypeVideo) { |
| 170 stream->AddTrack(static_cast<webrtc::VideoTrackInterface*>(track)); |
| 171 } else { |
| 172 stream->AddTrack(static_cast<webrtc::AudioTrackInterface*>(track)); |
| 173 } |
| 174 } |
| 175 |
| 176 native_peer_connection_->AddStream(stream); |
219 } | 177 } |
220 if (call_state_ == INITIATING || call_state_ == RECEIVING) { | 178 } |
221 local_label_ = label; | 179 |
222 if (media_stream_impl_->SetVideoCaptureModule(label)) | 180 void PeerConnectionHandler::RemoveStreams( |
223 native_peer_connection_->SetVideoCapture(""); | 181 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams) { |
224 if (call_state_ == INITIATING) | 182 for (size_t i = 0; i < streams.size(); ++i) { |
225 native_peer_connection_->Connect(); | 183 webrtc::MediaStreamInterface* stream = |
226 else if (call_state_ == RECEIVING) | 184 native_peer_connection_->remote_streams()->find( |
227 call_state_ = SENDING_AND_RECEIVING; | 185 UTF16ToUTF8(streams[i].label())); |
228 } else { | 186 native_peer_connection_->RemoveStream( |
229 DLOG(ERROR) << "Multiple streams not supported"; | 187 static_cast<webrtc::LocalMediaStreamInterface*>(stream)); |
230 } | 188 } |
231 } | 189 } |
232 | 190 |
233 void PeerConnectionHandler::OnAddStreamCallback( | 191 void PeerConnectionHandler::OnAddStreamCallback( |
234 const std::string& stream_label) { | 192 webrtc::MediaStreamInterface* stream) { |
235 // TODO(grunell): Fix code in this function after a new native PeerConnection | 193 DCHECK(remote_streams_.find(stream) == remote_streams_.end()); |
236 // version has been rolled out. | 194 WebKit::WebMediaStreamDescriptor descriptor = |
237 if (call_state_ == NOT_STARTED) { | 195 CreateWebKitStreamDescriptor(stream); |
238 remote_label_ = stream_label; | 196 remote_streams_.insert( |
239 call_state_ = RECEIVING; | 197 std::pair<webrtc::MediaStreamInterface*, |
240 } else if (call_state_ == INITIATING) { | 198 WebKit::WebMediaStreamDescriptor>(stream, descriptor)); |
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); | 199 client_->didAddRemoteStream(descriptor); |
258 } | 200 } |
259 | 201 |
260 void PeerConnectionHandler::OnRemoveStreamCallback( | 202 void PeerConnectionHandler::OnRemoveStreamCallback( |
261 const std::string& stream_label) { | 203 webrtc::MediaStreamInterface* stream) { |
262 // TODO(grunell): Support several tracks. | 204 RemoteStreamMap::iterator it = remote_streams_.find(stream); |
263 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( | 205 if (it == remote_streams_.end()) { |
264 static_cast<size_t>(2)); | 206 NOTREACHED() << "Stream not found"; |
265 source_vector[0].initialize(WebKit::WebString::fromUTF8(stream_label), | 207 return; |
266 WebKit::WebMediaStreamSource::TypeVideo, | 208 } |
267 WebKit::WebString::fromUTF8("RemoteVideo")); | 209 WebKit::WebMediaStreamDescriptor descriptor = it->second; |
268 source_vector[1].initialize(WebKit::WebString::fromUTF8(stream_label), | 210 DCHECK(!descriptor.isNull()); |
269 WebKit::WebMediaStreamSource::TypeAudio, | 211 remote_streams_.erase(it); |
270 WebKit::WebString::fromUTF8("RemoteAudio")); | |
271 WebKit::WebMediaStreamDescriptor descriptor; | |
272 descriptor.initialize(UTF8ToUTF16(stream_label), source_vector); | |
273 client_->didRemoveRemoteStream(descriptor); | 212 client_->didRemoveRemoteStream(descriptor); |
274 } | 213 } |
| 214 |
| 215 WebKit::WebMediaStreamDescriptor |
| 216 PeerConnectionHandler::CreateWebKitStreamDescriptor( |
| 217 webrtc::MediaStreamInterface* stream) { |
| 218 webrtc::AudioTracks* audio_tracks = stream->audio_tracks(); |
| 219 webrtc::VideoTracks* video_tracks = stream->video_tracks(); |
| 220 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( |
| 221 audio_tracks->count() + video_tracks->count()); |
| 222 |
| 223 // Add audio tracks. |
| 224 size_t i = 0; |
| 225 for (; i < audio_tracks->count(); ++i) { |
| 226 webrtc::AudioTrackInterface* audio_track = audio_tracks->at(i); |
| 227 DCHECK(audio_track); |
| 228 source_vector[i].initialize( |
| 229 // TODO(grunell): Set id to something unique. |
| 230 UTF8ToUTF16(audio_track->label()), |
| 231 WebKit::WebMediaStreamSource::TypeAudio, |
| 232 UTF8ToUTF16(audio_track->label())); |
| 233 } |
| 234 |
| 235 // Add video tracks. |
| 236 for (i = 0; i < video_tracks->count(); ++i) { |
| 237 webrtc::VideoTrackInterface* video_track = video_tracks->at(i); |
| 238 DCHECK(video_track); |
| 239 source_vector[audio_tracks->count() + i].initialize( |
| 240 // TODO(grunell): Set id to something unique. |
| 241 UTF8ToUTF16(video_track->label()), |
| 242 WebKit::WebMediaStreamSource::TypeVideo, |
| 243 UTF8ToUTF16(video_track->label())); |
| 244 } |
| 245 |
| 246 WebKit::WebMediaStreamDescriptor descriptor; |
| 247 descriptor.initialize(UTF8ToUTF16(stream->label()), source_vector); |
| 248 |
| 249 return descriptor; |
| 250 } |
OLD | NEW |