ZaStoGram/TMessagesProj/jni/voip/tgcalls/platform/fake/FakeInterface.cpp
2026-09-24 16:17:30 +04:00

172 lines
7.2 KiB
C++

#include "FakeInterface.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/match.h"
#include "api/environment/environment.h"
#include "api/video_codecs/builtin_video_encoder_factory.h"
#include "api/video_codecs/builtin_video_decoder_factory.h"
#include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/video_decoder_factory.h"
#include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/video_encoder_factory.h"
#include "media/base/media_constants.h"
//#include "api/video_track_source_proxy.h"
namespace tgcalls {
namespace {
bool gUseBuiltinCodecOrder = false;
// Reorders a builtin factory's supported formats into the shape the iOS
// platform factories advertise: two H264 entries (packetization-mode 1)
// first, then VP8, then VP9 profile 0. (iOS then lists H265, which the host
// build lacks.)
//
// PeerConnection assigns dynamic payload types by walking this list —
// 96, 98, 100, 102, ... with RTX at +1 — so the ORDER decides which codec
// lands on which number. The raw builtin host order happens to put an H264
// profile at PT 104, which hid that GroupInstanceReferenceImpl's
// auto-generated receive table did not match the group-call convention
// (VP8 100, VP9 102, H264 104): on the device PT 104 was H265 and incoming
// H264 never decoded, while the host test passed. With this order PT 104 is
// not H264 on the host either, so the testbench sees what the device sees.
//
// The constrained-baseline H264 entry is kept deliberately: WebRTC's decoder
// table builder appends a CB variant for any H264 profile that lacks one,
// and an appended entry would land right after VP9 — on PT 104.
std::vector<webrtc::SdpVideoFormat> iosLikeFormatOrder(std::vector<webrtc::SdpVideoFormat> formats) {
std::vector<webrtc::SdpVideoFormat> h264;
std::vector<webrtc::SdpVideoFormat> vp8;
std::vector<webrtc::SdpVideoFormat> vp9;
for (const auto& format : formats) {
if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) {
auto mode = format.parameters.find(cricket::kH264FmtpPacketizationMode);
if (mode != format.parameters.end() && mode->second != "1") continue;
h264.push_back(format);
} else if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) {
vp8.push_back(format);
} else if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) {
auto profile = format.parameters.find("profile-id");
if (profile != format.parameters.end() && profile->second != "0") continue;
vp9.push_back(format);
}
}
std::vector<webrtc::SdpVideoFormat> result;
// First H264 slot: the constrained-baseline entry if there is one.
for (const auto& format : h264) {
auto profile = format.parameters.find(cricket::kH264FmtpProfileLevelId);
if (profile != format.parameters.end() && absl::StartsWithIgnoreCase(profile->second, "42e0")) {
result.push_back(format);
break;
}
}
// Second H264 slot: the first entry not already taken.
for (const auto& format : h264) {
if (result.size() >= 2) break;
if (!result.empty() && result[0] == format) continue;
result.push_back(format);
}
if (!vp8.empty()) result.push_back(vp8[0]);
if (!vp9.empty()) result.push_back(vp9[0]);
return result;
}
class IosOrderVideoEncoderFactory : public webrtc::VideoEncoderFactory {
public:
explicit IosOrderVideoEncoderFactory(std::unique_ptr<webrtc::VideoEncoderFactory> inner) : _inner(std::move(inner)) {}
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override {
return iosLikeFormatOrder(_inner->GetSupportedFormats());
}
std::vector<webrtc::SdpVideoFormat> GetImplementations() const override {
return iosLikeFormatOrder(_inner->GetImplementations());
}
CodecSupport QueryCodecSupport(const webrtc::SdpVideoFormat& format,
absl::optional<std::string> scalability_mode) const override {
return _inner->QueryCodecSupport(format, scalability_mode);
}
std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder(const webrtc::SdpVideoFormat& format) override {
return _inner->CreateVideoEncoder(format);
}
std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override {
return _inner->GetEncoderSelector();
}
private:
std::unique_ptr<webrtc::VideoEncoderFactory> _inner;
};
class IosOrderVideoDecoderFactory : public webrtc::VideoDecoderFactory {
public:
explicit IosOrderVideoDecoderFactory(std::unique_ptr<webrtc::VideoDecoderFactory> inner) : _inner(std::move(inner)) {}
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override {
return iosLikeFormatOrder(_inner->GetSupportedFormats());
}
CodecSupport QueryCodecSupport(const webrtc::SdpVideoFormat& format, bool reference_scaling) const override {
return _inner->QueryCodecSupport(format, reference_scaling);
}
std::unique_ptr<webrtc::VideoDecoder> Create(const webrtc::Environment& env,
const webrtc::SdpVideoFormat& format) override {
return _inner->Create(env, format);
}
std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder(const webrtc::SdpVideoFormat& format) override {
return _inner->CreateVideoDecoder(format);
}
private:
std::unique_ptr<webrtc::VideoDecoderFactory> _inner;
};
} // namespace
void setFakePlatformBuiltinCodecOrder(bool useBuiltinOrder) {
gUseBuiltinCodecOrder = useBuiltinOrder;
}
std::unique_ptr<webrtc::VideoEncoderFactory> FakeInterface::makeVideoEncoderFactory(bool preferHardwareEncoding, bool isScreencast) {
auto factory = webrtc::CreateBuiltinVideoEncoderFactory();
if (gUseBuiltinCodecOrder) return factory;
return std::make_unique<IosOrderVideoEncoderFactory>(std::move(factory));
}
std::unique_ptr<webrtc::VideoDecoderFactory> FakeInterface::makeVideoDecoderFactory() {
auto factory = webrtc::CreateBuiltinVideoDecoderFactory();
if (gUseBuiltinCodecOrder) return factory;
return std::make_unique<IosOrderVideoDecoderFactory>(std::move(factory));
}
webrtc::scoped_refptr<webrtc::VideoTrackSourceInterface> 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(webrtc::scoped_refptr<webrtc::VideoTrackSourceInterface> videoSource, int width,
int height, int fps) {
}
std::unique_ptr<VideoCapturerInterface> FakeInterface::makeVideoCapturer(
webrtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source, std::string deviceId,
std::function<void(VideoState)> stateUpdated, std::function<void(PlatformCaptureInfo)> captureInfoUpdated,
std::shared_ptr<PlatformContext> platformContext, std::pair<int, int> &outResolution) {
return nullptr;
//return std::make_unique<VideoCapturerInterfaceImpl>(source, deviceId, stateUpdated, outResolution);
}
std::unique_ptr<PlatformInterface> CreatePlatformInterface() {
return std::make_unique<FakeInterface>();
}
} // namespace tgcalls