| /* |
| * Copyright (C) 2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "LibWebRTCProvider.h" |
| |
| #include "MediaCapabilitiesDecodingInfo.h" |
| #include "MediaCapabilitiesEncodingInfo.h" |
| #include "MediaDecodingConfiguration.h" |
| #include "MediaEncodingConfiguration.h" |
| #include "ProcessQualified.h" |
| |
| #if USE(LIBWEBRTC) |
| #include "ContentType.h" |
| #include "LibWebRTCAudioModule.h" |
| #include "Logging.h" |
| #include <dlfcn.h> |
| |
| ALLOW_UNUSED_PARAMETERS_BEGIN |
| |
| #include <webrtc/api/async_resolver_factory.h> |
| #include <webrtc/api/audio_codecs/builtin_audio_decoder_factory.h> |
| #include <webrtc/api/audio_codecs/builtin_audio_encoder_factory.h> |
| #include <webrtc/api/create_peerconnection_factory.h> |
| #include <webrtc/modules/audio_processing/include/audio_processing.h> |
| #include <webrtc/p2p/base/basic_packet_socket_factory.h> |
| #include <webrtc/p2p/client/basic_port_allocator.h> |
| #include <webrtc/pc/peer_connection_factory.h> |
| #include <webrtc/pc/peer_connection_factory_proxy.h> |
| #include <webrtc/rtc_base/physical_socket_server.h> |
| |
| ALLOW_UNUSED_PARAMETERS_END |
| |
| #include <wtf/Function.h> |
| #include <wtf/NeverDestroyed.h> |
| #endif |
| |
| namespace WebCore { |
| |
| #if !USE(LIBWEBRTC) |
| UniqueRef<LibWebRTCProvider> LibWebRTCProvider::create() |
| { |
| return makeUniqueRef<LibWebRTCProvider>(); |
| } |
| |
| bool LibWebRTCProvider::webRTCAvailable() |
| { |
| return false; |
| } |
| #endif |
| |
| #if USE(LIBWEBRTC) |
| LibWebRTCProvider::LibWebRTCProvider() |
| { |
| } |
| #endif |
| |
| LibWebRTCProvider::~LibWebRTCProvider() |
| { |
| } |
| |
| #if !USE(LIBWEBRTC) || !PLATFORM(COCOA) |
| void LibWebRTCProvider::registerWebKitVP9Decoder() |
| { |
| } |
| |
| void LibWebRTCProvider::setH264HardwareEncoderAllowed(bool) |
| { |
| } |
| #endif |
| |
| void LibWebRTCProvider::setActive(bool) |
| { |
| } |
| |
| #if USE(LIBWEBRTC) |
| static inline rtc::SocketAddress prepareSocketAddress(const rtc::SocketAddress& address, bool disableNonLocalhostConnections) |
| { |
| auto result = address; |
| if (disableNonLocalhostConnections) |
| result.SetIP("127.0.0.1"); |
| return result; |
| } |
| |
| class BasicPacketSocketFactory : public rtc::PacketSocketFactory { |
| WTF_MAKE_FAST_ALLOCATED; |
| public: |
| explicit BasicPacketSocketFactory(rtc::Thread& networkThread) |
| : m_socketFactory(makeUniqueRefWithoutFastMallocCheck<rtc::BasicPacketSocketFactory>(networkThread.socketserver())) |
| { |
| } |
| |
| void setDisableNonLocalhostConnections(bool disableNonLocalhostConnections) { m_disableNonLocalhostConnections = disableNonLocalhostConnections; } |
| |
| rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort) final |
| { |
| return m_socketFactory->CreateUdpSocket(prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort); |
| } |
| |
| rtc::AsyncPacketSocket* CreateServerTcpSocket(const rtc::SocketAddress& address, uint16_t minPort, uint16_t maxPort, int options) final |
| { |
| return m_socketFactory->CreateServerTcpSocket(prepareSocketAddress(address, m_disableNonLocalhostConnections), minPort, maxPort, options); |
| } |
| |
| rtc::AsyncPacketSocket* CreateClientTcpSocket(const rtc::SocketAddress& localAddress, const rtc::SocketAddress& remoteAddress, const rtc::ProxyInfo& info, const std::string& name, const rtc::PacketSocketTcpOptions& options) |
| { |
| return m_socketFactory->CreateClientTcpSocket(prepareSocketAddress(localAddress, m_disableNonLocalhostConnections), remoteAddress, info, name, options); |
| } |
| rtc::AsyncResolverInterface* CreateAsyncResolver() final { return m_socketFactory->CreateAsyncResolver(); } |
| |
| private: |
| bool m_disableNonLocalhostConnections { false }; |
| UniqueRef<rtc::BasicPacketSocketFactory> m_socketFactory; |
| }; |
| |
| struct PeerConnectionFactoryAndThreads : public rtc::MessageHandler { |
| std::unique_ptr<rtc::Thread> networkThread; |
| std::unique_ptr<rtc::Thread> signalingThread; |
| bool networkThreadWithSocketServer { false }; |
| std::unique_ptr<rtc::NetworkManager> networkManager; |
| std::unique_ptr<BasicPacketSocketFactory> packetSocketFactory; |
| std::unique_ptr<rtc::RTCCertificateGenerator> certificateGenerator; |
| |
| private: |
| void OnMessage(rtc::Message*); |
| }; |
| |
| static void doReleaseLogging(rtc::LoggingSeverity severity, const char* message) |
| { |
| #if RELEASE_LOG_DISABLED |
| UNUSED_PARAM(severity); |
| UNUSED_PARAM(message); |
| #else |
| if (severity == rtc::LS_ERROR) |
| RELEASE_LOG_ERROR(WebRTC, "LibWebRTC error: %" PUBLIC_LOG_STRING, message); |
| else |
| RELEASE_LOG(WebRTC, "LibWebRTC message: %" PUBLIC_LOG_STRING, message); |
| #endif |
| } |
| |
| static rtc::LoggingSeverity computeLogLevel(WTFLogLevel level) |
| { |
| #if !RELEASE_LOG_DISABLED |
| switch (level) { |
| case WTFLogLevel::Always: |
| case WTFLogLevel::Error: |
| return rtc::LS_ERROR; |
| case WTFLogLevel::Warning: |
| return rtc::LS_WARNING; |
| case WTFLogLevel::Info: |
| return rtc::LS_INFO; |
| case WTFLogLevel::Debug: |
| return rtc::LS_VERBOSE; |
| } |
| ASSERT_NOT_REACHED(); |
| #else |
| UNUSED_PARAM(level); |
| #endif |
| return rtc::LS_NONE; |
| } |
| |
| void LibWebRTCProvider::setRTCLogging(WTFLogLevel level) |
| { |
| auto rtcLevel = computeLogLevel(level); |
| rtc::LogMessage::SetLogOutput(rtcLevel, (rtcLevel == rtc::LS_NONE) ? nullptr : doReleaseLogging); |
| } |
| |
| static void initializePeerConnectionFactoryAndThreads(PeerConnectionFactoryAndThreads& factoryAndThreads) |
| { |
| ASSERT(!factoryAndThreads.networkThread); |
| |
| factoryAndThreads.networkThread = factoryAndThreads.networkThreadWithSocketServer ? rtc::Thread::CreateWithSocketServer() : rtc::Thread::Create(); |
| factoryAndThreads.networkThread->SetName("WebKitWebRTCNetwork", nullptr); |
| bool result = factoryAndThreads.networkThread->Start(); |
| ASSERT_UNUSED(result, result); |
| |
| factoryAndThreads.signalingThread = rtc::Thread::Create(); |
| factoryAndThreads.signalingThread->SetName("WebKitWebRTCSignaling", nullptr); |
| |
| result = factoryAndThreads.signalingThread->Start(); |
| ASSERT(result); |
| } |
| |
| static inline PeerConnectionFactoryAndThreads& staticFactoryAndThreads() |
| { |
| static NeverDestroyed<PeerConnectionFactoryAndThreads> factoryAndThreads; |
| return factoryAndThreads.get(); |
| } |
| |
| PeerConnectionFactoryAndThreads& LibWebRTCProvider::getStaticFactoryAndThreads(bool useNetworkThreadWithSocketServer) |
| { |
| auto& factoryAndThreads = staticFactoryAndThreads(); |
| |
| ASSERT(!factoryAndThreads.networkThread || factoryAndThreads.networkThreadWithSocketServer == useNetworkThreadWithSocketServer); |
| |
| if (!factoryAndThreads.networkThread) { |
| factoryAndThreads.networkThreadWithSocketServer = useNetworkThreadWithSocketServer; |
| initializePeerConnectionFactoryAndThreads(factoryAndThreads); |
| startedNetworkThread(); |
| } |
| return factoryAndThreads; |
| } |
| |
| struct ThreadMessageData : public rtc::MessageData { |
| ThreadMessageData(Function<void()>&& callback) |
| : callback(WTFMove(callback)) |
| { } |
| Function<void()> callback; |
| }; |
| |
| void PeerConnectionFactoryAndThreads::OnMessage(rtc::Message* message) |
| { |
| ASSERT(message->message_id == 1); |
| auto* data = static_cast<ThreadMessageData*>(message->pdata); |
| data->callback(); |
| delete data; |
| } |
| |
| bool LibWebRTCProvider::hasWebRTCThreads() |
| { |
| return !!staticFactoryAndThreads().networkThread; |
| } |
| |
| void LibWebRTCProvider::callOnWebRTCNetworkThread(Function<void()>&& callback) |
| { |
| PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads(); |
| threads.networkThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback))); |
| } |
| |
| void LibWebRTCProvider::callOnWebRTCSignalingThread(Function<void()>&& callback) |
| { |
| PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads(); |
| threads.signalingThread->Post(RTC_FROM_HERE, &threads, 1, new ThreadMessageData(WTFMove(callback))); |
| } |
| |
| rtc::Thread& LibWebRTCProvider::signalingThread() |
| { |
| PeerConnectionFactoryAndThreads& threads = staticFactoryAndThreads(); |
| return *threads.signalingThread; |
| } |
| |
| void LibWebRTCProvider::setLoggingLevel(WTFLogLevel level) |
| { |
| setRTCLogging(level); |
| } |
| |
| webrtc::PeerConnectionFactoryInterface* LibWebRTCProvider::factory() |
| { |
| if (m_factory) |
| return m_factory.get(); |
| |
| if (!webRTCAvailable()) { |
| RELEASE_LOG_ERROR(WebRTC, "LibWebRTC is not available to create a factory"); |
| return nullptr; |
| } |
| |
| auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer); |
| |
| m_factory = createPeerConnectionFactory(factoryAndThreads.networkThread.get(), factoryAndThreads.signalingThread.get()); |
| |
| return m_factory; |
| } |
| |
| void LibWebRTCProvider::clearFactory() |
| { |
| m_audioModule = nullptr; |
| m_factory = nullptr; |
| } |
| |
| rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> LibWebRTCProvider::createPeerConnectionFactory(rtc::Thread* networkThread, rtc::Thread* signalingThread) |
| { |
| ASSERT(!m_audioModule); |
| auto audioModule = rtc::scoped_refptr<LibWebRTCAudioModule>(new rtc::RefCountedObject<LibWebRTCAudioModule>()); |
| m_audioModule = audioModule.get(); |
| |
| return webrtc::CreatePeerConnectionFactory(networkThread, signalingThread, signalingThread, WTFMove(audioModule), webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), createEncoderFactory(), createDecoderFactory(), nullptr, nullptr, nullptr); |
| } |
| |
| std::unique_ptr<webrtc::VideoDecoderFactory> LibWebRTCProvider::createDecoderFactory() |
| { |
| return nullptr; |
| } |
| |
| std::unique_ptr<webrtc::VideoEncoderFactory> LibWebRTCProvider::createEncoderFactory() |
| { |
| return nullptr; |
| } |
| |
| void LibWebRTCProvider::setPeerConnectionFactory(rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>&& factory) |
| { |
| auto* thread = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer).signalingThread.get(); |
| m_factory = webrtc::PeerConnectionFactoryProxy::Create(thread, thread, WTFMove(factory)); |
| } |
| |
| void LibWebRTCProvider::disableEnumeratingAllNetworkInterfaces() |
| { |
| m_enableEnumeratingAllNetworkInterfaces = false; |
| } |
| |
| void LibWebRTCProvider::enableEnumeratingAllNetworkInterfaces() |
| { |
| m_enableEnumeratingAllNetworkInterfaces = true; |
| } |
| |
| rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(ScriptExecutionContextIdentifier, webrtc::PeerConnectionObserver& observer, rtc::PacketSocketFactory*, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration) |
| { |
| // Default WK1 implementation. |
| ASSERT(m_useNetworkThreadWithSocketServer); |
| auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer); |
| |
| if (!factoryAndThreads.networkManager) |
| factoryAndThreads.networkManager = makeUniqueWithoutFastMallocCheck<rtc::BasicNetworkManager>(); |
| |
| if (!factoryAndThreads.packetSocketFactory) |
| factoryAndThreads.packetSocketFactory = makeUnique<BasicPacketSocketFactory>(*factoryAndThreads.networkThread); |
| factoryAndThreads.packetSocketFactory->setDisableNonLocalhostConnections(m_disableNonLocalhostConnections); |
| |
| return createPeerConnection(observer, *factoryAndThreads.networkManager, *factoryAndThreads.packetSocketFactory, WTFMove(configuration), nullptr); |
| } |
| |
| void LibWebRTCProvider::setEnableWebRTCEncryption(bool enableWebRTCEncryption) |
| { |
| auto* factory = this->factory(); |
| if (!factory) |
| return; |
| |
| webrtc::PeerConnectionFactoryInterface::Options options; |
| options.disable_encryption = !enableWebRTCEncryption; |
| options.ssl_max_version = m_useDTLS10 ? rtc::SSL_PROTOCOL_DTLS_10 : rtc::SSL_PROTOCOL_DTLS_12; |
| m_factory->SetOptions(options); |
| } |
| |
| void LibWebRTCProvider::setUseDTLS10(bool useDTLS10) |
| { |
| m_useDTLS10 = useDTLS10; |
| |
| auto* factory = this->factory(); |
| if (!factory) |
| return; |
| |
| webrtc::PeerConnectionFactoryInterface::Options options; |
| options.ssl_max_version = useDTLS10 ? rtc::SSL_PROTOCOL_DTLS_10 : rtc::SSL_PROTOCOL_DTLS_12; |
| m_factory->SetOptions(options); |
| } |
| |
| rtc::scoped_refptr<webrtc::PeerConnectionInterface> LibWebRTCProvider::createPeerConnection(webrtc::PeerConnectionObserver& observer, rtc::NetworkManager& networkManager, rtc::PacketSocketFactory& packetSocketFactory, webrtc::PeerConnectionInterface::RTCConfiguration&& configuration, std::unique_ptr<webrtc::AsyncResolverFactory>&& asyncResolveFactory) |
| { |
| auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer); |
| |
| std::unique_ptr<cricket::BasicPortAllocator> portAllocator; |
| factoryAndThreads.signalingThread->Invoke<void>(RTC_FROM_HERE, [&]() { |
| auto basicPortAllocator = makeUniqueWithoutFastMallocCheck<cricket::BasicPortAllocator>(&networkManager, &packetSocketFactory); |
| |
| basicPortAllocator->set_allow_tcp_listen(false); |
| portAllocator = WTFMove(basicPortAllocator); |
| }); |
| |
| auto* factory = this->factory(); |
| if (!factory) |
| return nullptr; |
| |
| webrtc::PeerConnectionDependencies dependencies { &observer }; |
| dependencies.allocator = WTFMove(portAllocator); |
| dependencies.async_resolver_factory = WTFMove(asyncResolveFactory); |
| |
| auto peerConnectionOrError = m_factory->CreatePeerConnectionOrError(configuration, WTFMove(dependencies)); |
| if (!peerConnectionOrError.ok()) |
| return nullptr; |
| |
| return peerConnectionOrError.MoveValue(); |
| } |
| |
| void LibWebRTCProvider::prepareCertificateGenerator(Function<void(rtc::RTCCertificateGenerator&)>&& callback) |
| { |
| auto& factoryAndThreads = getStaticFactoryAndThreads(m_useNetworkThreadWithSocketServer); |
| if (!factoryAndThreads.certificateGenerator) |
| factoryAndThreads.certificateGenerator = makeUniqueWithoutFastMallocCheck<rtc::RTCCertificateGenerator>(factoryAndThreads.signalingThread.get(), factoryAndThreads.networkThread.get()); |
| |
| auto& generator = *factoryAndThreads.certificateGenerator; |
| callOnWebRTCSignalingThread([&generator, callback = WTFMove(callback)]() mutable { |
| callback(generator); |
| }); |
| } |
| |
| void LibWebRTCProvider::setH265Support(bool value) |
| { |
| m_supportsH265 = value; |
| m_videoDecodingCapabilities = { }; |
| m_videoEncodingCapabilities = { }; |
| } |
| |
| void LibWebRTCProvider::setVP9Support(bool supportsVP9Profile0, bool supportsVP9Profile2) |
| { |
| m_supportsVP9Profile0 = supportsVP9Profile0; |
| m_supportsVP9Profile2 = supportsVP9Profile2; |
| |
| m_videoDecodingCapabilities = { }; |
| m_videoEncodingCapabilities = { }; |
| } |
| |
| void LibWebRTCProvider::setVP9VTBSupport(bool value) |
| { |
| m_supportsVP9VTB = value; |
| |
| m_videoDecodingCapabilities = { }; |
| m_videoEncodingCapabilities = { }; |
| } |
| |
| static inline std::optional<cricket::MediaType> typeFromKind(const String& kind) |
| { |
| if (kind == "audio"_s) |
| return cricket::MediaType::MEDIA_TYPE_AUDIO; |
| if (kind == "video"_s) |
| return cricket::MediaType::MEDIA_TYPE_VIDEO; |
| return { }; |
| } |
| |
| static inline String fromStdString(const std::string& value) |
| { |
| return String::fromUTF8(value.data(), value.length()); |
| } |
| |
| static inline std::optional<uint16_t> toChannels(absl::optional<int> numChannels) |
| { |
| if (!numChannels) |
| return { }; |
| return static_cast<uint32_t>(*numChannels); |
| } |
| |
| static inline RTCRtpCapabilities toRTCRtpCapabilities(const webrtc::RtpCapabilities& rtpCapabilities) |
| { |
| RTCRtpCapabilities capabilities; |
| |
| capabilities.codecs.reserveInitialCapacity(rtpCapabilities.codecs.size()); |
| for (auto& codec : rtpCapabilities.codecs) { |
| StringBuilder sdpFmtpLineBuilder; |
| bool hasParameter = false; |
| for (auto& parameter : codec.parameters) { |
| sdpFmtpLineBuilder.append(hasParameter ? ";" : "", StringView(parameter.first.data(), parameter.first.length()), '=', StringView(parameter.second.data(), parameter.second.length())); |
| hasParameter = true; |
| } |
| String sdpFmtpLine; |
| if (sdpFmtpLineBuilder.length()) |
| sdpFmtpLine = sdpFmtpLineBuilder.toString(); |
| capabilities.codecs.uncheckedAppend(RTCRtpCodecCapability { fromStdString(codec.mime_type()), static_cast<uint32_t>(codec.clock_rate ? *codec.clock_rate : 0), toChannels(codec.num_channels), WTFMove(sdpFmtpLine) }); |
| } |
| |
| capabilities.headerExtensions.reserveInitialCapacity(rtpCapabilities.header_extensions.size()); |
| for (auto& header : rtpCapabilities.header_extensions) |
| capabilities.headerExtensions.uncheckedAppend(RTCRtpCapabilities::HeaderExtensionCapability { fromStdString(header.uri) }); |
| |
| return capabilities; |
| } |
| |
| std::optional<RTCRtpCapabilities> LibWebRTCProvider::receiverCapabilities(const String& kind) |
| { |
| auto mediaType = typeFromKind(kind); |
| if (!mediaType) |
| return { }; |
| |
| switch (*mediaType) { |
| case cricket::MediaType::MEDIA_TYPE_AUDIO: |
| return audioDecodingCapabilities(); |
| case cricket::MediaType::MEDIA_TYPE_VIDEO: |
| return videoDecodingCapabilities(); |
| case cricket::MediaType::MEDIA_TYPE_DATA: |
| ASSERT_NOT_REACHED(); |
| return { }; |
| case cricket::MediaType::MEDIA_TYPE_UNSUPPORTED: |
| ASSERT_NOT_REACHED(); |
| return { }; |
| } |
| } |
| |
| std::optional<RTCRtpCapabilities>& LibWebRTCProvider::audioDecodingCapabilities() |
| { |
| if (!m_audioDecodingCapabilities) { |
| if (auto* factory = this->factory()) |
| m_audioDecodingCapabilities = toRTCRtpCapabilities(factory->GetRtpReceiverCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)); |
| } |
| return m_audioDecodingCapabilities; |
| } |
| |
| std::optional<RTCRtpCapabilities>& LibWebRTCProvider::videoDecodingCapabilities() |
| { |
| if (!m_videoDecodingCapabilities) { |
| if (auto* factory = this->factory()) |
| m_videoDecodingCapabilities = toRTCRtpCapabilities(factory->GetRtpReceiverCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)); |
| } |
| return m_videoDecodingCapabilities; |
| } |
| |
| std::optional<RTCRtpCapabilities> LibWebRTCProvider::senderCapabilities(const String& kind) |
| { |
| auto mediaType = typeFromKind(kind); |
| if (!mediaType) |
| return { }; |
| |
| switch (*mediaType) { |
| case cricket::MediaType::MEDIA_TYPE_AUDIO: |
| return audioEncodingCapabilities(); |
| case cricket::MediaType::MEDIA_TYPE_VIDEO: |
| return videoEncodingCapabilities(); |
| case cricket::MediaType::MEDIA_TYPE_DATA: |
| ASSERT_NOT_REACHED(); |
| return { }; |
| case cricket::MediaType::MEDIA_TYPE_UNSUPPORTED: |
| ASSERT_NOT_REACHED(); |
| return { }; |
| } |
| } |
| |
| std::optional<RTCRtpCapabilities>& LibWebRTCProvider::audioEncodingCapabilities() |
| { |
| if (!m_audioEncodingCapabilities) { |
| if (auto* factory = this->factory()) |
| m_audioEncodingCapabilities = toRTCRtpCapabilities(factory->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)); |
| } |
| return m_audioEncodingCapabilities; |
| } |
| |
| std::optional<RTCRtpCapabilities>& LibWebRTCProvider::videoEncodingCapabilities() |
| { |
| if (!m_videoEncodingCapabilities) { |
| if (auto* factory = this->factory()) |
| m_videoEncodingCapabilities = toRTCRtpCapabilities(factory->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)); |
| } |
| return m_videoEncodingCapabilities; |
| } |
| |
| std::optional<RTCRtpCodecCapability> LibWebRTCProvider::codecCapability(const ContentType& contentType, const std::optional<RTCRtpCapabilities>& capabilities) |
| { |
| if (!capabilities) |
| return { }; |
| |
| auto containerType = contentType.containerType(); |
| for (auto& codec : capabilities->codecs) { |
| if (equalIgnoringASCIICase(containerType, codec.mimeType)) |
| return codec; |
| } |
| return { }; |
| } |
| #endif // USE(LIBWEBRTC) |
| |
| void LibWebRTCProvider::createDecodingConfiguration(MediaDecodingConfiguration&& configuration, DecodingConfigurationCallback&& callback) |
| { |
| ASSERT(configuration.type == MediaDecodingType::WebRTC); |
| |
| #if USE(LIBWEBRTC) |
| // FIXME: Validate additional parameters, in particular mime type parameters. |
| MediaCapabilitiesDecodingInfo info { WTFMove(configuration) }; |
| |
| if (info.supportedConfiguration.video) { |
| ContentType contentType { info.supportedConfiguration.video->contentType }; |
| auto codec = codecCapability(contentType, videoDecodingCapabilities()); |
| if (!codec) { |
| callback({ }); |
| return; |
| } |
| info.supported = true; |
| #if PLATFORM(COCOA) |
| auto containerType = contentType.containerType(); |
| if (containerType == "video/vp8") |
| info.powerEfficient = false; |
| else if (containerType == "video/vp9") |
| info.powerEfficient = isSupportingVP9VTB(); |
| else |
| info.powerEfficient = true; |
| info.smooth = info.powerEfficient; |
| #endif |
| } |
| if (info.supportedConfiguration.audio) { |
| ContentType contentType { info.supportedConfiguration.audio->contentType }; |
| auto codec = codecCapability(contentType, audioDecodingCapabilities()); |
| if (!codec) { |
| callback({ }); |
| return; |
| } |
| info.supported = true; |
| } |
| callback(WTFMove(info)); |
| #else |
| UNUSED_PARAM(configuration); |
| callback({ }); |
| #endif // USE(LIBWEBRTC) |
| } |
| |
| void LibWebRTCProvider::createEncodingConfiguration(MediaEncodingConfiguration&& configuration, EncodingConfigurationCallback&& callback) |
| { |
| ASSERT(configuration.type == MediaEncodingType::WebRTC); |
| |
| #if USE(LIBWEBRTC) |
| // FIXME: Validate additional parameters, in particular mime type parameters. |
| MediaCapabilitiesEncodingInfo info { WTFMove(configuration) }; |
| |
| if (info.supportedConfiguration.video) { |
| ContentType contentType { info.supportedConfiguration.video->contentType }; |
| auto codec = codecCapability(contentType, videoEncodingCapabilities()); |
| if (!codec) { |
| callback({ }); |
| return; |
| } |
| info.supported = true; |
| #if PLATFORM(COCOA) |
| auto containerType = contentType.containerType(); |
| if (containerType == "video/vp8") |
| info.powerEfficient = false; |
| else if (containerType == "video/vp9") |
| info.powerEfficient = isSupportingVP9VTB(); |
| else |
| info.powerEfficient = true; |
| info.smooth = info.powerEfficient; |
| #endif |
| } |
| if (info.supportedConfiguration.audio) { |
| ContentType contentType { info.supportedConfiguration.audio->contentType }; |
| auto codec = codecCapability(contentType, audioEncodingCapabilities()); |
| if (!codec) { |
| callback({ }); |
| return; |
| } |
| info.supported = true; |
| } |
| callback(WTFMove(info)); |
| #else |
| UNUSED_PARAM(configuration); |
| callback({ }); |
| #endif // USE(LIBWEBRTC) |
| } |
| |
| } // namespace WebCore |