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
HybridVideoMediaChannel(HybridVideoEngineInterface * engine,VideoMediaChannel * channel1,VideoMediaChannel * channel2)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
~HybridVideoMediaChannel()45 HybridVideoMediaChannel::~HybridVideoMediaChannel() {
46 }
47
SetInterface(NetworkInterface * iface)48 void HybridVideoMediaChannel::SetInterface(NetworkInterface* iface) {
49 if (channel1_) {
50 channel1_->SetInterface(iface);
51 }
52 if (channel2_) {
53 channel2_->SetInterface(iface);
54 }
55 }
56
SetOptions(const VideoOptions & options)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
GetOptions(VideoOptions * options) const68 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
SetRecvCodecs(const std::vector<VideoCodec> & codecs)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
SetRecvRtpHeaderExtensions(const std::vector<RtpHeaderExtension> & extensions)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
SetRenderer(uint32 ssrc,VideoRenderer * renderer)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
SetRender(bool render)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
MuteStream(uint32 ssrc,bool muted)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
SetSendCodecs(const std::vector<VideoCodec> & codecs)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
GetSendCodec(VideoCodec * send_codec)168 bool HybridVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
169 if (!active_channel_) {
170 return false;
171 }
172 return active_channel_->GetSendCodec(send_codec);
173 }
174
SetSendStreamFormat(uint32 ssrc,const VideoFormat & format)175 bool HybridVideoMediaChannel::SetSendStreamFormat(uint32 ssrc,
176 const VideoFormat& format) {
177 return active_channel_ && active_channel_->SetSendStreamFormat(ssrc, format);
178 }
179
SetSendRtpHeaderExtensions(const std::vector<RtpHeaderExtension> & extensions)180 bool HybridVideoMediaChannel::SetSendRtpHeaderExtensions(
181 const std::vector<RtpHeaderExtension>& extensions) {
182 return active_channel_ &&
183 active_channel_->SetSendRtpHeaderExtensions(extensions);
184 }
185
SetStartSendBandwidth(int bps)186 bool HybridVideoMediaChannel::SetStartSendBandwidth(int bps) {
187 return active_channel_ && active_channel_->SetStartSendBandwidth(bps);
188 }
189
SetMaxSendBandwidth(int bps)190 bool HybridVideoMediaChannel::SetMaxSendBandwidth(int bps) {
191 return active_channel_ && active_channel_->SetMaxSendBandwidth(bps);
192 }
193
SetSend(bool send)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
SetCapturer(uint32 ssrc,VideoCapturer * capturer)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
AddSendStream(const StreamParams & sp)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
RemoveSendStream(uint32 ssrc)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
AddRecvStream(const StreamParams & sp)256 bool HybridVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
257 return active_channel_ &&
258 active_channel_->AddRecvStream(sp);
259 }
260
RemoveRecvStream(uint32 ssrc)261 bool HybridVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
262 return active_channel_ &&
263 active_channel_->RemoveRecvStream(ssrc);
264 }
265
SendIntraFrame()266 bool HybridVideoMediaChannel::SendIntraFrame() {
267 return active_channel_ &&
268 active_channel_->SendIntraFrame();
269 }
270
RequestIntraFrame()271 bool HybridVideoMediaChannel::RequestIntraFrame() {
272 return active_channel_ &&
273 active_channel_->RequestIntraFrame();
274 }
275
GetStats(const StatsOptions & options,VideoMediaInfo * info)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
OnPacketReceived(talk_base::Buffer * packet,const talk_base::PacketTime & packet_time)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
OnRtcpReceived(talk_base::Buffer * packet,const talk_base::PacketTime & packet_time)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
OnReadyToSend(bool ready)303 void HybridVideoMediaChannel::OnReadyToSend(bool ready) {
304 if (channel1_) {
305 channel1_->OnReadyToSend(ready);
306 }
307 if (channel2_) {
308 channel2_->OnReadyToSend(ready);
309 }
310 }
311
UpdateAspectRatio(int ratio_w,int ratio_h)312 void HybridVideoMediaChannel::UpdateAspectRatio(int ratio_w, int ratio_h) {
313 if (active_channel_) active_channel_->UpdateAspectRatio(ratio_w, ratio_h);
314 }
315
SelectActiveChannel(const std::vector<VideoCodec> & codecs)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
SplitCodecs(const std::vector<VideoCodec> & codecs,std::vector<VideoCodec> * codecs1,std::vector<VideoCodec> * codecs2)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
OnMediaError(uint32 ssrc,Error error)352 void HybridVideoMediaChannel::OnMediaError(uint32 ssrc, Error error) {
353 SignalMediaError(ssrc, error);
354 }
355
356 } // namespace cricket
357