Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / media / base / hybridvideoengine.cc
1 /*
2  * libjingle
3  * Copyright 2004 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "talk/media/base/hybridvideoengine.h"
29
30 #include "talk/base/logging.h"
31
32 namespace cricket {
33
34 HybridVideoMediaChannel::HybridVideoMediaChannel(
35     HybridVideoEngineInterface* engine,
36     VideoMediaChannel* channel1,
37     VideoMediaChannel* channel2)
38     : engine_(engine),
39       channel1_(channel1),
40       channel2_(channel2),
41       active_channel_(NULL),
42       sending_(false) {
43 }
44
45 HybridVideoMediaChannel::~HybridVideoMediaChannel() {
46 }
47
48 void HybridVideoMediaChannel::SetInterface(NetworkInterface* iface) {
49   if (channel1_) {
50     channel1_->SetInterface(iface);
51   }
52   if (channel2_) {
53     channel2_->SetInterface(iface);
54   }
55 }
56
57 bool HybridVideoMediaChannel::SetOptions(const VideoOptions &options) {
58   bool ret = true;
59   if (channel1_) {
60     ret = channel1_->SetOptions(options);
61   }
62   if (channel2_ && ret) {
63     ret = channel2_->SetOptions(options);
64   }
65   return ret;
66 }
67
68 bool HybridVideoMediaChannel::GetOptions(VideoOptions *options) const {
69   if (active_channel_) {
70     return active_channel_->GetOptions(options);
71   }
72   if (channel1_) {
73     return channel1_->GetOptions(options);
74   }
75   if (channel2_) {
76     return channel2_->GetOptions(options);
77   }
78   return false;
79 }
80
81 bool HybridVideoMediaChannel::SetRecvCodecs(
82     const std::vector<VideoCodec>& codecs) {
83   // Only give each channel the codecs it knows about.
84   bool ret = true;
85   std::vector<VideoCodec> codecs1, codecs2;
86   SplitCodecs(codecs, &codecs1, &codecs2);
87   if (channel1_) {
88     ret = channel1_->SetRecvCodecs(codecs1);
89   }
90   if (channel2_ && ret) {
91     ret = channel2_->SetRecvCodecs(codecs2);
92   }
93   return ret;
94 }
95
96 bool HybridVideoMediaChannel::SetRecvRtpHeaderExtensions(
97     const std::vector<RtpHeaderExtension>& extensions) {
98   bool ret = true;
99   if (channel1_) {
100     ret = channel1_->SetRecvRtpHeaderExtensions(extensions);
101   }
102   if (channel2_ && ret) {
103     ret = channel2_->SetRecvRtpHeaderExtensions(extensions);
104   }
105   return ret;
106 }
107
108 bool HybridVideoMediaChannel::SetRenderer(uint32 ssrc,
109                                           VideoRenderer* renderer) {
110   bool ret = true;
111   if (channel1_) {
112     ret = channel1_->SetRenderer(ssrc, renderer);
113   }
114   if (channel2_ && ret) {
115     ret = channel2_->SetRenderer(ssrc, renderer);
116   }
117   return ret;
118 }
119
120 bool HybridVideoMediaChannel::SetRender(bool render) {
121   bool ret = true;
122   if (channel1_) {
123     ret = channel1_->SetRender(render);
124   }
125   if (channel2_ && ret) {
126     ret = channel2_->SetRender(render);
127   }
128   return ret;
129 }
130
131 bool HybridVideoMediaChannel::MuteStream(uint32 ssrc, bool muted) {
132   bool ret = true;
133   if (channel1_) {
134     ret = channel1_->MuteStream(ssrc, muted);
135   }
136   if (channel2_ && ret) {
137     ret = channel2_->MuteStream(ssrc, muted);
138   }
139   return ret;
140 }
141
142 bool HybridVideoMediaChannel::SetSendCodecs(
143     const std::vector<VideoCodec>& codecs) {
144   // Use the input to this function to decide what impl we're going to use.
145   if (!active_channel_ && !SelectActiveChannel(codecs)) {
146     LOG(LS_WARNING) << "Failed to select active channel";
147     return false;
148   }
149   // Only give the active channel the codecs it knows about.
150   std::vector<VideoCodec> codecs1, codecs2;
151   SplitCodecs(codecs, &codecs1, &codecs2);
152   const std::vector<VideoCodec>& codecs_to_set =
153       (active_channel_ == channel1_.get()) ? codecs1 : codecs2;
154   bool return_value = active_channel_->SetSendCodecs(codecs_to_set);
155   if (!return_value) {
156     return false;
157   }
158   VideoCodec send_codec;
159   return_value = active_channel_->GetSendCodec(&send_codec);
160   if (!return_value) {
161     return false;
162   }
163   engine_->OnNewSendResolution(send_codec.width, send_codec.height);
164   active_channel_->UpdateAspectRatio(send_codec.width, send_codec.height);
165   return true;
166 }
167
168 bool HybridVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
169   if (!active_channel_) {
170     return false;
171   }
172   return active_channel_->GetSendCodec(send_codec);
173 }
174
175 bool HybridVideoMediaChannel::SetSendStreamFormat(uint32 ssrc,
176                                                   const VideoFormat& format) {
177   return active_channel_ && active_channel_->SetSendStreamFormat(ssrc, format);
178 }
179
180 bool HybridVideoMediaChannel::SetSendRtpHeaderExtensions(
181     const std::vector<RtpHeaderExtension>& extensions) {
182   return active_channel_ &&
183       active_channel_->SetSendRtpHeaderExtensions(extensions);
184 }
185
186 bool HybridVideoMediaChannel::SetStartSendBandwidth(int bps) {
187   return active_channel_ && active_channel_->SetStartSendBandwidth(bps);
188 }
189
190 bool HybridVideoMediaChannel::SetMaxSendBandwidth(int bps) {
191   return active_channel_ && active_channel_->SetMaxSendBandwidth(bps);
192 }
193
194 bool HybridVideoMediaChannel::SetSend(bool send) {
195   if (send == sending()) {
196     return true;  // no action required if already set.
197   }
198
199   bool ret = active_channel_ &&
200       active_channel_->SetSend(send);
201
202   // Returns error and don't connect the signal if starting up.
203   // Disconnects the signal anyway if shutting down.
204   if (ret || !send) {
205     // TODO(juberti): Remove this hack that connects the WebRTC channel
206     // to the capturer.
207     if (active_channel_ == channel1_.get()) {
208       engine_->OnSendChange1(channel1_.get(), send);
209     } else {
210       engine_->OnSendChange2(channel2_.get(), send);
211     }
212     // If succeeded, remember the state as is.
213     // If failed to open, sending_ should be false.
214     // If failed to stop, sending_ should also be false, as we disconnect the
215     // capture anyway.
216     // The failure on SetSend(false) is a known issue in webrtc.
217     sending_ = send;
218   }
219   return ret;
220 }
221
222 bool HybridVideoMediaChannel::SetCapturer(uint32 ssrc,
223                                           VideoCapturer* capturer) {
224   bool ret = true;
225   if (channel1_.get()) {
226     ret = channel1_->SetCapturer(ssrc, capturer);
227   }
228   if (channel2_.get() && ret) {
229     ret = channel2_->SetCapturer(ssrc, capturer);
230   }
231   return ret;
232 }
233
234 bool HybridVideoMediaChannel::AddSendStream(const StreamParams& sp) {
235   bool ret = true;
236   if (channel1_) {
237     ret = channel1_->AddSendStream(sp);
238   }
239   if (channel2_ && ret) {
240     ret = channel2_->AddSendStream(sp);
241   }
242   return ret;
243 }
244
245 bool HybridVideoMediaChannel::RemoveSendStream(uint32 ssrc) {
246   bool ret = true;
247   if (channel1_) {
248     ret = channel1_->RemoveSendStream(ssrc);
249   }
250   if (channel2_ && ret) {
251     ret = channel2_->RemoveSendStream(ssrc);
252   }
253   return ret;
254 }
255
256 bool HybridVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
257   return active_channel_ &&
258       active_channel_->AddRecvStream(sp);
259 }
260
261 bool HybridVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
262   return active_channel_ &&
263       active_channel_->RemoveRecvStream(ssrc);
264 }
265
266 bool HybridVideoMediaChannel::SendIntraFrame() {
267   return active_channel_ &&
268       active_channel_->SendIntraFrame();
269 }
270
271 bool HybridVideoMediaChannel::RequestIntraFrame() {
272   return active_channel_ &&
273       active_channel_->RequestIntraFrame();
274 }
275
276 bool HybridVideoMediaChannel::GetStats(
277     const StatsOptions& options, VideoMediaInfo* info) {
278   // TODO(juberti): Ensure that returning no stats until SetSendCodecs is OK.
279   return active_channel_ &&
280       active_channel_->GetStats(options, info);
281 }
282
283 void HybridVideoMediaChannel::OnPacketReceived(
284     talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
285   // Eat packets until we have an active channel;
286   if (active_channel_) {
287     active_channel_->OnPacketReceived(packet, packet_time);
288   } else {
289     LOG(LS_INFO) << "HybridVideoChannel: Eating early RTP packet";
290   }
291 }
292
293 void HybridVideoMediaChannel::OnRtcpReceived(
294     talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
295   // Eat packets until we have an active channel;
296   if (active_channel_) {
297     active_channel_->OnRtcpReceived(packet, packet_time);
298   } else {
299     LOG(LS_INFO) << "HybridVideoChannel: Eating early RTCP packet";
300   }
301 }
302
303 void HybridVideoMediaChannel::OnReadyToSend(bool ready) {
304   if (channel1_) {
305     channel1_->OnReadyToSend(ready);
306   }
307   if (channel2_) {
308     channel2_->OnReadyToSend(ready);
309   }
310 }
311
312 void HybridVideoMediaChannel::UpdateAspectRatio(int ratio_w, int ratio_h) {
313   if (active_channel_) active_channel_->UpdateAspectRatio(ratio_w, ratio_h);
314 }
315
316 bool HybridVideoMediaChannel::SelectActiveChannel(
317     const std::vector<VideoCodec>& codecs) {
318   if (!active_channel_ && !codecs.empty()) {
319     if (engine_->HasCodec1(codecs[0])) {
320       channel2_.reset();
321       active_channel_ = channel1_.get();
322     } else if (engine_->HasCodec2(codecs[0])) {
323       channel1_.reset();
324       active_channel_ = channel2_.get();
325     }
326   }
327   if (NULL == active_channel_) {
328     return false;
329   }
330   // Connect signals from the active channel.
331   active_channel_->SignalMediaError.connect(
332       this,
333       &HybridVideoMediaChannel::OnMediaError);
334   return true;
335 }
336
337 void HybridVideoMediaChannel::SplitCodecs(
338     const std::vector<VideoCodec>& codecs,
339     std::vector<VideoCodec>* codecs1, std::vector<VideoCodec>* codecs2) {
340   codecs1->clear();
341   codecs2->clear();
342   for (size_t i = 0; i < codecs.size(); ++i) {
343     if (engine_->HasCodec1(codecs[i])) {
344       codecs1->push_back(codecs[i]);
345     }
346     if (engine_->HasCodec2(codecs[i])) {
347       codecs2->push_back(codecs[i]);
348     }
349   }
350 }
351
352 void HybridVideoMediaChannel::OnMediaError(uint32 ssrc, Error error) {
353   SignalMediaError(ssrc, error);
354 }
355
356 }  // namespace cricket