diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9d15924 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false diff --git a/tgcalls/AudioFrame.h b/tgcalls/AudioFrame.h new file mode 100644 index 0000000..bfb2cf0 --- /dev/null +++ b/tgcalls/AudioFrame.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace tgcalls { +struct AudioFrame { + const int16_t *audio_samples; + size_t num_samples; + size_t bytes_per_sample; + size_t num_channels; + uint32_t samples_per_sec; + int64_t elapsed_time_ms; + int64_t ntp_time_ms; +}; +} // namespace tgcalls diff --git a/tgcalls/FakeAudioDeviceModule.cpp b/tgcalls/FakeAudioDeviceModule.cpp new file mode 100644 index 0000000..4c5d7d6 --- /dev/null +++ b/tgcalls/FakeAudioDeviceModule.cpp @@ -0,0 +1,179 @@ +#include "FakeAudioDeviceModule.h" + +#include "modules/audio_device/include/audio_device_default.h" +#include "rtc_base/ref_counted_object.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/time_utils.h" + +#include + +namespace tgcalls { +class FakeAudioDeviceModuleImpl : public webrtc::webrtc_impl::AudioDeviceModuleDefault { + public: + static rtc::scoped_refptr Create(webrtc::TaskQueueFactory* taskQueueFactory, + std::shared_ptr renderer, + FakeAudioDeviceModule::Options options) { + return rtc::scoped_refptr( + new rtc::RefCountedObject(taskQueueFactory, options, std::move(renderer))); + } + + FakeAudioDeviceModuleImpl(webrtc::TaskQueueFactory*, FakeAudioDeviceModule::Options options, + std::shared_ptr renderer) + : num_channels_{options.num_channels}, samples_per_sec_{options.samples_per_sec}, renderer_(std::move(renderer)) { + RTC_CHECK(num_channels_ == 1 || num_channels_ == 2); + auto good_sample_rate = [](size_t sr) { + return sr == 8000 || sr == 16000 || sr == 32000 || sr == 44100 || sr == 48000; + }; + RTC_CHECK(good_sample_rate(samples_per_sec_)); + samples_per_frame_ = samples_per_sec_ / 100; + playout_buffer_.resize(samples_per_frame_ * 2 /* 2 in case stereo will be turned on later */, 0); + } + + ~FakeAudioDeviceModuleImpl() override { + StopPlayout(); + } + + int32_t PlayoutIsAvailable(bool* available) override { + if (available) { + *available = true; + } + return 0; + } + + int32_t StereoPlayoutIsAvailable(bool* available) const override { + if (available) { + *available = true; + } + return 0; + } + int32_t StereoPlayout(bool* enabled) const override { + if (enabled) { + *enabled = num_channels_ == 2; + } + return 0; + } + int32_t SetStereoPlayout(bool enable) override { + size_t new_num_channels = enable ? 2 : 1; + if (new_num_channels != num_channels_) { + return -1; + } + return 0; + } + + int32_t Init() override { + return 0; + } + + int32_t RegisterAudioCallback(webrtc::AudioTransport* callback) override { + webrtc::MutexLock lock(&lock_); + audio_callback_ = callback; + return 0; + } + + int32_t StartPlayout() override { + webrtc::MutexLock lock(&lock_); + RTC_CHECK(renderer_); + if (rendering_) { + return 0; + } + rendering_ = true; + renderThread_ = std::make_unique( + RenderThreadFunction, this, "webrtc_fake_audio_module_capture_thread", rtc::kRealtimePriority); + renderThread_->Start(); + + return 0; + } + + int32_t StopPlayout() override { + if (!rendering_) { + return 0; + } + decltype(renderThread_) thread; + + { + webrtc::MutexLock lock(&lock_); + thread = std::move(renderThread_); + rendering_ = false; + } + + thread->Stop(); + return 0; + } + + bool Playing() const override { + return rendering_; + } + + private: + static void RenderThreadFunction(void* pThis) { + auto* device = static_cast(pThis); + while (true) { + int wait_for_us = device->Render(); + if (wait_for_us < 0) { + break; + } + std::this_thread::sleep_for(std::chrono::microseconds(wait_for_us)); + } + } + + int32_t Render() { + webrtc::MutexLock lock(&lock_); + if (!rendering_) { + return -1; + } + size_t samples_out = 0; + int64_t elapsed_time_ms = -1; + int64_t ntp_time_ms = -1; + size_t bytes_per_sample = 2; + + RTC_CHECK(audio_callback_); + if (renderer_) { + renderer_->BeginFrame(0); + } + audio_callback_->NeedMorePlayData(samples_per_frame_, bytes_per_sample, num_channels_, samples_per_sec_, + playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); + if (renderer_) { + renderer_->EndFrame(); + } + if (samples_out != 0 && renderer_) { + AudioFrame frame; + frame.audio_samples = playout_buffer_.data(); + frame.num_samples = samples_out; + frame.bytes_per_sample = bytes_per_sample; + frame.num_channels = num_channels_; + frame.samples_per_sec = samples_per_sec_; + frame.elapsed_time_ms = elapsed_time_ms; + frame.ntp_time_ms = ntp_time_ms; + renderer_->Render(frame); + } + int32_t wait_for_us = -1; + if (renderer_) { + wait_for_us = renderer_->WaitForUs(); + } + return wait_for_us; + } + + size_t num_channels_; + const uint32_t samples_per_sec_; + size_t samples_per_frame_{0}; + + mutable webrtc::Mutex lock_; + std::atomic rendering_{false}; + std::unique_ptr renderThread_; + + webrtc::AudioTransport* audio_callback_{nullptr}; + const std::shared_ptr renderer_ RTC_GUARDED_BY(lock_); + std::vector playout_buffer_ RTC_GUARDED_BY(lock_); +}; + +std::function(webrtc::TaskQueueFactory*)> FakeAudioDeviceModule::Creator( + std::shared_ptr renderer, Options options) { + bool is_renderer_empty = bool(renderer); + auto boxed_renderer = std::make_shared>(std::move(renderer)); + return + [boxed_renderer = std::move(boxed_renderer), is_renderer_empty, options](webrtc::TaskQueueFactory* task_factory) { + RTC_CHECK(is_renderer_empty == bool(*boxed_renderer)); // call only once if renderer exists + return FakeAudioDeviceModuleImpl::Create(task_factory, std::move(*boxed_renderer), options); + }; +} +} // namespace tgcalls diff --git a/tgcalls/FakeAudioDeviceModule.h b/tgcalls/FakeAudioDeviceModule.h new file mode 100644 index 0000000..e383389 --- /dev/null +++ b/tgcalls/FakeAudioDeviceModule.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "AudioFrame.h" + +namespace webrtc { +class AudioDeviceModule; +class TaskQueueFactory; +} // namespace webrtc + +namespace rtc { +template +class scoped_refptr; +} + +namespace tgcalls { +class FakeAudioDeviceModule { + public: + class Renderer { + public: + virtual ~Renderer() = default; + virtual bool Render(const AudioFrame &samples) = 0; + virtual void BeginFrame(double timestamp) { + } + virtual void AddFrameChannel(uint32_t ssrc, const tgcalls::AudioFrame &frame) { + } + virtual void EndFrame() { + } + virtual int32_t WaitForUs() { + return 10000; + } + }; + struct Options { + uint32_t samples_per_sec{48000}; + uint32_t num_channels{2}; + }; + static std::function(webrtc::TaskQueueFactory *)> Creator( + std::shared_ptr renderer, Options options); +}; +} // namespace tgcalls diff --git a/tgcalls/StaticThreads.cpp b/tgcalls/StaticThreads.cpp index 69d1550..ba9f419 100644 --- a/tgcalls/StaticThreads.cpp +++ b/tgcalls/StaticThreads.cpp @@ -2,46 +2,134 @@ #include "rtc_base/thread.h" +#include +#include + namespace tgcalls { +template +class Pool : public std::enable_shared_from_this> { + struct Entry { + std::unique_ptr value; + size_t refcnt; + + bool operator < (const Entry &other) const { + return refcnt < other.refcnt; + } + }; + +public: + explicit Pool(CreatorT creator) : creator_(std::move(creator)) { + } + std::shared_ptr get() { + std::unique_lock lock(mutex_); + set_pool_size_locked(1); + auto i = std::min_element(entries_.begin(), entries_.end()) - entries_.begin(); + return std::shared_ptr(entries_[i].value.get(), + [i, self = this->shared_from_this()](auto *ptr) { + self->dec_ref(i); + }); + } + + void set_pool_size(size_t size) { + std::unique_lock lock(mutex_); + set_pool_size_locked(size); + } + + void dec_ref(size_t i) { + std::unique_lock lock(mutex_); + entries_.at(i).refcnt--; + } + +private: + std::mutex mutex_; + std::vector entries_; + + CreatorT creator_; + + void set_pool_size_locked(size_t size) { + for (size_t i = entries_.size(); i < size; i++) { + entries_.emplace_back(Entry{creator_(i + 1), 0}); + } + } +}; + +class ThreadsImpl : public Threads { + using Thread = std::unique_ptr; +public: + explicit ThreadsImpl(size_t i) { + auto suffix = i == 0 ? "" : "#" + std::to_string(i); + network_ = create_network("tgc-net" + suffix); + media_ = create("tgc-media" + suffix); + worker_ = create("tgc-work" + suffix); + } + + rtc::Thread *getNetworkThread() override { + return network_.get(); + } + rtc::Thread *getMediaThread() override { + return media_.get(); + } + rtc::Thread *getWorkerThread() override { + return worker_.get(); + } + +private: + Thread network_; + Thread media_; + Thread worker_; + + static Thread create(const std::string &name) { + return init(std::unique_ptr(rtc::Thread::Create()), name); + } + static Thread create_network(const std::string &name) { + return init(std::unique_ptr(rtc::Thread::CreateWithSocketServer()), name); + } + + static Thread init(Thread value, const std::string &name) { + value->SetName(name, nullptr); + value->Start(); + return value; + } +}; + +class ThreadsCreator { +public: + std::unique_ptr operator()(size_t i) { + return std::make_unique(i); + } +}; + +Pool &get_pool() { + static auto pool = std::make_shared>(ThreadsCreator()); + return *pool; +} + +void Threads::setPoolSize(size_t size){ + get_pool().set_pool_size(size); +} +std::shared_ptr Threads::getThreads(){ + return get_pool().get(); +} + namespace StaticThreads { -static rtc::Thread *makeNetworkThread() { - static std::unique_ptr value = rtc::Thread::CreateWithSocketServer(); - value->SetName("WebRTC-Network", nullptr); - value->Start(); - return value.get(); -} - rtc::Thread *getNetworkThread() { - static rtc::Thread *value = makeNetworkThread(); - return value; -} - -static rtc::Thread *makeMediaThread() { - static std::unique_ptr value = rtc::Thread::Create(); - value->SetName("WebRTC-Media", nullptr); - value->Start(); - return value.get(); + return getThreads()->getNetworkThread(); } rtc::Thread *getMediaThread() { - static rtc::Thread *value = makeMediaThread(); - return value; -} - -static rtc::Thread *makeWorkerThread() { - static std::unique_ptr value = rtc::Thread::Create(); - value->SetName("WebRTC-Worker", nullptr); - value->Start(); - return value.get(); + return getThreads()->getMediaThread(); } rtc::Thread *getWorkerThread() { - static rtc::Thread *value = makeWorkerThread(); - return value; + return getThreads()->getWorkerThread(); } +std::shared_ptr &getThreads() { + static std::shared_ptr threads = std::make_shared(0); + return threads; +} }; } diff --git a/tgcalls/StaticThreads.h b/tgcalls/StaticThreads.h index 641bcd8..b08ac32 100644 --- a/tgcalls/StaticThreads.h +++ b/tgcalls/StaticThreads.h @@ -1,3 +1,7 @@ +#pragma once + +#include +#include namespace rtc { class Thread; @@ -5,12 +9,23 @@ class Thread; namespace tgcalls { -namespace StaticThreads { +class Threads { +public: + virtual ~Threads() = default; + virtual rtc::Thread *getNetworkThread() = 0; + virtual rtc::Thread *getMediaThread() = 0; + virtual rtc::Thread *getWorkerThread() = 0; + // it is not possible to decrease pool size + static void setPoolSize(size_t size); + static std::shared_ptr getThreads(); +}; + +namespace StaticThreads { rtc::Thread *getNetworkThread(); rtc::Thread *getMediaThread(); rtc::Thread *getWorkerThread(); - +std::shared_ptr &getThreads(); } }; diff --git a/tgcalls/VideoCaptureInterface.cpp b/tgcalls/VideoCaptureInterface.cpp index fb7676c..adfb249 100644 --- a/tgcalls/VideoCaptureInterface.cpp +++ b/tgcalls/VideoCaptureInterface.cpp @@ -4,8 +4,10 @@ namespace tgcalls { -std::unique_ptr VideoCaptureInterface::Create(std::string deviceId, std::shared_ptr platformContext) { - return std::make_unique(deviceId, platformContext); +std::unique_ptr VideoCaptureInterface::Create( + std::shared_ptr threads, std::string deviceId, + std::shared_ptr platformContext) { + return std::make_unique(deviceId, platformContext, std::move(threads)); } VideoCaptureInterface::~VideoCaptureInterface() = default; diff --git a/tgcalls/VideoCaptureInterface.h b/tgcalls/VideoCaptureInterface.h index 1238c28..f00bf52 100644 --- a/tgcalls/VideoCaptureInterface.h +++ b/tgcalls/VideoCaptureInterface.h @@ -16,6 +16,7 @@ class VideoFrame; namespace tgcalls { class PlatformContext; +class Threads; enum class VideoState { Inactive, @@ -29,7 +30,8 @@ protected: public: static std::unique_ptr Create( - std::string deviceId = std::string(), + std::shared_ptr threads, + std::string deviceId = std::string(), std::shared_ptr platformContext = nullptr); virtual ~VideoCaptureInterface(); diff --git a/tgcalls/VideoCaptureInterfaceImpl.cpp b/tgcalls/VideoCaptureInterfaceImpl.cpp index d54ec48..d4f5c78 100644 --- a/tgcalls/VideoCaptureInterfaceImpl.cpp +++ b/tgcalls/VideoCaptureInterfaceImpl.cpp @@ -8,8 +8,8 @@ namespace tgcalls { -VideoCaptureInterfaceObject::VideoCaptureInterfaceObject(std::string deviceId, std::shared_ptr platformContext) -: _videoSource(PlatformInterface::SharedInstance()->makeVideoSource(StaticThreads::getMediaThread(), StaticThreads::getWorkerThread())) { +VideoCaptureInterfaceObject::VideoCaptureInterfaceObject(std::string deviceId, std::shared_ptr platformContext, Threads &threads) +: _videoSource(PlatformInterface::SharedInstance()->makeVideoSource(threads.getMediaThread(), threads.getWorkerThread())) { _platformContext = platformContext; switchToDevice(deviceId); @@ -103,9 +103,10 @@ void VideoCaptureInterfaceObject::setStateUpdated(std::function platformContext) : -_impl(StaticThreads::getMediaThread(), [deviceId, platformContext]() { - return new VideoCaptureInterfaceObject(deviceId, platformContext); +VideoCaptureInterfaceImpl::VideoCaptureInterfaceImpl(std::string deviceId, + std::shared_ptr platformContext, std::shared_ptr threads) : +_impl(threads->getMediaThread(), [deviceId, platformContext, threads]() { + return new VideoCaptureInterfaceObject(deviceId, platformContext, *threads); }) { } diff --git a/tgcalls/VideoCaptureInterfaceImpl.h b/tgcalls/VideoCaptureInterfaceImpl.h index 54e273d..d7be2ce 100644 --- a/tgcalls/VideoCaptureInterfaceImpl.h +++ b/tgcalls/VideoCaptureInterfaceImpl.h @@ -10,10 +10,11 @@ namespace tgcalls { class VideoCapturerInterface; +class Threads; class VideoCaptureInterfaceObject { public: - VideoCaptureInterfaceObject(std::string deviceId, std::shared_ptr platformContext); + VideoCaptureInterfaceObject(std::string deviceId, std::shared_ptr platformContext, Threads &threads); ~VideoCaptureInterfaceObject(); void switchToDevice(std::string deviceId); @@ -39,7 +40,7 @@ private: class VideoCaptureInterfaceImpl : public VideoCaptureInterface { public: - VideoCaptureInterfaceImpl(std::string deviceId, std::shared_ptr platformContext); + VideoCaptureInterfaceImpl(std::string deviceId, std::shared_ptr platformContext, std::shared_ptr threads); virtual ~VideoCaptureInterfaceImpl(); void switchToDevice(std::string deviceId) override; diff --git a/tgcalls/group/GroupInstanceCustomImpl.cpp b/tgcalls/group/GroupInstanceCustomImpl.cpp index 78a00be..16fa38c 100644 --- a/tgcalls/group/GroupInstanceCustomImpl.cpp +++ b/tgcalls/group/GroupInstanceCustomImpl.cpp @@ -35,6 +35,7 @@ #include "modules/audio_coding/neteq/default_neteq_factory.h" #include "modules/audio_coding/include/audio_coding_module.h" +#include "AudioFrame.h" #include "ThreadLocalObject.h" #include "Manager.h" #include "NetworkManager.h" @@ -195,6 +196,37 @@ struct VideoSsrcs { } }; +struct ChannelId { + uint32_t networkSsrc = 0; + uint32_t actualSsrc = 0; + + ChannelId(uint32_t networkSsrc_, uint32_t actualSsrc_) : + networkSsrc(networkSsrc_), + actualSsrc(actualSsrc_) { + } + + explicit ChannelId(uint32_t networkSsrc_) : + networkSsrc(networkSsrc_), + actualSsrc(networkSsrc_) { + } + + bool operator <(const ChannelId& rhs) const { + if (networkSsrc != rhs.networkSsrc) { + return networkSsrc < rhs.networkSsrc; + } + return actualSsrc < rhs.actualSsrc; + } + + std::string name() { + if (networkSsrc == actualSsrc) { + return uint32ToString(networkSsrc); + } else { + return uint32ToString(networkSsrc) + "to" + uint32ToString(actualSsrc); + } + } +}; + + class NetworkInterfaceImpl : public cricket::MediaChannel::NetworkInterface { public: NetworkInterfaceImpl(std::function sendPacket) : @@ -278,15 +310,27 @@ public: }; public: - AudioSinkImpl(std::function update) : - _update(update) { + AudioSinkImpl(std::function update, + ChannelId channel_id, std::function onAudioFrame) : + _update(update), _channel_id(channel_id), _onAudioFrame(std::move(onAudioFrame)) { } virtual ~AudioSinkImpl() { } virtual void OnData(const Data& audio) override { - if (audio.channels == 1) { + if (_onAudioFrame) { + AudioFrame frame; + frame.audio_samples = audio.data; + frame.num_samples = audio.samples_per_channel; + frame.bytes_per_sample = 2; + frame.num_channels = audio.channels; + frame.samples_per_sec = audio.sample_rate; + frame.elapsed_time_ms = 0; + frame.ntp_time_ms = 0; + _onAudioFrame(_channel_id.actualSsrc, frame); + } + if (audio.channels == 1) { const int16_t *samples = (const int16_t *)audio.data; int numberOfSamplesInFrame = (int)audio.samples_per_channel; @@ -318,8 +362,10 @@ public: private: std::function _update; + ChannelId _channel_id; + std::function _onAudioFrame; - int _peakCount = 0; + int _peakCount = 0; uint16_t _peak = 0; CombinedVad _vad; @@ -436,37 +482,6 @@ public: virtual ~AudioCaptureAnalyzer() = default; }; - -struct ChannelId { - uint32_t networkSsrc = 0; - uint32_t actualSsrc = 0; - - ChannelId(uint32_t networkSsrc_, uint32_t actualSsrc_) : - networkSsrc(networkSsrc_), - actualSsrc(actualSsrc_) { - } - - explicit ChannelId(uint32_t networkSsrc_) : - networkSsrc(networkSsrc_), - actualSsrc(networkSsrc_) { - } - - bool operator <(const ChannelId& rhs) const { - if (networkSsrc != rhs.networkSsrc) { - return networkSsrc < rhs.networkSsrc; - } - return actualSsrc < rhs.actualSsrc; - } - - std::string name() { - if (networkSsrc == actualSsrc) { - return uint32ToString(networkSsrc); - } else { - return uint32ToString(networkSsrc) + "to" + uint32ToString(actualSsrc); - } - } -}; - class IncomingAudioChannel : public sigslot::has_slots<> { public: IncomingAudioChannel( @@ -476,7 +491,9 @@ public: rtc::UniqueRandomIdGenerator *randomIdGenerator, bool isRawPcm, ChannelId ssrc, - std::function &&onAudioLevelUpdated) : + std::function &&onAudioLevelUpdated, + std::function onAudioFrame, + Threads &threads) : _ssrc(ssrc), _channelManager(channelManager), _call(call) { @@ -490,7 +507,7 @@ public: std::string streamId = std::string("stream") + ssrc.name(); - _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, StaticThreads::getMediaThread(), std::string("audio") + uint32ToString(ssrc.networkSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); + _audioChannel = _channelManager->CreateVoiceChannel(call, cricket::MediaConfig(), rtpTransport, threads.getMediaThread(), std::string("audio") + uint32ToString(ssrc.networkSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, audioOptions); const uint8_t opusMinBitrateKbps = 32; const uint8_t opusMaxBitrateKbps = 32; @@ -540,7 +557,7 @@ public: std::unique_ptr audioLevelSink(new AudioSinkImpl([onAudioLevelUpdated = std::move(onAudioLevelUpdated)](AudioSinkImpl::Update update) { onAudioLevelUpdated(update); - })); + }, _ssrc, std::move(onAudioFrame))); _audioChannel->media_channel()->SetRawAudioSink(ssrc.networkSsrc, std::move(audioLevelSink)); _audioChannel->SignalSentPacket().connect(this, &IncomingAudioChannel::OnSentPacket_w); @@ -592,7 +609,8 @@ public: webrtc::RtpTransport *rtpTransport, rtc::UniqueRandomIdGenerator *randomIdGenerator, std::vector const &availableVideoFormats, - GroupParticipantDescription const &description) : + GroupParticipantDescription const &description, + Threads &threads) : _channelManager(channelManager), _call(call) { _videoSink.reset(new VideoSinkImpl()); @@ -601,7 +619,7 @@ public: _videoBitrateAllocatorFactory = webrtc::CreateBuiltinVideoBitrateAllocatorFactory(); - _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, StaticThreads::getMediaThread(), std::string("video") + uint32ToString(description.audioSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); + _videoChannel = _channelManager->CreateVideoChannel(call, cricket::MediaConfig(), rtpTransport, threads.getMediaThread(), std::string("video") + uint32ToString(description.audioSsrc), false, GroupNetworkManager::getDefaulCryptoOptions(), randomIdGenerator, cricket::VideoOptions(), _videoBitrateAllocatorFactory.get()); auto payloadTypes = assignPayloadTypes(availableVideoFormats); if (!payloadTypes.has_value()) { @@ -756,9 +774,11 @@ struct DecodedBroadcastPart { class GroupInstanceCustomInternal : public sigslot::has_slots<>, public std::enable_shared_from_this { public: - GroupInstanceCustomInternal(GroupInstanceDescriptor &&descriptor) : + GroupInstanceCustomInternal(GroupInstanceDescriptor &&descriptor, std::shared_ptr threads) : + _threads(std::move(threads)), _networkStateUpdated(descriptor.networkStateUpdated), _audioLevelsUpdated(descriptor.audioLevelsUpdated), + _onAudioFrame(descriptor.onAudioFrame), _incomingVideoSourcesUpdated(descriptor.incomingVideoSourcesUpdated), _participantDescriptionsRequired(descriptor.participantDescriptionsRequired), _requestBroadcastPart(descriptor.requestBroadcastPart), @@ -767,7 +787,7 @@ public: _taskQueueFactory(webrtc::CreateDefaultTaskQueueFactory()), _createAudioDeviceModule(descriptor.createAudioDeviceModule), _missingPacketBuffer(100) { - assert(StaticThreads::getMediaThread()->IsCurrent()); + assert(_threads->getMediaThread()->IsCurrent()); auto generator = std::mt19937(std::random_device()()); auto distribution = std::uniform_int_distribution(); @@ -814,10 +834,10 @@ public: "WebRTC-Audio-OpusMinPacketLossRate/Enabled-1/" ); - _networkManager.reset(new ThreadLocalObject(StaticThreads::getNetworkThread(), [weak] () mutable { + _networkManager.reset(new ThreadLocalObject(_threads->getNetworkThread(), [weak, threads = _threads] () mutable { return new GroupNetworkManager( [=](const GroupNetworkManager::State &state) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [=] { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [=] { const auto strong = weak.lock(); if (!strong) { return; @@ -826,32 +846,32 @@ public: }); }, [=](rtc::CopyOnWriteBuffer const &message, bool isUnresolved) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message, isUnresolved]() mutable { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message, isUnresolved]() mutable { if (const auto strong = weak.lock()) { strong->receivePacket(message, isUnresolved); } }); }, [=](rtc::CopyOnWriteBuffer const &message, int64_t timestamp) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message, timestamp]() mutable { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message, timestamp]() mutable { if (const auto strong = weak.lock()) { strong->receiveRtcpPacket(message, timestamp); } }); }, [=](bool isDataChannelOpen) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, isDataChannelOpen]() mutable { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, isDataChannelOpen]() mutable { if (const auto strong = weak.lock()) { strong->updateIsDataChannelOpen(isDataChannelOpen); } }); }, [=](std::string const &message) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message]() mutable { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, message]() mutable { if (const auto strong = weak.lock()) { } }); - }); + }, threads); })); PlatformInterface::SharedInstance()->configurePlatformAudio(); @@ -864,8 +884,8 @@ public: mediaDeps.video_encoder_factory = PlatformInterface::SharedInstance()->makeVideoEncoderFactory(); mediaDeps.video_decoder_factory = PlatformInterface::SharedInstance()->makeVideoDecoderFactory(); - auto analyzer = new AudioCaptureAnalyzer([weak](GroupLevelValue const &level) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, level](){ + auto analyzer = new AudioCaptureAnalyzer([weak, threads = _threads](GroupLevelValue const &level) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, level](){ auto strong = weak.lock(); if (!strong) { return; @@ -889,7 +909,7 @@ public: std::unique_ptr mediaEngine = cricket::CreateMediaEngine(std::move(mediaDeps)); - _channelManager.reset(new cricket::ChannelManager(std::move(mediaEngine), std::make_unique(), StaticThreads::getMediaThread(), StaticThreads::getNetworkThread())); + _channelManager.reset(new cricket::ChannelManager(std::move(mediaEngine), std::make_unique(), _threads->getMediaThread(), _threads->getNetworkThread())); _channelManager->Init(); webrtc::Call::Config callConfig(_eventLog.get()); @@ -900,7 +920,7 @@ public: _uniqueRandomIdGenerator.reset(new rtc::UniqueRandomIdGenerator()); - StaticThreads::getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this]() { _rtpTransport = _networkManager->getSyncAssumingSameThread()->getRtpTransport(); }); @@ -943,7 +963,7 @@ public: std::vector streamIds; streamIds.push_back("1"); - _outgoingAudioChannel = _channelManager->CreateVoiceChannel(_call.get(), cricket::MediaConfig(), _rtpTransport, StaticThreads::getMediaThread(), "0", false, GroupNetworkManager::getDefaulCryptoOptions(), _uniqueRandomIdGenerator.get(), audioOptions); + _outgoingAudioChannel = _channelManager->CreateVoiceChannel(_call.get(), cricket::MediaConfig(), _rtpTransport, _threads->getMediaThread(), "0", false, GroupNetworkManager::getDefaulCryptoOptions(), _uniqueRandomIdGenerator.get(), audioOptions); const uint8_t opusMinBitrateKbps = 32; const uint8_t opusMaxBitrateKbps = 32; @@ -992,7 +1012,7 @@ public: void beginLevelsTimer(int timeoutMs) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -1032,7 +1052,7 @@ public: void beginNetworkStatusTimer(int delayMs) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -1184,8 +1204,8 @@ public: void requestNextBroadcastPart() { const auto weak = std::weak_ptr(shared_from_this()); - _currentRequestedBroadcastTask = _requestBroadcastPart(_nextBroadcastTimestampMilliseconds, _broadcastPartDurationMilliseconds, [weak](BroadcastPart &&part) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, part = std::move(part)]() mutable { + _currentRequestedBroadcastTask = _requestBroadcastPart(_nextBroadcastTimestampMilliseconds, _broadcastPartDurationMilliseconds, [weak, threads = _threads](BroadcastPart &&part) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, part = std::move(part)]() mutable { auto strong = weak.lock(); if (!strong) { return; @@ -1198,7 +1218,7 @@ public: void requestNextBroadcastPartWithDelay(int timeoutMs) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -1256,7 +1276,7 @@ public: void beginBroadcastPartsDecodeTimer(int timeoutMs) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -1579,7 +1599,7 @@ public: _isUnknownSsrcsScheduled = true; const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getMediaThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -1934,8 +1954,8 @@ public: _uniqueRandomIdGenerator.get(), isRawPcm, ssrc, - [weak, ssrc = ssrc](AudioSinkImpl::Update update) { - StaticThreads::getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update]() { + [weak, ssrc = ssrc, threads = _threads](AudioSinkImpl::Update update) { + threads->getMediaThread()->PostTask(RTC_FROM_HERE, [weak, ssrc, update]() { auto strong = weak.lock(); if (!strong) { return; @@ -1945,7 +1965,9 @@ public: mappedUpdate.voice = update.hasSpeech; strong->_audioLevels[ssrc] = mappedUpdate; }); - } + }, + _onAudioFrame, + *_threads )); auto volume = _volumeBySsrc.find(ssrc.actualSsrc); @@ -1977,7 +1999,8 @@ public: _rtpTransport, _uniqueRandomIdGenerator.get(), _availableVideoFormats, - participant + participant, + *_threads )); _incomingVideoChannels.insert(std::make_pair(participant.audioSsrc, std::move(channel))); @@ -2063,10 +2086,12 @@ private: } private: + std::shared_ptr _threads; GroupConnectionMode _connectionMode = GroupConnectionMode::GroupConnectionModeNone; std::function _networkStateUpdated; std::function _audioLevelsUpdated; + std::function _onAudioFrame; std::function const &)> _incomingVideoSourcesUpdated; std::function const &)> _participantDescriptionsRequired; std::function(int64_t, int64_t, std::function)> _requestBroadcastPart; @@ -2144,8 +2169,9 @@ GroupInstanceCustomImpl::GroupInstanceCustomImpl(GroupInstanceDescriptor &&descr rtc::LogMessage::AddLogToStream(_logSink.get(), rtc::LS_INFO); } - _internal.reset(new ThreadLocalObject(StaticThreads::getMediaThread(), [descriptor = std::move(descriptor)]() mutable { - return new GroupInstanceCustomInternal(std::move(descriptor)); + _threads = Threads::getThreads(); + _internal.reset(new ThreadLocalObject(_threads->getMediaThread(), [descriptor = std::move(descriptor), threads = _threads]() mutable { + return new GroupInstanceCustomInternal(std::move(descriptor), threads); })); _internal->perform(RTC_FROM_HERE, [](GroupInstanceCustomInternal *internal) { internal->start(); @@ -2159,7 +2185,7 @@ GroupInstanceCustomImpl::~GroupInstanceCustomImpl() { _internal.reset(); // Wait until _internal is destroyed - StaticThreads::getMediaThread()->Invoke(RTC_FROM_HERE, [] {}); + _threads->getMediaThread()->Invoke(RTC_FROM_HERE, [] {}); } void GroupInstanceCustomImpl::stop() { diff --git a/tgcalls/group/GroupInstanceCustomImpl.h b/tgcalls/group/GroupInstanceCustomImpl.h index 80ce7a0..9cca3af 100644 --- a/tgcalls/group/GroupInstanceCustomImpl.h +++ b/tgcalls/group/GroupInstanceCustomImpl.h @@ -14,6 +14,7 @@ namespace tgcalls { class LogSinkImpl; class GroupInstanceCustomInternal; +class Threads; class GroupInstanceCustomImpl final : public GroupInstanceInterface { public: @@ -40,6 +41,7 @@ public: void setFullSizeVideoSsrc(uint32_t ssrc); private: + std::shared_ptr _threads; std::unique_ptr> _internal; std::unique_ptr _logSink; diff --git a/tgcalls/group/GroupInstanceImpl.h b/tgcalls/group/GroupInstanceImpl.h index 6f3c20c..2589e3e 100644 --- a/tgcalls/group/GroupInstanceImpl.h +++ b/tgcalls/group/GroupInstanceImpl.h @@ -23,6 +23,7 @@ namespace tgcalls { class LogSinkImpl; class GroupInstanceManager; +class AudioFrame; struct GroupConfig { FilePath logPath; @@ -77,6 +78,7 @@ struct GroupInstanceDescriptor { GroupConfig config; std::function networkStateUpdated; std::function audioLevelsUpdated; + std::function onAudioFrame; std::string initialInputDeviceId; std::string initialOutputDeviceId; bool debugIgnoreMissingSsrcs = false; diff --git a/tgcalls/group/GroupNetworkManager.cpp b/tgcalls/group/GroupNetworkManager.cpp index 3e18de8..a9e32bb 100644 --- a/tgcalls/group/GroupNetworkManager.cpp +++ b/tgcalls/group/GroupNetworkManager.cpp @@ -41,13 +41,15 @@ public: SctpDataChannelProviderInterfaceImpl( cricket::DtlsTransport *transportChannel, std::function onStateChanged, - std::function onMessageReceived + std::function onMessageReceived, + std::shared_ptr threads ) : + _threads(std::move(threads)), _onStateChanged(onStateChanged), _onMessageReceived(onMessageReceived) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); - _sctpTransportFactory.reset(new cricket::SctpTransportFactory(StaticThreads::getNetworkThread())); + _sctpTransportFactory.reset(new cricket::SctpTransportFactory(_threads->getNetworkThread())); _sctpTransport = _sctpTransportFactory->CreateSctpTransport(transportChannel); _sctpTransport->SignalReadyToSendData.connect(this, &SctpDataChannelProviderInterfaceImpl::sctpReadyToSendData); @@ -59,15 +61,15 @@ public: this, "data", dataChannelInit, - StaticThreads::getNetworkThread(), - StaticThreads::getNetworkThread() + _threads->getNetworkThread(), + _threads->getNetworkThread() ); _dataChannel->RegisterObserver(this); } virtual ~SctpDataChannelProviderInterfaceImpl() { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _dataChannel->UnregisterObserver(); _dataChannel->Close(); @@ -78,7 +80,7 @@ public: } void sendDataChannelMessage(std::string const &message) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); if (_isDataChannelOpen) { RTC_LOG(LS_INFO) << "Outgoing DataChannel message: " << message; @@ -91,7 +93,7 @@ public: } virtual void OnStateChange() override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); auto state = _dataChannel->state(); bool isDataChannelOpen = state == webrtc::DataChannelInterface::DataState::kOpen; @@ -102,7 +104,7 @@ public: } virtual void OnMessage(const webrtc::DataBuffer& buffer) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); if (!buffer.binary) { std::string messageText(buffer.data.data(), buffer.data.data() + buffer.data.size()); @@ -113,7 +115,7 @@ public: } void updateIsConnected(bool isConnected) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); if (isConnected) { if (!_isSctpTransportStarted) { @@ -124,56 +126,57 @@ public: } void sctpReadyToSendData() { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _dataChannel->OnTransportReady(true); } void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _dataChannel->OnDataReceived(params, buffer); } virtual bool SendData(const cricket::SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, cricket::SendDataResult* result) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); return _sctpTransport->SendData(params, payload); } virtual bool ConnectDataChannel(webrtc::SctpDataChannel *data_channel) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); return true; } virtual void DisconnectDataChannel(webrtc::SctpDataChannel* data_channel) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); return; } virtual void AddSctpDataStream(int sid) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _sctpTransport->OpenStream(sid); } virtual void RemoveSctpDataStream(int sid) override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); - StaticThreads::getNetworkThread()->Invoke(RTC_FROM_HERE, [this, sid]() { + _threads->getNetworkThread()->Invoke(RTC_FROM_HERE, [this, sid]() { _sctpTransport->ResetStream(sid); }); } virtual bool ReadyToSendData() const override { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); return _sctpTransport->ReadyToSendData(); } private: + std::shared_ptr _threads; std::function _onStateChanged; std::function _onMessageReceived; @@ -198,19 +201,21 @@ GroupNetworkManager::GroupNetworkManager( std::function transportMessageReceived, std::function rtcpPacketReceived, std::function dataChannelStateUpdated, - std::function dataChannelMessageReceived) : + std::function dataChannelMessageReceived, + std::shared_ptr threads) : +_threads(std::move(threads)), _stateUpdated(std::move(stateUpdated)), _transportMessageReceived(std::move(transportMessageReceived)), _rtcpPacketReceived(std::move(rtcpPacketReceived)), _dataChannelStateUpdated(dataChannelStateUpdated), _dataChannelMessageReceived(dataChannelMessageReceived) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _localIceParameters = PeerIceParameters(rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), rtc::CreateRandomString(cricket::ICE_PWD_LENGTH)); _localCertificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(rtc::KT_ECDSA), absl::nullopt); - _socketFactory.reset(new rtc::BasicPacketSocketFactory(StaticThreads::getNetworkThread())); + _socketFactory.reset(new rtc::BasicPacketSocketFactory(_threads->getNetworkThread())); _networkManager = std::make_unique(); _asyncResolverFactory = std::make_unique(); @@ -226,7 +231,7 @@ _dataChannelMessageReceived(dataChannelMessageReceived) { } GroupNetworkManager::~GroupNetworkManager() { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); RTC_LOG(LS_INFO) << "GroupNetworkManager::~GroupNetworkManager()"; @@ -372,7 +377,7 @@ webrtc::RtpTransport *GroupNetworkManager::getRtpTransport() { void GroupNetworkManager::checkConnectionTimeout() { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getNetworkThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { + _threads->getNetworkThread()->PostDelayedTask(RTC_FROM_HERE, [weak]() { auto strong = weak.lock(); if (!strong) { return; @@ -393,26 +398,26 @@ void GroupNetworkManager::checkConnectionTimeout() { } void GroupNetworkManager::candidateGathered(cricket::IceTransportInternal *transport, const cricket::Candidate &candidate) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); } void GroupNetworkManager::candidateGatheringState(cricket::IceTransportInternal *transport) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); } void GroupNetworkManager::OnTransportWritableState_n(rtc::PacketTransportInternal *transport) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); UpdateAggregateStates_n(); } void GroupNetworkManager::OnTransportReceivingState_n(rtc::PacketTransportInternal *transport) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); UpdateAggregateStates_n(); } void GroupNetworkManager::OnDtlsHandshakeError(rtc::SSLHandshakeError error) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); } void GroupNetworkManager::DtlsStateChanged() { @@ -420,7 +425,7 @@ void GroupNetworkManager::DtlsStateChanged() { if (_dtlsTransport->IsDtlsActive()) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getNetworkThread()->PostTask(RTC_FROM_HERE, [weak]() { + _threads->getNetworkThread()->PostTask(RTC_FROM_HERE, [weak]() { const auto strong = weak.lock(); if (!strong) { return; @@ -435,7 +440,7 @@ void GroupNetworkManager::DtlsReadyToSend(bool isReadyToSend) { if (isReadyToSend) { const auto weak = std::weak_ptr(shared_from_this()); - StaticThreads::getNetworkThread()->PostTask(RTC_FROM_HERE, [weak]() { + _threads->getNetworkThread()->PostTask(RTC_FROM_HERE, [weak]() { const auto strong = weak.lock(); if (!strong) { return; @@ -450,11 +455,11 @@ void GroupNetworkManager::transportStateChanged(cricket::IceTransportInternal *t } void GroupNetworkManager::transportReadyToSend(cricket::IceTransportInternal *transport) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); } void GroupNetworkManager::transportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t ×tamp, int unused) { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); _lastNetworkActivityMs = rtc::TimeMillis(); } @@ -472,7 +477,7 @@ void GroupNetworkManager::OnRtcpPacketReceived_n(rtc::CopyOnWriteBuffer *packet, } void GroupNetworkManager::UpdateAggregateStates_n() { - assert(StaticThreads::getNetworkThread()->IsCurrent()); + assert(_threads->getNetworkThread()->IsCurrent()); auto state = _transportChannel->GetIceTransportState(); bool isConnected = false; diff --git a/tgcalls/group/GroupNetworkManager.h b/tgcalls/group/GroupNetworkManager.h index bbf4746..3477ec7 100644 --- a/tgcalls/group/GroupNetworkManager.h +++ b/tgcalls/group/GroupNetworkManager.h @@ -44,6 +44,7 @@ namespace tgcalls { struct Message; class SctpDataChannelProviderInterfaceImpl; +class Threads; class GroupNetworkManager : public sigslot::has_slots<>, public std::enable_shared_from_this { public: @@ -59,7 +60,8 @@ public: std::function transportMessageReceived, std::function rtcpPacketReceived, std::function dataChannelStateUpdated, - std::function dataChannelMessageReceived); + std::function dataChannelMessageReceived, + std::shared_ptr threads); ~GroupNetworkManager(); void start(); @@ -93,6 +95,7 @@ private: void sctpReadyToSendData(); void sctpDataReceived(const cricket::ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer); + std::shared_ptr _threads; std::function _stateUpdated; std::function _transportMessageReceived; std::function _rtcpPacketReceived; diff --git a/tgcalls/platform/fake/FakeInterface.cpp b/tgcalls/platform/fake/FakeInterface.cpp new file mode 100644 index 0000000..761b620 --- /dev/null +++ b/tgcalls/platform/fake/FakeInterface.cpp @@ -0,0 +1,43 @@ +#include "FakeInterface.h" + +#include "api/video_codecs/builtin_video_encoder_factory.h" +#include "api/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_track_source_proxy.h" + +namespace tgcalls { + +std::unique_ptr FakeInterface::makeVideoEncoderFactory() { + return webrtc::CreateBuiltinVideoEncoderFactory(); +} + +std::unique_ptr FakeInterface::makeVideoDecoderFactory() { + return webrtc::CreateBuiltinVideoDecoderFactory(); +} + +rtc::scoped_refptr FakeInterface::makeVideoSource(rtc::Thread *signalingThread, + rtc::Thread *workerThread) { + return nullptr; +} + +bool FakeInterface::supportsEncoding(const std::string &codecName) { + return false; + //return (codecName == cricket::kH264CodecName) || (codecName == cricket::kVp8CodecName); +} + +void FakeInterface::adaptVideoSource(rtc::scoped_refptr videoSource, int width, + int height, int fps) { +} + +std::unique_ptr FakeInterface::makeVideoCapturer( + rtc::scoped_refptr source, std::string deviceId, + std::function stateUpdated, std::function captureInfoUpdated, + std::shared_ptr platformContext, std::pair &outResolution) { + return nullptr; + //return std::make_unique(source, deviceId, stateUpdated, outResolution); +} + +std::unique_ptr CreatePlatformInterface() { + return std::make_unique(); +} + +} // namespace tgcalls diff --git a/tgcalls/platform/fake/FakeInterface.h b/tgcalls/platform/fake/FakeInterface.h new file mode 100644 index 0000000..c5f084a --- /dev/null +++ b/tgcalls/platform/fake/FakeInterface.h @@ -0,0 +1,24 @@ +#pragma once + +#include "platform/PlatformInterface.h" +#include "VideoCapturerInterface.h" + +namespace tgcalls { + +class FakeInterface : public PlatformInterface { + public: + std::unique_ptr makeVideoEncoderFactory() override; + std::unique_ptr makeVideoDecoderFactory() override; + bool supportsEncoding(const std::string &codecName) override; + rtc::scoped_refptr makeVideoSource(rtc::Thread *signalingThread, + rtc::Thread *workerThread) override; + void adaptVideoSource(rtc::scoped_refptr videoSource, int width, int height, + int fps) override; + std::unique_ptr makeVideoCapturer( + rtc::scoped_refptr source, std::string deviceId, + std::function stateUpdated, std::function captureInfoUpdated, + std::shared_ptr platformContext, std::pair &outResolution) override; +}; + +} // namespace tgcalls +