blob: 6a26fcc457d134366f96eabcd4fcd1fbed1a6ecb [file] [log] [blame]
Sebastian Janssoncb06cac2018-10-18 17:03:30 +02001/*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "media/base/fakemediaengine.h"
12
13#include <utility>
14
Niels Möller3c7d5992018-10-19 15:29:54 +020015#include "absl/strings/match.h"
Sebastian Janssoncb06cac2018-10-18 17:03:30 +020016#include "rtc_base/checks.h"
17
18namespace cricket {
19
20FakeVoiceMediaChannel::DtmfInfo::DtmfInfo(uint32_t ssrc,
21 int event_code,
22 int duration)
23 : ssrc(ssrc), event_code(event_code), duration(duration) {}
24
25FakeVoiceMediaChannel::VoiceChannelAudioSink::VoiceChannelAudioSink(
26 AudioSource* source)
27 : source_(source) {
28 source_->SetSink(this);
29}
30FakeVoiceMediaChannel::VoiceChannelAudioSink::~VoiceChannelAudioSink() {
31 if (source_) {
32 source_->SetSink(nullptr);
33 }
34}
35void FakeVoiceMediaChannel::VoiceChannelAudioSink::OnData(
36 const void* audio_data,
37 int bits_per_sample,
38 int sample_rate,
39 size_t number_of_channels,
40 size_t number_of_frames) {}
41void FakeVoiceMediaChannel::VoiceChannelAudioSink::OnClose() {
42 source_ = nullptr;
43}
44AudioSource* FakeVoiceMediaChannel::VoiceChannelAudioSink::source() const {
45 return source_;
46}
47
48FakeVoiceMediaChannel::FakeVoiceMediaChannel(FakeVoiceEngine* engine,
49 const AudioOptions& options)
50 : engine_(engine), max_bps_(-1) {
51 output_scalings_[0] = 1.0; // For default channel.
52 SetOptions(options);
53}
54FakeVoiceMediaChannel::~FakeVoiceMediaChannel() {
55 if (engine_) {
56 engine_->UnregisterChannel(this);
57 }
58}
59const std::vector<AudioCodec>& FakeVoiceMediaChannel::recv_codecs() const {
60 return recv_codecs_;
61}
62const std::vector<AudioCodec>& FakeVoiceMediaChannel::send_codecs() const {
63 return send_codecs_;
64}
65const std::vector<AudioCodec>& FakeVoiceMediaChannel::codecs() const {
66 return send_codecs();
67}
68const std::vector<FakeVoiceMediaChannel::DtmfInfo>&
69FakeVoiceMediaChannel::dtmf_info_queue() const {
70 return dtmf_info_queue_;
71}
72const AudioOptions& FakeVoiceMediaChannel::options() const {
73 return options_;
74}
75int FakeVoiceMediaChannel::max_bps() const {
76 return max_bps_;
77}
78bool FakeVoiceMediaChannel::SetSendParameters(
79 const AudioSendParameters& params) {
80 set_send_rtcp_parameters(params.rtcp);
81 return (SetSendCodecs(params.codecs) &&
82 SetSendRtpHeaderExtensions(params.extensions) &&
83 SetMaxSendBandwidth(params.max_bandwidth_bps) &&
84 SetOptions(params.options));
85}
86bool FakeVoiceMediaChannel::SetRecvParameters(
87 const AudioRecvParameters& params) {
88 set_recv_rtcp_parameters(params.rtcp);
89 return (SetRecvCodecs(params.codecs) &&
90 SetRecvRtpHeaderExtensions(params.extensions));
91}
92void FakeVoiceMediaChannel::SetPlayout(bool playout) {
93 set_playout(playout);
94}
95void FakeVoiceMediaChannel::SetSend(bool send) {
96 set_sending(send);
97}
98bool FakeVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
99 bool enable,
100 const AudioOptions* options,
101 AudioSource* source) {
102 if (!SetLocalSource(ssrc, source)) {
103 return false;
104 }
105 if (!RtpHelper<VoiceMediaChannel>::MuteStream(ssrc, !enable)) {
106 return false;
107 }
108 if (enable && options) {
109 return SetOptions(*options);
110 }
111 return true;
112}
113bool FakeVoiceMediaChannel::HasSource(uint32_t ssrc) const {
114 return local_sinks_.find(ssrc) != local_sinks_.end();
115}
116bool FakeVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
117 if (!RtpHelper<VoiceMediaChannel>::AddRecvStream(sp))
118 return false;
119 output_scalings_[sp.first_ssrc()] = 1.0;
120 return true;
121}
122bool FakeVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
123 if (!RtpHelper<VoiceMediaChannel>::RemoveRecvStream(ssrc))
124 return false;
125 output_scalings_.erase(ssrc);
126 return true;
127}
128bool FakeVoiceMediaChannel::CanInsertDtmf() {
129 for (std::vector<AudioCodec>::const_iterator it = send_codecs_.begin();
130 it != send_codecs_.end(); ++it) {
131 // Find the DTMF telephone event "codec".
Niels Möller3c7d5992018-10-19 15:29:54 +0200132 if (absl::EqualsIgnoreCase(it->name, "telephone-event")) {
Sebastian Janssoncb06cac2018-10-18 17:03:30 +0200133 return true;
134 }
135 }
136 return false;
137}
138bool FakeVoiceMediaChannel::InsertDtmf(uint32_t ssrc,
139 int event_code,
140 int duration) {
141 dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration));
142 return true;
143}
144bool FakeVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
145 if (0 == ssrc) {
146 std::map<uint32_t, double>::iterator it;
147 for (it = output_scalings_.begin(); it != output_scalings_.end(); ++it) {
148 it->second = volume;
149 }
150 return true;
151 } else if (output_scalings_.find(ssrc) != output_scalings_.end()) {
152 output_scalings_[ssrc] = volume;
153 return true;
154 }
155 return false;
156}
157bool FakeVoiceMediaChannel::GetOutputVolume(uint32_t ssrc, double* volume) {
158 if (output_scalings_.find(ssrc) == output_scalings_.end())
159 return false;
160 *volume = output_scalings_[ssrc];
161 return true;
162}
163bool FakeVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
164 return false;
165}
166void FakeVoiceMediaChannel::SetRawAudioSink(
167 uint32_t ssrc,
168 std::unique_ptr<webrtc::AudioSinkInterface> sink) {
169 sink_ = std::move(sink);
170}
171std::vector<webrtc::RtpSource> FakeVoiceMediaChannel::GetSources(
172 uint32_t ssrc) const {
173 return std::vector<webrtc::RtpSource>();
174}
175bool FakeVoiceMediaChannel::SetRecvCodecs(
176 const std::vector<AudioCodec>& codecs) {
177 if (fail_set_recv_codecs()) {
178 // Fake the failure in SetRecvCodecs.
179 return false;
180 }
181 recv_codecs_ = codecs;
182 return true;
183}
184bool FakeVoiceMediaChannel::SetSendCodecs(
185 const std::vector<AudioCodec>& codecs) {
186 if (fail_set_send_codecs()) {
187 // Fake the failure in SetSendCodecs.
188 return false;
189 }
190 send_codecs_ = codecs;
191 return true;
192}
193bool FakeVoiceMediaChannel::SetMaxSendBandwidth(int bps) {
194 max_bps_ = bps;
195 return true;
196}
197bool FakeVoiceMediaChannel::SetOptions(const AudioOptions& options) {
198 // Does a "merge" of current options and set options.
199 options_.SetAll(options);
200 return true;
201}
202bool FakeVoiceMediaChannel::SetLocalSource(uint32_t ssrc, AudioSource* source) {
203 auto it = local_sinks_.find(ssrc);
204 if (source) {
205 if (it != local_sinks_.end()) {
206 RTC_CHECK(it->second->source() == source);
207 } else {
208 local_sinks_.insert(std::make_pair(
209 ssrc, absl::make_unique<VoiceChannelAudioSink>(source)));
210 }
211 } else {
212 if (it != local_sinks_.end()) {
213 local_sinks_.erase(it);
214 }
215 }
216 return true;
217}
218
219bool CompareDtmfInfo(const FakeVoiceMediaChannel::DtmfInfo& info,
220 uint32_t ssrc,
221 int event_code,
222 int duration) {
223 return (info.duration == duration && info.event_code == event_code &&
224 info.ssrc == ssrc);
225}
226
227FakeVideoMediaChannel::FakeVideoMediaChannel(FakeVideoEngine* engine,
228 const VideoOptions& options)
229 : engine_(engine), max_bps_(-1) {
230 SetOptions(options);
231}
232FakeVideoMediaChannel::~FakeVideoMediaChannel() {
233 if (engine_) {
234 engine_->UnregisterChannel(this);
235 }
236}
237const std::vector<VideoCodec>& FakeVideoMediaChannel::recv_codecs() const {
238 return recv_codecs_;
239}
240const std::vector<VideoCodec>& FakeVideoMediaChannel::send_codecs() const {
241 return send_codecs_;
242}
243const std::vector<VideoCodec>& FakeVideoMediaChannel::codecs() const {
244 return send_codecs();
245}
246bool FakeVideoMediaChannel::rendering() const {
247 return playout();
248}
249const VideoOptions& FakeVideoMediaChannel::options() const {
250 return options_;
251}
252const std::map<uint32_t, rtc::VideoSinkInterface<webrtc::VideoFrame>*>&
253FakeVideoMediaChannel::sinks() const {
254 return sinks_;
255}
256int FakeVideoMediaChannel::max_bps() const {
257 return max_bps_;
258}
259bool FakeVideoMediaChannel::SetSendParameters(
260 const VideoSendParameters& params) {
261 set_send_rtcp_parameters(params.rtcp);
262 return (SetSendCodecs(params.codecs) &&
263 SetSendRtpHeaderExtensions(params.extensions) &&
264 SetMaxSendBandwidth(params.max_bandwidth_bps));
265}
266bool FakeVideoMediaChannel::SetRecvParameters(
267 const VideoRecvParameters& params) {
268 set_recv_rtcp_parameters(params.rtcp);
269 return (SetRecvCodecs(params.codecs) &&
270 SetRecvRtpHeaderExtensions(params.extensions));
271}
272bool FakeVideoMediaChannel::AddSendStream(const StreamParams& sp) {
273 return RtpHelper<VideoMediaChannel>::AddSendStream(sp);
274}
275bool FakeVideoMediaChannel::RemoveSendStream(uint32_t ssrc) {
276 return RtpHelper<VideoMediaChannel>::RemoveSendStream(ssrc);
277}
278bool FakeVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
279 if (send_codecs_.empty()) {
280 return false;
281 }
282 *send_codec = send_codecs_[0];
283 return true;
284}
285bool FakeVideoMediaChannel::SetSink(
286 uint32_t ssrc,
287 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
288 if (ssrc != 0 && sinks_.find(ssrc) == sinks_.end()) {
289 return false;
290 }
291 if (ssrc != 0) {
292 sinks_[ssrc] = sink;
293 }
294 return true;
295}
296bool FakeVideoMediaChannel::HasSink(uint32_t ssrc) const {
297 return sinks_.find(ssrc) != sinks_.end() && sinks_.at(ssrc) != nullptr;
298}
299bool FakeVideoMediaChannel::SetSend(bool send) {
300 return set_sending(send);
301}
302bool FakeVideoMediaChannel::SetVideoSend(
303 uint32_t ssrc,
304 const VideoOptions* options,
305 rtc::VideoSourceInterface<webrtc::VideoFrame>* source) {
306 if (options) {
307 if (!SetOptions(*options)) {
308 return false;
309 }
310 }
311 sources_[ssrc] = source;
312 return true;
313}
314bool FakeVideoMediaChannel::HasSource(uint32_t ssrc) const {
315 return sources_.find(ssrc) != sources_.end() && sources_.at(ssrc) != nullptr;
316}
317bool FakeVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
318 if (!RtpHelper<VideoMediaChannel>::AddRecvStream(sp))
319 return false;
320 sinks_[sp.first_ssrc()] = NULL;
321 return true;
322}
323bool FakeVideoMediaChannel::RemoveRecvStream(uint32_t ssrc) {
324 if (!RtpHelper<VideoMediaChannel>::RemoveRecvStream(ssrc))
325 return false;
326 sinks_.erase(ssrc);
327 return true;
328}
329void FakeVideoMediaChannel::FillBitrateInfo(BandwidthEstimationInfo* bwe_info) {
330}
331bool FakeVideoMediaChannel::GetStats(VideoMediaInfo* info) {
332 return false;
333}
334std::vector<webrtc::RtpSource> FakeVideoMediaChannel::GetSources(
335 uint32_t ssrc) const {
336 return {};
337}
338bool FakeVideoMediaChannel::SetRecvCodecs(
339 const std::vector<VideoCodec>& codecs) {
340 if (fail_set_recv_codecs()) {
341 // Fake the failure in SetRecvCodecs.
342 return false;
343 }
344 recv_codecs_ = codecs;
345 return true;
346}
347bool FakeVideoMediaChannel::SetSendCodecs(
348 const std::vector<VideoCodec>& codecs) {
349 if (fail_set_send_codecs()) {
350 // Fake the failure in SetSendCodecs.
351 return false;
352 }
353 send_codecs_ = codecs;
354
355 return true;
356}
357bool FakeVideoMediaChannel::SetOptions(const VideoOptions& options) {
358 options_ = options;
359 return true;
360}
361bool FakeVideoMediaChannel::SetMaxSendBandwidth(int bps) {
362 max_bps_ = bps;
363 return true;
364}
365
366FakeDataMediaChannel::FakeDataMediaChannel(void* unused,
367 const DataOptions& options)
368 : send_blocked_(false), max_bps_(-1) {}
369FakeDataMediaChannel::~FakeDataMediaChannel() {}
370const std::vector<DataCodec>& FakeDataMediaChannel::recv_codecs() const {
371 return recv_codecs_;
372}
373const std::vector<DataCodec>& FakeDataMediaChannel::send_codecs() const {
374 return send_codecs_;
375}
376const std::vector<DataCodec>& FakeDataMediaChannel::codecs() const {
377 return send_codecs();
378}
379int FakeDataMediaChannel::max_bps() const {
380 return max_bps_;
381}
382bool FakeDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
383 set_send_rtcp_parameters(params.rtcp);
384 return (SetSendCodecs(params.codecs) &&
385 SetMaxSendBandwidth(params.max_bandwidth_bps));
386}
387bool FakeDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
388 set_recv_rtcp_parameters(params.rtcp);
389 return SetRecvCodecs(params.codecs);
390}
391bool FakeDataMediaChannel::SetSend(bool send) {
392 return set_sending(send);
393}
394bool FakeDataMediaChannel::SetReceive(bool receive) {
395 set_playout(receive);
396 return true;
397}
398bool FakeDataMediaChannel::AddRecvStream(const StreamParams& sp) {
399 if (!RtpHelper<DataMediaChannel>::AddRecvStream(sp))
400 return false;
401 return true;
402}
403bool FakeDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
404 if (!RtpHelper<DataMediaChannel>::RemoveRecvStream(ssrc))
405 return false;
406 return true;
407}
408bool FakeDataMediaChannel::SendData(const SendDataParams& params,
409 const rtc::CopyOnWriteBuffer& payload,
410 SendDataResult* result) {
411 if (send_blocked_) {
412 *result = SDR_BLOCK;
413 return false;
414 } else {
415 last_sent_data_params_ = params;
416 last_sent_data_ = std::string(payload.data<char>(), payload.size());
417 return true;
418 }
419}
420SendDataParams FakeDataMediaChannel::last_sent_data_params() {
421 return last_sent_data_params_;
422}
423std::string FakeDataMediaChannel::last_sent_data() {
424 return last_sent_data_;
425}
426bool FakeDataMediaChannel::is_send_blocked() {
427 return send_blocked_;
428}
429void FakeDataMediaChannel::set_send_blocked(bool blocked) {
430 send_blocked_ = blocked;
431}
432bool FakeDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
433 if (fail_set_recv_codecs()) {
434 // Fake the failure in SetRecvCodecs.
435 return false;
436 }
437 recv_codecs_ = codecs;
438 return true;
439}
440bool FakeDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
441 if (fail_set_send_codecs()) {
442 // Fake the failure in SetSendCodecs.
443 return false;
444 }
445 send_codecs_ = codecs;
446 return true;
447}
448bool FakeDataMediaChannel::SetMaxSendBandwidth(int bps) {
449 max_bps_ = bps;
450 return true;
451}
452
453FakeBaseEngine::FakeBaseEngine()
454 : options_changed_(false), fail_create_channel_(false) {}
455void FakeBaseEngine::set_fail_create_channel(bool fail) {
456 fail_create_channel_ = fail;
457}
458void FakeBaseEngine::set_rtp_header_extensions(
459 const std::vector<webrtc::RtpExtension>& extensions) {
460 capabilities_.header_extensions = extensions;
461}
462void FakeBaseEngine::set_rtp_header_extensions(
463 const std::vector<RtpHeaderExtension>& extensions) {
464 for (const cricket::RtpHeaderExtension& ext : extensions) {
465 RtpExtension webrtc_ext;
466 webrtc_ext.uri = ext.uri;
467 webrtc_ext.id = ext.id;
468 capabilities_.header_extensions.push_back(webrtc_ext);
469 }
470}
471
472FakeVoiceEngine::FakeVoiceEngine() {
473 // Add a fake audio codec. Note that the name must not be "" as there are
474 // sanity checks against that.
475 codecs_.push_back(AudioCodec(101, "fake_audio_codec", 0, 0, 1));
476}
477RtpCapabilities FakeVoiceEngine::GetCapabilities() const {
478 return capabilities_;
479}
480void FakeVoiceEngine::Init() {}
481rtc::scoped_refptr<webrtc::AudioState> FakeVoiceEngine::GetAudioState() const {
482 return rtc::scoped_refptr<webrtc::AudioState>();
483}
484VoiceMediaChannel* FakeVoiceEngine::CreateChannel(
485 webrtc::Call* call,
486 const MediaConfig& config,
487 const AudioOptions& options,
488 const webrtc::CryptoOptions& crypto_options) {
489 if (fail_create_channel_) {
490 return nullptr;
491 }
492
493 FakeVoiceMediaChannel* ch = new FakeVoiceMediaChannel(this, options);
494 channels_.push_back(ch);
495 return ch;
496}
497FakeVoiceMediaChannel* FakeVoiceEngine::GetChannel(size_t index) {
498 return (channels_.size() > index) ? channels_[index] : NULL;
499}
500void FakeVoiceEngine::UnregisterChannel(VoiceMediaChannel* channel) {
501 channels_.erase(std::find(channels_.begin(), channels_.end(), channel));
502}
503const std::vector<AudioCodec>& FakeVoiceEngine::send_codecs() const {
504 return codecs_;
505}
506const std::vector<AudioCodec>& FakeVoiceEngine::recv_codecs() const {
507 return codecs_;
508}
509void FakeVoiceEngine::SetCodecs(const std::vector<AudioCodec>& codecs) {
510 codecs_ = codecs;
511}
512int FakeVoiceEngine::GetInputLevel() {
513 return 0;
514}
515bool FakeVoiceEngine::StartAecDump(rtc::PlatformFile file,
516 int64_t max_size_bytes) {
517 return false;
518}
519void FakeVoiceEngine::StopAecDump() {}
520bool FakeVoiceEngine::StartRtcEventLog(rtc::PlatformFile file,
521 int64_t max_size_bytes) {
522 return false;
523}
524void FakeVoiceEngine::StopRtcEventLog() {}
525
526FakeVideoEngine::FakeVideoEngine() : capture_(false) {
527 // Add a fake video codec. Note that the name must not be "" as there are
528 // sanity checks against that.
529 codecs_.push_back(VideoCodec(0, "fake_video_codec"));
530}
531RtpCapabilities FakeVideoEngine::GetCapabilities() const {
532 return capabilities_;
533}
534bool FakeVideoEngine::SetOptions(const VideoOptions& options) {
535 options_ = options;
536 options_changed_ = true;
537 return true;
538}
539VideoMediaChannel* FakeVideoEngine::CreateChannel(
540 webrtc::Call* call,
541 const MediaConfig& config,
542 const VideoOptions& options,
543 const webrtc::CryptoOptions& crypto_options) {
544 if (fail_create_channel_) {
545 return nullptr;
546 }
547
548 FakeVideoMediaChannel* ch = new FakeVideoMediaChannel(this, options);
549 channels_.emplace_back(ch);
550 return ch;
551}
552FakeVideoMediaChannel* FakeVideoEngine::GetChannel(size_t index) {
553 return (channels_.size() > index) ? channels_[index] : nullptr;
554}
555void FakeVideoEngine::UnregisterChannel(VideoMediaChannel* channel) {
556 auto it = std::find(channels_.begin(), channels_.end(), channel);
557 RTC_DCHECK(it != channels_.end());
558 channels_.erase(it);
559}
560std::vector<VideoCodec> FakeVideoEngine::codecs() const {
561 return codecs_;
562}
563void FakeVideoEngine::SetCodecs(const std::vector<VideoCodec> codecs) {
564 codecs_ = codecs;
565}
566bool FakeVideoEngine::SetCapture(bool capture) {
567 capture_ = capture;
568 return true;
569}
570
571FakeMediaEngine::FakeMediaEngine()
572 : CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine>(std::tuple<>(),
573 std::tuple<>()),
574 voice_(&voice()),
575 video_(&video()) {}
576FakeMediaEngine::~FakeMediaEngine() {}
577void FakeMediaEngine::SetAudioCodecs(const std::vector<AudioCodec>& codecs) {
578 voice_->SetCodecs(codecs);
579}
580void FakeMediaEngine::SetVideoCodecs(const std::vector<VideoCodec>& codecs) {
581 video_->SetCodecs(codecs);
582}
583void FakeMediaEngine::SetAudioRtpHeaderExtensions(
584 const std::vector<webrtc::RtpExtension>& extensions) {
585 voice_->set_rtp_header_extensions(extensions);
586}
587void FakeMediaEngine::SetVideoRtpHeaderExtensions(
588 const std::vector<webrtc::RtpExtension>& extensions) {
589 video_->set_rtp_header_extensions(extensions);
590}
591void FakeMediaEngine::SetAudioRtpHeaderExtensions(
592 const std::vector<RtpHeaderExtension>& extensions) {
593 voice_->set_rtp_header_extensions(extensions);
594}
595void FakeMediaEngine::SetVideoRtpHeaderExtensions(
596 const std::vector<RtpHeaderExtension>& extensions) {
597 video_->set_rtp_header_extensions(extensions);
598}
599FakeVoiceMediaChannel* FakeMediaEngine::GetVoiceChannel(size_t index) {
600 return voice_->GetChannel(index);
601}
602FakeVideoMediaChannel* FakeMediaEngine::GetVideoChannel(size_t index) {
603 return video_->GetChannel(index);
604}
605
606bool FakeMediaEngine::capture() const {
607 return video_->capture_;
608}
609bool FakeMediaEngine::options_changed() const {
610 return video_->options_changed_;
611}
612void FakeMediaEngine::clear_options_changed() {
613 video_->options_changed_ = false;
614}
615void FakeMediaEngine::set_fail_create_channel(bool fail) {
616 voice_->set_fail_create_channel(fail);
617 video_->set_fail_create_channel(fail);
618}
619
620DataMediaChannel* FakeDataEngine::CreateChannel(const MediaConfig& config) {
621 FakeDataMediaChannel* ch = new FakeDataMediaChannel(this, DataOptions());
622 channels_.push_back(ch);
623 return ch;
624}
625FakeDataMediaChannel* FakeDataEngine::GetChannel(size_t index) {
626 return (channels_.size() > index) ? channels_[index] : NULL;
627}
628void FakeDataEngine::UnregisterChannel(DataMediaChannel* channel) {
629 channels_.erase(std::find(channels_.begin(), channels_.end(), channel));
630}
631void FakeDataEngine::SetDataCodecs(const std::vector<DataCodec>& data_codecs) {
632 data_codecs_ = data_codecs;
633}
634const std::vector<DataCodec>& FakeDataEngine::data_codecs() {
635 return data_codecs_;
636}
637
638} // namespace cricket