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 DCHECK(stream); | |
tommi (sloooow) - chröme
2012/01/24 15:18:56
no need for this dcheck since you dereference the
Henrik Grunell
2012/01/26 13:03:16
Removed.
| |
40 webrtc::VideoTracks* video_tracks = stream->video_tracks(); | |
41 // We assume there is only one video track. | |
42 // TODO(grunell): BEFORE COMMIT. Find the enabled video track. | |
43 DCHECK_EQ(video_tracks->count(), 1u); | |
44 webrtc::VideoTrackInterface* video_track = video_tracks->at(0); | |
45 DCHECK(video_track); | |
tommi (sloooow) - chröme
2012/01/24 15:18:56
same here
Henrik Grunell
2012/01/26 13:03:16
Done.
| |
46 video_track->SetRenderer(renderer); | |
57 } | 47 } |
58 | 48 |
59 void PeerConnectionHandler::initialize( | 49 void PeerConnectionHandler::initialize( |
60 const WebKit::WebString& server_configuration, | 50 const WebKit::WebString& server_configuration, |
61 const WebKit::WebSecurityOrigin& security_origin) { | 51 const WebKit::WebSecurityOrigin& security_origin) { |
62 // We support the following server configuration format: | 52 native_peer_connection_ = dependency_factory_->CreatePeerConnection( |
63 // "STUN <address>:<port>". We only support STUN at the moment. | 53 UTF16ToUTF8(server_configuration), |
64 // TODO(grunell): Support TURN. | 54 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 } | 55 } |
105 | 56 |
106 void PeerConnectionHandler::produceInitialOffer( | 57 void PeerConnectionHandler::produceInitialOffer( |
107 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 58 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
108 pending_add_streams) { | 59 pending_add_streams) { |
109 // We currently don't support creating an initial offer without a stream. | 60 AddStreams(pending_add_streams); |
110 // Native PeerConnection will anyway create the initial offer when the first | 61 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 } | 62 } |
125 | 63 |
126 void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { | 64 void PeerConnectionHandler::handleInitialOffer(const WebKit::WebString& sdp) { |
127 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | 65 native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); |
128 } | 66 } |
129 | 67 |
130 void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { | 68 void PeerConnectionHandler::processSDP(const WebKit::WebString& sdp) { |
131 native_peer_connection_->SignalingMessage(UTF16ToUTF8(sdp)); | 69 native_peer_connection_->ProcessSignalingMessage(UTF16ToUTF8(sdp)); |
132 } | 70 } |
133 | 71 |
134 void PeerConnectionHandler::processPendingStreams( | 72 void PeerConnectionHandler::processPendingStreams( |
135 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 73 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
136 pending_add_streams, | 74 pending_add_streams, |
137 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& | 75 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& |
138 pending_remove_streams) { | 76 pending_remove_streams) { |
139 // TODO(grunell): Support several streams. | 77 AddStreams(pending_add_streams); |
140 if (!pending_add_streams.isEmpty()) { | 78 // TODO(grunell): BEFORE COMMIT. Implement and call RemoveStreams(). |
141 DCHECK_EQ(pending_add_streams.size(), 1u); | 79 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 } | 80 } |
150 | 81 |
151 void PeerConnectionHandler::sendDataStreamMessage( | 82 void PeerConnectionHandler::sendDataStreamMessage( |
152 const char* data, | 83 const char* data, |
153 size_t length) { | 84 size_t length) { |
154 // TODO(grunell): Implement. Not supported in native PeerConnection. | 85 // TODO(grunell): Implement. |
155 NOTIMPLEMENTED(); | 86 NOTIMPLEMENTED(); |
156 } | 87 } |
157 | 88 |
158 void PeerConnectionHandler::stop() { | 89 void PeerConnectionHandler::stop() { |
159 if (native_peer_connection_.get()) | 90 // TODO(ronghuawu): There's an issue with signaling messages being sent during |
160 native_peer_connection_->RegisterObserver(NULL); | 91 // close. We need to investigate further. Not calling Close() on native |
161 native_peer_connection_.reset(); | 92 // PeerConnection is OK for now. |
162 // The close function will delete us. | |
163 media_stream_impl_->ClosePeerConnection(); | 93 media_stream_impl_->ClosePeerConnection(); |
164 } | 94 } |
165 | 95 |
96 void PeerConnectionHandler::OnError() { | |
97 // TODO(grunell): Implement. | |
98 NOTIMPLEMENTED(); | |
99 } | |
100 | |
101 void PeerConnectionHandler::OnMessage(const std::string& msg) { | |
102 // TODO(grunell): Implement. | |
103 NOTIMPLEMENTED(); | |
104 } | |
105 | |
166 void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { | 106 void PeerConnectionHandler::OnSignalingMessage(const std::string& msg) { |
167 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 107 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
168 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 108 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
169 &PeerConnectionHandler::OnSignalingMessage, | 109 &PeerConnectionHandler::OnSignalingMessage, |
170 base::Unretained(this), | 110 base::Unretained(this), |
171 msg)); | 111 msg)); |
172 return; | 112 return; |
173 } | 113 } |
174 client_->didGenerateSDP(UTF8ToUTF16(msg)); | 114 client_->didGenerateSDP(UTF8ToUTF16(msg)); |
175 } | 115 } |
176 | 116 |
177 void PeerConnectionHandler::OnAddStream(const std::string& stream_id, | 117 void PeerConnectionHandler::OnStateChange(StateType state_changed) { |
178 bool video) { | 118 // TODO(grunell): Implement. |
179 if (!video) | 119 NOTIMPLEMENTED(); |
120 } | |
121 | |
122 void PeerConnectionHandler::OnAddStream(webrtc::MediaStreamInterface* stream) { | |
123 if (!stream) | |
180 return; | 124 return; |
181 | 125 |
182 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 126 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
183 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 127 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
184 &PeerConnectionHandler::OnAddStreamCallback, | 128 &PeerConnectionHandler::OnAddStreamCallback, |
185 base::Unretained(this), | 129 base::Unretained(this), |
186 stream_id)); | 130 stream)); |
187 } else { | 131 } else { |
188 OnAddStreamCallback(stream_id); | 132 OnAddStreamCallback(stream); |
189 } | 133 } |
190 } | 134 } |
191 | 135 |
192 void PeerConnectionHandler::OnRemoveStream( | 136 void PeerConnectionHandler::OnRemoveStream( |
193 const std::string& stream_id, | 137 webrtc::MediaStreamInterface* stream) { |
tommi (sloooow) - chröme
2012/01/24 15:18:56
fits on the line above?
Henrik Grunell
2012/01/26 13:03:16
Nope.
| |
194 bool video) { | 138 if (!stream) |
195 if (!video) | |
196 return; | 139 return; |
197 | 140 |
198 if (!message_loop_proxy_->BelongsToCurrentThread()) { | 141 if (!message_loop_proxy_->BelongsToCurrentThread()) { |
199 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 142 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
200 &PeerConnectionHandler::OnRemoveStreamCallback, | 143 &PeerConnectionHandler::OnRemoveStreamCallback, |
201 base::Unretained(this), | 144 base::Unretained(this), |
202 remote_label_)); | 145 stream)); |
203 } else { | 146 } else { |
204 OnRemoveStreamCallback(remote_label_); | 147 OnRemoveStreamCallback(stream); |
205 } | 148 } |
206 } | 149 } |
207 | 150 |
208 void PeerConnectionHandler::AddStream(const std::string label) { | 151 void PeerConnectionHandler::AddStreams( |
209 // TODO(grunell): Fix code in this function after a new native PeerConnection | 152 const WebKit::WebVector<WebKit::WebMediaStreamDescriptor>& streams) { |
210 // version has been rolled out. | 153 for (size_t i = 0; i < streams.size(); ++i) { |
211 if (call_state_ == NOT_STARTED) { | 154 talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream = |
212 // TODO(grunell): Add audio and/or video depending on what's enabled | 155 dependency_factory_->CreateLocalMediaStream( |
213 // in the stream. | 156 UTF16ToUTF8(streams[i].label())); |
tommi (sloooow) - chröme
2012/01/24 15:18:56
nit: you could use an iterator here instead of i/+
Henrik Grunell
2012/01/26 13:03:16
It's a WebVector, no iterator support there.
| |
214 std::string audio_label = label; | 157 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector; |
215 audio_label.append("-audio"); | 158 streams[i].sources(source_vector); |
216 native_peer_connection_->AddStream(audio_label, false); // Audio | 159 |
217 native_peer_connection_->AddStream(label, true); // Video | 160 // Get and add all tracks. |
218 call_state_ = INITIATING; | 161 for (size_t j = 0; j < source_vector.size(); ++j) { |
tommi (sloooow) - chröme
2012/01/24 15:18:56
same here
Henrik Grunell
2012/01/26 13:03:16
Same here :-)
| |
219 } | 162 webrtc::MediaStreamTrackInterface* track = |
220 if (call_state_ == INITIATING || call_state_ == RECEIVING) { | 163 media_stream_impl_->GetLocalMediaStreamTrack( |
221 local_label_ = label; | 164 UTF16ToUTF8(source_vector[j].id())); |
222 if (media_stream_impl_->SetVideoCaptureModule(label)) | 165 DCHECK(track); |
223 native_peer_connection_->SetVideoCapture(""); | 166 if (source_vector[j].type() == WebKit::WebMediaStreamSource::TypeVideo) { |
224 if (call_state_ == INITIATING) | 167 stream->AddTrack(static_cast<webrtc::VideoTrackInterface*>(track)); |
225 native_peer_connection_->Connect(); | 168 } else { |
226 else if (call_state_ == RECEIVING) | 169 stream->AddTrack(static_cast<webrtc::AudioTrackInterface*>(track)); |
227 call_state_ = SENDING_AND_RECEIVING; | 170 } |
228 } else { | 171 } |
229 DLOG(ERROR) << "Multiple streams not supported"; | 172 |
173 native_peer_connection_->AddStream(stream); | |
230 } | 174 } |
231 } | 175 } |
232 | 176 |
233 void PeerConnectionHandler::OnAddStreamCallback( | 177 void PeerConnectionHandler::OnAddStreamCallback( |
234 const std::string& stream_label) { | 178 webrtc::MediaStreamInterface* stream) { |
235 // TODO(grunell): Fix code in this function after a new native PeerConnection | 179 // TODO(grunell): BEFORE COMMIT. Maybe some DCHECKs to verify not already |
236 // version has been rolled out. | 180 // added. |
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 | 181 |
246 // TODO(grunell): Support several tracks. | 182 WebKit::WebMediaStreamDescriptor descriptor = |
247 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( | 183 CreateWebKitStreamDescriptor(stream); |
248 static_cast<size_t>(2)); | 184 remote_streams_.insert( |
249 source_vector[0].initialize(WebKit::WebString::fromUTF8(remote_label_), | 185 std::pair<webrtc::MediaStreamInterface*, |
250 WebKit::WebMediaStreamSource::TypeVideo, | 186 WebKit::WebMediaStreamDescriptor>(stream, descriptor)); |
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); | 187 client_->didAddRemoteStream(descriptor); |
258 } | 188 } |
259 | 189 |
260 void PeerConnectionHandler::OnRemoveStreamCallback( | 190 void PeerConnectionHandler::OnRemoveStreamCallback( |
261 const std::string& stream_label) { | 191 webrtc::MediaStreamInterface* stream) { |
262 // TODO(grunell): Support several tracks. | 192 RemoteStreamMap::iterator it = remote_streams_.find(stream); |
263 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( | 193 if (it == remote_streams_.end()) { |
264 static_cast<size_t>(2)); | 194 NOTREACHED() << "Stream not found"; |
265 source_vector[0].initialize(WebKit::WebString::fromUTF8(stream_label), | 195 return; |
266 WebKit::WebMediaStreamSource::TypeVideo, | 196 } |
267 WebKit::WebString::fromUTF8("RemoteVideo")); | 197 WebKit::WebMediaStreamDescriptor descriptor = it->second; |
tommi (sloooow) - chröme
2012/01/24 15:18:56
nit: remove the descriptor variable since it's onl
Henrik Grunell
2012/01/26 13:03:16
No, we need a copy to be able to remove it from th
| |
268 source_vector[1].initialize(WebKit::WebString::fromUTF8(stream_label), | 198 DCHECK(!descriptor.isNull()); |
269 WebKit::WebMediaStreamSource::TypeAudio, | 199 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); | 200 client_->didRemoveRemoteStream(descriptor); |
274 } | 201 } |
202 | |
203 WebKit::WebMediaStreamDescriptor | |
204 PeerConnectionHandler::CreateWebKitStreamDescriptor( | |
205 webrtc::MediaStreamInterface* stream) { | |
206 webrtc::AudioTracks* audio_tracks = stream->audio_tracks(); | |
207 webrtc::VideoTracks* video_tracks = stream->video_tracks(); | |
208 WebKit::WebVector<WebKit::WebMediaStreamSource> source_vector( | |
209 audio_tracks->count() + video_tracks->count()); | |
210 | |
211 // Add audio tracks. | |
212 size_t i = 0; | |
213 for (; i < audio_tracks->count(); ++i) { | |
tommi (sloooow) - chröme
2012/01/24 15:18:56
nit: could use iterator in the loops
Henrik Grunell
2012/01/26 13:03:16
Same here.
| |
214 webrtc::AudioTrackInterface* audio_track = audio_tracks->at(i); | |
215 DCHECK(audio_track); | |
216 source_vector[i].initialize( | |
217 // TODO(grunell): BEFORE COMMIT. Set id to something unique? | |
218 UTF8ToUTF16(audio_track->label()), | |
219 WebKit::WebMediaStreamSource::TypeAudio, | |
220 UTF8ToUTF16(audio_track->label())); | |
221 } | |
222 | |
223 // Add video tracks. | |
224 for (i = 0; i < video_tracks->count(); ++i) { | |
225 webrtc::VideoTrackInterface* video_track = video_tracks->at(i); | |
226 DCHECK(video_track); | |
227 source_vector[audio_tracks->count() + i].initialize( | |
228 // TODO(grunell): BEFORE COMMIT. Set id to something unique? | |
229 UTF8ToUTF16(video_track->label()), | |
230 WebKit::WebMediaStreamSource::TypeVideo, | |
231 UTF8ToUTF16(video_track->label())); | |
232 } | |
233 | |
234 WebKit::WebMediaStreamDescriptor descriptor; | |
235 descriptor.initialize(UTF8ToUTF16(stream->label()), source_vector); | |
236 | |
237 return descriptor; | |
238 } | |
OLD | NEW |