Source/WTF/ChangeLog

 12022-02-12 Philippe Normand <pnormand@igalia.com>
 2
 3 [GStreamer] Initial import of the GstWebRTC backend
 4 https://bugs.webkit.org/show_bug.cgi?id=236540
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * Scripts/Preferences/WebPreferences.yaml: Unconditionally enable WebRTC when GstWebRTC is
 9 enabled. We don't have a runtime Provider yet.
 10 * Scripts/Preferences/WebPreferencesExperimental.yaml: Disable encoded transforms unless libwebrtc is enabled.
 11 * wtf/glib/GRefPtr.cpp: Add GArray handling.
 12 (WTF::refGPtr):
 13 (WTF::derefGPtr):
 14 * wtf/glib/GRefPtr.h:
 15
1162022-02-24 Ryan Haddad <ryanhaddad@apple.com>
217
318 Unreviewed, reverting r290452.

Source/WebCore/ChangeLog

 12022-02-12 Philippe Normand <pnormand@igalia.com>
 2
 3 [GStreamer] Initial import of the GstWebRTC backend
 4 https://bugs.webkit.org/show_bug.cgi?id=236540
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Initial GstWebRTC backend. A lot of features unimplemented still, but we will incrementally
 9 improve the layout test coverage in follow-up patches. Most notable short-comings currently:
 10
 11 - DataChannel support is incomplete (bug 235879)
 12 - Network traffic not routed through Network process yet
 13 - Stats support incomplete
 14 - DTMF support unimplemented
 15 - ICE restarts not supported yet
 16 - Re-negotiation unlikely to work
 17 - Simulcast not handled yet
 18 - Balanced bundle not supported
 19 - RTX and FEC un-tested, but shouldn't be hard to fix
 20
 21 * Modules/mediastream/MediaDevices.cpp:
 22 * Modules/mediastream/PeerConnectionBackend.cpp:
 23 (WebCore::PeerConnectionBackend::generateCertificate):
 24 * Modules/mediastream/RTCPeerConnection.cpp:
 25 (WebCore::RTCPeerConnection::create):
 26 * Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp: Added.
 27 (WebCore::GStreamerDataChannelHandler::fromRTCDataChannelInit):
 28 (WebCore::GStreamerDataChannelHandler::channelEvent):
 29 (WebCore::GStreamerDataChannelHandler::GStreamerDataChannelHandler):
 30 (WebCore::GStreamerDataChannelHandler::~GStreamerDataChannelHandler):
 31 (WebCore::GStreamerDataChannelHandler::setClient):
 32 (WebCore::GStreamerDataChannelHandler::sendStringData):
 33 (WebCore::GStreamerDataChannelHandler::sendRawData):
 34 (WebCore::GStreamerDataChannelHandler::close):
 35 (WebCore::GStreamerDataChannelHandler::checkState):
 36 (WebCore::GStreamerDataChannelHandler::readyStateChanged):
 37 (WebCore::GStreamerDataChannelHandler::onMessageData):
 38 (WebCore::GStreamerDataChannelHandler::onMessageString):
 39 (WebCore::GStreamerDataChannelHandler::onError):
 40 (WebCore::GStreamerDataChannelHandler::onBufferedAmountLow):
 41 (WebCore::GStreamerDataChannelHandler::postTask):
 42 * Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h: Added.
 43 * Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp: Added.
 44 (WebCore::GStreamerDtlsTransportBackend::GStreamerDtlsTransportBackend):
 45 (WebCore::GStreamerDtlsTransportBackend::~GStreamerDtlsTransportBackend):
 46 (WebCore::GStreamerDtlsTransportBackend::iceTransportBackend):
 47 (WebCore::GStreamerDtlsTransportBackend::registerClient):
 48 (WebCore::GStreamerDtlsTransportBackend::unregisterClient):
 49 (WebCore::GStreamerDtlsTransportBackend::stateChanged):
 50 * Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.h: Added.
 51 * Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp: Added.
 52 (WebCore::GStreamerIceTransportBackend::GStreamerIceTransportBackend):
 53 (WebCore::GStreamerIceTransportBackend::~GStreamerIceTransportBackend):
 54 (WebCore::GStreamerIceTransportBackend::iceTransportChanged):
 55 (WebCore::GStreamerIceTransportBackend::registerClient):
 56 (WebCore::GStreamerIceTransportBackend::unregisterClient):
 57 (WebCore::GStreamerIceTransportBackend::stateChanged):
 58 (WebCore::GStreamerIceTransportBackend::gatheringStateChanged):
 59 * Modules/mediastream/gstreamer/GStreamerIceTransportBackend.h: Added.
 60 * Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp: Added.
 61 (WebCore::GStreamerMediaEndpoint::GStreamerMediaEndpoint):
 62 (WebCore::GStreamerMediaEndpoint::initializePipeline):
 63 (WebCore::GStreamerMediaEndpoint::~GStreamerMediaEndpoint):
 64 (WebCore::GStreamerMediaEndpoint::teardownPipeline):
 65 (WebCore::GStreamerMediaEndpoint::handleMessage):
 66 (WebCore::GStreamerMediaEndpoint::disposeElementChain):
 67 (WebCore::GStreamerMediaEndpoint::setConfiguration):
 68 (WebCore::GStreamerMediaEndpoint::restartIce):
 69 (WebCore::fetchDescription):
 70 (WebCore::fetchSignalingState):
 71 (WebCore::descriptionsFromWebRTCBin):
 72 (WebCore::GStreamerMediaEndpoint::doSetLocalDescription):
 73 (WebCore::GStreamerMediaEndpoint::setRemoteDescriptionSucceeded):
 74 (WebCore::GStreamerMediaEndpoint::doSetRemoteDescription):
 75 (WebCore::SetDescriptionCallData::SetDescriptionCallData):
 76 (WebCore::GStreamerMediaEndpoint::setDescription):
 77 (WebCore::GStreamerMediaEndpoint::storeRemoteMLineInfo):
 78 (WebCore::GStreamerMediaEndpoint::configureAndLinkSource):
 79 (WebCore::GStreamerMediaEndpoint::requestPad):
 80 (WebCore::GStreamerMediaEndpoint::addTrack):
 81 (WebCore::GStreamerMediaEndpoint::removeTrack):
 82 (WebCore::GStreamerMediaEndpoint::doCreateOffer):
 83 (WebCore::GStreamerMediaEndpoint::doCreateAnswer):
 84 (WebCore::GStreamerMediaEndpoint::initiate):
 85 (WebCore::GStreamerMediaEndpoint::getStats):
 86 (WebCore::GStreamerMediaEndpoint::mediaStreamFromRTCStream):
 87 (WebCore::GStreamerMediaEndpoint::addRemoteStream):
 88 (WebCore::GStreamerMediaEndpoint::removeRemoteStream):
 89 (WebCore::GStreamerMediaEndpoint::createTransceiverBackends):
 90 (WebCore::GStreamerMediaEndpoint::addTransceiver):
 91 (WebCore::GStreamerMediaEndpoint::createSourceForTrack):
 92 (WebCore::GStreamerMediaEndpoint::setSenderSourceFromTrack):
 93 (WebCore::GStreamerMediaEndpoint::transceiverBackendFromSender):
 94 (WebCore::GStreamerMediaEndpoint::addIceCandidate):
 95 (WebCore::GStreamerMediaEndpoint::createDataChannel):
 96 (WebCore::GStreamerMediaEndpoint::onDataChannel):
 97 (WebCore::GStreamerMediaEndpoint::close):
 98 (WebCore::GStreamerMediaEndpoint::stop):
 99 (WebCore::GStreamerMediaEndpoint::suspend):
 100 (WebCore::GStreamerMediaEndpoint::resume):
 101 (WebCore::GStreamerMediaEndpoint::onNegotiationNeeded):
 102 (WebCore::GStreamerMediaEndpoint::onIceConnectionChange):
 103 (WebCore::GStreamerMediaEndpoint::onIceGatheringChange):
 104 (WebCore::GStreamerMediaEndpoint::onIceCandidate):
 105 (WebCore::GStreamerMediaEndpoint::createSessionDescriptionSucceeded):
 106 (WebCore::GStreamerMediaEndpoint::createSessionDescriptionFailed):
 107 (WebCore::GStreamerMediaEndpoint::collectTransceivers):
 108 (WebCore::GStreamerMediaEndpoint::gatherStatsForLogging):
 109 (WebCore::RTCStatsLogger::RTCStatsLogger):
 110 (WebCore::RTCStatsLogger::toJSONString const):
 111 (WebCore::GStreamerMediaEndpoint::processStats):
 112 (WebCore::GStreamerMediaEndpoint::onStatsDelivered):
 113 (WebCore::GStreamerMediaEndpoint::startLoggingStats):
 114 (WebCore::GStreamerMediaEndpoint::stopLoggingStats):
 115 (WebCore::GStreamerMediaEndpoint::logChannel const):
 116 (WebCore::GStreamerMediaEndpoint::statsLogInterval const):
 117 (WebCore::GStreamerMediaEndpoint::gatherDecoderImplementationName):
 118 (WTF::LogArgument<WebCore::RTCStatsLogger>::toString):
 119 * Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h: Added.
 120 (WebCore::GStreamerMediaEndpoint::create):
 121 (WebCore::GStreamerMediaEndpoint::isStopped const):
 122 (WebCore::GStreamerMediaEndpoint::isNegotiationNeeded const):
 123 (WebCore::GStreamerMediaEndpoint::pipeline const):
 124 * Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp: Added.
 125 (WebCore::createGStreamerPeerConnectionBackend):
 126 (WebCore::PeerConnectionBackend::receiverCapabilities):
 127 (WebCore::PeerConnectionBackend::senderCapabilities):
 128 (WebCore::GStreamerPeerConnectionBackend::GStreamerPeerConnectionBackend):
 129 (WebCore::GStreamerPeerConnectionBackend::suspend):
 130 (WebCore::GStreamerPeerConnectionBackend::resume):
 131 (WebCore::GStreamerPeerConnectionBackend::restartIce):
 132 (WebCore::GStreamerPeerConnectionBackend::setConfiguration):
 133 (WebCore::GStreamerPeerConnectionBackend::getStats):
 134 (WebCore::backendFromRTPSender):
 135 (WebCore::GStreamerPeerConnectionBackend::doSetLocalDescription):
 136 (WebCore::GStreamerPeerConnectionBackend::doSetRemoteDescription):
 137 (WebCore::GStreamerPeerConnectionBackend::doCreateOffer):
 138 (WebCore::GStreamerPeerConnectionBackend::doCreateAnswer):
 139 (WebCore::GStreamerPeerConnectionBackend::close):
 140 (WebCore::GStreamerPeerConnectionBackend::doStop):
 141 (WebCore::GStreamerPeerConnectionBackend::doAddIceCandidate):
 142 (WebCore::GStreamerPeerConnectionBackend::createReceiver):
 143 (WebCore::GStreamerPeerConnectionBackend::createDataChannelHandler):
 144 (WebCore::findExistingSender):
 145 (WebCore::GStreamerPeerConnectionBackend::addTrack):
 146 (WebCore::GStreamerPeerConnectionBackend::addTransceiverFromTrackOrKind):
 147 (WebCore::GStreamerPeerConnectionBackend::addTransceiver):
 148 (WebCore::GStreamerPeerConnectionBackend::setSenderSourceFromTrack):
 149 (WebCore::backendFromRTPTransceiver):
 150 (WebCore::GStreamerPeerConnectionBackend::existingTransceiver):
 151 (WebCore::GStreamerPeerConnectionBackend::newRemoteTransceiver):
 152 (WebCore::GStreamerPeerConnectionBackend::collectTransceivers):
 153 (WebCore::GStreamerPeerConnectionBackend::removeTrack):
 154 (WebCore::GStreamerPeerConnectionBackend::applyRotationForOutgoingVideoSources):
 155 (WebCore::GStreamerPeerConnectionBackend::gatherDecoderImplementationName):
 156 (WebCore::GStreamerPeerConnectionBackend::isNegotiationNeeded const):
 157 * Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.h: Added.
 158 * Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp: Added.
 159 (WebCore::GStreamerRtpReceiverBackend::getParameters):
 160 (WebCore::GStreamerRtpReceiverBackend::getContributingSources const):
 161 (WebCore::GStreamerRtpReceiverBackend::getSynchronizationSources const):
 162 (WebCore::GStreamerRtpReceiverBackend::createSource):
 163 (WebCore::GStreamerRtpReceiverBackend::rtcRtpTransformBackend):
 164 (WebCore::GStreamerRtpReceiverBackend::dtlsTransportBackend):
 165 * Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.h: Added.
 166 * Modules/mediastream/gstreamer/GStreamerRtpReceiverTransformBackend.cpp: Added.
 167 (WebCore::mediaTypeFromReceiver):
 168 (WebCore::GStreamerRtpReceiverTransformBackend::GStreamerRtpReceiverTransformBackend):
 169 (WebCore::GStreamerRtpReceiverTransformBackend::~GStreamerRtpReceiverTransformBackend):
 170 (WebCore::GStreamerRtpReceiverTransformBackend::setTransformableFrameCallback):
 171 (WebCore::GStreamerRtpReceiverTransformBackend::requestKeyFrame):
 172 * Modules/mediastream/gstreamer/GStreamerRtpReceiverTransformBackend.h: Added.
 173 * Modules/mediastream/gstreamer/GStreamerRtpSenderBackend.cpp: Added.
 174 (WebCore::updateTrackSource):
 175 (WebCore::GStreamerRtpSenderBackend::startSource):
 176 (WebCore::GStreamerRtpSenderBackend::stopSource):
 177 (WebCore::GStreamerRtpSenderBackend::replaceTrack):
 178 (WebCore::GStreamerRtpSenderBackend::getParameters const):
 179 (WebCore::GStreamerRtpSenderBackend::setParameters):
 180 (WebCore::GStreamerRtpSenderBackend::createDTMFBackend):
 181 (WebCore::GStreamerRtpSenderBackend::rtcRtpTransformBackend):
 182 (WebCore::GStreamerRtpSenderBackend::setMediaStreamIds):
 183 (WebCore::GStreamerRtpSenderBackend::dtlsTransportBackend):
 184 * Modules/mediastream/gstreamer/GStreamerRtpSenderBackend.h: Added.
 185 * Modules/mediastream/gstreamer/GStreamerRtpSenderTransformBackend.cpp: Added.
 186 (WebCore::mediaTypeFromSender):
 187 (WebCore::GStreamerRtpSenderTransformBackend::GStreamerRtpSenderTransformBackend):
 188 (WebCore::GStreamerRtpSenderTransformBackend::~GStreamerRtpSenderTransformBackend):
 189 (WebCore::GStreamerRtpSenderTransformBackend::setTransformableFrameCallback):
 190 (WebCore::GStreamerRtpSenderTransformBackend::requestKeyFrame):
 191 * Modules/mediastream/gstreamer/GStreamerRtpSenderTransformBackend.h: Added.
 192 * Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp: Added.
 193 (WebCore::GStreamerRtpTransceiverBackend::GStreamerRtpTransceiverBackend):
 194 (WebCore::GStreamerRtpTransceiverBackend::createReceiverBackend):
 195 (WebCore::GStreamerRtpTransceiverBackend::createSenderBackend):
 196 (WebCore::GStreamerRtpTransceiverBackend::direction const):
 197 (WebCore::GStreamerRtpTransceiverBackend::currentDirection const):
 198 (WebCore::GStreamerRtpTransceiverBackend::setDirection):
 199 (WebCore::GStreamerRtpTransceiverBackend::mid):
 200 (WebCore::GStreamerRtpTransceiverBackend::stop):
 201 (WebCore::GStreamerRtpTransceiverBackend::stopped const):
 202 (WebCore::GStreamerRtpTransceiverBackend::setCodecPreferences):
 203 * Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.h: Added.
 204 * Modules/mediastream/gstreamer/GStreamerRtpTransformBackend.cpp: Added.
 205 (WebCore::GStreamerRtpTransformBackend::setInputCallback):
 206 (WebCore::GStreamerRtpTransformBackend::clearTransformableFrameCallback):
 207 (WebCore::GStreamerRtpTransformBackend::processTransformedFrame):
 208 * Modules/mediastream/gstreamer/GStreamerRtpTransformBackend.h: Added.
 209 (WebCore::GStreamerRtpTransformBackend::GStreamerRtpTransformBackend):
 210 * Modules/mediastream/gstreamer/GStreamerSctpTransportBackend.cpp: Added.
 211 (WebCore::toRTCSctpTransportState):
 212 (WebCore::GStreamerSctpTransportBackend::GStreamerSctpTransportBackend):
 213 (WebCore::GStreamerSctpTransportBackend::~GStreamerSctpTransportBackend):
 214 (WebCore::GStreamerSctpTransportBackend::dtlsTransportBackend):
 215 (WebCore::GStreamerSctpTransportBackend::registerClient):
 216 (WebCore::GStreamerSctpTransportBackend::unregisterClient):
 217 (WebCore::GStreamerSctpTransportBackend::stateChanged):
 218 * Modules/mediastream/gstreamer/GStreamerSctpTransportBackend.h: Added.
 219 * Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp: Added.
 220 (WebCore::fillRTCStats):
 221 (WebCore::fillRTCRTPStreamStats):
 222 (WebCore::fillRTCCodecStats):
 223 (WebCore::fillInboundRTPStreamStats):
 224 (WebCore::fillOutboundRTPStreamStats):
 225 (WebCore::fillRTCPeerConnectionStats):
 226 (WebCore::fillRTCTransportStats):
 227 (WebCore::fillReportCallback):
 228 (WebCore::CallbackHolder::CallbackHolder):
 229 (WebCore::GStreamerStatsCollector::getStats):
 230 * Modules/mediastream/gstreamer/GStreamerStatsCollector.h: Added.
 231 (WebCore::GStreamerStatsCollector::create):
 232 (WebCore::GStreamerStatsCollector::setElement):
 233 * Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp: Added.
 234 (WebCore::toRTCIceComponent):
 235 (WebCore::toRTCIceProtocol):
 236 (WebCore::toRTCIceTcpCandidateType):
 237 (WebCore::toRTCIceCandidateType):
 238 (WebCore::toRTCError):
 239 (WebCore::toWebRTCBitRatePriority):
 240 (WebCore::fromRTCEncodingParameters):
 241 (WebCore::fromWebRTCBitRatePriority):
 242 (WebCore::toRTCEncodingParameters):
 243 (WebCore::toRTCRtpSendParameters):
 244 (WebCore::ensureDebugCategoryInitialized):
 245 (WebCore::parseIceCandidateSDP):
 246 (WebCore::x509Serialize):
 247 (WebCore::privateKeySerialize):
 248 (WebCore::generateCertificate):
 249 (WebCore::sdpMediaHasAttributeKey):
 250 * Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h: Added.
 251 (WebCore::toRTCRtpTransceiverDirection):
 252 (WebCore::fromRTCRtpTransceiverDirection):
 253 (WebCore::toSessionDescriptionType):
 254 (WebCore::fromSessionDescriptionType):
 255 (WebCore::toSignalingState):
 256 (WebCore::toRTCIceConnectionState):
 257 (WebCore::toRTCDtlsTransportState):
 258 (WebCore::toRTCIceTransportState):
 259 (WebCore::toRTCIceGatheringState):
 260 (WebCore::bundlePolicyFromConfiguration):
 261 (WebCore::iceTransportPolicyFromConfiguration):
 262 (WebCore::toRTCErrorDetailType):
 263 * platform/GStreamer.cmake:
 264 * platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp:
 265 (WebCore::AudioSourceProviderGStreamer::AudioSourceProviderGStreamer):
 266 (WebCore::AudioSourceProviderGStreamer::~AudioSourceProviderGStreamer):
 267 (WebCore::AudioSourceProviderGStreamer::handleNewDeinterleavePad):
 268 * platform/audio/gstreamer/GStreamerAudioStreamDescription.h:
 269 * platform/graphics/gstreamer/GRefPtrGStreamer.cpp:
 270 (WTF::adoptGRef):
 271 (WTF::refGPtr<GstWebRTCRTPReceiver>):
 272 (WTF::derefGPtr<GstWebRTCRTPReceiver>):
 273 (WTF::refGPtr<GstWebRTCRTPSender>):
 274 (WTF::derefGPtr<GstWebRTCRTPSender>):
 275 (WTF::refGPtr<GstWebRTCRTPTransceiver>):
 276 (WTF::derefGPtr<GstWebRTCRTPTransceiver>):
 277 (WTF::refGPtr<GstWebRTCDataChannel>):
 278 (WTF::derefGPtr<GstWebRTCDataChannel>):
 279 (WTF::refGPtr<GstWebRTCDTLSTransport>):
 280 (WTF::derefGPtr<GstWebRTCDTLSTransport>):
 281 (WTF::refGPtr<GstWebRTCICETransport>):
 282 (WTF::derefGPtr<GstWebRTCICETransport>):
 283 * platform/graphics/gstreamer/GRefPtrGStreamer.h:
 284 * platform/graphics/gstreamer/GStreamerCommon.cpp:
 285 (WebCore::capsMediaType):
 286 * platform/graphics/gstreamer/GUniquePtrGStreamer.h:
 287 * platform/mediastream/MediaStreamTrackPrivate.cpp:
 288 (WebCore::MediaStreamTrackPrivate::createAudioSourceProvider):
 289 * platform/mediastream/gstreamer/GStreamerAudioCapturer.cpp:
 290 (WebCore::GStreamerAudioCapturer::GStreamerAudioCapturer):
 291 (WebCore::GStreamerAudioCapturer::createConverter):
 292 * platform/mediastream/gstreamer/GStreamerCapturer.cpp:
 293 (WebCore::GStreamerCapturer::createSource):
 294 * platform/mediastream/gstreamer/GStreamerDTMFSenderBackend.cpp: Added.
 295 (WebCore::GStreamerDTMFSenderBackend::GStreamerDTMFSenderBackend):
 296 (WebCore::GStreamerDTMFSenderBackend::~GStreamerDTMFSenderBackend):
 297 (WebCore::GStreamerDTMFSenderBackend::canInsertDTMF):
 298 (WebCore::GStreamerDTMFSenderBackend::playTone):
 299 (WebCore::GStreamerDTMFSenderBackend::tones const):
 300 (WebCore::GStreamerDTMFSenderBackend::duration const):
 301 (WebCore::GStreamerDTMFSenderBackend::interToneGap const):
 302 (WebCore::GStreamerDTMFSenderBackend::onTonePlayed):
 303 * platform/mediastream/gstreamer/GStreamerDTMFSenderBackend.h: Added.
 304 * platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:
 305 (webkitMediaStreamSrcAddTrack):
 306 * platform/mediastream/gstreamer/GStreamerVideoEncoder.cpp:
 307 (webkit_webrtc_video_encoder_class_init):
 308 * platform/mediastream/gstreamer/RealtimeIncomingAudioSourceGStreamer.cpp: Added.
 309 (WebCore::RealtimeIncomingAudioSourceGStreamer::RealtimeIncomingAudioSourceGStreamer):
 310 (WebCore::RealtimeIncomingAudioSourceGStreamer::~RealtimeIncomingAudioSourceGStreamer):
 311 (WebCore::RealtimeIncomingAudioSourceGStreamer::startProducingData):
 312 (WebCore::RealtimeIncomingAudioSourceGStreamer::stopProducingData):
 313 (WebCore::RealtimeIncomingAudioSourceGStreamer::capabilities):
 314 (WebCore::RealtimeIncomingAudioSourceGStreamer::settings):
 315 (WebCore::RealtimeIncomingAudioSourceGStreamer::dispatchSample):
 316 * platform/mediastream/gstreamer/RealtimeIncomingAudioSourceGStreamer.h: Added.
 317 (WebCore::RealtimeIncomingAudioSourceGStreamer::create):
 318 (isType):
 319 * platform/mediastream/gstreamer/RealtimeIncomingSourceGStreamer.cpp: Added.
 320 (WebCore::RealtimeIncomingSourceGStreamer::RealtimeIncomingSourceGStreamer):
 321 (WebCore::RealtimeIncomingSourceGStreamer::lockValve const):
 322 (WebCore::RealtimeIncomingSourceGStreamer::releaseValve const):
 323 (WebCore::RealtimeIncomingSourceGStreamer::registerClient):
 324 * platform/mediastream/gstreamer/RealtimeIncomingSourceGStreamer.h: Added.
 325 (WebCore::RealtimeIncomingSourceGStreamer::bin):
 326 (WebCore::RealtimeIncomingSourceGStreamer::dispatchSample):
 327 * platform/mediastream/gstreamer/RealtimeIncomingVideoSourceGStreamer.cpp: Added.
 328 (WebCore::RealtimeIncomingVideoSourceGStreamer::RealtimeIncomingVideoSourceGStreamer):
 329 (WebCore::RealtimeIncomingVideoSourceGStreamer::startProducingData):
 330 (WebCore::RealtimeIncomingVideoSourceGStreamer::stopProducingData):
 331 (WebCore::RealtimeIncomingVideoSourceGStreamer::capabilities):
 332 (WebCore::RealtimeIncomingVideoSourceGStreamer::settings):
 333 (WebCore::RealtimeIncomingVideoSourceGStreamer::settingsDidChange):
 334 (WebCore::RealtimeIncomingVideoSourceGStreamer::dispatchSample):
 335 * platform/mediastream/gstreamer/RealtimeIncomingVideoSourceGStreamer.h: Added.
 336 (WebCore::RealtimeIncomingVideoSourceGStreamer::create):
 337 (isType):
 338 * platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.cpp: Added.
 339 (WebCore::RealtimeOutgoingAudioSourceGStreamer::RealtimeOutgoingAudioSourceGStreamer):
 340 (WebCore::RealtimeOutgoingAudioSourceGStreamer::setPayloadType):
 341 * platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.h: Added.
 342 * platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.cpp: Added.
 343 (WebCore::RealtimeOutgoingMediaSourceGStreamer::RealtimeOutgoingMediaSourceGStreamer):
 344 (WebCore::RealtimeOutgoingMediaSourceGStreamer::~RealtimeOutgoingMediaSourceGStreamer):
 345 (WebCore::RealtimeOutgoingMediaSourceGStreamer::setSource):
 346 (WebCore::RealtimeOutgoingMediaSourceGStreamer::start):
 347 (WebCore::RealtimeOutgoingMediaSourceGStreamer::stop):
 348 (WebCore::RealtimeOutgoingMediaSourceGStreamer::sourceMutedChanged):
 349 (WebCore::RealtimeOutgoingMediaSourceGStreamer::sourceEnabledChanged):
 350 (WebCore::RealtimeOutgoingMediaSourceGStreamer::initializeFromTrack):
 351 (WebCore::RealtimeOutgoingMediaSourceGStreamer::link):
 352 (WebCore::RealtimeOutgoingMediaSourceGStreamer::setSinkPad):
 353 * platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.h: Added.
 354 (WebCore::RealtimeOutgoingMediaSourceGStreamer::source const):
 355 (WebCore::RealtimeOutgoingMediaSourceGStreamer::allowedCaps const):
 356 (WebCore::RealtimeOutgoingMediaSourceGStreamer::pad const):
 357 (WebCore::RealtimeOutgoingMediaSourceGStreamer::sender const):
 358 (WebCore::RealtimeOutgoingMediaSourceGStreamer::bin const):
 359 (WebCore::RealtimeOutgoingMediaSourceGStreamer::setPayloadType):
 360 * platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp: Added.
 361 (WebCore::RealtimeOutgoingVideoSourceGStreamer::RealtimeOutgoingVideoSourceGStreamer):
 362 (WebCore::RealtimeOutgoingVideoSourceGStreamer::setPayloadType):
 363 * platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h: Added.
 364 * testing/Internals.cpp:
 365 (WebCore::Internals::resetToConsistentState):
 366 (WebCore::Internals::setWebRTCH265Support):
 367 (WebCore::Internals::setWebRTCVP9Support):
 368 (WebCore::Internals::setWebRTCVP9VTBSupport):
 369 (WebCore::Internals::setEnableWebRTCEncryption):
 370 (WebCore::Internals::setUseDTLS10):
 371
13722022-02-25 Zan Dobersek <zdobersek@igalia.com>
2373
3374 [GTK][WPE] Uncouple libgbm, libdrm dependencies from ANGLE functionality

Source/WTF/Scripts/Preferences/WebPreferences.yaml

@@PeerConnectionEnabled:
17221722 WebKitLegacy:
17231723 default: true
17241724 WebKit:
1725  default: WebCore::LibWebRTCProvider::webRTCAvailable()
 1725 "USE(LIBWEBRTC)": WebCore::LibWebRTCProvider::webRTCAvailable()
 1726 "USE(GSTREAMER_WEBRTC)": true
 1727 default: false
17261728 WebCore:
17271729 default: true
17281730

Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml

@@WebRTCEncodedTransformEnabled:
17091709 WebKitLegacy:
17101710 default: false
17111711 WebKit:
1712  default: true
 1712 "USE(LIBWEBRTC)": true
 1713 default: false
17131714 WebCore:
1714  default: true
 1715 "USE(LIBWEBRTC)": true
 1716 default: false
17151717
17161718# FIXME: Is this implemented for WebKitLegacy? If not, this should be excluded from WebKitLegacy entirely.
17171719WebRTCH264LowLatencyEncoderEnabled:

Source/WTF/wtf/glib/GRefPtr.cpp

@@template <> void derefGPtr(GUri* ptr)
223223}
224224#endif
225225
 226template <>
 227GArray* refGPtr(GArray* ptr)
 228{
 229 if (ptr)
 230 g_array_ref(ptr);
 231
 232 return ptr;
 233}
 234
 235template <>
 236void derefGPtr(GArray* ptr)
 237{
 238 if (ptr)
 239 g_array_unref(ptr);
 240}
 241
226242} // namespace WTF
227243
228244#endif // USE(GLIB)

Source/WTF/wtf/glib/GRefPtr.h

@@template <> WTF_EXPORT_PRIVATE GDateTime* refGPtr(GDateTime* ptr);
250250template <> WTF_EXPORT_PRIVATE void derefGPtr(GDateTime* ptr);
251251template <> WTF_EXPORT_PRIVATE GDBusNodeInfo* refGPtr(GDBusNodeInfo* ptr);
252252template <> WTF_EXPORT_PRIVATE void derefGPtr(GDBusNodeInfo* ptr);
 253template <> WTF_EXPORT_PRIVATE GArray* refGPtr(GArray*);
 254template <> WTF_EXPORT_PRIVATE void derefGPtr(GArray*);
253255
254256#if HAVE(GURI)
255257template <> WTF_EXPORT_PRIVATE GUri* refGPtr(GUri*);

Source/WebCore/Modules/mediacapabilities/MediaCapabilities.cpp

@@static void gatherDecodingInfo(Document& document, MediaDecodingConfiguration&&
180180 configuration.canExposeVP9 = document.settings().vp9DecoderEnabled();
181181#endif
182182
183 #if ENABLE(WEB_RTC)
 183#if ENABLE(WEB_RTC) && USE(LIBWEBRTC)
184184 if (configuration.type == MediaDecodingType::WebRTC) {
185185 if (auto* page = document.page())
186186 page->libWebRTCProvider().createDecodingConfiguration(WTFMove(configuration), WTFMove(decodingCallback));

@@static void gatherEncodingInfo(Document& document, MediaEncodingConfiguration&&
200200 callback(WTFMove(result));
201201 };
202202
203 #if ENABLE(WEB_RTC)
 203#if ENABLE(WEB_RTC) && USE(LIBWEBRTC)
204204 if (configuration.type == MediaEncodingType::WebRTC) {
205205 if (auto* page = document.page())
206206 page->libWebRTCProvider().createEncodingConfiguration(WTFMove(configuration), WTFMove(encodingCallback));

Source/WebCore/Modules/mediastream/MediaDevices.cpp

4040#include "Frame.h"
4141#include "JSDOMPromiseDeferred.h"
4242#include "JSMediaDeviceInfo.h"
 43#include "Logging.h"
4344#include "MediaTrackSupportedConstraints.h"
4445#include "RealtimeMediaSourceSettings.h"
4546#include "Settings.h"

Source/WebCore/Modules/mediastream/PeerConnectionBackend.cpp

5353#include <wtf/text/StringBuilder.h>
5454#include <wtf/text/StringConcatenateNumbers.h>
5555
 56#if USE(GSTREAMER_WEBRTC)
 57#include "GStreamerWebRTCUtils.h"
 58#endif
 59
5660namespace WebCore {
5761
58 #if !USE(LIBWEBRTC)
 62#if !USE(LIBWEBRTC) && !USE(GSTREAMER_WEBRTC)
 63
5964static std::unique_ptr<PeerConnectionBackend> createNoPeerConnectionBackend(RTCPeerConnection&)
6065{
6166 return nullptr;

@@void PeerConnectionBackend::generateCertificate(Document& document, const Certif
437442 promise.reject(InvalidStateError);
438443 return;
439444 }
 445
440446 LibWebRTCCertificateGenerator::generateCertificate(document.securityOrigin(), page->libWebRTCProvider(), info, [promise = WTFMove(promise)](auto&& result) mutable {
441447 promise.settle(WTFMove(result));
442448 });
 449#elif USE(GSTREAMER_WEBRTC)
 450 auto certificate = ::WebCore::generateCertificate(document.securityOrigin(), info);
 451 if (certificate.has_value())
 452 promise.resolve(*certificate);
 453 else
 454 promise.reject(NotSupportedError);
443455#else
444456 UNUSED_PARAM(document);
445  UNUSED_PARAM(expires);
446  UNUSED_PARAM(type);
 457 UNUSED_PARAM(info);
447458 promise.reject(NotSupportedError);
448459#endif
449460}

Source/WebCore/Modules/mediastream/RTCPeerConnection.cpp

@@ExceptionOr<Ref<RTCPeerConnection>> RTCPeerConnection::create(Document& document
9595 if (!peerConnection->isClosed()) {
9696 if (auto* page = document.page()) {
9797 peerConnection->registerToController(page->rtcController());
98 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
 98#if USE(LIBWEBRTC) && (!LOG_DISABLED || !RELEASE_LOG_DISABLED)
9999 if (!page->sessionID().isEphemeral())
100100 page->libWebRTCProvider().setLoggingLevel(LogWebRTC.level);
101101#endif

Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerDataChannelHandler.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "EventNames.h"
 26#include "GStreamerWebRTCUtils.h"
 27#include "RTCDataChannel.h"
 28#include "RTCDataChannelEvent.h"
 29#include "RTCError.h"
 30#include "RTCPriorityType.h"
 31
 32#include <wtf/MainThread.h>
 33
 34GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 35#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 36
 37namespace WebCore {
 38
 39GUniquePtr<GstStructure> GStreamerDataChannelHandler::fromRTCDataChannelInit(const RTCDataChannelInit& options)
 40{
 41 GUniquePtr<GstStructure> init(gst_structure_new("options", "protocol", G_TYPE_STRING, options.protocol.utf8().data(), nullptr));
 42
 43 if (options.ordered)
 44 gst_structure_set(init.get(), "ordered", G_TYPE_BOOLEAN, *options.ordered, nullptr);
 45 if (options.maxPacketLifeTime)
 46 gst_structure_set(init.get(), "max-packet-lifetime", G_TYPE_INT, *options.maxPacketLifeTime, nullptr);
 47 if (options.maxRetransmits)
 48 gst_structure_set(init.get(), "max-retransmits", G_TYPE_INT, *options.maxRetransmits, nullptr);
 49 if (options.negotiated)
 50 gst_structure_set(init.get(), "negotiated", G_TYPE_BOOLEAN, *options.negotiated, nullptr);
 51 if (options.id)
 52 gst_structure_set(init.get(), "id", G_TYPE_INT, *options.id, nullptr);
 53
 54 GstWebRTCPriorityType priorityType;
 55 switch (options.priority) {
 56 case RTCPriorityType::VeryLow:
 57 priorityType = GST_WEBRTC_PRIORITY_TYPE_VERY_LOW;
 58 break;
 59 case RTCPriorityType::Low:
 60 priorityType = GST_WEBRTC_PRIORITY_TYPE_LOW;
 61 break;
 62 case RTCPriorityType::Medium:
 63 priorityType = GST_WEBRTC_PRIORITY_TYPE_MEDIUM;
 64 break;
 65 case RTCPriorityType::High:
 66 priorityType = GST_WEBRTC_PRIORITY_TYPE_HIGH;
 67 break;
 68 }
 69 gst_structure_set(init.get(), "priority", GST_TYPE_WEBRTC_PRIORITY_TYPE, priorityType, nullptr);
 70
 71 return init;
 72}
 73
 74Ref<RTCDataChannelEvent> GStreamerDataChannelHandler::createDataChannelEvent(Document& document, GRefPtr<GstWebRTCDataChannel>&& dataChannel)
 75{
 76 GUniqueOutPtr<char> label;
 77 GUniqueOutPtr<char> protocol;
 78 gboolean ordered, negotiated;
 79 gint maxPacketLifeTime, maxRetransmits, id;
 80 g_object_get(dataChannel.get(), "ordered", &ordered, "label", &label.outPtr(),
 81 "max-packet-lifetime", &maxPacketLifeTime, "max-retransmits", &maxRetransmits,
 82 "protocol", &protocol.outPtr(), "negotiated", &negotiated, "id", &id, nullptr);
 83
 84 RTCDataChannelInit init;
 85 init.ordered = ordered;
 86 init.maxPacketLifeTime = maxPacketLifeTime;
 87 init.maxRetransmits = maxRetransmits;
 88 init.protocol = String(protocol.get());
 89 init.negotiated = negotiated;
 90 init.id = id;
 91
 92 auto handler = WTF::makeUnique<GStreamerDataChannelHandler>(WTFMove(dataChannel));
 93 auto channel = RTCDataChannel::create(document, WTFMove(handler), String::fromUTF8(label.get()), WTFMove(init));
 94 return RTCDataChannelEvent::create(eventNames().datachannelEvent, Event::CanBubble::No, Event::IsCancelable::No, WTFMove(channel));
 95}
 96
 97GStreamerDataChannelHandler::GStreamerDataChannelHandler(GRefPtr<GstWebRTCDataChannel>&& channel)
 98 : m_channel(WTFMove(channel))
 99{
 100 ASSERT(m_channel);
 101
 102 g_signal_connect_swapped(m_channel.get(), "notify::ready-state", G_CALLBACK(+[](GStreamerDataChannelHandler* handler) {
 103 handler->readyStateChanged();
 104 }), this);
 105 g_signal_connect_swapped(m_channel.get(), "on-message-data", G_CALLBACK(+[](GStreamerDataChannelHandler* handler, GBytes* bytes) {
 106 handler->onMessageData(bytes);
 107 }), this);
 108 g_signal_connect_swapped(m_channel.get(), "on-message-string", G_CALLBACK(+[](GStreamerDataChannelHandler* handler, const char* message) {
 109 handler->onMessageString(message);
 110 }), this);
 111 g_signal_connect_swapped(m_channel.get(), "on-error", G_CALLBACK(+[](GStreamerDataChannelHandler* handler, GError* error) {
 112 handler->onError(error);
 113 }), this);
 114 g_signal_connect_swapped(m_channel.get(), "on-buffered-amount-low", G_CALLBACK(+[](GStreamerDataChannelHandler* handler) {
 115 // FIXME: We should pass the amount delta from webrtcbin to the WebCore handler.
 116 handler->onBufferedAmountLow();
 117 }), this);
 118}
 119
 120GStreamerDataChannelHandler::~GStreamerDataChannelHandler()
 121{
 122 g_signal_handlers_disconnect_by_data(m_channel.get(), this);
 123}
 124
 125void GStreamerDataChannelHandler::setClient(RTCDataChannelHandlerClient& client, ScriptExecutionContextIdentifier contextIdentifier)
 126{
 127 Locker locker { m_clientLock };
 128 ASSERT(!m_client);
 129 *m_client = client;
 130 m_contextIdentifier = contextIdentifier;
 131
 132 for (auto& message : m_pendingMessages) {
 133 switchOn(message, [&](Ref<FragmentedSharedBuffer>& data) {
 134 GST_DEBUG("Notifying queued raw data (size: %zu)", data->size());
 135 client.didReceiveRawData(data->makeContiguous()->data(), data->size());
 136 }, [&](String& text) {
 137 GST_DEBUG("Notifying queued string %s", text.ascii().data());
 138 client.didReceiveStringData(text);
 139 }, [&](StateChange stateChange) {
 140 if (stateChange.error) {
 141 if (auto rtcError = toRTCError(*stateChange.error))
 142 client.didDetectError(rtcError.releaseNonNull());
 143 }
 144 GST_DEBUG("Dispatching state change to %d", static_cast<int>(stateChange.state));
 145 client.didChangeReadyState(stateChange.state);
 146 });
 147 }
 148 m_pendingMessages.clear();
 149}
 150
 151bool GStreamerDataChannelHandler::sendStringData(const CString& text)
 152{
 153 GST_DEBUG("Sending string %s", text.data());
 154 g_signal_emit_by_name(m_channel.get(), "send-string", text.data());
 155 return true;
 156}
 157
 158bool GStreamerDataChannelHandler::sendRawData(const uint8_t* data, size_t length)
 159{
 160 auto bytes = adoptGRef(g_bytes_new(data, length));
 161 g_signal_emit_by_name(m_channel.get(), "send-data", bytes.get());
 162 return true;
 163}
 164
 165void GStreamerDataChannelHandler::close()
 166{
 167 g_signal_emit_by_name(m_channel.get(), "close");
 168}
 169
 170void GStreamerDataChannelHandler::checkState()
 171{
 172 ASSERT(m_clientLock.isHeld());
 173
 174 GstWebRTCDataChannelState channelState;
 175 g_object_get(m_channel.get(), "ready-state", &channelState, nullptr);
 176
 177 RTCDataChannelState state;
 178 switch (channelState) {
 179 case GST_WEBRTC_DATA_CHANNEL_STATE_NEW:
 180 case GST_WEBRTC_DATA_CHANNEL_STATE_CONNECTING:
 181 state = RTCDataChannelState::Connecting;
 182 break;
 183 case GST_WEBRTC_DATA_CHANNEL_STATE_OPEN:
 184 state = RTCDataChannelState::Open;
 185 break;
 186 case GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING:
 187 state = RTCDataChannelState::Closing;
 188 break;
 189 case GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED:
 190 state = RTCDataChannelState::Closed;
 191 break;
 192 }
 193
 194 if (!m_client) {
 195 GST_DEBUG("No client yet, queueing state");
 196 m_pendingMessages.append(StateChange { state, { } });
 197 return;
 198 }
 199
 200 if (!*m_client)
 201 return;
 202
 203 GST_DEBUG("Dispatching state change to %d", static_cast<int>(state));
 204 postTask([client = m_client, state] {
 205 if (!*client)
 206 return;
 207 client.value()->didChangeReadyState(state);
 208 });
 209}
 210
 211void GStreamerDataChannelHandler::readyStateChanged()
 212{
 213 Locker locker { m_clientLock };
 214 checkState();
 215}
 216
 217void GStreamerDataChannelHandler::onMessageData(GBytes* bytes)
 218{
 219 Locker locker { m_clientLock };
 220
 221 if (!m_client) {
 222 m_pendingMessages.append(FragmentedSharedBuffer::create(bytes));
 223 return;
 224 }
 225
 226 if (!*m_client)
 227 return;
 228
 229 postTask([client = m_client, bytes = GRefPtr<GBytes>(bytes)] {
 230 if (!*client)
 231 return;
 232 gsize size = 0;
 233 const auto* data = reinterpret_cast<const uint8_t*>(g_bytes_get_data(bytes.get(), &size));
 234 client.value()->didReceiveRawData(data, size);
 235 });
 236}
 237
 238void GStreamerDataChannelHandler::onMessageString(const char* message)
 239{
 240 Locker locker { m_clientLock };
 241
 242 GST_DEBUG("Incoming string: %s", message);
 243 if (!m_client) {
 244 GST_DEBUG("No client yet, keeping as buffered message");
 245 m_pendingMessages.append(String::fromUTF8(message));
 246 return;
 247 }
 248
 249 if (!*m_client)
 250 return;
 251
 252 GST_DEBUG("Dispatching payload");
 253 postTask([client = m_client, string = String::fromUTF8(message)] {
 254 if (!*client)
 255 return;
 256
 257 client.value()->didReceiveStringData(string);
 258 GST_DEBUG("Done");
 259 });
 260}
 261
 262void GStreamerDataChannelHandler::onError(GError* error)
 263{
 264 Locker locker { m_clientLock };
 265 if (!m_client)
 266 return;
 267
 268 GST_WARNING("Got data-channel error %s", error->message);
 269 GUniquePtr<GError> errorCopy(g_error_copy(error));
 270 postTask([client = m_client, error = WTFMove(errorCopy)] {
 271 if (!client || !error)
 272 return;
 273
 274 auto rtcError = toRTCError(error.get());
 275 if (!rtcError)
 276 rtcError = RTCError::create(RTCError::Init { RTCErrorDetailType::DataChannelFailure, { }, { }, { }, { } }, { });
 277 client.value()->didDetectError(rtcError.releaseNonNull());
 278 });
 279}
 280
 281void GStreamerDataChannelHandler::onBufferedAmountLow()
 282{
 283 Locker locker { m_clientLock };
 284 if (!m_client)
 285 return;
 286
 287 postTask([client = m_client] {
 288 if (!client)
 289 return;
 290
 291 // FIXME: Pass amount to handler instead of 0.
 292 client.value()->bufferedAmountIsDecreasing(0);
 293 });
 294}
 295
 296void GStreamerDataChannelHandler::postTask(Function<void()>&& function)
 297{
 298 ASSERT(m_clientLock.isHeld());
 299
 300 if (!m_contextIdentifier) {
 301 callOnMainThread(WTFMove(function));
 302 return;
 303 }
 304 ScriptExecutionContext::postTaskTo(m_contextIdentifier, WTFMove(function));
 305}
 306
 307} // namespace WebCore
 308
 309#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerDataChannelHandler.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GUniquePtrGStreamer.h"
 26#include "RTCDataChannelHandler.h"
 27#include "RTCDataChannelState.h"
 28#include "SharedBuffer.h"
 29
 30#include <wtf/Condition.h>
 31#include <wtf/Lock.h>
 32#include <wtf/WeakPtr.h>
 33
 34namespace WebCore {
 35
 36class Document;
 37class RTCDataChannelEvent;
 38class RTCDataChannelHandlerClient;
 39struct RTCDataChannelInit;
 40
 41class GStreamerDataChannelHandler final : public RTCDataChannelHandler {
 42 WTF_MAKE_FAST_ALLOCATED;
 43public:
 44 explicit GStreamerDataChannelHandler(GRefPtr<GstWebRTCDataChannel>&&);
 45 ~GStreamerDataChannelHandler();
 46
 47 static GUniquePtr<GstStructure> fromRTCDataChannelInit(const RTCDataChannelInit&);
 48 static Ref<RTCDataChannelEvent> createDataChannelEvent(Document&, GRefPtr<GstWebRTCDataChannel>&&);
 49
 50 void onMessageData(GBytes*);
 51 void onMessageString(const char*);
 52 void onError(GError*);
 53 void onBufferedAmountLow();
 54 void readyStateChanged();
 55
 56private:
 57 // RTCDataChannelHandler API
 58 void setClient(RTCDataChannelHandlerClient&, ScriptExecutionContextIdentifier) final;
 59 bool sendStringData(const CString&) final;
 60 bool sendRawData(const uint8_t*, size_t) final;
 61 void close() final;
 62
 63 void checkState();
 64 void postTask(Function<void()>&&);
 65
 66 struct StateChange {
 67 RTCDataChannelState state;
 68 std::optional<GError*> error;
 69 };
 70 using Message = std::variant<StateChange, String, Ref<FragmentedSharedBuffer>>;
 71 using PendingMessages = Vector<Message>;
 72
 73 Lock m_clientLock;
 74 GRefPtr<GstWebRTCDataChannel> m_channel;
 75 std::optional<WeakPtr<RTCDataChannelHandlerClient>> m_client WTF_GUARDED_BY_LOCK(m_clientLock);
 76 ScriptExecutionContextIdentifier m_contextIdentifier;
 77 std::optional<uint64_t> m_previousBufferedAmount;
 78 PendingMessages m_pendingMessages WTF_GUARDED_BY_LOCK(m_clientLock);
 79
 80 Lock m_openLock;
 81 Condition m_openCondition WTF_GUARDED_BY_LOCK(m_openLock);
 82};
 83
 84} // namespace WebCore
 85
 86#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerDtlsTransportBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerIceTransportBackend.h"
 26#include "GStreamerWebRTCUtils.h"
 27#include <JavaScriptCore/ArrayBuffer.h>
 28#include <wtf/glib/GUniquePtr.h>
 29
 30namespace WebCore {
 31
 32GStreamerDtlsTransportBackend::GStreamerDtlsTransportBackend(const GRefPtr<GstWebRTCDTLSTransport>& transport)
 33 : m_backend(transport)
 34{
 35 ASSERT(m_backend);
 36 ASSERT(isMainThread());
 37}
 38
 39GStreamerDtlsTransportBackend::~GStreamerDtlsTransportBackend()
 40{
 41 unregisterClient();
 42}
 43
 44UniqueRef<RTCIceTransportBackend> GStreamerDtlsTransportBackend::iceTransportBackend()
 45{
 46 return makeUniqueRef<GStreamerIceTransportBackend>(m_backend);
 47}
 48
 49void GStreamerDtlsTransportBackend::registerClient(Client& client)
 50{
 51 ASSERT(!m_client);
 52 m_client = client;
 53 g_signal_connect_swapped(m_backend.get(), "notify::state", G_CALLBACK(+[](GStreamerDtlsTransportBackend* backend) {
 54 backend->stateChanged();
 55 }), this);
 56}
 57
 58void GStreamerDtlsTransportBackend::unregisterClient()
 59{
 60 g_signal_handlers_disconnect_by_data(m_backend.get(), this);
 61 m_client.clear();
 62}
 63
 64void GStreamerDtlsTransportBackend::stateChanged() const
 65{
 66 callOnMainThreadAndWait([weakThis = WeakPtr { this }] {
 67 if (!weakThis)
 68 return;
 69 if (!weakThis->m_client)
 70 return;
 71
 72 GUniqueOutPtr<char> remoteCertificate;
 73 GUniqueOutPtr<char> certificate;
 74 GstWebRTCDTLSTransportState state;
 75 g_object_get(weakThis->m_backend.get(), "state", &state, "remote-certificate", &remoteCertificate.outPtr(), "certificate", &certificate.outPtr(), nullptr);
 76
 77 Vector<Ref<JSC::ArrayBuffer>> certificates;
 78 certificates.reserveInitialCapacity(2);
 79 if (remoteCertificate) {
 80 auto remoteCertificateString = makeString(remoteCertificate.get());
 81 auto jsRemoteCertificate = JSC::ArrayBuffer::create(remoteCertificateString.characters8(), remoteCertificateString.sizeInBytes());
 82 certificates.uncheckedAppend(WTFMove(jsRemoteCertificate));
 83
 84 auto certificateString = makeString(certificate.get());
 85 auto jsCertificate = JSC::ArrayBuffer::create(certificateString.characters8(), certificateString.sizeInBytes());
 86 certificates.uncheckedAppend(WTFMove(jsCertificate));
 87 }
 88 weakThis->m_client->onStateChanged(toRTCDtlsTransportState(state), WTFMove(certificates));
 89 });
 90}
 91
 92} // namespace WebCore
 93
 94#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GStreamerPeerConnectionBackend.h"
 26#include "RTCDtlsTransportBackend.h"
 27#include <wtf/WeakPtr.h>
 28
 29namespace WebCore {
 30
 31class GStreamerDtlsTransportBackend final : public RTCDtlsTransportBackend, public CanMakeWeakPtr<GStreamerDtlsTransportBackend, WeakPtrFactoryInitialization::Eager> {
 32 WTF_MAKE_FAST_ALLOCATED;
 33
 34public:
 35 explicit GStreamerDtlsTransportBackend(const GRefPtr<GstWebRTCDTLSTransport>&);
 36 ~GStreamerDtlsTransportBackend();
 37
 38private:
 39 // RTCDtlsTransportBackend
 40 const void* backend() const final { return m_backend.get(); }
 41 UniqueRef<RTCIceTransportBackend> iceTransportBackend() final;
 42 void registerClient(Client&) final;
 43 void unregisterClient() final;
 44
 45 void stateChanged() const;
 46
 47 GRefPtr<GstWebRTCDTLSTransport> m_backend;
 48 WeakPtr<Client> m_client;
 49};
 50
 51} // namespace WebCore
 52
 53#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerIceTransportBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerWebRTCUtils.h"
 26#include <JavaScriptCore/ArrayBuffer.h>
 27#include <wtf/glib/GUniquePtr.h>
 28
 29namespace WebCore {
 30
 31GStreamerIceTransportBackend::GStreamerIceTransportBackend(const GRefPtr<GstWebRTCDTLSTransport>& transport)
 32 : m_backend(transport)
 33{
 34 ASSERT(m_backend);
 35
 36 iceTransportChanged();
 37 g_signal_connect_swapped(m_backend.get(), "notify::transport", G_CALLBACK(+[](GStreamerIceTransportBackend* backend) {
 38 backend->iceTransportChanged();
 39 }), this);
 40}
 41
 42GStreamerIceTransportBackend::~GStreamerIceTransportBackend()
 43{
 44 if (G_IS_OBJECT(m_iceTransport.get()))
 45 g_signal_handlers_disconnect_by_data(m_iceTransport.get(), this);
 46 g_signal_handlers_disconnect_by_data(m_backend.get(), this);
 47}
 48
 49void GStreamerIceTransportBackend::iceTransportChanged()
 50{
 51 if (G_IS_OBJECT(m_iceTransport.get()))
 52 g_signal_handlers_disconnect_by_data(m_iceTransport.get(), this);
 53
 54 g_object_get(m_backend.get(), "transport", &m_iceTransport.outPtr(), nullptr);
 55
 56 g_signal_connect_swapped(m_iceTransport.get(), "notify::state", G_CALLBACK(+[](GStreamerIceTransportBackend* backend) {
 57 backend->stateChanged();
 58 }), this);
 59 g_signal_connect_swapped(m_iceTransport.get(), "notify::gathering-state", G_CALLBACK(+[](GStreamerIceTransportBackend* backend) {
 60 backend->gatheringStateChanged();
 61 }), this);
 62}
 63
 64void GStreamerIceTransportBackend::registerClient(Client& client)
 65{
 66 ASSERT(!m_client);
 67 m_client = client;
 68
 69 GstWebRTCICEConnectionState transportState;
 70 GstWebRTCICEGatheringState gatheringState;
 71 g_object_get(m_iceTransport.get(), "state", &transportState, "gathering-state", &gatheringState, nullptr);
 72
 73 callOnMainThread([weakThis = WeakPtr { *this }, transportState, gatheringState] {
 74 if (!weakThis || !weakThis->m_client)
 75 return;
 76
 77 // We start observing a bit late and might miss the checking state. Synthesize it as needed.
 78 if (transportState > GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING && transportState != GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED)
 79 weakThis->m_client->onStateChanged(RTCIceTransportState::Checking);
 80
 81 weakThis->m_client->onStateChanged(toRTCIceTransportState(transportState));
 82 weakThis->m_client->onGatheringStateChanged(toRTCIceGatheringState(gatheringState));
 83 });
 84}
 85
 86void GStreamerIceTransportBackend::unregisterClient()
 87{
 88 ASSERT(m_client);
 89 m_client.clear();
 90}
 91
 92void GStreamerIceTransportBackend::stateChanged() const
 93{
 94 if (!m_client)
 95 return;
 96
 97 GstWebRTCICEConnectionState transportState;
 98 g_object_get(m_iceTransport.get(), "state", &transportState, nullptr);
 99 callOnMainThread([weakThis = WeakPtr { *this }, transportState] {
 100 if (!weakThis || !weakThis->m_client)
 101 return;
 102 weakThis->m_client->onStateChanged(toRTCIceTransportState(transportState));
 103 });
 104}
 105
 106void GStreamerIceTransportBackend::gatheringStateChanged() const
 107{
 108 if (!m_client)
 109 return;
 110
 111 GstWebRTCICEGatheringState gatheringState;
 112 g_object_get(m_iceTransport.get(), "gathering-state", &gatheringState, nullptr);
 113 callOnMainThread([weakThis = WeakPtr { *this }, gatheringState] {
 114 if (!weakThis || !weakThis->m_client)
 115 return;
 116 weakThis->m_client->onGatheringStateChanged(toRTCIceGatheringState(gatheringState));
 117 });
 118}
 119
 120} // namespace WebCore
 121
 122#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerIceTransportBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "RTCIceTransportBackend.h"
 26#include <wtf/WeakPtr.h>
 27
 28namespace WebCore {
 29
 30class GStreamerIceTransportBackend final : public RTCIceTransportBackend, public CanMakeWeakPtr<GStreamerIceTransportBackend> {
 31 WTF_MAKE_FAST_ALLOCATED;
 32
 33public:
 34 explicit GStreamerIceTransportBackend(const GRefPtr<GstWebRTCDTLSTransport>&);
 35 ~GStreamerIceTransportBackend();
 36
 37private:
 38 // RTCIceTransportBackend
 39 const void* backend() const final { return m_backend.get(); }
 40
 41 void registerClient(Client&) final;
 42 void unregisterClient() final;
 43
 44 void stateChanged() const;
 45 void gatheringStateChanged() const;
 46 void iceTransportChanged();
 47
 48 GRefPtr<GstWebRTCDTLSTransport> m_backend;
 49 GRefPtr<GstWebRTCICETransport> m_iceTransport;
 50 WeakPtr<Client> m_client;
 51};
 52
 53} // namespace WebCore
 54
 55#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerMediaEndpoint.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "Document.h"
 26#include "GStreamerCommon.h"
 27#include "GStreamerDataChannelHandler.h"
 28#include "GStreamerRtpReceiverBackend.h"
 29#include "GStreamerRtpTransceiverBackend.h"
 30#include "GStreamerSctpTransportBackend.h"
 31#include "GStreamerWebRTCUtils.h"
 32#include "JSDOMPromiseDeferred.h"
 33#include "JSRTCStatsReport.h"
 34#include "Logging.h"
 35#include "MediaEndpointConfiguration.h"
 36#include "NotImplemented.h"
 37#include "RTCDataChannel.h"
 38#include "RTCDataChannelEvent.h"
 39#include "RTCIceCandidate.h"
 40#include "RTCOfferOptions.h"
 41#include "RTCPeerConnection.h"
 42#include "RTCSctpTransportBackend.h"
 43#include "RTCSessionDescription.h"
 44#include "RTCStatsReport.h"
 45#include "RTCTrackEvent.h"
 46#include "RealtimeIncomingAudioSourceGStreamer.h"
 47#include "RealtimeIncomingVideoSourceGStreamer.h"
 48#include "RealtimeOutgoingAudioSourceGStreamer.h"
 49#include "RealtimeOutgoingVideoSourceGStreamer.h"
 50
 51#include <gst/sdp/sdp.h>
 52#include <wtf/MainThread.h>
 53#include <wtf/Scope.h>
 54#include <wtf/glib/RunLoopSourcePriority.h>
 55#include <wtf/text/StringToIntegerConversion.h>
 56
 57GST_DEBUG_CATEGORY(webkit_webrtc_endpoint_debug);
 58#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 59
 60namespace WebCore {
 61
 62GStreamerMediaEndpoint::GStreamerMediaEndpoint(GStreamerPeerConnectionBackend& peerConnection)
 63 : m_peerConnectionBackend(peerConnection)
 64 , m_statsCollector(GStreamerStatsCollector::create())
 65#if !RELEASE_LOG_DISABLED
 66 , m_statsLogTimer(*this, &GStreamerMediaEndpoint::gatherStatsForLogging)
 67 , m_logger(peerConnection.logger())
 68 , m_logIdentifier(peerConnection.logIdentifier())
 69#endif
 70{
 71 ensureGStreamerInitialized();
 72
 73 static std::once_flag debugRegisteredFlag;
 74 std::call_once(debugRegisteredFlag, [] {
 75 GST_DEBUG_CATEGORY_INIT(webkit_webrtc_endpoint_debug, "webkitwebrtcendpoint", 0, "WebKit WebRTC end-point");
 76 });
 77}
 78
 79bool GStreamerMediaEndpoint::initializePipeline()
 80{
 81 static uint32_t nPipeline = 0;
 82 auto pipelineName = makeString("webkit-webrt-pipeline-", nPipeline);
 83 m_pipeline = gst_pipeline_new(pipelineName.ascii().data());
 84
 85 connectSimpleBusMessageCallback(m_pipeline.get(), [this](GstMessage* message) {
 86 handleMessage(message);
 87 });
 88
 89 auto binName = makeString("webkit-webrtcbin-", nPipeline++);
 90 m_webrtcBin = makeGStreamerElement("webrtcbin", binName.ascii().data());
 91 if (!m_webrtcBin)
 92 return false;
 93
 94 m_statsCollector->setElement(m_webrtcBin.get());
 95 g_signal_connect_swapped(m_webrtcBin.get(), "notify::ice-connection-state", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint) {
 96 endPoint->onIceConnectionChange();
 97 }), this);
 98 g_signal_connect_swapped(m_webrtcBin.get(), "notify::ice-gathering-state", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint) {
 99 endPoint->onIceGatheringChange();
 100 }), this);
 101 g_signal_connect_swapped(m_webrtcBin.get(), "on-negotiation-needed", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint) {
 102 endPoint->onNegotiationNeeded();
 103 }), this);
 104 g_signal_connect_swapped(m_webrtcBin.get(), "on-ice-candidate", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint, guint sdpMLineIndex, gchararray candidate) {
 105 endPoint->onIceCandidate(sdpMLineIndex, candidate);
 106 }), this);
 107 g_signal_connect_swapped(m_webrtcBin.get(), "pad-added", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint, GstPad* pad) {
 108 // Ignore outgoing pad notifications.
 109 if (GST_PAD_DIRECTION(pad) != GST_PAD_SRC)
 110 return;
 111
 112 callOnMainThreadAndWait([protectedThis = Ref(*endPoint), pad] {
 113 if (protectedThis->isStopped())
 114 return;
 115
 116 protectedThis->addRemoteStream(pad);
 117 });
 118 }), this);
 119 g_signal_connect_swapped(m_webrtcBin.get(), "pad-removed", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint, GstPad* pad) {
 120 // Ignore outgoing pad notifications.
 121 if (GST_PAD_DIRECTION(pad) != GST_PAD_SRC)
 122 return;
 123
 124 callOnMainThreadAndWait([protectedThis = Ref(*endPoint), pad] {
 125 if (protectedThis->isStopped())
 126 return;
 127
 128 protectedThis->removeRemoteStream(pad);
 129 });
 130 }), this);
 131
 132 g_signal_connect_swapped(m_webrtcBin.get(), "on-data-channel", G_CALLBACK(+[](GStreamerMediaEndpoint* endPoint, GstWebRTCDataChannel* channel) {
 133 endPoint->onDataChannel(channel);
 134 }), this);
 135
 136 gst_bin_add(GST_BIN_CAST(m_pipeline.get()), m_webrtcBin.get());
 137 return true;
 138}
 139
 140GStreamerMediaEndpoint::~GStreamerMediaEndpoint()
 141{
 142 if (m_pipeline)
 143 teardownPipeline();
 144}
 145
 146void GStreamerMediaEndpoint::teardownPipeline()
 147{
 148 RELEASE_ASSERT(m_pipeline);
 149#if !RELEASE_LOG_DISABLED
 150 stopLoggingStats();
 151#endif
 152 m_statsCollector->setElement(nullptr);
 153
 154 g_signal_handlers_disconnect_by_data(m_webrtcBin.get(), this);
 155 disconnectSimpleBusMessageCallback(m_pipeline.get());
 156 gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
 157
 158 m_sources.clear();
 159 m_remoteMLineInfos.clear();
 160 m_remoteStreamsById.clear();
 161 m_webrtcBin = nullptr;
 162 m_pipeline = nullptr;
 163}
 164
 165bool GStreamerMediaEndpoint::handleMessage(GstMessage* message)
 166{
 167 switch (GST_MESSAGE_TYPE(message)) {
 168 case GST_MESSAGE_EOS:
 169 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "eos");
 170 break;
 171 case GST_MESSAGE_ELEMENT: {
 172 const auto* data = gst_message_get_structure(message);
 173 if (!g_strcmp0(gst_structure_get_name(data), "GstBinForwarded")) {
 174 GRefPtr<GstMessage> subMessage;
 175 gst_structure_get(data, "message", GST_TYPE_MESSAGE, &subMessage.outPtr(), nullptr);
 176 if (GST_MESSAGE_TYPE(subMessage.get()) == GST_MESSAGE_EOS)
 177 disposeElementChain(GST_ELEMENT_CAST(GST_MESSAGE_SRC(subMessage.get())));
 178 }
 179 break;
 180 }
 181 default:
 182 break;
 183 }
 184 return true;
 185}
 186
 187void GStreamerMediaEndpoint::disposeElementChain(GstElement* element)
 188{
 189 GST_DEBUG_OBJECT(m_pipeline.get(), "Got element EOS message from %" GST_PTR_FORMAT, element);
 190
 191 auto pad = adoptGRef(gst_element_get_static_pad(element, "sink"));
 192 auto peer = adoptGRef(gst_pad_get_peer(pad.get()));
 193
 194 gst_element_set_locked_state(m_pipeline.get(), TRUE);
 195 gst_pad_unlink(peer.get(), pad.get());
 196 gst_bin_remove(GST_BIN_CAST(m_pipeline.get()), element);
 197 gst_element_release_request_pad(m_webrtcBin.get(), peer.get());
 198 gst_element_set_state(element, GST_STATE_NULL);
 199 gst_element_set_locked_state(m_pipeline.get(), FALSE);
 200}
 201
 202bool GStreamerMediaEndpoint::setConfiguration(MediaEndpointConfiguration& configuration)
 203{
 204 if (m_pipeline)
 205 teardownPipeline();
 206
 207 if (!initializePipeline())
 208 return false;
 209
 210 auto bundlePolicy = bundlePolicyFromConfiguration(configuration);
 211 auto iceTransportPolicy = iceTransportPolicyFromConfiguration(configuration);
 212 g_object_set(m_webrtcBin.get(), "bundle-policy", bundlePolicy, "ice-transport-policy", iceTransportPolicy, nullptr);
 213
 214 for (auto& server : configuration.iceServers) {
 215 bool stunSet = false;
 216 for (auto& url : server.urls) {
 217 if (url.protocol().startsWith("turn")) {
 218 auto valid = url.string().isolatedCopy().replace("turn:", "turn://").replace("turns:", "turns://");
 219 URL validURL(URL(), valid);
 220 // FIXME: libnice currently doesn't seem to handle IPv6 addresses very well.
 221 if (validURL.host().startsWith('['))
 222 continue;
 223 validURL.setUser(server.username);
 224 validURL.setPassword(server.credential);
 225 bool result = false;
 226 g_signal_emit_by_name(m_webrtcBin.get(), "add-turn-server", validURL.string().utf8().data(), &result);
 227 if (!result)
 228 GST_WARNING("Unable to use TURN server: %s", validURL.string().utf8().data());
 229 }
 230 if (!stunSet && url.protocol().startsWith("stun")) {
 231 auto valid = url.string().isolatedCopy().replace("stun:", "stun://");
 232 URL validURL(URL(), valid);
 233 // FIXME: libnice currently doesn't seem to handle IPv6 addresses very well.
 234 if (validURL.host().startsWith('['))
 235 continue;
 236 validURL.setUser(server.username);
 237 validURL.setPassword(server.credential);
 238 g_object_set(m_webrtcBin.get(), "stun-server", validURL.string().utf8().data(), nullptr);
 239 stunSet = true;
 240 }
 241 }
 242 }
 243
 244 // WIP: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/302
 245 GST_FIXME("%zu custom certificates not propagated to webrtcbin", configuration.certificates.size());
 246
 247 gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING);
 248 GST_DEBUG_OBJECT(m_pipeline.get(), "End-point ready");
 249 return true;
 250}
 251
 252void GStreamerMediaEndpoint::restartIce()
 253{
 254 GST_DEBUG_OBJECT(m_pipeline.get(), "restarting ICE");
 255 // WIP in https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1877
 256 initiate(true, gst_structure_new("webrtcbin-offer-options", "ice-restart", G_TYPE_BOOLEAN, TRUE, nullptr));
 257}
 258
 259static std::optional<std::pair<RTCSdpType, String>> fetchDescription(GstElement* webrtcBin, const char* name)
 260{
 261 if (!webrtcBin)
 262 return { };
 263
 264 GUniqueOutPtr<GstWebRTCSessionDescription> description;
 265 g_object_get(webrtcBin, makeString(name, "-description").utf8().data(), &description.outPtr(), nullptr);
 266 if (!description)
 267 return { };
 268
 269 GUniquePtr<char> sdpString(gst_sdp_message_as_text(description->sdp));
 270 GST_TRACE_OBJECT(webrtcBin, "%s-description SDP: %s", name, sdpString.get());
 271 return { { fromSessionDescriptionType(*description.get()), sdpString.get() } };
 272}
 273
 274static GstWebRTCSignalingState fetchSignalingState(GstElement* webrtcBin)
 275{
 276 GstWebRTCSignalingState state;
 277 g_object_get(webrtcBin, "signaling-state", &state, nullptr);
 278#ifndef GST_DISABLE_GST_DEBUG
 279 GUniquePtr<char> desc(g_enum_to_string(GST_TYPE_WEBRTC_SIGNALING_STATE, state));
 280 GST_DEBUG_OBJECT(webrtcBin, "Signaling state set to %s", desc.get());
 281#endif
 282 return state;
 283}
 284
 285enum class GatherSignalingState { No, Yes };
 286static std::optional<PeerConnectionBackend::DescriptionStates> descriptionsFromWebRTCBin(GstElement* webrtcBin, GatherSignalingState gatherSignalingState = GatherSignalingState::No)
 287{
 288 std::optional<RTCSdpType> currentLocalDescriptionSdpType, pendingLocalDescriptionSdpType, currentRemoteDescriptionSdpType, pendingRemoteDescriptionSdpType;
 289 String currentLocalDescriptionSdp, pendingLocalDescriptionSdp, currentRemoteDescriptionSdp, pendingRemoteDescriptionSdp;
 290 if (auto currentLocalDescription = fetchDescription(webrtcBin, "current-local")) {
 291 auto [sdpType, description] = *currentLocalDescription;
 292 currentLocalDescriptionSdpType = sdpType;
 293 currentLocalDescriptionSdp = WTFMove(description);
 294 }
 295 if (auto pendingLocalDescription = fetchDescription(webrtcBin, "pending-local")) {
 296 auto [sdpType, description] = *pendingLocalDescription;
 297 pendingLocalDescriptionSdpType = sdpType;
 298 pendingLocalDescriptionSdp = WTFMove(description);
 299 }
 300 if (auto currentRemoteDescription = fetchDescription(webrtcBin, "current-remote")) {
 301 auto [sdpType, description] = *currentRemoteDescription;
 302 currentRemoteDescriptionSdpType = sdpType;
 303 currentRemoteDescriptionSdp = WTFMove(description);
 304 }
 305 if (auto pendingRemoteDescription = fetchDescription(webrtcBin, "pending-remote")) {
 306 auto [sdpType, description] = *pendingRemoteDescription;
 307 pendingRemoteDescriptionSdpType = sdpType;
 308 pendingRemoteDescriptionSdp = WTFMove(description);
 309 }
 310
 311 std::optional<RTCSignalingState> signalingState;
 312 if (gatherSignalingState == GatherSignalingState::Yes)
 313 signalingState = toSignalingState(fetchSignalingState(webrtcBin));
 314
 315 return PeerConnectionBackend::DescriptionStates {
 316 signalingState,
 317 currentLocalDescriptionSdpType, currentLocalDescriptionSdp,
 318 pendingLocalDescriptionSdpType, pendingLocalDescriptionSdp,
 319 currentRemoteDescriptionSdpType, currentRemoteDescriptionSdp,
 320 pendingRemoteDescriptionSdpType, pendingRemoteDescriptionSdp
 321 };
 322}
 323
 324void GStreamerMediaEndpoint::doSetLocalDescription(const RTCSessionDescription* description)
 325{
 326 setDescription(description, true, [protectedThis = Ref(*this)] {
 327 auto descriptions = descriptionsFromWebRTCBin(protectedThis->m_webrtcBin.get(), GatherSignalingState::Yes);
 328 GRefPtr<GstWebRTCSCTPTransport> transport;
 329 g_object_get(protectedThis->m_webrtcBin.get(), "sctp-transport", &transport.outPtr(), nullptr);
 330 protectedThis->m_peerConnectionBackend.setLocalDescriptionSucceeded(WTFMove(descriptions), transport ? makeUnique<GStreamerSctpTransportBackend>(WTFMove(transport)) : nullptr);
 331 }, [protectedThis = Ref(*this)](const GError* error) {
 332 if (error && error->code == GST_WEBRTC_ERROR_INVALID_STATE)
 333 protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { InvalidStateError, "Failed to set local answer sdp: no pending remote description."_s });
 334 else
 335 protectedThis->m_peerConnectionBackend.setLocalDescriptionFailed(Exception { OperationError, "Unable to apply session local description"_s });
 336 });
 337}
 338
 339void GStreamerMediaEndpoint::setRemoteDescriptionSucceeded()
 340{
 341 GST_DEBUG_OBJECT(m_pipeline.get(), "Acking remote description");
 342 auto descriptions = descriptionsFromWebRTCBin(m_webrtcBin.get(), GatherSignalingState::Yes);
 343 GRefPtr<GstWebRTCSCTPTransport> transport;
 344 g_object_get(m_webrtcBin.get(), "sctp-transport", &transport.outPtr(), nullptr);
 345 m_peerConnectionBackend.setRemoteDescriptionSucceeded(WTFMove(descriptions), transport ? makeUnique<GStreamerSctpTransportBackend>(WTFMove(transport)) : nullptr);
 346}
 347
 348void GStreamerMediaEndpoint::doSetRemoteDescription(const RTCSessionDescription& description)
 349{
 350 setDescription(&description, false, [protectedThis = Ref(*this)] {
 351 protectedThis->setRemoteDescriptionSucceeded();
 352 }, [protectedThis = Ref(*this)](const GError* error) {
 353 if (error && error->code == GST_WEBRTC_ERROR_INVALID_STATE)
 354 protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { InvalidStateError, "Failed to set remote answer sdp"_s });
 355 else
 356 protectedThis->m_peerConnectionBackend.setRemoteDescriptionFailed(Exception { OperationError, "Unable to apply session remote description"_s });
 357 });
 358#if !RELEASE_LOG_DISABLED
 359 startLoggingStats();
 360#endif
 361}
 362
 363struct SetDescriptionCallData {
 364 WTF_MAKE_STRUCT_FAST_ALLOCATED;
 365 SetDescriptionCallData(GStreamerMediaEndpoint& endPoint, Function<void()>&& successCallback, Function<void(const GError*)>&& failureCallback)
 366 : successCallback(WTFMove(successCallback))
 367 , failureCallback(WTFMove(failureCallback))
 368 , endPoint(endPoint) { }
 369
 370 Function<void()> successCallback;
 371 Function<void(const GError*)> failureCallback;
 372 GStreamerMediaEndpoint& endPoint;
 373};
 374
 375void GStreamerMediaEndpoint::setDescription(const RTCSessionDescription* description, bool isLocal, Function<void()>&& successCallback, Function<void(const GError*)>&& failureCallback)
 376{
 377 GstSDPMessage* message;
 378 auto sdpType = RTCSdpType::Offer;
 379
 380 if (description) {
 381 if (gst_sdp_message_new_from_text(reinterpret_cast<const char*>(description->sdp().characters8()), &message) != GST_SDP_OK) {
 382 failureCallback(nullptr);
 383 return;
 384 }
 385 sdpType = description->type();
 386 } else if (gst_sdp_message_new(&message) != GST_SDP_OK) {
 387 failureCallback(nullptr);
 388 return;
 389 }
 390
 391 if (!isLocal)
 392 storeRemoteMLineInfo(message);
 393
 394 auto type = toSessionDescriptionType(sdpType);
 395 GST_DEBUG_OBJECT(m_pipeline.get(), "Creating %s session for SDP %s", isLocal ? "local" : "remote", gst_webrtc_sdp_type_to_string(type));
 396
 397 GUniquePtr<GstWebRTCSessionDescription> sessionDescription(gst_webrtc_session_description_new(type, message));
 398 auto signalName = makeString("set-", isLocal ? "local" : "remote", "-description");
 399 auto data = makeUnique<SetDescriptionCallData>(*this, WTFMove(successCallback), WTFMove(failureCallback));
 400 g_signal_emit_by_name(m_webrtcBin.get(), signalName.ascii().data(), sessionDescription.get(), gst_promise_new_with_change_func([](GstPromise* rawPromise, gpointer userData) {
 401 std::unique_ptr<SetDescriptionCallData> data(reinterpret_cast<SetDescriptionCallData*>(userData));
 402 auto promise = adoptGRef(rawPromise);
 403 auto result = gst_promise_wait(promise.get());
 404 const auto* reply = gst_promise_get_reply(promise.get());
 405 if (result != GST_PROMISE_RESULT_REPLIED || (reply && gst_structure_has_field(reply, "error"))) {
 406 GUniqueOutPtr<GError> error;
 407 if (reply) {
 408 gst_structure_get(reply, "error", G_TYPE_ERROR, &error.outPtr(), nullptr);
 409 GST_ERROR_OBJECT(data->endPoint.pipeline(), "Unable to set description, error: %s", error->message);
 410 }
 411 callOnMainThread([error = error.get(), protectedThis = Ref(data->endPoint), failureCallback = WTFMove(data->failureCallback)] {
 412 if (protectedThis->isStopped())
 413 return;
 414 failureCallback(error);
 415 });
 416 return;
 417 }
 418 callOnMainThread([protectedThis = Ref(data->endPoint), successCallback = WTFMove(data->successCallback)] {
 419 if (protectedThis->isStopped())
 420 return;
 421 successCallback();
 422 });
 423 }, data.release(), nullptr));
 424}
 425
 426void GStreamerMediaEndpoint::storeRemoteMLineInfo(GstSDPMessage* message)
 427{
 428 m_remoteMLineInfos.clear();
 429 unsigned totalMedias = gst_sdp_message_medias_len(message);
 430 m_remoteMLineInfos.reserveCapacity(totalMedias);
 431 GST_DEBUG_OBJECT(m_pipeline.get(), "Storing %u remote pending mlines", totalMedias);
 432 for (unsigned i = 0; i < totalMedias; i++) {
 433 const GstSDPMedia* media = gst_sdp_message_get_media(message, i);
 434 const char* typ = gst_sdp_media_get_media(media);
 435 if (!g_str_equal(typ, "audio") && !g_str_equal(typ, "video"))
 436 continue;
 437
 438#ifndef GST_DISABLE_GST_DEBUG
 439 GUniquePtr<char> mediaRepresentation(gst_sdp_media_as_text(media));
 440 GST_LOG_OBJECT(m_pipeline.get(), "Processing media:\n%s", mediaRepresentation.get());
 441#endif
 442 const char* mid = gst_sdp_media_get_attribute_val(media, "mid");
 443 if (!mid)
 444 continue;
 445
 446 bool isInactive = false;
 447 for (unsigned ii = 0; ii < gst_sdp_media_attributes_len(media); ii++) {
 448 const GstSDPAttribute* attr = gst_sdp_media_get_attribute(media, ii);
 449 if (!g_strcmp0(attr->key, "inactive")) {
 450 isInactive = true;
 451 break;
 452 }
 453 }
 454 if (isInactive) {
 455 GST_DEBUG_OBJECT(m_pipeline.get(), "Skipping inactive media");
 456 continue;
 457 }
 458
 459 m_mediaForMid.set(String(mid), g_str_equal(typ, "audio") ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video);
 460
 461 // https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1907
 462 if (sdpMediaHasAttributeKey(media, "ice-lite")) {
 463 GRefPtr<GObject> ice;
 464 g_object_get(m_webrtcBin.get(), "ice-agent", &ice.outPtr(), nullptr);
 465 g_object_set(ice.get(), "ice-lite", TRUE, nullptr);
 466 }
 467
 468 auto caps = adoptGRef(gst_caps_new_empty());
 469 Vector<int> payloadTypes;
 470 unsigned totalFormats = gst_sdp_media_formats_len(media);
 471 GST_DEBUG_OBJECT(m_pipeline.get(), "Media %s has %u formats", typ, totalFormats);
 472 for (unsigned j = 0; j < totalFormats; j++) {
 473 auto format = String(gst_sdp_media_get_format(media, j));
 474 auto payloadType = parseInteger<int>(format);
 475 if (!payloadType || !*payloadType) {
 476 GST_WARNING_OBJECT(m_pipeline.get(), "Invalid payload type: %s", format.utf8().data());
 477 continue;
 478 }
 479 auto formatCaps = adoptGRef(gst_sdp_media_get_caps_from_media(media, *payloadType));
 480 if (!formatCaps) {
 481 GST_WARNING_OBJECT(m_pipeline.get(), "No caps found for payload type %d", *payloadType);
 482 continue;
 483 }
 484
 485 // Relay SDP attributes to the caps, this is specially useful so that elements in
 486 // webrtcbin will be able to enable RTP header extensions.
 487 gst_sdp_media_attributes_to_caps(media, formatCaps.get());
 488
 489 gst_caps_append(caps.get(), formatCaps.leakRef());
 490 m_ptCounter = std::max(m_ptCounter, *payloadType + 1);
 491 payloadTypes.append(*payloadType);
 492 }
 493
 494 unsigned totalCaps = gst_caps_get_size(caps.get());
 495 if (totalCaps) {
 496 for (unsigned j = 0; j < totalCaps; j++) {
 497 GstStructure* structure = gst_caps_get_structure(caps.get(), j);
 498 gst_structure_set_name(structure, "application/x-rtp");
 499 }
 500 GST_DEBUG_OBJECT(m_pipeline.get(), "Caching payload caps: %" GST_PTR_FORMAT, caps.get());
 501 m_remoteMLineInfos.uncheckedAppend({ WTFMove(caps), false, WTFMove(payloadTypes) });
 502 }
 503 }
 504}
 505
 506void GStreamerMediaEndpoint::configureAndLinkSource(RealtimeOutgoingMediaSourceGStreamer& source)
 507{
 508 auto caps = source.allowedCaps();
 509 std::optional<std::pair<PendingMLineInfo, GRefPtr<GstCaps>>> found;
 510 for (auto& mLineInfo : m_remoteMLineInfos) {
 511 if (mLineInfo.isUsed)
 512 continue;
 513
 514 for (unsigned i = 0; i < gst_caps_get_size(mLineInfo.caps.get()); i++) {
 515 auto* structure = gst_caps_get_structure(mLineInfo.caps.get(), i);
 516 auto caps2 = adoptGRef(gst_caps_new_full(gst_structure_copy(structure), nullptr));
 517 auto intersected = adoptGRef(gst_caps_intersect(caps.get(), caps2.get()));
 518 if (!gst_caps_is_empty(intersected.get())) {
 519 found = std::make_pair(mLineInfo, WTFMove(intersected));
 520 break;
 521 }
 522 }
 523 if (found.has_value())
 524 break;
 525 }
 526
 527 bool payloadTypeWasSet = false;
 528 if (found) {
 529 GST_DEBUG_OBJECT(m_pipeline.get(), "Unused and compatible caps found for %" GST_PTR_FORMAT "... %" GST_PTR_FORMAT, caps.get(), found->second.get());
 530 payloadTypeWasSet = source.setPayloadType(found->second);
 531 found->first.isUsed = true;
 532 } else
 533 payloadTypeWasSet = source.setPayloadType(caps);
 534
 535 if (!payloadTypeWasSet)
 536 return;
 537
 538 if (!source.pad()) {
 539 source.setSinkPad(requestPad(m_requestPadCounter, source.allowedCaps()));
 540 m_requestPadCounter++;
 541 }
 542
 543 auto& sinkPad = source.pad();
 544 RELEASE_ASSERT(!gst_pad_is_linked(sinkPad.get()));
 545 auto sourceBin = source.bin();
 546 gst_bin_add(GST_BIN_CAST(m_pipeline.get()), sourceBin.get());
 547 source.link();
 548
 549 GUniquePtr<char> padId(gst_pad_get_name(sinkPad.get()));
 550 auto dotFileName = makeString(GST_OBJECT_NAME(m_pipeline.get()), ".outgoing-", padId.get());
 551 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data());
 552}
 553
 554GRefPtr<GstPad> GStreamerMediaEndpoint::requestPad(unsigned mlineIndex, const GRefPtr<GstCaps>& allowedCaps)
 555{
 556 auto padId = makeString("sink_", mlineIndex);
 557 auto caps = adoptGRef(gst_caps_copy(allowedCaps.get()));
 558
 559 gst_caps_map_in_place(caps.get(), [](GstCapsFeatures*, GstStructure* structure, gpointer userData) -> gboolean {
 560 auto* endPoint = reinterpret_cast<GStreamerMediaEndpoint*>(userData);
 561 gst_structure_set(structure, "payload", G_TYPE_INT, endPoint->m_ptCounter++, nullptr);
 562 return TRUE;
 563 }, this);
 564
 565 // FIXME: Restricting caps and codec-preferences breaks caps negotiation of outgoing sources in
 566 // some case (jitsi).
 567 GST_DEBUG_OBJECT(m_pipeline.get(), "Requesting pad %s restricted to %" GST_PTR_FORMAT, padId.utf8().data(), caps.get());
 568 auto* padTemplate = gst_element_get_pad_template(m_webrtcBin.get(), "sink_%u");
 569 auto sinkPad = adoptGRef(gst_element_request_pad(m_webrtcBin.get(), padTemplate, padId.utf8().data(), caps.get()));
 570 GRefPtr<GstWebRTCRTPTransceiver> transceiver;
 571 g_object_get(sinkPad.get(), "transceiver", &transceiver.outPtr(), nullptr);
 572 g_object_set(transceiver.get(), "codec-preferences", caps.get(), nullptr);
 573 return sinkPad;
 574}
 575
 576bool GStreamerMediaEndpoint::addTrack(GStreamerRtpSenderBackend& sender, MediaStreamTrack& track, const FixedVector<String>&)
 577{
 578 GStreamerRtpSenderBackend::Source source;
 579 GRefPtr<GstWebRTCRTPSender> rtcSender;
 580
 581 if (track.privateTrack().hasAudio()) {
 582 GST_DEBUG_OBJECT(m_pipeline.get(), "Adding outgoing audio source");
 583 auto audioSource = RealtimeOutgoingAudioSourceGStreamer::create(track.privateTrack());
 584 configureAndLinkSource(audioSource);
 585
 586 rtcSender = audioSource->sender();
 587 source = WTFMove(audioSource);
 588 } else {
 589 RELEASE_ASSERT(track.privateTrack().hasVideo());
 590 GST_DEBUG_OBJECT(m_pipeline.get(), "Adding outgoing video source");
 591 auto videoSource = RealtimeOutgoingVideoSourceGStreamer::create(track.privateTrack());
 592 configureAndLinkSource(videoSource);
 593
 594 rtcSender = videoSource->sender();
 595 source = WTFMove(videoSource);
 596 }
 597
 598 sender.setSource(WTFMove(source));
 599
 600 if (auto rtpSender = sender.rtcSender()) {
 601 GST_DEBUG_OBJECT(m_pipeline.get(), "Already has a sender.");
 602 return true;
 603 }
 604
 605 sender.setRTCSender(WTFMove(rtcSender));
 606
 607 GST_DEBUG_OBJECT(m_pipeline.get(), "Sender configured");
 608 return true;
 609}
 610
 611void GStreamerMediaEndpoint::removeTrack(GStreamerRtpSenderBackend& sender)
 612{
 613 GST_DEBUG_OBJECT(m_pipeline.get(), "Removing track");
 614 if (auto bin = sender.stopSource())
 615 gst_bin_remove(GST_BIN_CAST(m_pipeline.get()), bin.get());
 616 sender.clearSource();
 617 onNegotiationNeeded();
 618}
 619
 620void GStreamerMediaEndpoint::doCreateOffer(const RTCOfferOptions& options)
 621{
 622 // https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1877
 623 // FIXME: Plumb options.voiceActivityDetection.
 624 initiate(true, gst_structure_new("webrtcbin-offer-options", "ice-restart", G_TYPE_BOOLEAN, options.iceRestart, nullptr));
 625}
 626
 627void GStreamerMediaEndpoint::doCreateAnswer()
 628{
 629 initiate(false, nullptr);
 630}
 631
 632void GStreamerMediaEndpoint::initiate(bool isInitiator, GstStructure* rawOptions)
 633{
 634 m_isInitiator = isInitiator;
 635 const char* type = isInitiator ? "offer" : "answer";
 636 GST_DEBUG_OBJECT(m_pipeline.get(), "Creating %s", type);
 637 auto signalName = makeString("create-", type);
 638 GUniquePtr<GstStructure> options(rawOptions);
 639 g_signal_emit_by_name(m_webrtcBin.get(), signalName.ascii().data(), options.get(), gst_promise_new_with_change_func([](GstPromise* rawPromise, gpointer userData) {
 640 auto* endpoint = reinterpret_cast<GStreamerMediaEndpoint*>(userData);
 641 auto promise = adoptGRef(rawPromise);
 642 auto result = gst_promise_wait(promise.get());
 643 if (result != GST_PROMISE_RESULT_REPLIED) {
 644 endpoint->createSessionDescriptionFailed({ });
 645 return;
 646 }
 647
 648 const auto* reply = gst_promise_get_reply(promise.get());
 649 RELEASE_ASSERT(reply);
 650 if (gst_structure_has_field(reply, "error")) {
 651 GUniqueOutPtr<GError> promiseError;
 652 gst_structure_get(reply, "error", G_TYPE_ERROR, &promiseError.outPtr(), nullptr);
 653 GUniquePtr<GError> error(promiseError.release());
 654 endpoint->createSessionDescriptionFailed(WTFMove(error));
 655 return;
 656 }
 657
 658 const char* type = endpoint->m_isInitiator ? "offer" : "answer";
 659 GUniqueOutPtr<GstWebRTCSessionDescription> sessionDescription;
 660 gst_structure_get(reply, type, GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &sessionDescription.outPtr(), nullptr);
 661
 662#ifndef GST_DISABLE_GST_DEBUG
 663 GUniquePtr<char> sdp(gst_sdp_message_as_text(sessionDescription->sdp));
 664 GST_DEBUG_OBJECT(endpoint->pipeline(), "Created %s: %s", type, sdp.get());
 665#endif
 666 GUniquePtr<GstWebRTCSessionDescription> description(sessionDescription.release());
 667 endpoint->createSessionDescriptionSucceeded(WTFMove(description));
 668 }, this, nullptr));
 669}
 670
 671void GStreamerMediaEndpoint::getStats(GstPad* pad, Ref<DeferredPromise>&& promise)
 672{
 673 m_statsCollector->getStats([promise = WTFMove(promise), protectedThis = Ref(*this)](auto&& report) mutable {
 674 ASSERT(isMainThread());
 675 if (protectedThis->isStopped() || !report)
 676 return;
 677
 678 promise->resolve<IDLInterface<RTCStatsReport>>(report.releaseNonNull());
 679 }, pad);
 680}
 681
 682MediaStream& GStreamerMediaEndpoint::mediaStreamFromRTCStream(String label)
 683{
 684 auto mediaStream = m_remoteStreamsById.ensure(label, [label, this]() mutable {
 685 auto& document = downcast<Document>(*m_peerConnectionBackend.connection().scriptExecutionContext());
 686 return MediaStream::create(document, MediaStreamPrivate::create(document.logger(), { }, WTFMove(label)));
 687 });
 688 return *mediaStream.iterator->value;
 689}
 690
 691void GStreamerMediaEndpoint::addRemoteStream(GstPad* pad)
 692{
 693 m_pendingIncomingStreams++;
 694
 695 auto caps = adoptGRef(gst_pad_query_caps(pad, nullptr));
 696 const char* mediaType = capsMediaType(caps.get());
 697 GST_DEBUG_OBJECT(m_pipeline.get(), "Adding remote %s stream to %" GST_PTR_FORMAT " %u pending incoming streams, caps: %" GST_PTR_FORMAT, mediaType, pad, m_pendingIncomingStreams, caps.get());
 698
 699 GRefPtr<GstWebRTCRTPTransceiver> rtcTransceiver;
 700 g_object_get(pad, "transceiver", &rtcTransceiver.outPtr(), nullptr);
 701
 702 auto* transceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
 703 return rtcTransceiver.get() == transceiverBackend.rtcTransceiver();
 704 });
 705 if (!transceiver) {
 706 auto type = doCapsHaveType(caps.get(), "audio") ? RealtimeMediaSource::Type::Audio : RealtimeMediaSource::Type::Video;
 707 transceiver = &m_peerConnectionBackend.newRemoteTransceiver(makeUnique<GStreamerRtpTransceiverBackend>(WTFMove(rtcTransceiver)), type);
 708 }
 709
 710 GUniqueOutPtr<GstWebRTCSessionDescription> description;
 711 g_object_get(m_webrtcBin.get(), "remote-description", &description.outPtr(), nullptr);
 712
 713 unsigned mLineIndex;
 714 g_object_get(rtcTransceiver.get(), "mlineindex", &mLineIndex, nullptr);
 715 const auto* media = gst_sdp_message_get_media(description->sdp, mLineIndex);
 716 GUniquePtr<char> sdp(gst_sdp_media_as_text(media));
 717 auto sdpString = makeString(sdp.get());
 718
 719 GUniquePtr<gchar> name(gst_pad_get_name(pad));
 720 String label(name.get());
 721 auto key = makeString("msid:");
 722 auto lines = sdpString.split('\n');
 723 for (auto& line : lines) {
 724 auto i = line.find(key);
 725 if (i != notFound) {
 726 auto tmp = line.substring(i + key.ascii().length());
 727 label = tmp.substring(0, tmp.find(' '));
 728 break;
 729 }
 730 }
 731
 732 GST_DEBUG_OBJECT(m_pipeline.get(), "msid: %s", label.ascii().data());
 733
 734 GstElement* bin = nullptr;
 735 auto& track = transceiver->receiver().track();
 736 auto& source = track.privateTrack().source();
 737 if (source.isIncomingAudioSource())
 738 bin = static_cast<RealtimeIncomingAudioSourceGStreamer&>(source).bin();
 739 else if (source.isIncomingVideoSource())
 740 bin = static_cast<RealtimeIncomingVideoSourceGStreamer&>(source).bin();
 741 else
 742 RELEASE_ASSERT_NOT_REACHED();
 743
 744 gst_bin_add(GST_BIN_CAST(m_pipeline.get()), bin);
 745 auto sinkPad = adoptGRef(gst_element_get_static_pad(bin, "sink"));
 746 gst_pad_link(pad, sinkPad.get());
 747 gst_element_sync_state_with_parent(bin);
 748
 749 track.setEnabled(true);
 750 source.setMuted(false);
 751
 752 auto& mediaStream = mediaStreamFromRTCStream(label);
 753 mediaStream.addTrackFromPlatform(track);
 754 m_pendingStreams.append(&mediaStream);
 755
 756 auto dotFileName = makeString(GST_OBJECT_NAME(m_pipeline.get()), ".incoming-", mediaType, '-', GST_OBJECT_NAME(pad));
 757 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data());
 758}
 759
 760void GStreamerMediaEndpoint::removeRemoteStream(GstPad*)
 761{
 762 GST_FIXME_OBJECT(m_pipeline.get(), "removeRemoteStream");
 763 notImplemented();
 764}
 765
 766std::optional<GStreamerMediaEndpoint::Backends> GStreamerMediaEndpoint::createTransceiverBackends(const String& kind, const RTCRtpTransceiverInit& init, GStreamerRtpSenderBackend::Source&& source)
 767{
 768 if (!m_webrtcBin)
 769 return std::nullopt;
 770
 771 GST_DEBUG_OBJECT(m_pipeline.get(), "%zu streams in init data", init.streams.size());
 772
 773 // FIXME: Should we build the caps from the init.sendEncodings? Problem is there is no
 774 // encodingName or clockRate in RTCRtpEncodingParameters.
 775 Vector<std::pair<const char*, int>> encodings;
 776 const char* media = kind.utf8().data();
 777 if (kind == "video"_s) {
 778 encodings.reserveInitialCapacity(3);
 779 encodings.uncheckedAppend({ "VP8", 90000 });
 780 encodings.uncheckedAppend({ "VP9", 90000 });
 781 encodings.uncheckedAppend({ "H264", 90000 });
 782 } else {
 783 encodings.reserveInitialCapacity(1);
 784 encodings.uncheckedAppend({ "OPUS", 48000 });
 785 }
 786
 787 auto caps = adoptGRef(gst_caps_new_empty());
 788 for (auto& [encodingName, clockRate] : encodings) {
 789 gst_caps_append(caps.get(), gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, media, "encoding-name", G_TYPE_STRING, encodingName,
 790 "payload", G_TYPE_INT, m_ptCounter++, "clock-rate", G_TYPE_INT, clockRate, nullptr));
 791 }
 792
 793 auto direction = fromRTCRtpTransceiverDirection(init.direction);
 794#ifndef GST_DISABLE_GST_DEBUG
 795 GUniquePtr<char> desc(g_enum_to_string(GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction));
 796 GST_DEBUG_OBJECT(m_pipeline.get(), "Adding %s transceiver for payload %" GST_PTR_FORMAT, desc.get(), caps.get());
 797#endif
 798
 799 // FIXME: None of this (excepted direction) is passed to webrtcbin yet.
 800 GUniquePtr<GstStructure> initData(gst_structure_new("transceiver-init-data", "direction", GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, direction, nullptr));
 801
 802 GValue streamIdsValue = G_VALUE_INIT;
 803 g_value_init(&streamIdsValue, GST_TYPE_LIST);
 804 for (auto& stream : init.streams) {
 805 GValue value = G_VALUE_INIT;
 806 g_value_init(&value, G_TYPE_STRING);
 807 g_value_set_string(&value, stream->id().utf8().data());
 808 gst_value_list_append_value(&streamIdsValue, &value);
 809 g_value_unset(&value);
 810 }
 811 gst_structure_take_value(initData.get(), "stream-ids", &streamIdsValue);
 812
 813 GValue encodingsValue = G_VALUE_INIT;
 814 g_value_init(&encodingsValue, GST_TYPE_LIST);
 815 if (kind == "audio") {
 816 if (!init.sendEncodings.isEmpty()) {
 817 auto encodingData = fromRTCEncodingParameters(init.sendEncodings[0]);
 818 GValue value = G_VALUE_INIT;
 819 g_value_init(&value, GST_TYPE_STRUCTURE);
 820 gst_value_set_structure(&value, encodingData.get());
 821 gst_value_list_append_value(&encodingsValue, &value);
 822 g_value_unset(&value);
 823 }
 824 } else {
 825 for (auto& encoding : init.sendEncodings) {
 826 auto encodingData = fromRTCEncodingParameters(encoding);
 827 GValue value = G_VALUE_INIT;
 828 g_value_init(&value, GST_TYPE_STRUCTURE);
 829 gst_value_set_structure(&value, encodingData.get());
 830 gst_value_list_append_value(&encodingsValue, &value);
 831 g_value_unset(&value);
 832 }
 833 }
 834 gst_structure_take_value(initData.get(), "encodings", &encodingsValue);
 835
 836 GRefPtr<GstWebRTCRTPTransceiver> rtcTransceiver;
 837 g_signal_emit_by_name(m_webrtcBin.get(), "add-transceiver", direction, caps.get(), &rtcTransceiver.outPtr());
 838 if (!rtcTransceiver)
 839 return std::nullopt;
 840
 841 auto transceiver = makeUnique<GStreamerRtpTransceiverBackend>(WTFMove(rtcTransceiver));
 842 return GStreamerMediaEndpoint::Backends { transceiver->createSenderBackend(m_peerConnectionBackend, WTFMove(source), WTFMove(initData)), transceiver->createReceiverBackend(), WTFMove(transceiver) };
 843}
 844
 845std::optional<GStreamerMediaEndpoint::Backends> GStreamerMediaEndpoint::addTransceiver(const String& trackKind, const RTCRtpTransceiverInit& init)
 846{
 847 return createTransceiverBackends(trackKind, init, nullptr);
 848}
 849
 850GStreamerRtpSenderBackend::Source GStreamerMediaEndpoint::createSourceForTrack(MediaStreamTrack& track)
 851{
 852 if (track.privateTrack().hasAudio())
 853 return RealtimeOutgoingAudioSourceGStreamer::create(track.privateTrack());
 854
 855 RELEASE_ASSERT(track.privateTrack().hasVideo());
 856 return RealtimeOutgoingVideoSourceGStreamer::create(track.privateTrack());
 857}
 858
 859std::optional<GStreamerMediaEndpoint::Backends> GStreamerMediaEndpoint::addTransceiver(MediaStreamTrack& track, const RTCRtpTransceiverInit& init)
 860{
 861 return createTransceiverBackends(track.kind(), init, createSourceForTrack(track));
 862}
 863
 864void GStreamerMediaEndpoint::setSenderSourceFromTrack(GStreamerRtpSenderBackend&, MediaStreamTrack&)
 865{
 866 GST_FIXME_OBJECT(m_pipeline.get(), "setSenderSourceFromTrack");
 867 notImplemented();
 868}
 869
 870std::unique_ptr<GStreamerRtpTransceiverBackend> GStreamerMediaEndpoint::transceiverBackendFromSender(GStreamerRtpSenderBackend& backend)
 871{
 872 GRefPtr<GArray> transceivers;
 873 g_signal_emit_by_name(m_webrtcBin.get(), "get-transceivers", &transceivers.outPtr());
 874
 875 GST_DEBUG_OBJECT(m_pipeline.get(), "Looking for sender %p in %u existing transceivers", backend.rtcSender(), transceivers->len);
 876 for (unsigned i = 0; i < transceivers->len; i++) {
 877 GstWebRTCRTPTransceiver* current = g_array_index(transceivers.get(), GstWebRTCRTPTransceiver*, i);
 878 GRefPtr<GstWebRTCRTPSender> sender;
 879 g_object_get(current, "sender", &sender.outPtr(), nullptr);
 880
 881 if (!sender)
 882 continue;
 883 if (sender.get() == backend.rtcSender())
 884 return WTF::makeUnique<GStreamerRtpTransceiverBackend>(current);
 885 }
 886
 887 return nullptr;
 888}
 889
 890void GStreamerMediaEndpoint::addIceCandidate(GStreamerIceCandidate& candidate, PeerConnectionBackend::AddIceCandidateCallback&& callback)
 891{
 892 GST_DEBUG_OBJECT(m_pipeline.get(), "Adding ICE candidate %s", candidate.candidate.utf8().data());
 893
 894 if (!candidate.candidate.startsWith("candidate:")) {
 895 callOnMainThread([task = createSharedTask<PeerConnectionBackend::AddIceCandidateCallbackFunction>(WTFMove(callback))]() mutable {
 896 task->run(Exception { OperationError, "Expect line: candidate:<candidate-str>" });
 897 });
 898 return;
 899 }
 900
 901 auto parsedCandidate = parseIceCandidateSDP(candidate.candidate);
 902 if (!parsedCandidate) {
 903 callOnMainThread([task = createSharedTask<PeerConnectionBackend::AddIceCandidateCallbackFunction>(WTFMove(callback))]() mutable {
 904 task->run(Exception { OperationError, "Error processing ICE candidate" });
 905 });
 906 return;
 907 }
 908
 909 // FIXME: invalid sdpMLineIndex exception not relayed from webrtcbin.
 910 // FIXME: Ideally this should pass the result/error to a GstPromise object.
 911 g_signal_emit_by_name(m_webrtcBin.get(), "add-ice-candidate", candidate.sdpMLineIndex, candidate.candidate.utf8().data());
 912 callOnMainThread([task = createSharedTask<PeerConnectionBackend::AddIceCandidateCallbackFunction>(WTFMove(callback)), descriptions = descriptionsFromWebRTCBin(m_webrtcBin.get())]() mutable {
 913 task->run(WTFMove(descriptions));
 914 });
 915}
 916
 917std::unique_ptr<RTCDataChannelHandler> GStreamerMediaEndpoint::createDataChannel(const String& label, const RTCDataChannelInit& options)
 918{
 919 if (!m_webrtcBin)
 920 return nullptr;
 921
 922 auto init = GStreamerDataChannelHandler::fromRTCDataChannelInit(options);
 923 GST_DEBUG_OBJECT(m_pipeline.get(), "Creating data channel for init options %" GST_PTR_FORMAT, init.get());
 924 GRefPtr<GstWebRTCDataChannel> channel;
 925 g_signal_emit_by_name(m_webrtcBin.get(), "create-data-channel", label.utf8().data(), init.get(), &channel.outPtr());
 926 if (!channel)
 927 return nullptr;
 928
 929 return WTF::makeUnique<GStreamerDataChannelHandler>(WTFMove(channel));
 930}
 931
 932void GStreamerMediaEndpoint::onDataChannel(GstWebRTCDataChannel* dataChannel)
 933{
 934 GST_DEBUG_OBJECT(m_pipeline.get(), "Incoming data channel");
 935 GRefPtr<GstWebRTCDataChannel> channel = dataChannel;
 936 callOnMainThread([protectedThis = Ref(*this), dataChannel = WTFMove(channel)]() mutable {
 937 GST_DEBUG_OBJECT(protectedThis->m_pipeline.get(), "Incoming data channel 1");
 938 if (protectedThis->isStopped())
 939 return;
 940 GST_DEBUG_OBJECT(protectedThis->m_pipeline.get(), "Incoming data channel 2");
 941 auto& connection = protectedThis->m_peerConnectionBackend.connection();
 942 connection.dispatchEvent(GStreamerDataChannelHandler::createDataChannelEvent(*connection.document(), WTFMove(dataChannel)));
 943 });
 944}
 945
 946void GStreamerMediaEndpoint::close()
 947{
 948 // https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1181
 949 GST_DEBUG_OBJECT(m_pipeline.get(), "Closing");
 950 if (m_pipeline)
 951 gst_element_set_state(m_pipeline.get(), GST_STATE_READY);
 952
 953#if !RELEASE_LOG_DISABLED
 954 stopLoggingStats();
 955#endif
 956}
 957
 958void GStreamerMediaEndpoint::stop()
 959{
 960#if !RELEASE_LOG_DISABLED
 961 stopLoggingStats();
 962#endif
 963
 964 if (!m_pipeline)
 965 return;
 966
 967 GST_DEBUG_OBJECT(m_pipeline.get(), "Stopping");
 968 teardownPipeline();
 969}
 970
 971void GStreamerMediaEndpoint::suspend()
 972{
 973 if (!m_pipeline)
 974 return;
 975
 976 GST_DEBUG_OBJECT(m_pipeline.get(), "Suspending");
 977 gst_element_set_state(m_pipeline.get(), GST_STATE_PAUSED);
 978}
 979
 980void GStreamerMediaEndpoint::resume()
 981{
 982 if (!m_pipeline)
 983 return;
 984
 985 GST_DEBUG_OBJECT(m_pipeline.get(), "Resuming");
 986 gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING);
 987}
 988
 989void GStreamerMediaEndpoint::onNegotiationNeeded()
 990{
 991 m_isNegotiationNeeded = true;
 992
 993 GST_DEBUG_OBJECT(m_pipeline.get(), "Checking negotiation status");
 994
 995 callOnMainThread([protectedThis = Ref(*this)] {
 996 if (protectedThis->isStopped())
 997 return;
 998 GST_DEBUG_OBJECT(protectedThis->m_pipeline.get(), "Negotiation needed!");
 999 protectedThis->m_peerConnectionBackend.markAsNeedingNegotiation(0);
 1000 });
 1001}
 1002
 1003void GStreamerMediaEndpoint::onIceConnectionChange()
 1004{
 1005 GstWebRTCICEConnectionState state;
 1006 g_object_get(m_webrtcBin.get(), "ice-connection-state", &state, nullptr);
 1007 callOnMainThread([protectedThis = Ref(*this), connectionState = toRTCIceConnectionState(state)] {
 1008 if (protectedThis->isStopped())
 1009 return;
 1010 auto& connection = protectedThis->m_peerConnectionBackend.connection();
 1011 if (connection.iceConnectionState() != connectionState)
 1012 connection.updateIceConnectionState(connectionState);
 1013 });
 1014}
 1015
 1016void GStreamerMediaEndpoint::onIceGatheringChange()
 1017{
 1018 GstWebRTCICEGatheringState state;
 1019 g_object_get(m_webrtcBin.get(), "ice-gathering-state", &state, nullptr);
 1020 callOnMainThread([protectedThis = Ref(*this), state] {
 1021 if (protectedThis->isStopped())
 1022 return;
 1023 auto& connection = protectedThis->m_peerConnectionBackend.connection();
 1024 if (state == GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE)
 1025 protectedThis->m_peerConnectionBackend.doneGatheringCandidates();
 1026 else if (state == GST_WEBRTC_ICE_GATHERING_STATE_GATHERING)
 1027 connection.updateIceGatheringState(RTCIceGatheringState::Gathering);
 1028 else if (state == GST_WEBRTC_ICE_GATHERING_STATE_NEW)
 1029 connection.updateIceGatheringState(RTCIceGatheringState::New);
 1030 });
 1031}
 1032
 1033void GStreamerMediaEndpoint::onIceCandidate(guint sdpMLineIndex, gchararray candidate)
 1034{
 1035 // FIXME: Get mid from candidate?
 1036 GUniqueOutPtr<GstWebRTCSessionDescription> description;
 1037 g_object_get(m_webrtcBin.get(), "local-description", &description.outPtr(), nullptr);
 1038 if (!description)
 1039 return;
 1040
 1041 const GstSDPMedia* media = gst_sdp_message_get_media(description->sdp, sdpMLineIndex);
 1042 String candidateMid(gst_sdp_media_get_attribute_val(media, "mid"));
 1043 String candidateSDP(candidate);
 1044 callOnMainThread([protectedThis = Ref(*this), mid = WTFMove(candidateMid), sdp = WTFMove(candidateSDP), sdpMLineIndex, descriptions = descriptionsFromWebRTCBin(m_webrtcBin.get())]() mutable {
 1045 if (protectedThis->isStopped())
 1046 return;
 1047 protectedThis->m_peerConnectionBackend.newICECandidate(WTFMove(sdp), WTFMove(mid), sdpMLineIndex, { }, WTFMove(descriptions));
 1048 });
 1049}
 1050
 1051void GStreamerMediaEndpoint::createSessionDescriptionSucceeded(GUniquePtr<GstWebRTCSessionDescription>&& description)
 1052{
 1053 callOnMainThread([protectedThis = Ref(*this), description = WTFMove(description)] {
 1054 if (protectedThis->isStopped())
 1055 return;
 1056
 1057 GUniquePtr<char> sdp(gst_sdp_message_as_text(description->sdp));
 1058 if (protectedThis->m_isInitiator)
 1059 protectedThis->m_peerConnectionBackend.createOfferSucceeded(sdp.get());
 1060 else
 1061 protectedThis->m_peerConnectionBackend.createAnswerSucceeded(sdp.get());
 1062 });
 1063}
 1064
 1065void GStreamerMediaEndpoint::createSessionDescriptionFailed(GUniquePtr<GError>&& error)
 1066{
 1067 callOnMainThread([protectedThis = Ref(*this), error = WTFMove(error)] {
 1068 if (protectedThis->isStopped())
 1069 return;
 1070
 1071 auto exc = Exception { OperationError, error ? error->message : "Unknown Error" };
 1072 if (protectedThis->m_isInitiator)
 1073 protectedThis->m_peerConnectionBackend.createOfferFailed(WTFMove(exc));
 1074 else
 1075 protectedThis->m_peerConnectionBackend.createAnswerFailed(WTFMove(exc));
 1076 });
 1077}
 1078
 1079void GStreamerMediaEndpoint::collectTransceivers()
 1080{
 1081 GRefPtr<GArray> transceivers;
 1082 g_signal_emit_by_name(m_webrtcBin.get(), "get-transceivers", &transceivers.outPtr());
 1083 for (unsigned i = 0; i < transceivers->len; i++) {
 1084 GstWebRTCRTPTransceiver* current = g_array_index(transceivers.get(), GstWebRTCRTPTransceiver*, i);
 1085
 1086 auto* existingTransceiver = m_peerConnectionBackend.existingTransceiver([&](auto& transceiverBackend) {
 1087 return current == transceiverBackend.rtcTransceiver();
 1088 });
 1089 if (existingTransceiver)
 1090 continue;
 1091
 1092 GRefPtr<GstWebRTCRTPReceiver> receiver;
 1093 GUniqueOutPtr<char> mid;
 1094 g_object_get(current, "receiver", &receiver.outPtr(), "mid", &mid.outPtr(), nullptr);
 1095
 1096 if (!receiver)
 1097 continue;
 1098
 1099 if (!mid)
 1100 continue;
 1101
 1102 m_peerConnectionBackend.newRemoteTransceiver(WTF::makeUnique<GStreamerRtpTransceiverBackend>(WTFMove(current)), m_mediaForMid.get(mid.get()));
 1103 }
 1104}
 1105
 1106#if !RELEASE_LOG_DISABLED
 1107void GStreamerMediaEndpoint::gatherStatsForLogging()
 1108{
 1109 g_signal_emit_by_name(m_webrtcBin.get(), "get-stats", nullptr, gst_promise_new_with_change_func([](GstPromise* rawPromise, gpointer userData) {
 1110 auto promise = adoptGRef(rawPromise);
 1111 auto result = gst_promise_wait(promise.get());
 1112 if (result != GST_PROMISE_RESULT_REPLIED)
 1113 return;
 1114
 1115 const auto* reply = gst_promise_get_reply(promise.get());
 1116 RELEASE_ASSERT(reply);
 1117 if (gst_structure_has_field(reply, "error"))
 1118 return;
 1119
 1120 auto* endPoint = reinterpret_cast<GStreamerMediaEndpoint*>(userData);
 1121 endPoint->onStatsDelivered(reply);
 1122 }, this, nullptr));
 1123}
 1124
 1125class RTCStatsLogger {
 1126public:
 1127 explicit RTCStatsLogger(const GstStructure* stats)
 1128 : m_stats(stats)
 1129 { }
 1130
 1131 String toJSONString() const { return gstStructureToJSONString(m_stats); }
 1132
 1133private:
 1134 const GstStructure* m_stats;
 1135};
 1136
 1137void GStreamerMediaEndpoint::processStats(const GValue* value)
 1138{
 1139 if (!GST_VALUE_HOLDS_STRUCTURE(value))
 1140 return;
 1141
 1142 const GstStructure* structure = gst_value_get_structure(value);
 1143 GstWebRTCStatsType statsType;
 1144 if (!gst_structure_get(structure, "type", GST_TYPE_WEBRTC_STATS_TYPE, &statsType, nullptr))
 1145 return;
 1146
 1147 // Just check a single timestamp, inbound RTP for instance.
 1148 if (!m_statsFirstDeliveredTimestamp && statsType == GST_WEBRTC_STATS_INBOUND_RTP) {
 1149 double timestamp;
 1150 if (gst_structure_get_double(structure, "timestamp", &timestamp)) {
 1151 auto ts = Seconds::fromMilliseconds(timestamp);
 1152 m_statsFirstDeliveredTimestamp = ts;
 1153
 1154 if (!isStopped() && m_statsLogTimer.repeatInterval() != statsLogInterval(ts)) {
 1155 m_statsLogTimer.stop();
 1156 m_statsLogTimer.startRepeating(statsLogInterval(ts));
 1157 }
 1158 }
 1159 }
 1160
 1161 if (logger().willLog(logChannel(), WTFLogLevel::Debug)) {
 1162 // Stats are very verbose, let's only display them in inspector console in verbose mode.
 1163 logger().debug(LogWebRTC,
 1164 Logger::LogSiteIdentifier("GStreamerMediaEndpoint", "onStatsDelivered", logIdentifier()),
 1165 RTCStatsLogger { structure });
 1166 } else {
 1167 logger().logAlways(LogWebRTCStats,
 1168 Logger::LogSiteIdentifier("GStreamerMediaEndpoint", "onStatsDelivered", logIdentifier()),
 1169 RTCStatsLogger { structure });
 1170 }
 1171}
 1172
 1173void GStreamerMediaEndpoint::onStatsDelivered(const GstStructure* stats)
 1174{
 1175 GUniquePtr<GstStructure> statsCopy(gst_structure_copy(stats));
 1176 callOnMainThread([protectedThis = Ref(*this), this, stats = WTFMove(statsCopy)] {
 1177 gst_structure_foreach(stats.get(), static_cast<GstStructureForeachFunc>([](GQuark, const GValue* value, gpointer userData) -> gboolean {
 1178 auto* endPoint = reinterpret_cast<GStreamerMediaEndpoint*>(userData);
 1179 endPoint->processStats(value);
 1180 return TRUE;
 1181 }), this);
 1182 });
 1183}
 1184#endif
 1185
 1186#if !RELEASE_LOG_DISABLED
 1187void GStreamerMediaEndpoint::startLoggingStats()
 1188{
 1189 if (m_statsLogTimer.isActive())
 1190 m_statsLogTimer.stop();
 1191 m_statsLogTimer.startRepeating(statsLogInterval(Seconds::nan()));
 1192}
 1193
 1194void GStreamerMediaEndpoint::stopLoggingStats()
 1195{
 1196 m_statsLogTimer.stop();
 1197}
 1198
 1199WTFLogChannel& GStreamerMediaEndpoint::logChannel() const
 1200{
 1201 return LogWebRTC;
 1202}
 1203
 1204Seconds GStreamerMediaEndpoint::statsLogInterval(Seconds reportTimestamp) const
 1205{
 1206 if (logger().willLog(logChannel(), WTFLogLevel::Info))
 1207 return 2_s;
 1208
 1209 if (reportTimestamp - m_statsFirstDeliveredTimestamp > 15_s)
 1210 return 10_s;
 1211
 1212 return 4_s;
 1213}
 1214#endif
 1215
 1216void GStreamerMediaEndpoint::gatherDecoderImplementationName(Function<void(String&&)>&& callback)
 1217{
 1218 // TODO: collect stats and lookup InboundRtp "decoder_implementation" field.
 1219 callback({ });
 1220}
 1221
 1222} // namespace WebCore
 1223
 1224#if !RELEASE_LOG_DISABLED
 1225namespace WTF {
 1226
 1227template<typename Type>
 1228struct LogArgument;
 1229
 1230template <>
 1231struct LogArgument<WebCore::RTCStatsLogger> {
 1232 static String toString(const WebCore::RTCStatsLogger& logger)
 1233 {
 1234 return String(logger.toJSONString());
 1235 }
 1236};
 1237
 1238}; // namespace WTF
 1239#endif // !RELEASE_LOG_DISABLED
 1240
 1241#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerMediaEndpoint.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GStreamerPeerConnectionBackend.h"
 26#include "GStreamerRtpSenderBackend.h"
 27#include "GStreamerStatsCollector.h"
 28#include "GUniquePtrGStreamer.h"
 29#include "RTCRtpReceiver.h"
 30
 31#include <wtf/LoggerHelper.h>
 32#include <wtf/ThreadSafeRefCounted.h>
 33#include <wtf/glib/GUniquePtr.h>
 34
 35namespace WebCore {
 36
 37class GStreamerRtpReceiverBackend;
 38class GStreamerRtpTransceiverBackend;
 39class MediaStreamTrack;
 40class RTCSessionDescription;
 41class RealtimeOutgoingMediaSourceGStreamer;
 42
 43class GStreamerMediaEndpoint : public ThreadSafeRefCounted<GStreamerMediaEndpoint, WTF::DestructionThread::Main>
 44#if !RELEASE_LOG_DISABLED
 45 , private LoggerHelper
 46#endif
 47{
 48public:
 49 static Ref<GStreamerMediaEndpoint> create(GStreamerPeerConnectionBackend& peerConnection) { return adoptRef(*new GStreamerMediaEndpoint(peerConnection)); }
 50 virtual ~GStreamerMediaEndpoint();
 51
 52 bool setConfiguration(MediaEndpointConfiguration&);
 53 void restartIce();
 54
 55 void doSetLocalDescription(const RTCSessionDescription*);
 56 void doSetRemoteDescription(const RTCSessionDescription&);
 57 void doCreateOffer(const RTCOfferOptions&);
 58 void doCreateAnswer();
 59
 60 void getStats(GstPad*, Ref<DeferredPromise>&&);
 61
 62 std::unique_ptr<RTCDataChannelHandler> createDataChannel(const String&, const RTCDataChannelInit&);
 63 void onDataChannel(GstWebRTCDataChannel*);
 64
 65 void addIceCandidate(GStreamerIceCandidate&, PeerConnectionBackend::AddIceCandidateCallback&&);
 66
 67 void close();
 68 void stop();
 69 bool isStopped() const { return !m_pipeline; }
 70
 71 void suspend();
 72 void resume();
 73
 74 void gatherDecoderImplementationName(Function<void(String&&)>&&);
 75 bool isNegotiationNeeded() const { return m_isNegotiationNeeded; }
 76
 77 void configureAndLinkSource(RealtimeOutgoingMediaSourceGStreamer&);
 78
 79 bool addTrack(GStreamerRtpSenderBackend&, MediaStreamTrack&, const FixedVector<String>&);
 80 void removeTrack(GStreamerRtpSenderBackend&);
 81
 82 struct Backends {
 83 std::unique_ptr<GStreamerRtpSenderBackend> senderBackend;
 84 std::unique_ptr<GStreamerRtpReceiverBackend> receiverBackend;
 85 std::unique_ptr<GStreamerRtpTransceiverBackend> transceiverBackend;
 86 };
 87 std::optional<Backends> addTransceiver(const String& trackKind, const RTCRtpTransceiverInit&);
 88 std::optional<Backends> addTransceiver(MediaStreamTrack&, const RTCRtpTransceiverInit&);
 89 std::unique_ptr<GStreamerRtpTransceiverBackend> transceiverBackendFromSender(GStreamerRtpSenderBackend&);
 90
 91 void setSenderSourceFromTrack(GStreamerRtpSenderBackend&, MediaStreamTrack&);
 92
 93 void collectTransceivers();
 94
 95 void createSessionDescriptionSucceeded(GUniquePtr<GstWebRTCSessionDescription>&&);
 96 void createSessionDescriptionFailed(GUniquePtr<GError>&&);
 97
 98 GstElement* pipeline() const { return m_pipeline.get(); }
 99 bool handleMessage(GstMessage*);
 100
 101#if !RELEASE_LOG_DISABLED
 102 void processStats(const GValue*);
 103#endif
 104
 105protected:
 106#if !RELEASE_LOG_DISABLED
 107 void onStatsDelivered(const GstStructure*);
 108#endif
 109
 110private:
 111 GStreamerMediaEndpoint(GStreamerPeerConnectionBackend&);
 112
 113 bool initializePipeline();
 114 void teardownPipeline();
 115 void disposeElementChain(GstElement*);
 116
 117 void setDescription(const RTCSessionDescription*, bool isLocal, Function<void()>&& successCallback, Function<void(const GError*)>&& failureCallback);
 118 void initiate(bool isInitiator, GstStructure*);
 119
 120 void onNegotiationNeeded();
 121 void onIceConnectionChange();
 122 void onIceGatheringChange();
 123 void onIceCandidate(guint sdpMLineIndex, gchararray candidate);
 124
 125 MediaStream& mediaStreamFromRTCStream(String label);
 126
 127 void addRemoteStream(GstPad*);
 128 void removeRemoteStream(GstPad*);
 129
 130 std::optional<Backends> createTransceiverBackends(const String& kind, const RTCRtpTransceiverInit&, GStreamerRtpSenderBackend::Source&&);
 131 GStreamerRtpSenderBackend::Source createSourceForTrack(MediaStreamTrack&);
 132
 133 void storeRemoteMLineInfo(GstSDPMessage*);
 134
 135 GRefPtr<GstPad> requestPad(unsigned mlineIndex, const GRefPtr<GstCaps>&);
 136
 137 void setRemoteDescriptionSucceeded();
 138
 139#if !RELEASE_LOG_DISABLED
 140 void gatherStatsForLogging();
 141 void startLoggingStats();
 142 void stopLoggingStats();
 143
 144 const Logger& logger() const final { return m_logger.get(); }
 145 const void* logIdentifier() const final { return m_logIdentifier; }
 146 const char* logClassName() const final { return "GStreamerMediaEndpoint"; }
 147 WTFLogChannel& logChannel() const final;
 148
 149 Seconds statsLogInterval(Seconds) const;
 150#endif
 151
 152 HashMap<String, RealtimeMediaSource::Type> m_mediaForMid;
 153 RealtimeMediaSource::Type mediaTypeForMid(const char* mid);
 154
 155 GStreamerPeerConnectionBackend& m_peerConnectionBackend;
 156 GRefPtr<GstElement> m_webrtcBin;
 157 GRefPtr<GstElement> m_pipeline;
 158
 159 HashMap<String, RefPtr<MediaStream>> m_remoteStreamsById;
 160
 161 struct PendingMLineInfo {
 162 GRefPtr<GstCaps> caps;
 163 bool isUsed;
 164 Vector<int> payloadTypes;
 165 };
 166 Vector<PendingMLineInfo> m_remoteMLineInfos;
 167
 168 Ref<GStreamerStatsCollector> m_statsCollector;
 169
 170 unsigned m_requestPadCounter { 0 };
 171 int m_ptCounter { 96 };
 172
 173 unsigned m_mlineIndex { 0 };
 174
 175 Vector<Ref<RealtimeOutgoingMediaSourceGStreamer>> m_sources;
 176
 177 Vector<RefPtr<MediaStream>> m_pendingStreams;
 178 unsigned m_pendingIncomingStreams { 0 };
 179
 180 bool m_isInitiator { false };
 181 bool m_isNegotiationNeeded { false };
 182
 183#if !RELEASE_LOG_DISABLED
 184 Timer m_statsLogTimer;
 185 Seconds m_statsFirstDeliveredTimestamp;
 186 Ref<const Logger> m_logger;
 187 const void* m_logIdentifier;
 188#endif
 189};
 190
 191} // namespace WebCore
 192
 193#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerPeerConnectionBackend.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "Document.h"
 26#include "GStreamerCommon.h"
 27#include "GStreamerMediaEndpoint.h"
 28#include "GStreamerRtpReceiverBackend.h"
 29#include "GStreamerRtpSenderBackend.h"
 30#include "GStreamerRtpTransceiverBackend.h"
 31#include "IceCandidate.h"
 32#include "JSRTCStatsReport.h"
 33#include "MediaEndpointConfiguration.h"
 34#include "NotImplemented.h"
 35#include "RTCIceCandidate.h"
 36#include "RTCPeerConnection.h"
 37#include "RTCRtpCapabilities.h"
 38#include "RTCRtpReceiver.h"
 39#include "RTCSessionDescription.h"
 40#include "RealtimeIncomingAudioSourceGStreamer.h"
 41#include "RealtimeIncomingVideoSourceGStreamer.h"
 42#include "RealtimeOutgoingAudioSourceGStreamer.h"
 43#include "RealtimeOutgoingVideoSourceGStreamer.h"
 44
 45namespace WebCore {
 46
 47static std::unique_ptr<PeerConnectionBackend> createGStreamerPeerConnectionBackend(RTCPeerConnection& peerConnection)
 48{
 49 ensureGStreamerInitialized();
 50 if (!isGStreamerPluginAvailable("webrtc")) {
 51 WTFLogAlways("GstWebRTC plugin not found. Make sure to install gst-plugins-bad >= 1.20 with the webrtc plugin enabled.");
 52 return nullptr;
 53 }
 54 return WTF::makeUnique<GStreamerPeerConnectionBackend>(peerConnection);
 55}
 56
 57CreatePeerConnectionBackend PeerConnectionBackend::create = createGStreamerPeerConnectionBackend;
 58
 59std::optional<RTCRtpCapabilities> PeerConnectionBackend::receiverCapabilities(ScriptExecutionContext&, const String& kind)
 60{
 61 RTCRtpCapabilities capabilities;
 62 capabilities.headerExtensions.append({ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" });
 63 if (kind == "audio"_s) {
 64 capabilities.codecs.append({ .mimeType = "audio/OPUS",
 65 .clockRate = 48000,
 66 .channels = 2,
 67 .sdpFmtpLine = ""
 68 });
 69 } else {
 70 capabilities.headerExtensions.append({ "urn:3gpp:video-orientation" });
 71 capabilities.codecs.append({ .mimeType = "video/VP8",
 72 .clockRate = 90000,
 73 .sdpFmtpLine = "" });
 74 capabilities.codecs.append({ .mimeType = "video/VP9",
 75 .clockRate = 90000,
 76 .sdpFmtpLine = "profile-id=0" });
 77 capabilities.codecs.append({ .mimeType = "video/VP9",
 78 .clockRate = 90000,
 79 .sdpFmtpLine = "profile-id=1" });
 80 capabilities.codecs.append({ .mimeType = "video/H264",
 81 .clockRate = 90000,
 82 .sdpFmtpLine = "" });
 83 }
 84 return capabilities;
 85}
 86
 87std::optional<RTCRtpCapabilities> PeerConnectionBackend::senderCapabilities(ScriptExecutionContext&, const String& kind)
 88{
 89 RTCRtpCapabilities capabilities;
 90 capabilities.headerExtensions.append({ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" });
 91 if (kind == "audio"_s) {
 92 capabilities.codecs.append({ .mimeType = "audio/OPUS",
 93 .clockRate = 48000,
 94 .channels = 2,
 95 .sdpFmtpLine = "" });
 96 } else {
 97 capabilities.headerExtensions.append({ "urn:3gpp:video-orientation" });
 98 capabilities.codecs.append({ .mimeType = "video/VP8",
 99 .clockRate = 90000,
 100 .sdpFmtpLine = "" });
 101 capabilities.codecs.append({ .mimeType = "video/VP9",
 102 .clockRate = 90000,
 103 .sdpFmtpLine = "profile-id=0" });
 104 capabilities.codecs.append({ .mimeType = "video/VP9",
 105 .clockRate = 90000,
 106 .sdpFmtpLine = "profile-id=1" });
 107 capabilities.codecs.append({ .mimeType = "video/H264",
 108 .clockRate = 90000,
 109 .sdpFmtpLine = "" });
 110 }
 111 return capabilities;
 112}
 113
 114GStreamerPeerConnectionBackend::GStreamerPeerConnectionBackend(RTCPeerConnection& peerConnection)
 115 : PeerConnectionBackend(peerConnection)
 116 , m_endpoint(GStreamerMediaEndpoint::create(*this))
 117{
 118 disableICECandidateFiltering();
 119}
 120
 121GStreamerPeerConnectionBackend::~GStreamerPeerConnectionBackend() = default;
 122
 123void GStreamerPeerConnectionBackend::suspend()
 124{
 125 m_endpoint->suspend();
 126}
 127
 128void GStreamerPeerConnectionBackend::resume()
 129{
 130 m_endpoint->resume();
 131}
 132
 133void GStreamerPeerConnectionBackend::restartIce()
 134{
 135 m_endpoint->restartIce();
 136}
 137
 138bool GStreamerPeerConnectionBackend::setConfiguration(MediaEndpointConfiguration&& configuration)
 139{
 140 return m_endpoint->setConfiguration(configuration);
 141}
 142
 143void GStreamerPeerConnectionBackend::getStats(Ref<DeferredPromise>&& promise)
 144{
 145 m_endpoint->getStats(nullptr, WTFMove(promise));
 146}
 147
 148static inline GStreamerRtpSenderBackend& backendFromRTPSender(RTCRtpSender& sender)
 149{
 150 ASSERT(!sender.isStopped());
 151 return static_cast<GStreamerRtpSenderBackend&>(*sender.backend());
 152}
 153
 154void GStreamerPeerConnectionBackend::getStats(RTCRtpSender& sender, Ref<DeferredPromise>&& promise)
 155{
 156 if (!sender.backend()) {
 157 m_endpoint->getStats(nullptr, WTFMove(promise));
 158 return;
 159 }
 160
 161 auto& backend = backendFromRTPSender(sender);
 162 GRefPtr<GstPad> pad;
 163 if (RealtimeOutgoingAudioSourceGStreamer* source = backend.audioSource())
 164 pad = source->pad();
 165 else if (RealtimeOutgoingVideoSourceGStreamer* source = backend.videoSource())
 166 pad = source->pad();
 167 m_endpoint->getStats(pad.get(), WTFMove(promise));
 168}
 169
 170void GStreamerPeerConnectionBackend::getStats(RTCRtpReceiver& receiver, Ref<DeferredPromise>&& promise)
 171{
 172 if (!receiver.backend()) {
 173 m_endpoint->getStats(nullptr, WTFMove(promise));
 174 return;
 175 }
 176
 177 GstElement* bin = nullptr;
 178 auto& source = receiver.track().privateTrack().source();
 179 if (source.isIncomingAudioSource())
 180 bin = static_cast<RealtimeIncomingAudioSourceGStreamer&>(source).bin();
 181 else if (source.isIncomingVideoSource())
 182 bin = static_cast<RealtimeIncomingVideoSourceGStreamer&>(source).bin();
 183 else
 184 RELEASE_ASSERT_NOT_REACHED();
 185
 186 auto sinkPad = adoptGRef(gst_element_get_static_pad(bin, "sink"));
 187 auto srcPad = adoptGRef(gst_pad_get_peer(sinkPad.get()));
 188 m_endpoint->getStats(srcPad.get(), WTFMove(promise));
 189}
 190
 191void GStreamerPeerConnectionBackend::doSetLocalDescription(const RTCSessionDescription* description)
 192{
 193 m_endpoint->doSetLocalDescription(description);
 194 m_isLocalDescriptionSet = true;
 195}
 196
 197void GStreamerPeerConnectionBackend::doSetRemoteDescription(const RTCSessionDescription& description)
 198{
 199 m_endpoint->doSetRemoteDescription(description);
 200 m_isRemoteDescriptionSet = true;
 201}
 202
 203void GStreamerPeerConnectionBackend::doCreateOffer(RTCOfferOptions&& options)
 204{
 205 m_endpoint->doCreateOffer(options);
 206}
 207
 208void GStreamerPeerConnectionBackend::doCreateAnswer(RTCAnswerOptions&&)
 209{
 210 if (!m_isRemoteDescriptionSet) {
 211 createAnswerFailed(Exception { InvalidStateError, "No remote description set" });
 212 return;
 213 }
 214 m_endpoint->doCreateAnswer();
 215}
 216
 217void GStreamerPeerConnectionBackend::close()
 218{
 219 m_endpoint->close();
 220}
 221
 222void GStreamerPeerConnectionBackend::doStop()
 223{
 224 m_endpoint->stop();
 225 m_pendingReceivers.clear();
 226}
 227
 228void GStreamerPeerConnectionBackend::doAddIceCandidate(RTCIceCandidate& candidate, AddIceCandidateCallback&& callback)
 229{
 230 unsigned sdpMLineIndex = candidate.sdpMLineIndex() ? candidate.sdpMLineIndex().value() : 0;
 231 auto rtcCandidate = WTF::makeUnique<GStreamerIceCandidate>(*new GStreamerIceCandidate { sdpMLineIndex, candidate.candidate() });
 232 m_endpoint->addIceCandidate(*rtcCandidate, WTFMove(callback));
 233}
 234
 235Ref<RTCRtpReceiver> GStreamerPeerConnectionBackend::createReceiver(std::unique_ptr<GStreamerRtpReceiverBackend>&& backend, const String& trackKind, const String& trackId)
 236{
 237 auto& document = downcast<Document>(*m_peerConnection.scriptExecutionContext());
 238
 239 auto source = backend->createSource(trackKind, trackId);
 240 // Remote source is initially muted and will be unmuted when receiving the first packet.
 241 source->setMuted(true);
 242 auto trackID = source->persistentID();
 243 auto remoteTrackPrivate = MediaStreamTrackPrivate::create(document.logger(), WTFMove(source), WTFMove(trackID));
 244 auto remoteTrack = MediaStreamTrack::create(document, WTFMove(remoteTrackPrivate));
 245
 246 return RTCRtpReceiver::create(*this, WTFMove(remoteTrack), WTFMove(backend));
 247}
 248
 249std::unique_ptr<RTCDataChannelHandler> GStreamerPeerConnectionBackend::createDataChannelHandler(const String& label, const RTCDataChannelInit& options)
 250{
 251 return m_endpoint->createDataChannel(label, options);
 252}
 253
 254static inline RefPtr<RTCRtpSender> findExistingSender(const Vector<RefPtr<RTCRtpTransceiver>>& transceivers, GStreamerRtpSenderBackend& senderBackend)
 255{
 256 ASSERT(senderBackend.rtcSender());
 257 for (auto& transceiver : transceivers) {
 258 auto& sender = transceiver->sender();
 259 if (!sender.isStopped() && senderBackend.rtcSender() == backendFromRTPSender(sender).rtcSender())
 260 return Ref(sender);
 261 }
 262 return nullptr;
 263}
 264
 265ExceptionOr<Ref<RTCRtpSender>> GStreamerPeerConnectionBackend::addTrack(MediaStreamTrack& track, FixedVector<String>&& mediaStreamIds)
 266{
 267 auto senderBackend = WTF::makeUnique<GStreamerRtpSenderBackend>(*this, nullptr, nullptr);
 268 if (!m_endpoint->addTrack(*senderBackend, track, mediaStreamIds))
 269 return Exception { TypeError, "Unable to add track"_s };
 270
 271 if (auto sender = findExistingSender(m_peerConnection.currentTransceivers(), *senderBackend)) {
 272 backendFromRTPSender(*sender).takeSource(*senderBackend);
 273 sender->setTrack(Ref(track));
 274 sender->setMediaStreamIds(WTFMove(mediaStreamIds));
 275 return sender.releaseNonNull();
 276 }
 277
 278 auto transceiverBackend = m_endpoint->transceiverBackendFromSender(*senderBackend);
 279
 280 auto sender = RTCRtpSender::create(m_peerConnection, Ref(track), WTFMove(senderBackend));
 281 sender->setMediaStreamIds(WTFMove(mediaStreamIds));
 282 auto receiver = createReceiver(transceiverBackend->createReceiverBackend(), track.kind(), track.id());
 283 auto transceiver = RTCRtpTransceiver::create(sender.copyRef(), WTFMove(receiver), WTFMove(transceiverBackend));
 284 m_peerConnection.addInternalTransceiver(WTFMove(transceiver));
 285 return sender;
 286}
 287
 288template<typename T>
 289ExceptionOr<Ref<RTCRtpTransceiver>> GStreamerPeerConnectionBackend::addTransceiverFromTrackOrKind(T&& trackOrKind, const RTCRtpTransceiverInit& init)
 290{
 291 auto backends = m_endpoint->addTransceiver(trackOrKind, init);
 292 if (!backends)
 293 return Exception { InvalidAccessError, "Unable to add transceiver"_s };
 294
 295 auto sender = RTCRtpSender::create(m_peerConnection, WTFMove(trackOrKind), WTFMove(backends->senderBackend));
 296 auto receiver = createReceiver(WTFMove(backends->receiverBackend), sender->trackKind(), sender->trackId());
 297 auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(backends->transceiverBackend));
 298 m_peerConnection.addInternalTransceiver(transceiver.copyRef());
 299 return transceiver;
 300}
 301
 302ExceptionOr<Ref<RTCRtpTransceiver>> GStreamerPeerConnectionBackend::addTransceiver(const String& trackKind, const RTCRtpTransceiverInit& init)
 303{
 304 return addTransceiverFromTrackOrKind(String { trackKind }, init);
 305}
 306
 307ExceptionOr<Ref<RTCRtpTransceiver>> GStreamerPeerConnectionBackend::addTransceiver(Ref<MediaStreamTrack>&& track, const RTCRtpTransceiverInit& init)
 308{
 309 return addTransceiverFromTrackOrKind(WTFMove(track), init);
 310}
 311
 312void GStreamerPeerConnectionBackend::setSenderSourceFromTrack(GStreamerRtpSenderBackend& sender, MediaStreamTrack& track)
 313{
 314 m_endpoint->setSenderSourceFromTrack(sender, track);
 315}
 316
 317static inline GStreamerRtpTransceiverBackend& backendFromRTPTransceiver(RTCRtpTransceiver& transceiver)
 318{
 319 return static_cast<GStreamerRtpTransceiverBackend&>(*transceiver.backend());
 320}
 321
 322RTCRtpTransceiver* GStreamerPeerConnectionBackend::existingTransceiver(WTF::Function<bool(GStreamerRtpTransceiverBackend&)>&& matchingFunction)
 323{
 324 for (auto& transceiver : m_peerConnection.currentTransceivers()) {
 325 if (matchingFunction(backendFromRTPTransceiver(*transceiver)))
 326 return transceiver.get();
 327 }
 328 return nullptr;
 329}
 330
 331RTCRtpTransceiver& GStreamerPeerConnectionBackend::newRemoteTransceiver(std::unique_ptr<GStreamerRtpTransceiverBackend>&& transceiverBackend, RealtimeMediaSource::Type type)
 332{
 333 auto trackKind = type == RealtimeMediaSource::Type::Audio ? "audio"_s : "video"_s;
 334 auto sender = RTCRtpSender::create(m_peerConnection, trackKind, transceiverBackend->createSenderBackend(*this, nullptr, nullptr));
 335 auto receiver = createReceiver(transceiverBackend->createReceiverBackend(), trackKind, sender->trackId());
 336 auto transceiver = RTCRtpTransceiver::create(WTFMove(sender), WTFMove(receiver), WTFMove(transceiverBackend));
 337 m_peerConnection.addInternalTransceiver(transceiver.copyRef());
 338 return transceiver.get();
 339}
 340
 341void GStreamerPeerConnectionBackend::collectTransceivers()
 342{
 343 m_endpoint->collectTransceivers();
 344}
 345
 346void GStreamerPeerConnectionBackend::removeTrack(RTCRtpSender& sender)
 347{
 348 m_endpoint->removeTrack(backendFromRTPSender(sender));
 349}
 350
 351void GStreamerPeerConnectionBackend::applyRotationForOutgoingVideoSources()
 352{
 353 for (auto& transceiver : m_peerConnection.currentTransceivers()) {
 354 if (!transceiver->sender().isStopped()) {
 355 if (auto* videoSource = backendFromRTPSender(transceiver->sender()).videoSource())
 356 videoSource->setApplyRotation(true);
 357 }
 358 }
 359}
 360
 361void GStreamerPeerConnectionBackend::gatherDecoderImplementationName(Function<void(String&&)>&& callback)
 362{
 363 m_endpoint->gatherDecoderImplementationName(WTFMove(callback));
 364}
 365
 366bool GStreamerPeerConnectionBackend::isNegotiationNeeded(uint32_t) const
 367{
 368 return m_endpoint->isNegotiationNeeded();
 369}
 370
 371} // namespace WebCore
 372
 373#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "PeerConnectionBackend.h"
 25#include "RealtimeMediaSource.h"
 26#include <gst/gst.h>
 27#include <wtf/HashMap.h>
 28
 29namespace WebCore {
 30
 31class GStreamerMediaEndpoint;
 32class GStreamerRtpReceiverBackend;
 33class GStreamerRtpSenderBackend;
 34class GStreamerRtpTransceiverBackend;
 35class RTCRtpReceiver;
 36class RTCRtpReceiverBackend;
 37class RTCSessionDescription;
 38class RTCStatsReport;
 39class RealtimeIncomingAudioSourceGStreamer;
 40class RealtimeIncomingVideoSourceGStreamer;
 41class RealtimeMediaSourceGStreamer;
 42class RealtimeOutgoingAudioSourceGStreamer;
 43class RealtimeOutgoingVideoSourceGStreamer;
 44
 45struct GStreamerIceCandidate {
 46 WTF_MAKE_STRUCT_FAST_ALLOCATED;
 47 unsigned sdpMLineIndex;
 48 String candidate;
 49};
 50
 51class GStreamerPeerConnectionBackend final : public PeerConnectionBackend {
 52 WTF_MAKE_FAST_ALLOCATED;
 53public:
 54 explicit GStreamerPeerConnectionBackend(RTCPeerConnection&);
 55 ~GStreamerPeerConnectionBackend();
 56
 57private:
 58 void close() final;
 59 void doCreateOffer(RTCOfferOptions&&) final;
 60 void doCreateAnswer(RTCAnswerOptions&&) final;
 61 void doSetLocalDescription(const RTCSessionDescription*) final;
 62 void doSetRemoteDescription(const RTCSessionDescription&) final;
 63 void doAddIceCandidate(RTCIceCandidate&, AddIceCandidateCallback&&) final;
 64 void doStop() final;
 65 std::unique_ptr<RTCDataChannelHandler> createDataChannelHandler(const String&, const RTCDataChannelInit&) final;
 66 void restartIce() final;
 67 bool setConfiguration(MediaEndpointConfiguration&&) final;
 68 void getStats(Ref<DeferredPromise>&&) final;
 69 void getStats(RTCRtpSender&, Ref<DeferredPromise>&&) final;
 70 void getStats(RTCRtpReceiver&, Ref<DeferredPromise>&&) final;
 71
 72 void emulatePlatformEvent(const String&) final { }
 73 void applyRotationForOutgoingVideoSources() final;
 74
 75 void gatherDecoderImplementationName(Function<void(String&&)>&&) final;
 76
 77 bool isNegotiationNeeded(uint32_t) const final;
 78
 79 std::optional<bool> canTrickleIceCandidates() const { return true; };
 80
 81 friend class GStreamerMediaEndpoint;
 82 friend class GStreamerRtpSenderBackend;
 83 RTCPeerConnection& connection() { return m_peerConnection; }
 84
 85 void getStatsSucceeded(const DeferredPromise&, Ref<RTCStatsReport>&&);
 86
 87 ExceptionOr<Ref<RTCRtpSender>> addTrack(MediaStreamTrack&, FixedVector<String>&&) final;
 88 void removeTrack(RTCRtpSender&) final;
 89
 90 ExceptionOr<Ref<RTCRtpTransceiver>> addTransceiver(const String&, const RTCRtpTransceiverInit&) final;
 91 ExceptionOr<Ref<RTCRtpTransceiver>> addTransceiver(Ref<MediaStreamTrack>&&, const RTCRtpTransceiverInit&) final;
 92 void setSenderSourceFromTrack(GStreamerRtpSenderBackend&, MediaStreamTrack&);
 93
 94 RTCRtpTransceiver* existingTransceiver(WTF::Function<bool(GStreamerRtpTransceiverBackend&)>&&);
 95 RTCRtpTransceiver& newRemoteTransceiver(std::unique_ptr<GStreamerRtpTransceiverBackend>&&, RealtimeMediaSource::Type);
 96
 97 void collectTransceivers() final;
 98
 99private:
 100 bool isLocalDescriptionSet() const final { return m_isLocalDescriptionSet; }
 101
 102 template<typename T>
 103 ExceptionOr<Ref<RTCRtpTransceiver>> addTransceiverFromTrackOrKind(T&& trackOrKind, const RTCRtpTransceiverInit&);
 104
 105 Ref<RTCRtpReceiver> createReceiver(std::unique_ptr<GStreamerRtpReceiverBackend>&&, const String& trackKind, const String& trackId);
 106
 107 void suspend() final;
 108 void resume() final;
 109
 110 Ref<GStreamerMediaEndpoint> m_endpoint;
 111 bool m_isLocalDescriptionSet { false };
 112 bool m_isRemoteDescriptionSet { false };
 113
 114 Vector<std::unique_ptr<GStreamerIceCandidate>> m_pendingCandidates;
 115 Vector<Ref<RTCRtpReceiver>> m_pendingReceivers;
 116};
 117
 118} // namespace WebCore
 119
 120#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpReceiverBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerDtlsTransportBackend.h"
 26#include "GStreamerRtpReceiverTransformBackend.h"
 27#include "GStreamerWebRTCUtils.h"
 28#include "NotImplemented.h"
 29#include "RealtimeIncomingAudioSourceGStreamer.h"
 30#include "RealtimeIncomingVideoSourceGStreamer.h"
 31#include <wtf/glib/GUniquePtr.h>
 32
 33namespace WebCore {
 34
 35RTCRtpParameters GStreamerRtpReceiverBackend::getParameters()
 36{
 37 notImplemented();
 38 return { };
 39}
 40
 41Vector<RTCRtpContributingSource> GStreamerRtpReceiverBackend::getContributingSources() const
 42{
 43 notImplemented();
 44 return { };
 45}
 46
 47Vector<RTCRtpSynchronizationSource> GStreamerRtpReceiverBackend::getSynchronizationSources() const
 48{
 49 notImplemented();
 50 return { };
 51}
 52
 53Ref<RealtimeMediaSource> GStreamerRtpReceiverBackend::createSource(const String& trackKind, const String& trackId)
 54{
 55 if (trackKind == "video"_s)
 56 return RealtimeIncomingVideoSourceGStreamer::create(trackId.isolatedCopy());
 57
 58 RELEASE_ASSERT(trackKind == "audio"_s);
 59 return RealtimeIncomingAudioSourceGStreamer::create(trackId.isolatedCopy());
 60}
 61
 62Ref<RTCRtpTransformBackend> GStreamerRtpReceiverBackend::rtcRtpTransformBackend()
 63{
 64 return GStreamerRtpReceiverTransformBackend::create(m_rtcReceiver);
 65}
 66
 67std::unique_ptr<RTCDtlsTransportBackend> GStreamerRtpReceiverBackend::dtlsTransportBackend()
 68{
 69 GRefPtr<GstWebRTCDTLSTransport> transport;
 70 g_object_get(m_rtcReceiver.get(), "transport", &transport.outPtr(), nullptr);
 71 return transport ? makeUnique<GStreamerDtlsTransportBackend>(transport) : nullptr;
 72}
 73
 74} // namespace WebCore
 75
 76#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "RTCRtpReceiverBackend.h"
 26#include "RealtimeMediaSource.h"
 27
 28namespace WebCore {
 29
 30class GStreamerRtpReceiverBackend final : public RTCRtpReceiverBackend {
 31 WTF_MAKE_FAST_ALLOCATED;
 32public:
 33 explicit GStreamerRtpReceiverBackend(GRefPtr<GstWebRTCRTPReceiver>&& rtcReceiver)
 34 : m_rtcReceiver(WTFMove(rtcReceiver))
 35 {
 36 }
 37
 38 GstWebRTCRTPReceiver* rtcReceiver() { return m_rtcReceiver.get(); }
 39 Ref<RealtimeMediaSource> createSource(const String& trackKind, const String& trackId);
 40
 41private:
 42 RTCRtpParameters getParameters() final;
 43 Vector<RTCRtpContributingSource> getContributingSources() const final;
 44 Vector<RTCRtpSynchronizationSource> getSynchronizationSources() const final;
 45 Ref<RTCRtpTransformBackend> rtcRtpTransformBackend() final;
 46 std::unique_ptr<RTCDtlsTransportBackend> dtlsTransportBackend() final;
 47
 48 GRefPtr<GstWebRTCRTPReceiver> m_rtcReceiver;
 49};
 50
 51} // namespace WebCore
 52
 53#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverTransformBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpReceiverTransformBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "NotImplemented.h"
 26
 27namespace WebCore {
 28
 29static inline GStreamerRtpReceiverTransformBackend::MediaType mediaTypeFromReceiver(const GstWebRTCRTPReceiver&)
 30{
 31 notImplemented();
 32 return RTCRtpTransformBackend::MediaType::Video;
 33}
 34
 35GStreamerRtpReceiverTransformBackend::GStreamerRtpReceiverTransformBackend(const GRefPtr<GstWebRTCRTPReceiver>& rtcReceiver)
 36 : GStreamerRtpTransformBackend(mediaTypeFromReceiver(*rtcReceiver), Side::Receiver)
 37 , m_rtcReceiver(rtcReceiver)
 38{
 39}
 40
 41GStreamerRtpReceiverTransformBackend::~GStreamerRtpReceiverTransformBackend()
 42{
 43}
 44
 45void GStreamerRtpReceiverTransformBackend::setTransformableFrameCallback(Callback&& callback)
 46{
 47 setInputCallback(WTFMove(callback));
 48 notImplemented();
 49}
 50
 51void GStreamerRtpReceiverTransformBackend::requestKeyFrame()
 52{
 53 ASSERT(mediaType() == MediaType::Video);
 54 notImplemented();
 55}
 56
 57} // namespace WebCore
 58
 59#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpReceiverTransformBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GStreamerRtpTransformBackend.h"
 26#include "GStreamerWebRTCUtils.h"
 27#include <wtf/Forward.h>
 28
 29namespace WebCore {
 30
 31class GStreamerRtpReceiverTransformBackend final : public GStreamerRtpTransformBackend {
 32public:
 33 static Ref<GStreamerRtpReceiverTransformBackend> create(const GRefPtr<GstWebRTCRTPReceiver>& receiver) { return adoptRef(*new GStreamerRtpReceiverTransformBackend(receiver)); }
 34 ~GStreamerRtpReceiverTransformBackend();
 35
 36private:
 37 explicit GStreamerRtpReceiverTransformBackend(const GRefPtr<GstWebRTCRTPReceiver>&);
 38
 39 // RTCRtpTransformBackend
 40 void setTransformableFrameCallback(Callback&&) final;
 41 void requestKeyFrame() final;
 42
 43 GRefPtr<GstWebRTCRTPReceiver> m_rtcReceiver;
 44};
 45
 46} // namespace WebCore
 47
 48#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpSenderBackend.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpSenderBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerDTMFSenderBackend.h"
 26#include "GStreamerDtlsTransportBackend.h"
 27#include "GStreamerPeerConnectionBackend.h"
 28#include "GStreamerRtpSenderTransformBackend.h"
 29#include "GStreamerWebRTCUtils.h"
 30#include "JSDOMPromiseDeferred.h"
 31#include "NotImplemented.h"
 32#include "RTCPeerConnection.h"
 33#include "RTCRtpSender.h"
 34#include "RealtimeOutgoingAudioSourceGStreamer.h"
 35#include "RealtimeOutgoingVideoSourceGStreamer.h"
 36#include "RuntimeEnabledFeatures.h"
 37#include "ScriptExecutionContext.h"
 38
 39namespace WebCore {
 40
 41template<typename Source>
 42static inline bool updateTrackSource(Source& source, MediaStreamTrack* track)
 43{
 44 if (!track) {
 45 source.stop();
 46 return true;
 47 }
 48 return source.setTrack(track->privateTrack());
 49}
 50
 51void GStreamerRtpSenderBackend::startSource()
 52{
 53 switchOn(m_source, [](Ref<RealtimeOutgoingAudioSourceGStreamer>& source) {
 54 source->start();
 55 }, [](Ref<RealtimeOutgoingVideoSourceGStreamer>& source) {
 56 source->start();
 57 }, [](std::nullptr_t&) {
 58 });
 59}
 60
 61WARN_UNUSED_RETURN GRefPtr<GstElement> GStreamerRtpSenderBackend::stopSource()
 62{
 63 switchOn(m_source, [](Ref<RealtimeOutgoingAudioSourceGStreamer>& source) {
 64 source->stop();
 65 return GRefPtr<GstElement>(source->bin());
 66 }, [](Ref<RealtimeOutgoingVideoSourceGStreamer>& source) {
 67 source->stop();
 68 return GRefPtr<GstElement>(source->bin());
 69 }, [](std::nullptr_t&) {
 70 return GRefPtr<GstElement>(nullptr);
 71 });
 72 return nullptr;
 73}
 74
 75bool GStreamerRtpSenderBackend::replaceTrack(RTCRtpSender& sender, MediaStreamTrack* track)
 76{
 77 if (!track) {
 78 auto stoppedSource = stopSource();
 79 return true;
 80 }
 81
 82 if (sender.track()) {
 83 switchOn(m_source, [&](Ref<RealtimeOutgoingAudioSourceGStreamer>& source) {
 84 ASSERT(track->source().type() == RealtimeMediaSource::Type::Audio);
 85 source->stop();
 86 source->setSource(track->privateTrack());
 87 source->start();
 88 }, [&](Ref<RealtimeOutgoingVideoSourceGStreamer>& source) {
 89 ASSERT(track->source().type() == RealtimeMediaSource::Type::Video);
 90 source->stop();
 91 source->setSource(track->privateTrack());
 92 source->start();
 93 }, [](std::nullptr_t&) {
 94 });
 95 }
 96
 97 m_peerConnectionBackend->setSenderSourceFromTrack(*this, *track);
 98 return true;
 99}
 100
 101RTCRtpSendParameters GStreamerRtpSenderBackend::getParameters() const
 102{
 103 return toRTCRtpSendParameters(m_initData.get());
 104}
 105
 106void GStreamerRtpSenderBackend::setParameters(const RTCRtpSendParameters&, DOMPromiseDeferred<void>&& promise)
 107{
 108 if (!m_rtcSender) {
 109 promise.reject(NotSupportedError);
 110 return;
 111 }
 112
 113 notImplemented();
 114 promise.resolve();
 115}
 116
 117std::unique_ptr<RTCDTMFSenderBackend> GStreamerRtpSenderBackend::createDTMFBackend()
 118{
 119 return makeUnique<GStreamerDTMFSenderBackend>();
 120}
 121
 122Ref<RTCRtpTransformBackend> GStreamerRtpSenderBackend::rtcRtpTransformBackend()
 123{
 124 return GStreamerRtpSenderTransformBackend::create(m_rtcSender);
 125}
 126
 127void GStreamerRtpSenderBackend::setMediaStreamIds(const FixedVector<String>&)
 128{
 129 notImplemented();
 130}
 131
 132std::unique_ptr<RTCDtlsTransportBackend> GStreamerRtpSenderBackend::dtlsTransportBackend()
 133{
 134 GRefPtr<GstWebRTCDTLSTransport> transport;
 135 g_object_get(m_rtcSender.get(), "transport", &transport.outPtr(), nullptr);
 136 return transport ? makeUnique<GStreamerDtlsTransportBackend>(transport) : nullptr;
 137}
 138
 139} // namespace WebCore
 140
 141#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpSenderBackend.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GStreamerPeerConnectionBackend.h"
 25#include "GUniquePtrGStreamer.h"
 26#include "RTCRtpSenderBackend.h"
 27#include "RealtimeOutgoingAudioSourceGStreamer.h"
 28#include "RealtimeOutgoingVideoSourceGStreamer.h"
 29#include <wtf/WeakPtr.h>
 30
 31namespace WebCore {
 32
 33class GStreamerPeerConnectionBackend;
 34
 35class GStreamerRtpSenderBackend final : public RTCRtpSenderBackend {
 36 WTF_MAKE_FAST_ALLOCATED;
 37public:
 38 GStreamerRtpSenderBackend(GStreamerPeerConnectionBackend& backend, GRefPtr<GstWebRTCRTPSender>&& rtcSender, GUniquePtr<GstStructure>&& initData)
 39 : m_peerConnectionBackend(WeakPtr { &backend })
 40 , m_rtcSender(WTFMove(rtcSender))
 41 , m_initData(WTFMove(initData))
 42 {
 43 }
 44
 45 using Source = std::variant<std::nullptr_t, Ref<RealtimeOutgoingAudioSourceGStreamer>, Ref<RealtimeOutgoingVideoSourceGStreamer>>;
 46 GStreamerRtpSenderBackend(GStreamerPeerConnectionBackend& backend, GRefPtr<GstWebRTCRTPSender>&& rtcSender, Source&& source, GUniquePtr<GstStructure>&& initData)
 47 : m_peerConnectionBackend(WeakPtr { &backend })
 48 , m_rtcSender(WTFMove(rtcSender))
 49 , m_source(WTFMove(source))
 50 , m_initData(WTFMove(initData))
 51 {
 52 }
 53
 54 void setRTCSender(GRefPtr<GstWebRTCRTPSender>&& rtcSender) { m_rtcSender = WTFMove(rtcSender); }
 55 GstWebRTCRTPSender* rtcSender() { return m_rtcSender.get(); }
 56
 57 RealtimeOutgoingAudioSourceGStreamer* audioSource()
 58 {
 59 return WTF::switchOn(m_source,
 60 [] (Ref<RealtimeOutgoingAudioSourceGStreamer>& source) { return source.ptr(); },
 61 [] (const auto&) -> RealtimeOutgoingAudioSourceGStreamer* { return nullptr; }
 62 );
 63 }
 64
 65 RealtimeOutgoingVideoSourceGStreamer* videoSource()
 66 {
 67 return WTF::switchOn(m_source,
 68 [] (Ref<RealtimeOutgoingVideoSourceGStreamer>& source) { return source.ptr(); },
 69 [] (const auto&) -> RealtimeOutgoingVideoSourceGStreamer* { return nullptr; }
 70 );
 71 }
 72
 73 bool hasSource() const
 74 {
 75 return WTF::switchOn(m_source,
 76 [] (const std::nullptr_t&) { return false; },
 77 [] (const auto&) { return true; }
 78 );
 79 }
 80
 81 void clearSource()
 82 {
 83 ASSERT(hasSource());
 84 m_source = nullptr;
 85 }
 86
 87 void setSource(Source&& source)
 88 {
 89 ASSERT(!hasSource());
 90 m_source = WTFMove(source);
 91 ASSERT(hasSource());
 92 }
 93
 94 void takeSource(GStreamerRtpSenderBackend& backend)
 95 {
 96 ASSERT(backend.hasSource());
 97 setSource(WTFMove(backend.m_source));
 98 }
 99
 100 WARN_UNUSED_RETURN GRefPtr<GstElement> stopSource();
 101
 102private:
 103 bool replaceTrack(RTCRtpSender&, MediaStreamTrack*) final;
 104 RTCRtpSendParameters getParameters() const final;
 105 void setParameters(const RTCRtpSendParameters&, DOMPromiseDeferred<void>&&) final;
 106 std::unique_ptr<RTCDTMFSenderBackend> createDTMFBackend() final;
 107 Ref<RTCRtpTransformBackend> rtcRtpTransformBackend() final;
 108 void setMediaStreamIds(const FixedVector<String>&) final;
 109 std::unique_ptr<RTCDtlsTransportBackend> dtlsTransportBackend() final;
 110
 111 void startSource();
 112
 113 WeakPtr<GStreamerPeerConnectionBackend> m_peerConnectionBackend;
 114 GRefPtr<GstWebRTCRTPSender> m_rtcSender;
 115 Source m_source;
 116 GUniquePtr<GstStructure> m_initData;
 117};
 118
 119} // namespace WebCore
 120
 121#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpSenderTransformBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpSenderTransformBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "NotImplemented.h"
 26
 27namespace WebCore {
 28
 29static inline GStreamerRtpSenderTransformBackend::MediaType mediaTypeFromSender(const GstWebRTCRTPSender&)
 30{
 31 notImplemented();
 32 return RTCRtpTransformBackend::MediaType::Video;
 33}
 34
 35GStreamerRtpSenderTransformBackend::GStreamerRtpSenderTransformBackend(const GRefPtr<GstWebRTCRTPSender>& rtcSender)
 36 : GStreamerRtpTransformBackend(mediaTypeFromSender(*rtcSender), Side::Sender)
 37 , m_rtcSender(rtcSender)
 38{
 39}
 40
 41GStreamerRtpSenderTransformBackend::~GStreamerRtpSenderTransformBackend()
 42{
 43}
 44
 45void GStreamerRtpSenderTransformBackend::setTransformableFrameCallback(Callback&& callback)
 46{
 47 setInputCallback(WTFMove(callback));
 48 notImplemented();
 49}
 50
 51void GStreamerRtpSenderTransformBackend::requestKeyFrame()
 52{
 53 ASSERT(mediaType() == MediaType::Video);
 54 notImplemented();
 55}
 56
 57} // namespace WebCore
 58
 59#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpSenderTransformBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GStreamerRtpTransformBackend.h"
 26#include "GStreamerWebRTCUtils.h"
 27#include <wtf/Forward.h>
 28
 29namespace WebCore {
 30
 31class GStreamerSenderTransformer;
 32
 33class GStreamerRtpSenderTransformBackend final : public GStreamerRtpTransformBackend {
 34 WTF_MAKE_FAST_ALLOCATED;
 35public:
 36 static Ref<GStreamerRtpSenderTransformBackend> create(const GRefPtr<GstWebRTCRTPSender>& sender) { return adoptRef(*new GStreamerRtpSenderTransformBackend(sender)); }
 37 ~GStreamerRtpSenderTransformBackend();
 38
 39private:
 40 explicit GStreamerRtpSenderTransformBackend(const GRefPtr<GstWebRTCRTPSender>&);
 41
 42 // RTCRtpTransformBackend
 43 void setTransformableFrameCallback(Callback&&) final;
 44 void requestKeyFrame() final;
 45
 46 GRefPtr<GstWebRTCRTPSender> m_rtcSender;
 47};
 48
 49} // namespace WebCore
 50
 51#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpTransceiverBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerRtpReceiverBackend.h"
 26#include "GStreamerRtpSenderBackend.h"
 27#include "GStreamerWebRTCUtils.h"
 28#include "NotImplemented.h"
 29#include "RTCRtpCodecCapability.h"
 30#include <wtf/glib/GUniquePtr.h>
 31
 32GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 33#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 34
 35namespace WebCore {
 36
 37GStreamerRtpTransceiverBackend::GStreamerRtpTransceiverBackend(GRefPtr<GstWebRTCRTPTransceiver>&& rtcTransceiver)
 38 : m_rtcTransceiver(WTFMove(rtcTransceiver))
 39{
 40 g_object_set(m_rtcTransceiver.get(), "do-nack", true, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, nullptr);
 41}
 42
 43std::unique_ptr<GStreamerRtpReceiverBackend> GStreamerRtpTransceiverBackend::createReceiverBackend()
 44{
 45 GRefPtr<GstWebRTCRTPReceiver> receiver;
 46 g_object_get(m_rtcTransceiver.get(), "receiver", &receiver.outPtr(), nullptr);
 47 return WTF::makeUnique<GStreamerRtpReceiverBackend>(WTFMove(receiver));
 48}
 49
 50std::unique_ptr<GStreamerRtpSenderBackend> GStreamerRtpTransceiverBackend::createSenderBackend(GStreamerPeerConnectionBackend& backend, GStreamerRtpSenderBackend::Source&& source, GUniquePtr<GstStructure>&& initData)
 51{
 52 GRefPtr<GstWebRTCRTPSender> sender;
 53 g_object_get(m_rtcTransceiver.get(), "sender", &sender.outPtr(), nullptr);
 54 return WTF::makeUnique<GStreamerRtpSenderBackend>(backend, WTFMove(sender), WTFMove(source), WTFMove(initData));
 55}
 56
 57RTCRtpTransceiverDirection GStreamerRtpTransceiverBackend::direction() const
 58{
 59 GstWebRTCRTPTransceiverDirection gstDirection;
 60 g_object_get(m_rtcTransceiver.get(), "direction", &gstDirection, nullptr);
 61 return toRTCRtpTransceiverDirection(gstDirection);
 62}
 63
 64std::optional<RTCRtpTransceiverDirection> GStreamerRtpTransceiverBackend::currentDirection() const
 65{
 66 GstWebRTCRTPTransceiverDirection gstDirection;
 67 g_object_get(m_rtcTransceiver.get(), "current-direction", &gstDirection, nullptr);
 68 if (!gstDirection)
 69 return std::nullopt;
 70 return toRTCRtpTransceiverDirection(gstDirection);
 71}
 72
 73void GStreamerRtpTransceiverBackend::setDirection(RTCRtpTransceiverDirection direction)
 74{
 75 g_object_set(m_rtcTransceiver.get(), "direction", fromRTCRtpTransceiverDirection(direction), nullptr);
 76}
 77
 78String GStreamerRtpTransceiverBackend::mid()
 79{
 80 GUniqueOutPtr<char> mid;
 81 g_object_get(m_rtcTransceiver.get(), "mid", &mid.outPtr(), nullptr);
 82 return mid.get();
 83}
 84
 85void GStreamerRtpTransceiverBackend::stop()
 86{
 87 // FIXME: webrtcbin transceivers can't be stopped yet.
 88 notImplemented();
 89}
 90
 91bool GStreamerRtpTransceiverBackend::stopped() const
 92{
 93 // FIXME: webrtcbin transceivers can't be stopped yet.
 94 return false;
 95}
 96
 97static inline WARN_UNUSED_RETURN ExceptionOr<GstCaps*> toRtpCodecCapability(const RTCRtpCodecCapability& codec)
 98{
 99 if (!codec.mimeType.startsWith("video/") && !codec.mimeType.startsWith("audio/"))
 100 return Exception { InvalidModificationError, "RTCRtpCodecCapability bad mimeType" };
 101
 102 auto components = codec.mimeType.split('/');
 103 auto* caps = gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, components[0].ascii().data(), "encoding-name", G_TYPE_STRING, components[1].ascii().data(), nullptr);
 104 gst_caps_set_simple(caps, "clock-rate", G_TYPE_INT, codec.clockRate, nullptr);
 105 if (codec.channels)
 106 gst_caps_set_simple(caps, "channels", G_TYPE_INT, *codec.channels, nullptr);
 107
 108 if (!codec.sdpFmtpLine.isEmpty())
 109 GST_FIXME("Unprocessed SDP FmtpLine: %s", codec.sdpFmtpLine.utf8().data());
 110 GST_DEBUG("Codec capability: %" GST_PTR_FORMAT, caps);
 111 return caps;
 112}
 113
 114ExceptionOr<void> GStreamerRtpTransceiverBackend::setCodecPreferences(const Vector<RTCRtpCodecCapability>& codecs)
 115{
 116 auto gstCodecs = adoptGRef(gst_caps_new_empty());
 117 for (auto& codec : codecs) {
 118 auto result = toRtpCodecCapability(codec);
 119 if (result.hasException())
 120 return result.releaseException();
 121 gst_caps_append(gstCodecs.get(), result.releaseReturnValue());
 122 }
 123 g_object_set(m_rtcTransceiver.get(), "codec-preferences", gstCodecs.get(), nullptr);
 124 return { };
 125}
 126
 127} // namespace WebCore
 128
 129#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "GStreamerRtpSenderBackend.h"
 26#include "GUniquePtrGStreamer.h"
 27#include "RTCRtpTransceiverBackend.h"
 28
 29namespace WebCore {
 30
 31class GStreamerRtpReceiverBackend;
 32
 33class GStreamerRtpTransceiverBackend final : public RTCRtpTransceiverBackend {
 34 WTF_MAKE_FAST_ALLOCATED;
 35public:
 36 GStreamerRtpTransceiverBackend(GRefPtr<GstWebRTCRTPTransceiver>&&);
 37
 38 std::unique_ptr<GStreamerRtpReceiverBackend> createReceiverBackend();
 39 std::unique_ptr<GStreamerRtpSenderBackend> createSenderBackend(GStreamerPeerConnectionBackend&, GStreamerRtpSenderBackend::Source&&, GUniquePtr<GstStructure>&&);
 40
 41 GstWebRTCRTPTransceiver* rtcTransceiver() { return m_rtcTransceiver.get(); }
 42
 43private:
 44 RTCRtpTransceiverDirection direction() const final;
 45 std::optional<RTCRtpTransceiverDirection> currentDirection() const final;
 46 void setDirection(RTCRtpTransceiverDirection) final;
 47 String mid() final;
 48 void stop() final;
 49 bool stopped() const final;
 50 ExceptionOr<void> setCodecPreferences(const Vector<RTCRtpCodecCapability>&) final;
 51
 52 GRefPtr<GstWebRTCRTPTransceiver> m_rtcTransceiver;
 53};
 54
 55} // namespace WebCore
 56
 57#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransformBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerRtpTransformBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "NotImplemented.h"
 26
 27namespace WebCore {
 28
 29void GStreamerRtpTransformBackend::setInputCallback(Callback&& callback)
 30{
 31 Locker holdLock { m_inputCallbackLock };
 32 m_inputCallback = WTFMove(callback);
 33}
 34
 35void GStreamerRtpTransformBackend::clearTransformableFrameCallback()
 36{
 37 setInputCallback({ });
 38}
 39
 40void GStreamerRtpTransformBackend::processTransformedFrame(RTCRtpTransformableFrame&)
 41{
 42 notImplemented();
 43}
 44
 45} // namespace WebCore
 46
 47#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerRtpTransformBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "RTCRtpTransformBackend.h"
 25#include <wtf/Lock.h>
 26
 27namespace WebCore {
 28
 29class GStreamerRtpTransformBackend : public RTCRtpTransformBackend {
 30protected:
 31 GStreamerRtpTransformBackend(MediaType, Side);
 32 void setInputCallback(Callback&&);
 33
 34protected:
 35 MediaType mediaType() const final { return m_mediaType; }
 36
 37private:
 38 // RTCRtpTransformBackend
 39 void processTransformedFrame(RTCRtpTransformableFrame&) final;
 40 void clearTransformableFrameCallback() final;
 41 Side side() const final { return m_side; }
 42
 43 MediaType m_mediaType;
 44 Side m_side;
 45
 46 Lock m_inputCallbackLock;
 47 Callback m_inputCallback;
 48
 49 Lock m_outputCallbackLock;
 50};
 51
 52inline GStreamerRtpTransformBackend::GStreamerRtpTransformBackend(MediaType mediaType, Side side)
 53 : m_mediaType(mediaType)
 54 , m_side(side)
 55{
 56}
 57
 58} // namespace WebCore
 59
 60#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerSctpTransportBackend.cpp

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerSctpTransportBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerDtlsTransportBackend.h"
 26#include "GStreamerWebRTCUtils.h"
 27
 28namespace WebCore {
 29
 30static inline RTCSctpTransportState toRTCSctpTransportState(GstWebRTCSCTPTransportState state)
 31{
 32 switch (state) {
 33 case GST_WEBRTC_SCTP_TRANSPORT_STATE_NEW:
 34 case GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTING:
 35 return RTCSctpTransportState::Connecting;
 36 case GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED:
 37 return RTCSctpTransportState::Connected;
 38 case GST_WEBRTC_SCTP_TRANSPORT_STATE_CLOSED:
 39 return RTCSctpTransportState::Closed;
 40 }
 41
 42 RELEASE_ASSERT_NOT_REACHED();
 43}
 44
 45GStreamerSctpTransportBackend::GStreamerSctpTransportBackend(GRefPtr<GstWebRTCSCTPTransport>&& transport)
 46 : m_backend(WTFMove(transport))
 47{
 48 ASSERT(m_backend);
 49}
 50
 51GStreamerSctpTransportBackend::~GStreamerSctpTransportBackend()
 52{
 53 unregisterClient();
 54}
 55
 56UniqueRef<RTCDtlsTransportBackend> GStreamerSctpTransportBackend::dtlsTransportBackend()
 57{
 58 GRefPtr<GstWebRTCDTLSTransport> transport;
 59 g_object_get(m_backend.get(), "transport", &transport.outPtr(), nullptr);
 60 return makeUniqueRef<GStreamerDtlsTransportBackend>(transport);
 61}
 62
 63void GStreamerSctpTransportBackend::registerClient(Client& client)
 64{
 65 ASSERT(!m_client);
 66 m_client = client;
 67 g_signal_connect_swapped(m_backend.get(), "notify::state", G_CALLBACK(+[](GStreamerSctpTransportBackend* backend) {
 68 backend->stateChanged();
 69 }), this);
 70}
 71
 72void GStreamerSctpTransportBackend::unregisterClient()
 73{
 74 g_signal_handlers_disconnect_by_data(m_backend.get(), this);
 75 m_client.clear();
 76}
 77
 78void GStreamerSctpTransportBackend::stateChanged()
 79{
 80 if (!m_client)
 81 return;
 82
 83 GstWebRTCSCTPTransportState transportState;
 84 guint16 maxChannels;
 85 uint64_t maxMessageSize;
 86 g_object_get(m_backend.get(), "state", &transportState, "max-message-size", &maxMessageSize, "max-channels", &maxChannels, nullptr);
 87 callOnMainThread([this, transportState, maxChannels, maxMessageSize] {
 88 if (!m_client)
 89 return;
 90
 91 m_client->onStateChanged(toRTCSctpTransportState(transportState), maxMessageSize, maxChannels);
 92 });
 93}
 94
 95} // namespace WebCore
 96
 97#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerSctpTransportBackend.h

 1/*
 2 * Copyright (C) 2021-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "RTCSctpTransportBackend.h"
 26#include <wtf/WeakPtr.h>
 27
 28typedef struct _GstWebRTCSCTPTransport GstWebRTCSCTPTransport;
 29
 30namespace WebCore {
 31
 32class GStreamerSctpTransportBackend final : public RTCSctpTransportBackend, public CanMakeWeakPtr<GStreamerSctpTransportBackend> {
 33 WTF_MAKE_FAST_ALLOCATED;
 34public:
 35 explicit GStreamerSctpTransportBackend(GRefPtr<GstWebRTCSCTPTransport>&&);
 36 ~GStreamerSctpTransportBackend();
 37
 38protected:
 39 void stateChanged();
 40
 41private :
 42 // RTCSctpTransportBackend
 43 const void* backend() const final { return m_backend.get(); }
 44 UniqueRef<RTCDtlsTransportBackend> dtlsTransportBackend() final;
 45 void registerClient(Client&) final;
 46 void unregisterClient() final;
 47
 48 GRefPtr<GstWebRTCSCTPTransport> m_backend;
 49 WeakPtr<Client> m_client;
 50};
 51
 52} // namespace WebCore
 53
 54#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerStatsCollector.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "GUniquePtrGStreamer.h"
 26#include "JSDOMMapLike.h"
 27#include "JSRTCStatsReport.h"
 28
 29#define GST_USE_UNSTABLE_API
 30#include <gst/webrtc/webrtc.h>
 31#undef GST_USE_UNSTABLE_API
 32
 33#include <wtf/MainThread.h>
 34
 35GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 36#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 37
 38namespace WebCore {
 39
 40static inline void fillRTCStats(RTCStatsReport::Stats& stats, const GstStructure* structure)
 41{
 42 double timestamp;
 43 if (gst_structure_get_double(structure, "timestamp", &timestamp))
 44 stats.timestamp = timestamp;
 45 stats.id = gst_structure_get_string(structure, "id");
 46}
 47
 48static inline void fillRTCRTPStreamStats(RTCStatsReport::RtpStreamStats& stats, const GstStructure* structure)
 49{
 50 fillRTCStats(stats, structure);
 51
 52 stats.transportId = gst_structure_get_string(structure, "transport-id");
 53 stats.codecId = gst_structure_get_string(structure, "codec-id");
 54
 55 unsigned value;
 56 if (gst_structure_get_uint(structure, "ssrc", &value))
 57 stats.ssrc = value;
 58
 59 // FIXME:
 60 // stats.transportId
 61 // stats.codecId
 62 // stats.mediaType
 63 // stats.kind
 64}
 65
 66static inline void fillRTCCodecStats(RTCStatsReport::CodecStats& stats, const GstStructure* structure)
 67{
 68 fillRTCStats(stats, structure);
 69
 70 unsigned value;
 71 if (gst_structure_get_uint(structure, "payload-type", &value))
 72 stats.payloadType = value;
 73 if (gst_structure_get_uint(structure, "clock-rate", &value))
 74 stats.clockRate = value;
 75
 76 // FIXME:
 77 // stats.mimeType =
 78 // stats.channels =
 79 // stats.sdpFmtpLine =
 80 // stats.implementation =
 81}
 82
 83static inline void fillInboundRTPStreamStats(RTCStatsReport::InboundRtpStreamStats& stats, const GstStructure* structure)
 84{
 85 fillRTCRTPStreamStats(stats, structure);
 86
 87 uint64_t value;
 88 if (gst_structure_get_uint64(structure, "packets-received", &value))
 89 stats.packetsReceived = value;
 90 if (gst_structure_get_uint64(structure, "bytes-received", &value))
 91 stats.bytesReceived = value;
 92
 93 unsigned packetsLost;
 94 if (gst_structure_get_uint(structure, "packets-lost", &packetsLost))
 95 stats.packetsLost = packetsLost;
 96
 97 double jitter;
 98 if (gst_structure_get_double(structure, "jitter", &jitter))
 99 stats.jitter = jitter;
 100
 101 // FIXME:
 102 // stats.fractionLost =
 103 // stats.packetsDiscarded =
 104 // stats.packetsRepaired =
 105 // stats.burstPacketsLost =
 106 // stats.burstPacketsDiscarded =
 107 // stats.burstLossCount =
 108 // stats.burstDiscardCount =
 109 // stats.burstLossRate =
 110 // stats.burstDiscardRate =
 111 // stats.gapLossRate =
 112 // stats.gapDiscardRate =
 113 // stats.framesDecoded =
 114}
 115
 116static inline void fillOutboundRTPStreamStats(RTCStatsReport::OutboundRtpStreamStats& stats, const GstStructure* structure)
 117{
 118 fillRTCRTPStreamStats(stats, structure);
 119
 120 uint64_t value;
 121 if (gst_structure_get_uint64(structure, "packets-sent", &value))
 122 stats.packetsSent = value;
 123 if (gst_structure_get_uint64(structure, "bytes-sent", &value))
 124 stats.bytesSent = value;
 125
 126 // FIXME
 127 // stats.targetBitrate =
 128 // stats.framesEncoded =
 129}
 130
 131static inline void fillRTCPeerConnectionStats(RTCStatsReport::PeerConnectionStats& stats, const GstStructure* structure)
 132{
 133 fillRTCStats(stats, structure);
 134
 135 int value;
 136 if (gst_structure_get_int(structure, "data-channels-opened", &value))
 137 stats.dataChannelsOpened = value;
 138 if (gst_structure_get_int(structure, "data-channels-closed", &value))
 139 stats.dataChannelsClosed = value;
 140}
 141
 142static inline void fillRTCTransportStats(RTCStatsReport::TransportStats& stats, const GstStructure* structure)
 143{
 144 fillRTCStats(stats, structure);
 145
 146 // FIXME
 147}
 148
 149static gboolean fillReportCallback(GQuark, const GValue* value, gpointer userData)
 150{
 151 if (!GST_VALUE_HOLDS_STRUCTURE(value))
 152 return TRUE;
 153
 154 const GstStructure* structure = gst_value_get_structure(value);
 155 GstWebRTCStatsType statsType;
 156 if (!gst_structure_get(structure, "type", GST_TYPE_WEBRTC_STATS_TYPE, &statsType, nullptr))
 157 return TRUE;
 158
 159 DOMMapAdapter& report = *reinterpret_cast<DOMMapAdapter*>(userData);
 160
 161 switch (statsType) {
 162 case GST_WEBRTC_STATS_CODEC: {
 163 RTCStatsReport::CodecStats stats;
 164 fillRTCCodecStats(stats, structure);
 165 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::CodecStats>>(stats.id, WTFMove(stats));
 166 break;
 167 }
 168 case GST_WEBRTC_STATS_INBOUND_RTP: {
 169 RTCStatsReport::InboundRtpStreamStats stats;
 170 fillInboundRTPStreamStats(stats, structure);
 171 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::InboundRtpStreamStats>>(stats.id, WTFMove(stats));
 172 break;
 173 }
 174 case GST_WEBRTC_STATS_OUTBOUND_RTP: {
 175 RTCStatsReport::OutboundRtpStreamStats stats;
 176 fillOutboundRTPStreamStats(stats, structure);
 177 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::OutboundRtpStreamStats>>(stats.id, WTFMove(stats));
 178 break;
 179 }
 180 case GST_WEBRTC_STATS_REMOTE_INBOUND_RTP: {
 181 RTCStatsReport::InboundRtpStreamStats stats;
 182 fillInboundRTPStreamStats(stats, structure);
 183 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::InboundRtpStreamStats>>(stats.id, WTFMove(stats));
 184 break;
 185 }
 186 case GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP: {
 187 RTCStatsReport::OutboundRtpStreamStats stats;
 188 fillOutboundRTPStreamStats(stats, structure);
 189 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::OutboundRtpStreamStats>>(stats.id, WTFMove(stats));
 190 break;
 191 }
 192 case GST_WEBRTC_STATS_CSRC:
 193 GST_FIXME("Deprecated stats: csrc");
 194 break;
 195 case GST_WEBRTC_STATS_PEER_CONNECTION: {
 196 RTCStatsReport::PeerConnectionStats stats;
 197 fillRTCPeerConnectionStats(stats, structure);
 198 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::PeerConnectionStats>>(stats.id, WTFMove(stats));
 199 break;
 200 }
 201 case GST_WEBRTC_STATS_TRANSPORT: {
 202 RTCStatsReport::TransportStats stats;
 203 fillRTCTransportStats(stats, structure);
 204 report.set<IDLDOMString, IDLDictionary<RTCStatsReport::TransportStats>>(stats.id, WTFMove(stats));
 205 break;
 206 }
 207 case GST_WEBRTC_STATS_STREAM:
 208 GST_FIXME("Deprecated stats: stream");
 209 break;
 210 case GST_WEBRTC_STATS_DATA_CHANNEL:
 211 GST_FIXME("Missing data-channel stats support");
 212 break;
 213 case GST_WEBRTC_STATS_CANDIDATE_PAIR:
 214 case GST_WEBRTC_STATS_LOCAL_CANDIDATE:
 215 case GST_WEBRTC_STATS_REMOTE_CANDIDATE:
 216 GST_FIXME("Missing candidate stats support");
 217 break;
 218 case GST_WEBRTC_STATS_CERTIFICATE:
 219 GST_FIXME("Missing certificate stats support");
 220 break;
 221 }
 222
 223 return TRUE;
 224}
 225
 226struct CallbackHolder {
 227 WTF_MAKE_STRUCT_FAST_ALLOCATED;
 228 CallbackHolder(GStreamerStatsCollector::CollectorCallback&& collectorCallback)
 229 : callback(WTFMove(collectorCallback))
 230 {
 231 }
 232 GStreamerStatsCollector::CollectorCallback callback;
 233};
 234
 235void GStreamerStatsCollector::getStats(CollectorCallback&& callback, GstPad* pad)
 236{
 237 if (!m_webrtcBin) {
 238 callback(nullptr);
 239 return;
 240 }
 241
 242 auto holder = WTF::makeUnique<CallbackHolder>(WTFMove(callback));
 243 auto* promise = gst_promise_new_with_change_func([](GstPromise* rawPromise, gpointer userData) {
 244 auto promise = adoptGRef(rawPromise);
 245 std::unique_ptr<CallbackHolder> holder(reinterpret_cast<CallbackHolder*>(userData));
 246 if (gst_promise_wait(promise.get()) != GST_PROMISE_RESULT_REPLIED) {
 247 holder->callback(nullptr);
 248 return;
 249 }
 250
 251 const auto* stats = gst_promise_get_reply(promise.get());
 252 if (!stats) {
 253 holder->callback(nullptr);
 254 return;
 255 }
 256
 257 callOnMainThreadAndWait([promise = WTFMove(promise), holder = holder.get()] {
 258 holder->callback(RTCStatsReport::create([&](auto& mapAdapter) {
 259 const auto* stats = gst_promise_get_reply(promise.get());
 260 gst_structure_foreach(stats, fillReportCallback, &mapAdapter);
 261 }));
 262 });
 263 }, holder.release(), nullptr);
 264 g_signal_emit_by_name(m_webrtcBin.get(), "get-stats", pad, promise);
 265}
 266
 267}; // namespace WebCore
 268
 269#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerStatsCollector.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25
 26#include <wtf/CompletionHandler.h>
 27#include <wtf/RefPtr.h>
 28#include <wtf/ThreadSafeRefCounted.h>
 29
 30namespace WebCore {
 31
 32class RTCStatsReport;
 33
 34class GStreamerStatsCollector : public ThreadSafeRefCounted<GStreamerStatsCollector, WTF::DestructionThread::Main> {
 35public:
 36 using CollectorCallback = CompletionHandler<void(RefPtr<RTCStatsReport>&&)>;
 37 static Ref<GStreamerStatsCollector> create() { return adoptRef(*new GStreamerStatsCollector()); }
 38
 39 void setElement(GstElement* element) { m_webrtcBin = element; }
 40 void getStats(CollectorCallback&&, GstPad*);
 41
 42private:
 43 GRefPtr<GstElement> m_webrtcBin;
 44};
 45
 46} // namespace WebCore
 47
 48#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23#include "GStreamerWebRTCUtils.h"
 24
 25#include "RTCIceCandidate.h"
 26#include "RTCIceProtocol.h"
 27
 28#include <openssl/bn.h>
 29#include <openssl/rsa.h>
 30#include <openssl/ssl.h>
 31#include <wtf/CryptographicallyRandomNumber.h>
 32#include <wtf/Scope.h>
 33#include <wtf/WallTime.h>
 34#include <wtf/text/Base64.h>
 35#include <wtf/text/StringToIntegerConversion.h>
 36
 37GST_DEBUG_CATEGORY_STATIC(webkit_webrtc_utils_debug);
 38#define GST_CAT_DEFAULT webkit_webrtc_utils_debug
 39
 40namespace WebCore {
 41
 42static inline RTCIceComponent toRTCIceComponent(int component)
 43{
 44 return component == 1 ? RTCIceComponent::Rtp : RTCIceComponent::Rtcp;
 45}
 46
 47static inline std::optional<RTCIceProtocol> toRTCIceProtocol(const String& protocol)
 48{
 49 if (protocol.isEmpty())
 50 return { };
 51 if (protocol == "udp")
 52 return RTCIceProtocol::Udp;
 53 ASSERT(protocol == "tcp");
 54 return RTCIceProtocol::Tcp;
 55}
 56
 57static inline std::optional<RTCIceTcpCandidateType> toRTCIceTcpCandidateType(const String& type)
 58{
 59 if (type.isEmpty())
 60 return { };
 61 if (type == "active")
 62 return RTCIceTcpCandidateType::Active;
 63 if (type == "passive")
 64 return RTCIceTcpCandidateType::Passive;
 65 ASSERT(type == "so");
 66 return RTCIceTcpCandidateType::So;
 67}
 68
 69static inline std::optional<RTCIceCandidateType> toRTCIceCandidateType(const String& type)
 70{
 71 if (type.isEmpty())
 72 return { };
 73 if (type == "host")
 74 return RTCIceCandidateType::Host;
 75 if (type == "srflx")
 76 return RTCIceCandidateType::Srflx;
 77 if (type == "prflx")
 78 return RTCIceCandidateType::Prflx;
 79 ASSERT(type == "relay");
 80 return RTCIceCandidateType::Relay;
 81}
 82
 83RefPtr<RTCError> toRTCError(GError* rtcError)
 84{
 85 auto detail = toRTCErrorDetailType(static_cast<GstWebRTCError>(rtcError->code));
 86 if (!detail)
 87 return nullptr;
 88 return RTCError::create(*detail, rtcError->message);
 89}
 90
 91static inline double toWebRTCBitRatePriority(RTCPriorityType priority)
 92{
 93 switch (priority) {
 94 case RTCPriorityType::VeryLow:
 95 return 0.5;
 96 case RTCPriorityType::Low:
 97 return 1;
 98 case RTCPriorityType::Medium:
 99 return 2;
 100 case RTCPriorityType::High:
 101 return 4;
 102 }
 103
 104 RELEASE_ASSERT_NOT_REACHED();
 105}
 106
 107GUniquePtr<GstStructure> fromRTCEncodingParameters(const RTCRtpEncodingParameters& parameters)
 108{
 109 GUniquePtr<GstStructure> rtcParameters(gst_structure_new("encoding-parameters", "active", G_TYPE_BOOLEAN, parameters.active,
 110 "rid", G_TYPE_STRING, parameters.rid.utf8().data(), "bitrate-priority", G_TYPE_DOUBLE, toWebRTCBitRatePriority(parameters.priority), nullptr));
 111
 112 if (parameters.ssrc)
 113 gst_structure_set(rtcParameters.get(), "ssrc", G_TYPE_ULONG, parameters.ssrc, nullptr);
 114
 115 if (parameters.maxBitrate)
 116 gst_structure_set(rtcParameters.get(), "max-bitrate", G_TYPE_ULONG, parameters.maxBitrate, nullptr);
 117
 118 if (parameters.maxFramerate)
 119 gst_structure_set(rtcParameters.get(), "max-framerate", G_TYPE_ULONG, parameters.maxFramerate, nullptr);
 120
 121 if (parameters.scaleResolutionDownBy)
 122 gst_structure_set(rtcParameters.get(), "scale-resolution-down-by", G_TYPE_DOUBLE, parameters.scaleResolutionDownBy, nullptr);
 123
 124 if (parameters.networkPriority)
 125 gst_structure_set(rtcParameters.get(), "network-priority", G_TYPE_INT, *parameters.networkPriority, nullptr);
 126
 127 return rtcParameters;
 128}
 129
 130static inline RTCPriorityType fromWebRTCBitRatePriority(double priority)
 131{
 132 if (priority < 0.7)
 133 return RTCPriorityType::VeryLow;
 134 if (priority < 1.5)
 135 return RTCPriorityType::Low;
 136 if (priority < 2.5)
 137 return RTCPriorityType::Medium;
 138 return RTCPriorityType::High;
 139}
 140
 141static inline RTCRtpEncodingParameters toRTCEncodingParameters(const GstStructure* rtcParameters)
 142{
 143 RTCRtpEncodingParameters parameters;
 144
 145 unsigned ssrc;
 146 if (gst_structure_get_uint(rtcParameters, "ssrc", &ssrc))
 147 parameters.ssrc = ssrc;
 148
 149 gst_structure_get(rtcParameters, "active", G_TYPE_BOOLEAN, &(parameters.active), nullptr);
 150
 151 uint64_t maxBitrate;
 152 if (gst_structure_get_uint64(rtcParameters, "max-bitrate", &maxBitrate))
 153 parameters.maxBitrate = maxBitrate;
 154
 155 uint64_t maxFramerate;
 156 if (gst_structure_get_uint64(rtcParameters, "max-framerate", &maxFramerate))
 157 parameters.maxFramerate = maxFramerate;
 158
 159 parameters.rid = gst_structure_get_string(rtcParameters, "rid");
 160
 161 double scaleResolutionDownBy;
 162 if (gst_structure_get_double(rtcParameters, "scale-resolution-down-by", &scaleResolutionDownBy))
 163 parameters.scaleResolutionDownBy = scaleResolutionDownBy;
 164
 165 double bitratePriority;
 166 if (gst_structure_get_double(rtcParameters, "bitrate-priority", &bitratePriority))
 167 parameters.priority = fromWebRTCBitRatePriority(bitratePriority);
 168
 169 int networkPriority;
 170 if (gst_structure_get_int(rtcParameters, "network-priority", &networkPriority))
 171 parameters.networkPriority = static_cast<RTCPriorityType>(networkPriority);
 172
 173 return parameters;
 174}
 175
 176RTCRtpSendParameters toRTCRtpSendParameters(const GstStructure* rtcParameters)
 177{
 178 if (!rtcParameters)
 179 return { };
 180
 181 RTCRtpSendParameters parameters;
 182 auto* encodings = gst_structure_get_value(rtcParameters, "encodings");
 183 unsigned size = gst_value_list_get_size(encodings);
 184 for (unsigned i = 0; i < size; i++) {
 185 const auto* value = gst_value_list_get_value(encodings, i);
 186 parameters.encodings.append(toRTCEncodingParameters(GST_STRUCTURE_CAST(value)));
 187 }
 188
 189 // FIXME: Handle rtcParameters.degradation_preference.
 190 return parameters;
 191}
 192
 193
 194static void ensureDebugCategoryInitialized()
 195{
 196 static std::once_flag onceFlag;
 197 std::call_once(onceFlag, [] {
 198 GST_DEBUG_CATEGORY_INIT(webkit_webrtc_utils_debug, "webkitwebrtcutils", 0, "WebKit WebRTC utilities");
 199 });
 200}
 201
 202std::optional<RTCIceCandidate::Fields> parseIceCandidateSDP(const String& sdp)
 203{
 204 ensureDebugCategoryInitialized();
 205 GST_DEBUG("Parsing ICE Candidate: %s", sdp.utf8().data());
 206 if (!sdp.startsWith("candidate:"))
 207 return { };
 208
 209 String foundation;
 210 unsigned componentId = 0;
 211 String transport;
 212 unsigned priority = 0;
 213 String address;
 214 uint32_t port = 0;
 215 String type;
 216 String tcptype;
 217 String relatedAddress;
 218 guint16 relatedPort = 0;
 219 String usernameFragment;
 220 auto tokens = sdp.convertToASCIILowercase().substring(10).split(' ');
 221
 222 for (auto it = tokens.begin(); it != tokens.end(); ++it) {
 223 auto i = std::distance(tokens.begin(), it);
 224 auto token = *it;
 225 switch (i) {
 226 case 0:
 227 foundation = token;
 228 break;
 229 case 1:
 230 if (auto value = parseInteger<unsigned>(token))
 231 componentId = *value;
 232 else
 233 return { };
 234 break;
 235 case 2:
 236 transport = token;
 237 break;
 238 case 3:
 239 if (auto value = parseInteger<unsigned>(token))
 240 priority = *value;
 241 else
 242 return { };
 243 break;
 244 case 4:
 245 address = token;
 246 break;
 247 case 5:
 248 if (auto value = parseInteger<unsigned>(token))
 249 port = *value;
 250 else
 251 return { };
 252 break;
 253 default:
 254 if (it + 1 == tokens.end())
 255 return { };
 256
 257 it++;
 258 if (token == "typ")
 259 type = *it;
 260 else if (token == "raddr")
 261 relatedAddress = *it;
 262 else if (token == "rport")
 263 relatedPort = parseInteger<unsigned>(*it).value_or(0);
 264 else if (token == "tcptype")
 265 tcptype = *it;
 266 else if (token == "ufrag")
 267 usernameFragment = *it;
 268 break;
 269 }
 270 }
 271
 272 if (type.isEmpty())
 273 return { };
 274
 275 RTCIceCandidate::Fields fields;
 276 fields.foundation = foundation;
 277 fields.component = toRTCIceComponent(componentId);
 278 fields.priority = priority;
 279 fields.protocol = toRTCIceProtocol(transport);
 280 if (!address.isEmpty()) {
 281 fields.address = address;
 282 fields.port = port;
 283 }
 284 fields.type = toRTCIceCandidateType(type);
 285 fields.tcpType = toRTCIceTcpCandidateType(tcptype);
 286 if (!relatedAddress.isEmpty()) {
 287 fields.relatedAddress = relatedAddress;
 288 fields.relatedPort = relatedPort;
 289 }
 290 fields.usernameFragment = usernameFragment;
 291 return fields;
 292}
 293
 294static String x509Serialize(X509* x509)
 295{
 296 BIO* bio = BIO_new(BIO_s_mem());
 297 if (!bio)
 298 return { };
 299
 300 auto scopeExit = WTF::makeScopeExit([&] {
 301 BIO_free(bio);
 302 });
 303
 304 if (!PEM_write_bio_X509(bio, x509))
 305 return { };
 306
 307 Vector<char> buffer;
 308 buffer.reserveCapacity(4096);
 309 int length = BIO_read(bio, buffer.data(), 4096);
 310 if (!length)
 311 return { };
 312
 313 return String(buffer.data(), length);
 314}
 315
 316static String privateKeySerialize(EVP_PKEY* privateKey)
 317{
 318 BIO* bio = BIO_new(BIO_s_mem());
 319 if (!bio)
 320 return { };
 321
 322 auto scopeExit = WTF::makeScopeExit([&] {
 323 BIO_free(bio);
 324 });
 325
 326 if (!PEM_write_bio_PrivateKey(bio, privateKey, nullptr, nullptr, 0, nullptr, nullptr))
 327 return { };
 328
 329 Vector<char> buffer;
 330 buffer.reserveCapacity(4096);
 331 int length = BIO_read(bio, buffer.data(), 4096);
 332 if (!length)
 333 return { };
 334
 335 return String(buffer.data(), length);
 336}
 337
 338std::optional<Ref<RTCCertificate>> generateCertificate(Ref<SecurityOrigin>&& origin, const PeerConnectionBackend::CertificateInformation& info)
 339{
 340 ensureDebugCategoryInitialized();
 341 EVP_PKEY* privateKey = EVP_PKEY_new();
 342 if (!privateKey) {
 343 GST_WARNING("Failed to create private key");
 344 return { };
 345 }
 346
 347 auto scopeExit = WTF::makeScopeExit([&] {
 348 EVP_PKEY_free(privateKey);
 349 });
 350
 351 switch (info.type) {
 352 case PeerConnectionBackend::CertificateInformation::Type::ECDSAP256: {
 353 EC_KEY* ecKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
 354 // Ensure curve name is included when EC key is serialized.
 355 // Without this call, OpenSSL versions before 1.1.0 will create
 356 // certificates that don't work for TLS.
 357 // This is a no-op for BoringSSL and OpenSSL 1.1.0+
 358 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
 359 if (!privateKey || !ecKey || !EC_KEY_generate_key(ecKey) || !EVP_PKEY_assign_EC_KEY(privateKey, ecKey)) {
 360 EC_KEY_free(ecKey);
 361 return { };
 362 }
 363 break;
 364 }
 365 case PeerConnectionBackend::CertificateInformation::Type::RSASSAPKCS1v15: {
 366 RSA* rsa = RSA_new();
 367 if (!rsa)
 368 return { };
 369
 370 BIGNUM* exponent = BN_new();
 371 int publicExponent = info.rsaParameters ? info.rsaParameters->publicExponent : 65537;
 372 auto modulusLength = info.rsaParameters ? info.rsaParameters->modulusLength : 2048;
 373 if (!BN_set_word(exponent, publicExponent) || !RSA_generate_key_ex(rsa, modulusLength, exponent, nullptr)
 374 || !EVP_PKEY_assign_RSA(privateKey, rsa)) {
 375 RSA_free(rsa);
 376 return { };
 377 }
 378 BN_free(exponent);
 379 break;
 380 }
 381 }
 382
 383 X509* x509 = X509_new();
 384 if (!x509) {
 385 GST_WARNING("Failed to create certificate");
 386 return { };
 387 }
 388
 389 auto certScopeExit = WTF::makeScopeExit([&] {
 390 X509_free(x509);
 391 });
 392
 393 X509_set_version(x509, 2);
 394
 395 // Set a random 64 bit integer as serial number.
 396 BIGNUM* serialNumber = BN_new();
 397 BN_pseudo_rand(serialNumber, 64, 0, 0);
 398 ASN1_INTEGER* asn1SerialNumber = X509_get_serialNumber(x509);
 399 BN_to_ASN1_INTEGER(serialNumber, asn1SerialNumber);
 400 BN_free(serialNumber);
 401
 402 // Set a random 8 byte base64 string as issuer/subject.
 403 X509_NAME* name = X509_NAME_new();
 404 Vector<uint8_t> buffer;
 405 buffer.reserveInitialCapacity(8);
 406 WTF::cryptographicallyRandomValues(buffer.data(), 8);
 407 auto commonName = base64EncodeToString(buffer);
 408 X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC, (const guchar*)commonName.ascii().data(), -1, -1, 0);
 409 X509_set_subject_name(x509, name);
 410 X509_set_issuer_name(x509, name);
 411 X509_NAME_free(name);
 412
 413 // Fallback to 30 days, max out at one year.
 414 uint64_t expires = info.expires.value_or(2592000);
 415 expires = std::min<uint64_t>(expires, 31536000000);
 416 X509_gmtime_adj(X509_getm_notBefore(x509), 0);
 417 X509_gmtime_adj(X509_getm_notAfter(x509), expires);
 418 X509_set_pubkey(x509, privateKey);
 419
 420 if (!X509_sign(x509, privateKey, EVP_sha256())) {
 421 GST_WARNING("Failed to sign certificate");
 422 return { };
 423 }
 424
 425 auto pem = x509Serialize(x509);
 426 GST_DEBUG("Generated certificate PEM: %s", pem.ascii().data());
 427 auto serializedPrivateKey = privateKeySerialize(privateKey);
 428 Vector<RTCCertificate::DtlsFingerprint> fingerprints;
 429 // FIXME: Fill fingerprints.
 430 auto expirationTime = WTF::WallTime::now().secondsSinceEpoch() + WTF::Seconds(expires);
 431 return RTCCertificate::create(WTFMove(origin), expirationTime.milliseconds(), WTFMove(fingerprints), WTFMove(pem), WTFMove(serializedPrivateKey));
 432}
 433
 434bool sdpMediaHasAttributeKey(const GstSDPMedia* media, const char* key)
 435{
 436 unsigned len = gst_sdp_media_attributes_len(media);
 437 for (unsigned i = 0; i < len; i++) {
 438 const auto* attribute = gst_sdp_media_get_attribute(media, i);
 439 if (!g_strcmp0(attribute->key, key))
 440 return true;
 441 }
 442
 443 return false;
 444}
 445
 446} // namespace WebCore
 447
 448#endif

Source/WebCore/Modules/mediastream/gstreamer/GStreamerWebRTCUtils.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "GUniquePtrGStreamer.h"
 25#include "MediaEndpointConfiguration.h"
 26#include "PeerConnectionBackend.h"
 27#include "RTCBundlePolicy.h"
 28#include "RTCCertificate.h"
 29#include "RTCDtlsTransport.h"
 30#include "RTCError.h"
 31#include "RTCIceConnectionState.h"
 32#include "RTCIceTransportPolicy.h"
 33#include "RTCIceTransportState.h"
 34#include "RTCRtpSendParameters.h"
 35#include "RTCRtpTransceiverDirection.h"
 36#include "RTCSdpType.h"
 37#include "RTCSignalingState.h"
 38
 39#define GST_USE_UNSTABLE_API
 40#include <gst/webrtc/webrtc.h>
 41#undef GST_USE_UNSTABLE_API
 42
 43namespace WebCore {
 44
 45inline RTCRtpTransceiverDirection toRTCRtpTransceiverDirection(GstWebRTCRTPTransceiverDirection direction)
 46{
 47 switch (direction) {
 48 case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE:
 49 // ¯\_(ツ)_/¯
 50 return RTCRtpTransceiverDirection::Inactive;
 51 case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE:
 52 return RTCRtpTransceiverDirection::Inactive;
 53 case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY:
 54 return RTCRtpTransceiverDirection::Sendonly;
 55 case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY:
 56 return RTCRtpTransceiverDirection::Recvonly;
 57 case GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV:
 58 return RTCRtpTransceiverDirection::Sendrecv;
 59 }
 60 RELEASE_ASSERT_NOT_REACHED();
 61 return RTCRtpTransceiverDirection::Inactive;
 62}
 63
 64inline GstWebRTCRTPTransceiverDirection fromRTCRtpTransceiverDirection(RTCRtpTransceiverDirection direction)
 65{
 66 switch (direction) {
 67 case RTCRtpTransceiverDirection::Inactive:
 68 return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE;
 69 case RTCRtpTransceiverDirection::Sendonly:
 70 return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY;
 71 case RTCRtpTransceiverDirection::Recvonly:
 72 return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
 73 case RTCRtpTransceiverDirection::Sendrecv:
 74 return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
 75 }
 76 RELEASE_ASSERT_NOT_REACHED();
 77 return GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE;
 78}
 79
 80static inline GstWebRTCSDPType toSessionDescriptionType(RTCSdpType sdpType)
 81{
 82 switch (sdpType) {
 83 case RTCSdpType::Offer:
 84 return GST_WEBRTC_SDP_TYPE_OFFER;
 85 case RTCSdpType::Pranswer:
 86 return GST_WEBRTC_SDP_TYPE_PRANSWER;
 87 case RTCSdpType::Answer:
 88 return GST_WEBRTC_SDP_TYPE_ANSWER;
 89 case RTCSdpType::Rollback:
 90 return GST_WEBRTC_SDP_TYPE_ROLLBACK;
 91 }
 92
 93 RELEASE_ASSERT_NOT_REACHED();
 94 return GST_WEBRTC_SDP_TYPE_OFFER;
 95}
 96
 97static inline RTCSdpType fromSessionDescriptionType(const GstWebRTCSessionDescription& description)
 98{
 99 auto type = description.type;
 100 if (type == GST_WEBRTC_SDP_TYPE_OFFER)
 101 return RTCSdpType::Offer;
 102 if (type == GST_WEBRTC_SDP_TYPE_ANSWER)
 103 return RTCSdpType::Answer;
 104 ASSERT(type == GST_WEBRTC_SDP_TYPE_PRANSWER);
 105 return RTCSdpType::Pranswer;
 106}
 107
 108static inline RTCSignalingState toSignalingState(GstWebRTCSignalingState state)
 109{
 110 switch (state) {
 111 case GST_WEBRTC_SIGNALING_STATE_STABLE:
 112 return RTCSignalingState::Stable;
 113 case GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER:
 114 return RTCSignalingState::HaveLocalOffer;
 115 case GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_PRANSWER:
 116 return RTCSignalingState::HaveLocalPranswer;
 117 case GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER:
 118 return RTCSignalingState::HaveRemoteOffer;
 119 case GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_PRANSWER:
 120 return RTCSignalingState::HaveRemotePranswer;
 121 case GST_WEBRTC_SIGNALING_STATE_CLOSED:
 122 return RTCSignalingState::Closed;
 123 }
 124
 125 RELEASE_ASSERT_NOT_REACHED();
 126 return RTCSignalingState::Stable;
 127}
 128
 129static inline RTCIceConnectionState toRTCIceConnectionState(GstWebRTCICEConnectionState state)
 130{
 131 switch (state) {
 132 case GST_WEBRTC_ICE_CONNECTION_STATE_NEW:
 133 return RTCIceConnectionState::New;
 134 case GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING:
 135 return RTCIceConnectionState::Checking;
 136 case GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED:
 137 return RTCIceConnectionState::Connected;
 138 case GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED:
 139 return RTCIceConnectionState::Completed;
 140 case GST_WEBRTC_ICE_CONNECTION_STATE_FAILED:
 141 return RTCIceConnectionState::Failed;
 142 case GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED:
 143 return RTCIceConnectionState::Disconnected;
 144 case GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED:
 145 return RTCIceConnectionState::Closed;
 146 }
 147
 148 RELEASE_ASSERT_NOT_REACHED();
 149 return RTCIceConnectionState::New;
 150}
 151
 152static inline RTCDtlsTransportState toRTCDtlsTransportState(GstWebRTCDTLSTransportState state)
 153{
 154 switch (state) {
 155 case GST_WEBRTC_DTLS_TRANSPORT_STATE_NEW:
 156 return RTCDtlsTransportState::New;
 157 case GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTING:
 158 return RTCDtlsTransportState::Connecting;
 159 case GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTED:
 160 return RTCDtlsTransportState::Connected;
 161 case GST_WEBRTC_DTLS_TRANSPORT_STATE_CLOSED:
 162 return RTCDtlsTransportState::Closed;
 163 case GST_WEBRTC_DTLS_TRANSPORT_STATE_FAILED:
 164 return RTCDtlsTransportState::Failed;
 165 }
 166
 167 RELEASE_ASSERT_NOT_REACHED();
 168}
 169
 170static inline RTCIceTransportState toRTCIceTransportState(GstWebRTCICEConnectionState state)
 171{
 172 // FIXME: No GstWebRTCICETransportState ?
 173 switch (state) {
 174 case GST_WEBRTC_ICE_CONNECTION_STATE_NEW:
 175 return RTCIceTransportState::New;
 176 case GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING:
 177 return RTCIceTransportState::Checking;
 178 case GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED:
 179 return RTCIceTransportState::Connected;
 180 case GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED:
 181 return RTCIceTransportState::Completed;
 182 case GST_WEBRTC_ICE_CONNECTION_STATE_FAILED:
 183 return RTCIceTransportState::Failed;
 184 case GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED:
 185 return RTCIceTransportState::Disconnected;
 186 case GST_WEBRTC_ICE_CONNECTION_STATE_CLOSED:
 187 return RTCIceTransportState::Closed;
 188 }
 189
 190 RELEASE_ASSERT_NOT_REACHED();
 191 return RTCIceTransportState::New;
 192}
 193
 194static inline RTCIceGatheringState toRTCIceGatheringState(GstWebRTCICEGatheringState state)
 195{
 196 switch (state) {
 197 case GST_WEBRTC_ICE_GATHERING_STATE_NEW:
 198 return RTCIceGatheringState::New;
 199 case GST_WEBRTC_ICE_GATHERING_STATE_GATHERING:
 200 return RTCIceGatheringState::Gathering;
 201 case GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE:
 202 return RTCIceGatheringState::Complete;
 203 }
 204
 205 RELEASE_ASSERT_NOT_REACHED();
 206}
 207
 208static inline GstWebRTCBundlePolicy bundlePolicyFromConfiguration(const MediaEndpointConfiguration& configuration)
 209{
 210 switch (configuration.bundlePolicy) {
 211 case RTCBundlePolicy::Balanced:
 212 return GST_WEBRTC_BUNDLE_POLICY_BALANCED;
 213 case RTCBundlePolicy::MaxCompat:
 214 return GST_WEBRTC_BUNDLE_POLICY_MAX_COMPAT;
 215 case RTCBundlePolicy::MaxBundle:
 216 return GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE;
 217 }
 218
 219 RELEASE_ASSERT_NOT_REACHED();
 220 return GST_WEBRTC_BUNDLE_POLICY_NONE;
 221}
 222
 223static inline GstWebRTCICETransportPolicy iceTransportPolicyFromConfiguration(const MediaEndpointConfiguration& configuration)
 224{
 225 switch (configuration.iceTransportPolicy) {
 226 case RTCIceTransportPolicy::All:
 227 return GST_WEBRTC_ICE_TRANSPORT_POLICY_ALL;
 228 case RTCIceTransportPolicy::Relay:
 229 return GST_WEBRTC_ICE_TRANSPORT_POLICY_RELAY;
 230 }
 231
 232 RELEASE_ASSERT_NOT_REACHED();
 233 return GST_WEBRTC_ICE_TRANSPORT_POLICY_ALL;
 234}
 235
 236static inline std::optional<RTCErrorDetailType> toRTCErrorDetailType(GstWebRTCError code)
 237{
 238 switch (code) {
 239 case GST_WEBRTC_ERROR_DATA_CHANNEL_FAILURE:
 240 return RTCErrorDetailType::DataChannelFailure;
 241 case GST_WEBRTC_ERROR_DTLS_FAILURE:
 242 return RTCErrorDetailType::DtlsFailure;
 243 case GST_WEBRTC_ERROR_FINGERPRINT_FAILURE:
 244 return RTCErrorDetailType::FingerprintFailure;
 245 case GST_WEBRTC_ERROR_SCTP_FAILURE:
 246 return RTCErrorDetailType::SctpFailure;
 247 case GST_WEBRTC_ERROR_SDP_SYNTAX_ERROR:
 248 return RTCErrorDetailType::SdpSyntaxError;
 249 case GST_WEBRTC_ERROR_HARDWARE_ENCODER_NOT_AVAILABLE:
 250 case GST_WEBRTC_ERROR_ENCODER_ERROR:
 251 // FIXME
 252 default:
 253 return { };
 254 };
 255}
 256
 257RefPtr<RTCError> toRTCError(GError*);
 258
 259GUniquePtr<GstStructure> fromRTCEncodingParameters(const RTCRtpEncodingParameters&);
 260RTCRtpSendParameters toRTCRtpSendParameters(const GstStructure*);
 261
 262std::optional<Ref<RTCCertificate>> generateCertificate(Ref<SecurityOrigin>&&, const PeerConnectionBackend::CertificateInformation&);
 263
 264bool sdpMediaHasAttributeKey(const GstSDPMedia*, const char* key);
 265
 266}
 267#endif

Source/WebCore/platform/GStreamer.cmake

11if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
22 list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES
 3 "${WEBCORE_DIR}/Modules/mediastream/gstreamer"
34 "${WEBCORE_DIR}/platform/graphics/gstreamer"
45 "${WEBCORE_DIR}/platform/graphics/gstreamer/mse"
56 "${WEBCORE_DIR}/platform/graphics/gstreamer/eme"

@@if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
78 )
89
910 list(APPEND WebCore_SOURCES
 11 Modules/mediastream/gstreamer/GStreamerDataChannelHandler.cpp
 12 Modules/mediastream/gstreamer/GStreamerDtlsTransportBackend.cpp
 13 Modules/mediastream/gstreamer/GStreamerIceTransportBackend.cpp
 14 Modules/mediastream/gstreamer/GStreamerMediaEndpoint.cpp
 15 Modules/mediastream/gstreamer/GStreamerPeerConnectionBackend.cpp
 16 Modules/mediastream/gstreamer/GStreamerRtpReceiverBackend.cpp
 17 Modules/mediastream/gstreamer/GStreamerRtpReceiverTransformBackend.cpp
 18 Modules/mediastream/gstreamer/GStreamerRtpSenderBackend.cpp
 19 Modules/mediastream/gstreamer/GStreamerRtpSenderTransformBackend.cpp
 20 Modules/mediastream/gstreamer/GStreamerRtpTransceiverBackend.cpp
 21 Modules/mediastream/gstreamer/GStreamerRtpTransformBackend.cpp
 22 Modules/mediastream/gstreamer/GStreamerSctpTransportBackend.cpp
 23 Modules/mediastream/gstreamer/GStreamerStatsCollector.cpp
 24 Modules/mediastream/gstreamer/GStreamerWebRTCUtils.cpp
 25
1026 Modules/webaudio/MediaStreamAudioSourceGStreamer.cpp
 27
1128 platform/graphics/gstreamer/AudioTrackPrivateGStreamer.cpp
1229 platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp
1330 platform/graphics/gstreamer/GLVideoSinkGStreamer.cpp

@@if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
6481 platform/mediastream/gstreamer/GStreamerAudioCapturer.cpp
6582 platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.cpp
6683 platform/mediastream/gstreamer/GStreamerCapturer.cpp
 84 platform/mediastream/gstreamer/GStreamerDTMFSenderBackend.cpp
6785 platform/mediastream/gstreamer/GStreamerDisplayCaptureDeviceManager.cpp
6886 platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp
6987 platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp

@@if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
7189 platform/mediastream/gstreamer/GStreamerVideoEncoder.cpp
7290 platform/mediastream/gstreamer/MockRealtimeAudioSourceGStreamer.cpp
7391 platform/mediastream/gstreamer/MockRealtimeVideoSourceGStreamer.cpp
 92 platform/mediastream/gstreamer/RealtimeIncomingAudioSourceGStreamer.cpp
 93 platform/mediastream/gstreamer/RealtimeIncomingSourceGStreamer.cpp
 94 platform/mediastream/gstreamer/RealtimeIncomingVideoSourceGStreamer.cpp
7495 platform/mediastream/gstreamer/RealtimeMediaSourceCenterGStreamer.cpp
 96 platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.cpp
 97 platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.cpp
 98 platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp
7599 )
76100
77101 list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS

@@if (ENABLE_VIDEO)
161185 )
162186 endif ()
163187
164  if (ENABLE_MEDIA_STREAM OR ENABLE_WEB_RTC)
 188 if (USE_LIBWEBRTC)
165189 list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES
166190 ${GSTREAMER_CODECPARSERS_INCLUDE_DIRS}
167191 )

@@if (ENABLE_VIDEO)
170194 ${GSTREAMER_CODECPARSERS_LIBRARIES}
171195 )
172196 endif ()
 197 elseif (USE_GSTREAMER_WEBRTC)
 198 list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES
 199 ${GSTREAMER_RTP_INCLUDE_DIRS}
 200 ${GSTREAMER_SDP_INCLUDE_DIRS}
 201 ${GSTREAMER_WEBRTC_INCLUDE_DIRS}
 202 )
 203 if (NOT USE_GSTREAMER_FULL)
 204 list(APPEND WebCore_LIBRARIES
 205 ${GSTREAMER_RTP_LIBRARIES}
 206 ${GSTREAMER_SDP_LIBRARIES}
 207 ${GSTREAMER_WEBRTC_LIBRARIES}
 208 )
 209 endif ()
 210
 211 list(APPEND WebCore_LIBRARIES OpenSSL::Crypto)
173212 endif ()
174213endif ()
175214

Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp

@@AudioSourceProviderGStreamer::AudioSourceProviderGStreamer(MediaStreamTrackPriva
100100
101101 m_audioSinkBin = gst_parse_bin_from_description("tee name=audioTee", true, nullptr);
102102
103  gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), src, m_audioSinkBin.get(), nullptr);
104  gst_element_link(src, m_audioSinkBin.get());
 103 auto* decodebin = makeGStreamerElement("decodebin3", nullptr);
 104 g_signal_connect_swapped(decodebin, "pad-added", G_CALLBACK(+[](AudioSourceProviderGStreamer* provider, GstPad* pad) {
 105 auto padCaps = adoptGRef(gst_pad_query_caps(pad, nullptr));
 106 bool isAudio = doCapsHaveType(padCaps.get(), "audio");
 107 if (webkitGstCheckVersion(1, 18, 0))
 108 RELEASE_ASSERT(isAudio);
 109 else if (!isAudio)
 110 return;
 111
 112 auto sinkPad = adoptGRef(gst_element_get_static_pad(provider->m_audioSinkBin.get(), "sink"));
 113 gst_pad_link(pad, sinkPad.get());
 114 gst_element_sync_state_with_parent(provider->m_audioSinkBin.get());
 115 }), this);
 116
 117 gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), src, decodebin, m_audioSinkBin.get(), nullptr);
 118 gst_element_link(src, decodebin);
 119
 120 auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
 121 ASSERT(bus);
 122
 123 gst_bus_set_sync_handler(bus.get(), [](GstBus*, GstMessage* message, gpointer userData) -> GstBusSyncReply {
 124 auto* decodebin = GST_ELEMENT_CAST(userData);
 125 if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STREAM_COLLECTION || GST_MESSAGE_SRC(message) != GST_OBJECT_CAST(decodebin)) {
 126 gst_message_unref(message);
 127 return GST_BUS_DROP;
 128 }
 129
 130 GRefPtr<GstStreamCollection> collection;
 131 gst_message_parse_stream_collection(message, &collection.outPtr());
 132 if (!collection) {
 133 gst_message_unref(message);
 134 return GST_BUS_DROP;
 135 }
 136
 137 unsigned size = gst_stream_collection_get_size(collection.get());
 138 GList* streams = nullptr;
 139 for (unsigned i = 0; i < size; i++) {
 140 auto* stream = gst_stream_collection_get_stream(collection.get(), i);
 141 auto streamType = gst_stream_get_stream_type(stream);
 142 if (streamType == GST_STREAM_TYPE_AUDIO) {
 143 streams = g_list_append(streams, const_cast<char*>(gst_stream_get_stream_id(stream)));
 144 break;
 145 }
 146 }
 147 if (streams) {
 148 gst_element_send_event(decodebin, gst_event_new_select_streams(streams));
 149 g_list_free(streams);
 150 }
105151
106  connectSimpleBusMessageCallback(m_pipeline.get());
 152 gst_message_unref(message);
 153 return GST_BUS_DROP;
 154 }, gst_object_ref(decodebin), gst_object_unref);
107155}
108156#endif
109157

@@AudioSourceProviderGStreamer::~AudioSourceProviderGStreamer()
120168
121169 setClient(nullptr);
122170#if ENABLE(MEDIA_STREAM)
123  if (m_pipeline) {
124  disconnectSimpleBusMessageCallback(m_pipeline.get());
 171 if (m_pipeline)
125172 gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
126  }
127173#endif
128174}
129175

@@void AudioSourceProviderGStreamer::handleNewDeinterleavePad(GstPad* pad)
345391
346392 GQuark quark = g_quark_from_static_string("peer");
347393 g_object_set_qdata(G_OBJECT(pad), quark, sinkPad.get());
348 
349394 m_deinterleaveSourcePads++;
350395 GQuark channelIdQuark = g_quark_from_static_string("channel-id");
351396 g_object_set_qdata(G_OBJECT(sink), channelIdQuark, GINT_TO_POINTER(m_deinterleaveSourcePads));

Source/WebCore/platform/audio/gstreamer/GStreamerAudioStreamDescription.h

@@class GStreamerAudioStreamDescription final: public AudioStreamDescription {
3232public:
3333 GStreamerAudioStreamDescription(GstAudioInfo&& info)
3434 : m_info(WTFMove(info))
35  , m_caps(adoptGRef(gst_audio_info_to_caps(&m_info)))
3635 {
3736 }
3837
3938 GStreamerAudioStreamDescription(const GstAudioInfo& info)
4039 : m_info(info)
41  , m_caps(adoptGRef(gst_audio_info_to_caps(&m_info)))
4240 {
4341 }
4442
4543 GStreamerAudioStreamDescription(GstAudioInfo* info)
4644 : m_info(*info)
47  , m_caps(adoptGRef(gst_audio_info_to_caps(&m_info)))
4845 {
4946 }
5047

@@public:
9996 bool operator==(const GStreamerAudioStreamDescription& other) { return gst_audio_info_is_equal(&m_info, &other.m_info); }
10097 bool operator!=(const GStreamerAudioStreamDescription& other) { return !operator == (other); }
10198
102  const GRefPtr<GstCaps>& caps() const { return m_caps; }
 99 const GRefPtr<GstCaps>& caps()
 100 {
 101 if (!m_caps)
 102 m_caps = adoptGRef(gst_audio_info_to_caps(&m_info));
 103 return m_caps;
 104 }
103105 const GstAudioInfo& getInfo() const { return m_info; }
104106
105107private:

Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp

2727#include <gst/gl/egl/gsteglimage.h>
2828#endif
2929
 30#if USE(GSTREAMER_WEBRTC)
 31#define GST_USE_UNSTABLE_API
 32#include <gst/webrtc/webrtc.h>
 33#undef GST_USE_UNSTABLE_API
 34#endif
 35
3036namespace WTF {
3137
3238template<> GRefPtr<GstMiniObject> adoptGRef(GstMiniObject* ptr)

@@GstEncodingProfile* refGPtr<GstEncodingProfile>(GstEncodingProfile* ptr)
584590 return ptr;
585591}
586592
587 template <>
 593template<>
588594void derefGPtr<GstEncodingProfile>(GstEncodingProfile* ptr)
589595{
590596 if (ptr)
591597 gst_encoding_profile_unref(ptr);
592598}
593599
 600#if USE(GSTREAMER_WEBRTC)
 601
 602template <> GRefPtr<GstWebRTCRTPReceiver> adoptGRef(GstWebRTCRTPReceiver* ptr)
 603{
 604 return GRefPtr<GstWebRTCRTPReceiver>(ptr, GRefPtrAdopt);
 605}
 606
 607template <> GstWebRTCRTPReceiver* refGPtr<GstWebRTCRTPReceiver>(GstWebRTCRTPReceiver* ptr)
 608{
 609 if (ptr)
 610 gst_object_ref(GST_OBJECT(ptr));
 611
 612 return ptr;
 613}
 614
 615template <> void derefGPtr<GstWebRTCRTPReceiver>(GstWebRTCRTPReceiver* ptr)
 616{
 617 if (ptr)
 618 gst_object_unref(ptr);
 619}
 620
 621template <> GRefPtr<GstWebRTCRTPSender> adoptGRef(GstWebRTCRTPSender* ptr)
 622{
 623 return GRefPtr<GstWebRTCRTPSender>(ptr, GRefPtrAdopt);
 624}
 625
 626template <> GstWebRTCRTPSender* refGPtr<GstWebRTCRTPSender>(GstWebRTCRTPSender* ptr)
 627{
 628 if (ptr)
 629 gst_object_ref(GST_OBJECT(ptr));
 630
 631 return ptr;
 632}
 633
 634template <> void derefGPtr<GstWebRTCRTPSender>(GstWebRTCRTPSender* ptr)
 635{
 636 if (ptr)
 637 gst_object_unref(ptr);
 638}
 639
 640template <> GRefPtr<GstWebRTCRTPTransceiver> adoptGRef(GstWebRTCRTPTransceiver* ptr)
 641{
 642 return GRefPtr<GstWebRTCRTPTransceiver>(ptr, GRefPtrAdopt);
 643}
 644
 645template <> GstWebRTCRTPTransceiver* refGPtr<GstWebRTCRTPTransceiver>(GstWebRTCRTPTransceiver* ptr)
 646{
 647 if (ptr)
 648 gst_object_ref(GST_OBJECT(ptr));
 649
 650 return ptr;
 651}
 652
 653template <> void derefGPtr<GstWebRTCRTPTransceiver>(GstWebRTCRTPTransceiver* ptr)
 654{
 655 if (ptr)
 656 gst_object_unref(ptr);
 657}
 658
 659template <> GRefPtr<GstWebRTCDataChannel> adoptGRef(GstWebRTCDataChannel* ptr)
 660{
 661 return GRefPtr<GstWebRTCDataChannel>(ptr, GRefPtrAdopt);
 662}
 663
 664template <> GstWebRTCDataChannel* refGPtr<GstWebRTCDataChannel>(GstWebRTCDataChannel* ptr)
 665{
 666 if (ptr)
 667 g_object_ref(G_OBJECT(ptr));
 668
 669 return ptr;
 670}
 671
 672template <> void derefGPtr<GstWebRTCDataChannel>(GstWebRTCDataChannel* ptr)
 673{
 674 if (ptr)
 675 g_object_unref(ptr);
 676}
 677
 678template <> GRefPtr<GstWebRTCDTLSTransport> adoptGRef(GstWebRTCDTLSTransport* ptr)
 679{
 680 return GRefPtr<GstWebRTCDTLSTransport>(ptr, GRefPtrAdopt);
 681}
 682
 683template <> GstWebRTCDTLSTransport* refGPtr<GstWebRTCDTLSTransport>(GstWebRTCDTLSTransport* ptr)
 684{
 685 if (ptr)
 686 gst_object_ref(GST_OBJECT(ptr));
 687
 688 return ptr;
 689}
 690
 691template <> void derefGPtr<GstWebRTCDTLSTransport>(GstWebRTCDTLSTransport* ptr)
 692{
 693 if (ptr)
 694 gst_object_unref(ptr);
 695}
 696
 697template <> GRefPtr<GstWebRTCICETransport> adoptGRef(GstWebRTCICETransport* ptr)
 698{
 699 return GRefPtr<GstWebRTCICETransport>(ptr, GRefPtrAdopt);
 700}
 701
 702template <> GstWebRTCICETransport* refGPtr<GstWebRTCICETransport>(GstWebRTCICETransport* ptr)
 703{
 704 if (ptr)
 705 gst_object_ref(GST_OBJECT(ptr));
 706
 707 return ptr;
 708}
 709
 710template <> void derefGPtr<GstWebRTCICETransport>(GstWebRTCICETransport* ptr)
 711{
 712 if (ptr)
 713 gst_object_unref(ptr);
 714}
 715
 716template<> GRefPtr<GstPromise> adoptGRef(GstPromise* ptr)
 717{
 718 return GRefPtr<GstPromise>(ptr, GRefPtrAdopt);
 719}
 720
 721template<> GstPromise* refGPtr<GstPromise>(GstPromise* ptr)
 722{
 723 if (ptr)
 724 gst_promise_ref(ptr);
 725
 726 return ptr;
 727}
 728
 729template<> void derefGPtr<GstPromise>(GstPromise* ptr)
 730{
 731 if (ptr)
 732 gst_promise_unref(ptr);
 733}
 734
 735#endif // USE(GSTREAMER_WEBRTC)
 736
594737} // namespace WTF
595738
596739#endif // USE(GSTREAMER)

Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h

@@typedef struct _GstGLContext GstGLContext;
3434typedef struct _GstEGLImage GstEGLImage;
3535#endif
3636
 37#if USE(GSTREAMER_WEBRTC)
 38typedef struct _GstPromise GstPromise;
 39typedef struct _GstWebRTCDTLSTransport GstWebRTCDTLSTransport;
 40typedef struct _GstWebRTCDataChannel GstWebRTCDataChannel;
 41typedef struct _GstWebRTCICETransport GstWebRTCICETransport;
 42typedef struct _GstWebRTCRTPReceiver GstWebRTCRTPReceiver;
 43typedef struct _GstWebRTCRTPSender GstWebRTCRTPSender;
 44typedef struct _GstWebRTCRTPTransceiver GstWebRTCRTPTransceiver;
 45#endif
 46
3747namespace WTF {
3848
3949template<> GRefPtr<GstPlugin> adoptGRef(GstPlugin* ptr);

@@template<> GRefPtr<GstEncodingProfile> adoptGRef(GstEncodingProfile*);
151161template<> GstEncodingProfile* refGPtr<GstEncodingProfile>(GstEncodingProfile*);
152162template<> void derefGPtr<GstEncodingProfile>(GstEncodingProfile*);
153163
 164#if USE(GSTREAMER_WEBRTC)
 165template <> GRefPtr<GstWebRTCRTPReceiver> adoptGRef(GstWebRTCRTPReceiver*);
 166template <> GstWebRTCRTPReceiver* refGPtr<GstWebRTCRTPReceiver>(GstWebRTCRTPReceiver*);
 167template <> void derefGPtr<GstWebRTCRTPReceiver>(GstWebRTCRTPReceiver*);
 168
 169template <> GRefPtr<GstWebRTCRTPSender> adoptGRef(GstWebRTCRTPSender*);
 170template <> GstWebRTCRTPSender* refGPtr<GstWebRTCRTPSender>(GstWebRTCRTPSender*);
 171template <> void derefGPtr<GstWebRTCRTPSender>(GstWebRTCRTPSender*);
 172
 173template <> GRefPtr<GstWebRTCRTPTransceiver> adoptGRef(GstWebRTCRTPTransceiver*);
 174template <> GstWebRTCRTPTransceiver* refGPtr<GstWebRTCRTPTransceiver>(GstWebRTCRTPTransceiver*);
 175template <> void derefGPtr<GstWebRTCRTPTransceiver>(GstWebRTCRTPTransceiver*);
 176
 177template <> GRefPtr<GstWebRTCDataChannel> adoptGRef(GstWebRTCDataChannel*);
 178template <> GstWebRTCDataChannel* refGPtr<GstWebRTCDataChannel>(GstWebRTCDataChannel*);
 179template <> void derefGPtr<GstWebRTCDataChannel>(GstWebRTCDataChannel*);
 180
 181template <> GRefPtr<GstWebRTCDTLSTransport> adoptGRef(GstWebRTCDTLSTransport*);
 182template <> GstWebRTCDTLSTransport* refGPtr<GstWebRTCDTLSTransport>(GstWebRTCDTLSTransport*);
 183template <> void derefGPtr<GstWebRTCDTLSTransport>(GstWebRTCDTLSTransport*);
 184
 185template <> GRefPtr<GstWebRTCICETransport> adoptGRef(GstWebRTCICETransport*);
 186template <> GstWebRTCICETransport* refGPtr<GstWebRTCICETransport>(GstWebRTCICETransport*);
 187template <> void derefGPtr<GstWebRTCICETransport>(GstWebRTCICETransport*);
 188
 189template <> GRefPtr<GstPromise> adoptGRef(GstPromise*);
 190template <> GstPromise* refGPtr<GstPromise>(GstPromise*);
 191template <> void derefGPtr<GstPromise>(GstPromise*);
 192#endif
 193
154194} // namespace WTF
155195
156196#endif // USE(GSTREAMER)

Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp

@@const char* capsMediaType(const GstCaps* caps)
188188 if (gst_structure_has_name(structure, "application/x-cenc") || gst_structure_has_name(structure, "application/x-cbcs") || gst_structure_has_name(structure, "application/x-webm-enc"))
189189 return gst_structure_get_string(structure, "original-media-type");
190190#endif
 191 if (gst_structure_has_name(structure, "application/x-rtp"))
 192 return gst_structure_get_string(structure, "media");
 193
191194 return gst_structure_get_name(structure);
192195}
193196

Source/WebCore/platform/graphics/gstreamer/GUniquePtrGStreamer.h

3030#include <gst/video/video.h>
3131#include <wtf/glib/GUniquePtr.h>
3232
 33#if defined(BUILDING_WebCore) && USE(GSTREAMER_WEBRTC)
 34#define GST_USE_UNSTABLE_API
 35#include <gst/webrtc/webrtc.h>
 36#undef GST_USE_UNSTABLE_API
 37#endif
 38
3339#if USE(WPE_VIDEO_PLANE_DISPLAY_DMABUF)
3440#include <wpe/extensions/video-plane-display-dmabuf.h>
3541#endif

@@WTF_DEFINE_GPTR_DELETER(GstByteReader, gst_byte_reader_free)
4955WTF_DEFINE_GPTR_DELETER(GstVideoConverter, gst_video_converter_free)
5056WTF_DEFINE_GPTR_DELETER(GstAudioConverter, gst_audio_converter_free)
5157
 58#if defined(BUILDING_WebCore) && USE(GSTREAMER_WEBRTC)
 59WTF_DEFINE_GPTR_DELETER(GstWebRTCSessionDescription, gst_webrtc_session_description_free)
 60#endif
 61
5262#if USE(WPE_VIDEO_PLANE_DISPLAY_DMABUF)
5363WTF_DEFINE_GPTR_DELETER(struct wpe_video_plane_display_dmabuf_source, wpe_video_plane_display_dmabuf_source_destroy)
5464#endif

Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp

3838
3939#if PLATFORM(COCOA)
4040#include "MediaStreamTrackAudioSourceProviderCocoa.h"
41 #elif ENABLE(WEB_AUDIO) && ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
 41#elif ENABLE(WEB_AUDIO) && ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
4242#include "AudioSourceProviderGStreamer.h"
4343#else
4444#include "WebAudioSourceProvider.h"

@@RefPtr<WebAudioSourceProvider> MediaStreamTrackPrivate::createAudioSourceProvide
199199
200200#if PLATFORM(COCOA)
201201 return MediaStreamTrackAudioSourceProviderCocoa::create(*this);
202 #elif USE(LIBWEBRTC) && USE(GSTREAMER)
 202#elif USE(GSTREAMER)
203203 return AudioSourceProviderGStreamer::create(*this);
204204#else
205205 return nullptr;

Source/WebCore/platform/mediastream/gstreamer/GStreamerAudioCapturer.cpp

2929#include "LibWebRTCAudioFormat.h"
3030#endif
3131
32 #include <gst/app/gstappsink.h>
33 
3432namespace WebCore {
3533
3634#if USE(LIBWEBRTC)
37 static constexpr size_t AudioCaptureSampleRate = LibWebRTCAudioFormat::sampleRate;
 35static constexpr size_t s_audioCaptureSampleRate = LibWebRTCAudioFormat::sampleRate;
3836#else
39 static constexpr size_t AudioCaptureSampleRate = 48000;
 37static constexpr size_t s_audioCaptureSampleRate = 48000;
4038#endif
4139
4240GStreamerAudioCapturer::GStreamerAudioCapturer(GStreamerCaptureDevice device)
43  : GStreamerCapturer(device, adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, AudioCaptureSampleRate, nullptr)))
 41 : GStreamerCapturer(device, adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, s_audioCaptureSampleRate, nullptr)))
4442{
4543}
4644
4745GStreamerAudioCapturer::GStreamerAudioCapturer()
48  : GStreamerCapturer("appsrc", adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, AudioCaptureSampleRate, nullptr)), CaptureDevice::DeviceType::Microphone)
 46 : GStreamerCapturer("appsrc", adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, s_audioCaptureSampleRate, nullptr)), CaptureDevice::DeviceType::Microphone)
4947{
5048}
5149
5250GstElement* GStreamerAudioCapturer::createConverter()
5351{
54  return makeGStreamerBin("audioconvert ! audioresample", true);
 52 auto* bin = gst_bin_new(nullptr);
 53 auto* audioconvert = gst_element_factory_make("audioconvert", nullptr);
 54 auto* audioresample = gst_element_factory_make("audioresample", nullptr);
 55 gst_bin_add_many(GST_BIN_CAST(bin), audioconvert, audioresample, nullptr);
 56 gst_element_link(audioconvert, audioresample);
 57
 58#if USE(GSTREAMER_WEBRTC)
 59 if (auto* webrtcdsp = makeGStreamerElement("webrtcdsp", nullptr)) {
 60 g_object_set(webrtcdsp, "echo-cancel", false, "voice-detection", true, nullptr);
 61 gst_bin_add(GST_BIN_CAST(bin), webrtcdsp);
 62 gst_element_link(webrtcdsp, audioconvert);
 63 }
 64#endif
 65
 66 if (auto pad = adoptGRef(gst_bin_find_unlinked_pad(GST_BIN_CAST(bin), GST_PAD_SRC)))
 67 gst_element_add_pad(GST_ELEMENT_CAST(bin), gst_ghost_pad_new("src", pad.get()));
 68 if (auto pad = adoptGRef(gst_bin_find_unlinked_pad(GST_BIN_CAST(bin), GST_PAD_SINK)))
 69 gst_element_add_pad(GST_ELEMENT_CAST(bin), gst_ghost_pad_new("sink", pad.get()));
 70
 71 return bin;
5572}
5673
5774bool GStreamerAudioCapturer::setSampleRate(int sampleRate)

Source/WebCore/platform/mediastream/gstreamer/GStreamerCapturer.cpp

@@GstElement* GStreamerCapturer::createSource()
100100 m_src = makeElement(m_sourceFactory);
101101 ASSERT(m_src);
102102 if (GST_IS_APP_SRC(m_src.get()))
103  g_object_set(m_src.get(), "is-live", true, "format", GST_FORMAT_TIME, nullptr);
 103 g_object_set(m_src.get(), "is-live", true, "format", GST_FORMAT_TIME, "do-timestamp", true, nullptr);
104104
105105 auto srcPad = adoptGRef(gst_element_get_static_pad(m_src.get(), "src"));
106106 if (m_deviceType == CaptureDevice::DeviceType::Camera) {

Source/WebCore/platform/mediastream/gstreamer/GStreamerDTMFSenderBackend.cpp

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "GStreamerDTMFSenderBackend.h"
 22
 23#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 24
 25#include "NotImplemented.h"
 26#include <wtf/MainThread.h>
 27
 28namespace WebCore {
 29
 30GStreamerDTMFSenderBackend::GStreamerDTMFSenderBackend()
 31{
 32 notImplemented();
 33}
 34
 35GStreamerDTMFSenderBackend::~GStreamerDTMFSenderBackend()
 36{
 37 notImplemented();
 38}
 39
 40bool GStreamerDTMFSenderBackend::canInsertDTMF()
 41{
 42 notImplemented();
 43 return false;
 44}
 45
 46void GStreamerDTMFSenderBackend::playTone(const String&, size_t, size_t)
 47{
 48 notImplemented();
 49}
 50
 51String GStreamerDTMFSenderBackend::tones() const
 52{
 53 notImplemented();
 54 return { };
 55}
 56
 57size_t GStreamerDTMFSenderBackend::duration() const
 58{
 59 notImplemented();
 60 return 0;
 61}
 62
 63size_t GStreamerDTMFSenderBackend::interToneGap() const
 64{
 65 notImplemented();
 66 return 0;
 67}
 68
 69void GStreamerDTMFSenderBackend::onTonePlayed(Function<void(const String&)>&& onTonePlayed)
 70{
 71 m_onTonePlayed = WTFMove(onTonePlayed);
 72}
 73
 74} // namespace WebCore
 75
 76#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/GStreamerDTMFSenderBackend.h

 1/*
 2 * Copyright (C) 2019-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)
 23
 24#include "RTCDTMFSenderBackend.h"
 25#include <wtf/WeakPtr.h>
 26
 27namespace WebCore {
 28
 29// Use eager initialization for the WeakPtrFactory since we call makeWeakPtr() from another thread.
 30class GStreamerDTMFSenderBackend final : public RTCDTMFSenderBackend, public CanMakeWeakPtr<GStreamerDTMFSenderBackend, WeakPtrFactoryInitialization::Eager> {
 31 WTF_MAKE_FAST_ALLOCATED;
 32public:
 33 explicit GStreamerDTMFSenderBackend();
 34 ~GStreamerDTMFSenderBackend();
 35
 36private:
 37 // RTCDTMFSenderBackend
 38 bool canInsertDTMF() final;
 39 void playTone(const String& tone, size_t duration, size_t interToneGap) final;
 40 void onTonePlayed(Function<void(const String&)>&&) final;
 41 String tones() const final;
 42 size_t duration() const final;
 43 size_t interToneGap() const final;
 44
 45 Function<void(const String&)> m_onTonePlayed;
 46};
 47
 48} // namespace WebCore
 49
 50#endif // ENABLE(WEB_RTC) && USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp

3434#include "VideoFrameMetadataGStreamer.h"
3535#include "VideoTrackPrivateMediaStream.h"
3636
 37#if USE(GSTREAMER_WEBRTC)
 38#include "RealtimeIncomingAudioSourceGStreamer.h"
 39#include "RealtimeIncomingVideoSourceGStreamer.h"
 40#endif
 41
3742#include <gst/app/gstappsrc.h>
 43#include <gst/base/gstflowcombiner.h>
3844#include <wtf/UUID.h>
3945#include <wtf/glib/WTFGType.h>
4046
4147using namespace WebCore;
4248
4349static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES,
44  GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8"));
 50 GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8;video/x-vp9;application/x-rtp, media=(string)video"));
4551
4652static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src%u", GST_PAD_SRC, GST_PAD_SOMETIMES,
47  GST_STATIC_CAPS("audio/x-raw(ANY);"));
 53 GST_STATIC_CAPS("audio/x-raw(ANY);application/x-rtp, media=(string)audio"));
4854
4955GST_DEBUG_CATEGORY_STATIC(webkitMediaStreamSrcDebug);
5056#define GST_CAT_DEFAULT webkitMediaStreamSrcDebug

@@public:
236242
237243 if (drop) {
238244 m_needsDiscont = true;
239  GST_INFO_OBJECT(m_src.get(), "%s queue full already... not pushing", m_track.hasVideo() ? "Video" : "Audio");
 245 GST_TRACE_OBJECT(m_src.get(), "%s queue full already... not pushing", m_track.hasVideo() ? "Video" : "Audio");
240246 return;
241247 }
242248

@@void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPr
688694 const char* sourceType;
689695 unsigned counter;
690696 GstStaticPadTemplate* padTemplate;
 697
691698 if (track->hasAudio()) {
692699 padTemplate = &audioSrcTemplate;
693700 sourceType = "audio";

@@void webkitMediaStreamSrcAddTrack(WebKitMediaStreamSrc* self, MediaStreamTrackPr
699706 counter = self->priv->videoPadCounter.exchangeAdd(1);
700707 }
701708
702  auto padName = makeString(sourceType, "_src", counter);
 709#if USE(GSTREAMER_WEBRTC)
 710 if (track->source().isIncomingAudioSource()) {
 711 auto& source = static_cast<RealtimeIncomingAudioSourceGStreamer&>(track->source());
 712 source.registerClient();
 713 } else if (track->source().isIncomingVideoSource()) {
 714 auto& source = static_cast<RealtimeIncomingVideoSourceGStreamer&>(track->source());
 715 source.registerClient();
 716 }
 717#endif
 718
703719 GST_DEBUG_OBJECT(self, "Setup %s source for track %s, only track: %s", sourceType, track->id().utf8().data(), boolForPrinting(onlyTrack));
704720
 721 auto padName = makeString(sourceType, "_src", counter);
705722 auto source = makeUnique<InternalSource>(GST_ELEMENT_CAST(self), *track, padName);
706723 auto* element = source->get();
707724 gst_bin_add(GST_BIN_CAST(self), element);

Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoEncoder.cpp

@@static void webkit_webrtc_video_encoder_class_init(WebKitWebrtcVideoEncoderClass
297297 g_object_set(self->priv->parser.get(), "config-interval", 1, nullptr);
298298 }, "target-bitrate", setBitrateBitPerSec, "interval-intraframes");
299299 Encoders::registerEncoder(X264, "x264enc", "h264parse", "video/x-h264",
300  "video/x-h264,alignment=au,stream-format=byte-stream,profile=baseline",
 300 "video/x-h264,alignment=au,stream-format=byte-stream,profile=constrained-baseline",
301301 [](WebKitWebrtcVideoEncoder* self) {
302302 gst_util_set_object_arg(G_OBJECT(self->priv->encoder.get()), "tune", "zerolatency");
 303 gst_util_set_object_arg(G_OBJECT(self->priv->encoder.get()), "speed-preset", "ultrafast");
 304 g_object_set(G_OBJECT(self->priv->encoder.get()), "key-int-max", 15, NULL);
303305 g_object_set(self->priv->parser.get(), "config-interval", 1, nullptr);
304306 }, "bitrate", setBitrateKbitPerSec, "key-int-max");
305307 Encoders::registerEncoder(OpenH264, "openh264enc", "h264parse", "video/x-h264",

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingAudioSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21
 22#if USE(GSTREAMER_WEBRTC)
 23#include "RealtimeIncomingAudioSourceGStreamer.h"
 24
 25#include "GStreamerAudioData.h"
 26#include "GStreamerAudioStreamDescription.h"
 27
 28namespace WebCore {
 29
 30RealtimeIncomingAudioSourceGStreamer::RealtimeIncomingAudioSourceGStreamer(String&& audioTrackId)
 31 : RealtimeMediaSource(RealtimeMediaSource::Type::Audio, WTFMove(audioTrackId))
 32 , RealtimeIncomingSourceGStreamer()
 33{
 34 start();
 35}
 36
 37RealtimeIncomingAudioSourceGStreamer::~RealtimeIncomingAudioSourceGStreamer()
 38{
 39 stop();
 40}
 41
 42void RealtimeIncomingAudioSourceGStreamer::startProducingData()
 43{
 44 openValve();
 45}
 46
 47void RealtimeIncomingAudioSourceGStreamer::stopProducingData()
 48{
 49 closeValve();
 50}
 51
 52const RealtimeMediaSourceCapabilities& RealtimeIncomingAudioSourceGStreamer::capabilities()
 53{
 54 return RealtimeMediaSourceCapabilities::emptyCapabilities();
 55}
 56
 57const RealtimeMediaSourceSettings& RealtimeIncomingAudioSourceGStreamer::settings()
 58{
 59 return m_currentSettings;
 60}
 61
 62void RealtimeIncomingAudioSourceGStreamer::dispatchSample(GRefPtr<GstSample>&& gstSample)
 63{
 64 auto* buffer = gst_sample_get_buffer(gstSample.get());
 65 GStreamerAudioStreamDescription description;
 66 GStreamerAudioData frames(WTFMove(gstSample), description.getInfo());
 67
 68 audioSamplesAvailable(MediaTime(GST_TIME_AS_USECONDS(GST_BUFFER_PTS(buffer)), G_USEC_PER_SEC), frames, description, 0);
 69}
 70
 71}
 72
 73#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingAudioSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "RealtimeIncomingSourceGStreamer.h"
 25#include "RealtimeMediaSource.h"
 26
 27namespace WebCore {
 28
 29class RealtimeIncomingAudioSourceGStreamer : public RealtimeMediaSource, public RealtimeIncomingSourceGStreamer {
 30public:
 31 static Ref<RealtimeIncomingAudioSourceGStreamer> create(String&& audioTrackId) { return adoptRef(*new RealtimeIncomingAudioSourceGStreamer(WTFMove(audioTrackId))); }
 32
 33protected:
 34 RealtimeIncomingAudioSourceGStreamer(String&&);
 35 ~RealtimeIncomingAudioSourceGStreamer();
 36
 37private:
 38 // RealtimeMediaSource API
 39 void startProducingData() final;
 40 void stopProducingData() final;
 41 const RealtimeMediaSourceCapabilities& capabilities() final;
 42 const RealtimeMediaSourceSettings& settings() final;
 43 bool isIncomingAudioSource() const final { return true; }
 44
 45 // RealtimeIncomingSourceGStreamer API
 46 void dispatchSample(GRefPtr<GstSample>&&) final;
 47
 48 RealtimeMediaSourceSettings m_currentSettings;
 49};
 50
 51} // namespace WebCore
 52
 53SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::RealtimeIncomingAudioSourceGStreamer)
 54 static bool isType(const WebCore::RealtimeMediaSource& source) { return source.isIncomingAudioSource(); }
 55SPECIALIZE_TYPE_TRAITS_END()
 56
 57#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21
 22#if USE(GSTREAMER_WEBRTC)
 23#include "RealtimeIncomingSourceGStreamer.h"
 24
 25#include "MediaSampleGStreamer.h"
 26#include <gst/app/gstappsink.h>
 27#include <wtf/text/WTFString.h>
 28
 29GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 30#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 31
 32namespace WebCore {
 33
 34RealtimeIncomingSourceGStreamer::RealtimeIncomingSourceGStreamer()
 35{
 36 m_bin = gst_bin_new(nullptr);
 37 m_valve = gst_element_factory_make("valve", nullptr);
 38 m_tee = gst_element_factory_make("tee", nullptr);
 39 g_object_set(m_tee.get(), "allow-not-linked", true, nullptr);
 40
 41 auto* queue = gst_element_factory_make("queue", nullptr);
 42 gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_valve.get(), queue, m_tee.get(), nullptr);
 43
 44 gst_element_link_many(m_valve.get(), queue, m_tee.get(), nullptr);
 45 gst_element_sync_state_with_parent(m_valve.get());
 46 gst_element_sync_state_with_parent(queue);
 47 gst_element_sync_state_with_parent(m_tee.get());
 48
 49 auto sinkPad = adoptGRef(gst_element_get_static_pad(m_valve.get(), "sink"));
 50 gst_element_add_pad(m_bin.get(), gst_ghost_pad_new("sink", sinkPad.get()));
 51}
 52
 53void RealtimeIncomingSourceGStreamer::closeValve() const
 54{
 55 if (m_valve)
 56 g_object_set(m_valve.get(), "drop", true, nullptr);
 57}
 58
 59void RealtimeIncomingSourceGStreamer::openValve() const
 60{
 61 if (m_valve)
 62 g_object_set(m_valve.get(), "drop", false, nullptr);
 63}
 64
 65void RealtimeIncomingSourceGStreamer::registerClient()
 66{
 67 GST_DEBUG("Registering new client");
 68 auto* queue = gst_element_factory_make("queue", nullptr);
 69 auto* sink = gst_element_factory_make("appsink", nullptr);
 70 g_object_set(sink, "enable-last-sample", FALSE, "emit-signals", TRUE, "max-buffers", 1, nullptr);
 71 g_signal_connect_swapped(sink, "new-sample", G_CALLBACK(+[](RealtimeIncomingSourceGStreamer* self, GstElement* sink) -> GstFlowReturn {
 72 auto sample = adoptGRef(gst_app_sink_pull_sample(GST_APP_SINK(sink)));
 73 self->dispatchSample(WTFMove(sample));
 74 return GST_FLOW_OK;
 75 }), this);
 76
 77 g_signal_connect_swapped(sink, "new-preroll", G_CALLBACK(+[](RealtimeIncomingSourceGStreamer* self, GstElement* sink) -> GstFlowReturn {
 78 auto sample = adoptGRef(gst_app_sink_pull_preroll(GST_APP_SINK(sink)));
 79 self->dispatchSample(WTFMove(sample));
 80 return GST_FLOW_OK;
 81 }), this);
 82
 83 gst_bin_add_many(GST_BIN_CAST(m_bin.get()), queue, sink, nullptr);
 84 gst_element_link_many(m_tee.get(), queue, sink, nullptr);
 85 gst_element_sync_state_with_parent(queue);
 86 gst_element_sync_state_with_parent(sink);
 87
 88 auto dotFileName = makeString(GST_OBJECT_NAME(m_bin.get()), ".incoming");
 89 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN_CAST(m_bin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.utf8().data());
 90}
 91
 92} // namespace WebCore
 93
 94#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25
 26namespace WebCore {
 27
 28class RealtimeIncomingSourceGStreamer {
 29public:
 30 GstElement* bin() { return m_bin.get(); }
 31 void registerClient();
 32
 33protected:
 34 RealtimeIncomingSourceGStreamer();
 35
 36 void closeValve() const;
 37 void openValve() const;
 38
 39 GRefPtr<GstElement> m_valve;
 40
 41private:
 42 virtual void dispatchSample(GRefPtr<GstSample>&&) { }
 43
 44 GRefPtr<GstElement> m_bin;
 45 GRefPtr<GstElement> m_tee;
 46};
 47
 48} // namespace WebCore
 49
 50#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingVideoSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21
 22#if USE(GSTREAMER_WEBRTC)
 23#include "RealtimeIncomingVideoSourceGStreamer.h"
 24
 25#include "MediaSampleGStreamer.h"
 26#include "VideoFrameMetadataGStreamer.h"
 27#include <gst/rtp/rtp.h>
 28
 29namespace WebCore {
 30
 31RealtimeIncomingVideoSourceGStreamer::RealtimeIncomingVideoSourceGStreamer(String&& videoTrackId)
 32 : RealtimeMediaSource(RealtimeMediaSource::Type::Video, WTFMove(videoTrackId))
 33 , RealtimeIncomingSourceGStreamer()
 34{
 35 RealtimeMediaSourceSupportedConstraints constraints;
 36 constraints.setSupportsWidth(true);
 37 constraints.setSupportsHeight(true);
 38 m_currentSettings = RealtimeMediaSourceSettings { };
 39 m_currentSettings->setSupportedConstraints(WTFMove(constraints));
 40
 41 auto sinkPad = adoptGRef(gst_element_get_static_pad(m_valve.get(), "sink"));
 42 gst_pad_add_probe(sinkPad.get(), static_cast<GstPadProbeType>(GST_PAD_PROBE_TYPE_BUFFER), [](GstPad*, GstPadProbeInfo* info, gpointer) -> GstPadProbeReturn {
 43 auto videoSampleMetadata = std::make_optional<VideoSampleMetadata>({ });
 44 videoSampleMetadata->receiveTime = MonotonicTime::now().secondsSinceEpoch();
 45
 46 auto* buffer = GST_BUFFER_CAST(GST_PAD_PROBE_INFO_DATA(info));
 47 GstRTPBuffer rtpBuffer GST_RTP_BUFFER_INIT;
 48 if (gst_rtp_buffer_map(buffer, GST_MAP_READ, &rtpBuffer)) {
 49 videoSampleMetadata->rtpTimestamp = gst_rtp_buffer_get_timestamp(&rtpBuffer);
 50 gst_rtp_buffer_unmap(&rtpBuffer);
 51 }
 52 buffer = webkitGstBufferSetVideoSampleMetadata(buffer, WTFMove(videoSampleMetadata));
 53 GST_PAD_PROBE_INFO_DATA(info) = buffer;
 54 return GST_PAD_PROBE_OK;
 55 }, nullptr, nullptr);
 56
 57 start();
 58}
 59
 60void RealtimeIncomingVideoSourceGStreamer::startProducingData()
 61{
 62 openValve();
 63}
 64
 65void RealtimeIncomingVideoSourceGStreamer::stopProducingData()
 66{
 67 closeValve();
 68}
 69
 70const RealtimeMediaSourceCapabilities& RealtimeIncomingVideoSourceGStreamer::capabilities()
 71{
 72 return RealtimeMediaSourceCapabilities::emptyCapabilities();
 73}
 74
 75const RealtimeMediaSourceSettings& RealtimeIncomingVideoSourceGStreamer::settings()
 76{
 77 if (m_currentSettings)
 78 return m_currentSettings.value();
 79
 80 RealtimeMediaSourceSupportedConstraints constraints;
 81 constraints.setSupportsWidth(true);
 82 constraints.setSupportsHeight(true);
 83
 84 RealtimeMediaSourceSettings settings;
 85 auto& size = this->size();
 86 settings.setWidth(size.width());
 87 settings.setHeight(size.height());
 88 settings.setSupportedConstraints(constraints);
 89
 90 m_currentSettings = WTFMove(settings);
 91 return m_currentSettings.value();
 92}
 93
 94void RealtimeIncomingVideoSourceGStreamer::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
 95{
 96 if (settings.containsAny({ RealtimeMediaSourceSettings::Flag::Width, RealtimeMediaSourceSettings::Flag::Height }))
 97 m_currentSettings = std::nullopt;
 98}
 99
 100void RealtimeIncomingVideoSourceGStreamer::dispatchSample(GRefPtr<GstSample>&& gstSample)
 101{
 102 videoSampleAvailable(MediaSampleGStreamer::createWrappedSample(gstSample), { });
 103}
 104
 105} // namespace WebCore
 106
 107#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeIncomingVideoSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "RealtimeIncomingSourceGStreamer.h"
 25#include "RealtimeMediaSource.h"
 26
 27namespace WebCore {
 28
 29class RealtimeIncomingVideoSourceGStreamer : public RealtimeMediaSource, public RealtimeIncomingSourceGStreamer {
 30public:
 31 static Ref<RealtimeIncomingVideoSourceGStreamer> create(String&& videoTrackId) { return adoptRef(*new RealtimeIncomingVideoSourceGStreamer(WTFMove(videoTrackId))); }
 32 ~RealtimeIncomingVideoSourceGStreamer() = default;
 33
 34protected:
 35 RealtimeIncomingVideoSourceGStreamer(String&&);
 36
 37private:
 38 // RealtimeMediaSource API
 39 void startProducingData() final;
 40 void stopProducingData() final;
 41 void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) final;
 42 const RealtimeMediaSourceCapabilities& capabilities() final;
 43 const RealtimeMediaSourceSettings& settings() final;
 44 bool isIncomingVideoSource() const final { return true; }
 45
 46 // RealtimeIncomingSourceGStreamer API
 47 void dispatchSample(GRefPtr<GstSample>&&) final;
 48
 49 std::optional<RealtimeMediaSourceSettings> m_currentSettings;
 50};
 51
 52} // namespace WebCore
 53
 54SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::RealtimeIncomingVideoSourceGStreamer)
 55 static bool isType(const WebCore::RealtimeMediaSource& source) { return source.isIncomingVideoSource(); }
 56SPECIALIZE_TYPE_TRAITS_END()
 57
 58#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "RealtimeOutgoingAudioSourceGStreamer.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerAudioCaptureSource.h"
 26#include <wtf/text/StringToIntegerConversion.h>
 27
 28GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 29#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 30
 31namespace WebCore {
 32
 33RealtimeOutgoingAudioSourceGStreamer::RealtimeOutgoingAudioSourceGStreamer(Ref<MediaStreamTrackPrivate>&& source)
 34 : RealtimeOutgoingMediaSourceGStreamer()
 35{
 36 m_allowedCaps = adoptGRef(gst_caps_new_simple("application/x-rtp", "media", G_TYPE_STRING, "audio",
 37 "encoding-name", G_TYPE_STRING, "OPUS", "clock-rate", G_TYPE_INT, 48000, nullptr));
 38
 39 m_audioconvert = gst_element_factory_make("audioconvert", nullptr);
 40 m_audioresample = gst_element_factory_make("audioresample", nullptr);
 41
 42 m_encoder = makeGStreamerElement("opusenc", nullptr);
 43 if (!m_encoder)
 44 return;
 45
 46 // FIXME: Enable dtx too?
 47 gst_util_set_object_arg(G_OBJECT(m_encoder.get()), "audio-type", "voice");
 48
 49 m_payloader = makeGStreamerElement("rtpopuspay", nullptr);
 50 if (!m_payloader)
 51 return;
 52
 53 g_object_set(m_payloader.get(), "auto-header-extension", FALSE, nullptr);
 54
 55 gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_audioconvert.get(), m_audioresample.get(), m_encoder.get(), m_payloader.get(), nullptr);
 56 setSource(WTFMove(source));
 57}
 58
 59bool RealtimeOutgoingAudioSourceGStreamer::setPayloadType(const GRefPtr<GstCaps>& caps)
 60{
 61 GST_DEBUG_OBJECT(m_bin.get(), "Outgoing audio source payload caps: %" GST_PTR_FORMAT, caps.get());
 62 auto* structure = gst_caps_get_structure(caps.get(), 0);
 63 if (const char* encodingName = gst_structure_get_string(structure, "encoding-name")) {
 64 if (!equal(encodingName, "OPUS")) {
 65 GST_ERROR_OBJECT(m_bin.get(), "Unsupported outgoing audio encoding: %s", encodingName);
 66 return false;
 67 }
 68 } else {
 69 GST_ERROR_OBJECT(m_bin.get(), "encoding-name not found");
 70 return false;
 71 }
 72
 73 if (const char* useInbandFec = gst_structure_get_string(structure, "useinbandfec")) {
 74 if (!strcmp(useInbandFec, "1"))
 75 g_object_set(m_encoder.get(), "inband-fec", true, nullptr);
 76 }
 77
 78 if (const char* minPTime = gst_structure_get_string(structure, "minptime")) {
 79 String time(minPTime);
 80 if (auto value = parseIntegerAllowingTrailingJunk<int64_t>(time))
 81 g_object_set(m_payloader.get(), "min-ptime", *value * GST_MSECOND, nullptr);
 82 }
 83
 84 int payloadType;
 85 if (gst_structure_get_int(structure, "payload", &payloadType))
 86 g_object_set(m_payloader.get(), "pt", payloadType, nullptr);
 87
 88 g_object_set(m_capsFilter.get(), "caps", caps.get(), nullptr);
 89
 90 gst_element_link_many(m_outgoingSource.get(), m_valve.get(), m_audioconvert.get(), m_audioresample.get(), m_preEncoderQueue.get(), m_encoder.get(), m_payloader.get(), m_postEncoderQueue.get(), nullptr);
 91 return true;
 92}
 93
 94} // namespace WebCore
 95
 96#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingAudioSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "RealtimeOutgoingMediaSourceGStreamer.h"
 25
 26namespace WebCore {
 27
 28class RealtimeOutgoingAudioSourceGStreamer final : public RealtimeOutgoingMediaSourceGStreamer {
 29public:
 30 static Ref<RealtimeOutgoingAudioSourceGStreamer> create(Ref<MediaStreamTrackPrivate>&& audioSource) { return adoptRef(*new RealtimeOutgoingAudioSourceGStreamer(WTFMove(audioSource))); }
 31
 32 bool setPayloadType(const GRefPtr<GstCaps>&) final;
 33
 34protected:
 35 explicit RealtimeOutgoingAudioSourceGStreamer(Ref<MediaStreamTrackPrivate>&&);
 36
 37private:
 38 GRefPtr<GstElement> m_audioconvert;
 39 GRefPtr<GstElement> m_audioresample;
 40};
 41
 42} // namespace WebCore
 43
 44#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "RealtimeOutgoingMediaSourceGStreamer.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerCommon.h"
 26#include "GStreamerMediaStreamSource.h"
 27
 28#define GST_USE_UNSTABLE_API
 29#include <gst/webrtc/webrtc.h>
 30#undef GST_USE_UNSTABLE_API
 31
 32GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 33#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 34
 35namespace WebCore {
 36
 37RealtimeOutgoingMediaSourceGStreamer::RealtimeOutgoingMediaSourceGStreamer()
 38{
 39 m_bin = gst_bin_new(nullptr);
 40
 41 m_valve = gst_element_factory_make("valve", nullptr);
 42 m_preEncoderQueue = gst_element_factory_make("queue", nullptr);
 43 m_postEncoderQueue = gst_element_factory_make("queue", nullptr);
 44 m_capsFilter = gst_element_factory_make("capsfilter", nullptr);
 45
 46 gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_valve.get(), m_preEncoderQueue.get(),
 47 m_postEncoderQueue.get(), m_capsFilter.get(), nullptr);
 48
 49 auto srcPad = adoptGRef(gst_element_get_static_pad(m_capsFilter.get(), "src"));
 50 gst_element_add_pad(m_bin.get(), gst_ghost_pad_new("src", srcPad.get()));
 51}
 52
 53RealtimeOutgoingMediaSourceGStreamer::~RealtimeOutgoingMediaSourceGStreamer()
 54{
 55 stop();
 56
 57 gst_element_set_state(m_bin.get(), GST_STATE_NULL);
 58 if (auto pipeline = adoptGRef(gst_element_get_parent(m_bin.get())))
 59 gst_bin_remove(GST_BIN_CAST(pipeline.get()), m_bin.get());
 60}
 61
 62void RealtimeOutgoingMediaSourceGStreamer::setSource(Ref<MediaStreamTrackPrivate>&& newSource)
 63{
 64 if (m_source && !m_initialSettings)
 65 m_initialSettings = m_source.value()->settings();
 66
 67 if (m_source)
 68 m_source.value()->removeObserver(*this);
 69 m_source = WTFMove(newSource);
 70 initializeFromTrack();
 71}
 72
 73void RealtimeOutgoingMediaSourceGStreamer::start()
 74{
 75 m_source.value()->addObserver(*this);
 76 m_isStopped = false;
 77}
 78
 79void RealtimeOutgoingMediaSourceGStreamer::stop()
 80{
 81 if (m_source) {
 82 m_source.value()->removeObserver(*this);
 83 gst_element_send_event(m_outgoingSource.get(), gst_event_new_eos());
 84
 85 gst_element_set_locked_state(m_bin.get(), TRUE);
 86 gst_element_set_state(m_outgoingSource.get(), GST_STATE_NULL);
 87
 88 if (m_webrtcSinkPad) {
 89 auto srcPad = adoptGRef(gst_element_get_static_pad(m_bin.get(), "src"));
 90 gst_pad_unlink(srcPad.get(), m_webrtcSinkPad.get());
 91
 92 auto parent = adoptGRef(gst_pad_get_parent_element(m_webrtcSinkPad.get()));
 93 GST_DEBUG_OBJECT(parent.get(), "Removing pad %" GST_PTR_FORMAT, m_webrtcSinkPad.get());
 94 gst_element_release_request_pad(parent.get(), m_webrtcSinkPad.get());
 95 }
 96
 97 gst_element_set_locked_state(m_bin.get(), FALSE);
 98 m_source.reset();
 99 }
 100 m_isStopped = true;
 101}
 102
 103void RealtimeOutgoingMediaSourceGStreamer::sourceMutedChanged()
 104{
 105 if (!m_source)
 106 return;
 107 ASSERT(m_muted != m_source.value()->muted());
 108 m_muted = m_source.value()->muted();
 109}
 110
 111void RealtimeOutgoingMediaSourceGStreamer::sourceEnabledChanged()
 112{
 113 if (!m_source)
 114 return;
 115
 116 m_enabled = m_source.value()->enabled();
 117 if (m_valve)
 118 g_object_set(m_valve.get(), "drop", !m_enabled, nullptr);
 119}
 120
 121void RealtimeOutgoingMediaSourceGStreamer::initializeFromTrack()
 122{
 123 m_muted = m_source.value()->muted();
 124 m_enabled = m_source.value()->enabled();
 125 m_outgoingSource = webkitMediaStreamSrcNew();
 126 gst_bin_add(GST_BIN_CAST(m_bin.get()), m_outgoingSource.get());
 127 webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC(m_outgoingSource.get()), m_source->ptr(), true);
 128}
 129
 130void RealtimeOutgoingMediaSourceGStreamer::link()
 131{
 132 gst_element_link(m_postEncoderQueue.get(), m_capsFilter.get());
 133
 134 auto srcPad = adoptGRef(gst_element_get_static_pad(m_bin.get(), "src"));
 135 gst_pad_link(srcPad.get(), m_webrtcSinkPad.get());
 136 gst_element_sync_state_with_parent(m_bin.get());
 137}
 138
 139void RealtimeOutgoingMediaSourceGStreamer::setSinkPad(const GRefPtr<GstPad>& pad)
 140{
 141 m_webrtcSinkPad = pad;
 142 GRefPtr<GstWebRTCRTPTransceiver> transceiver;
 143 g_object_get(m_webrtcSinkPad.get(), "transceiver", &transceiver.outPtr(), nullptr);
 144 g_object_get(transceiver.get(), "sender", &m_sender.outPtr(), nullptr);
 145}
 146
 147} // namespace WebCore
 148
 149#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingMediaSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "GRefPtrGStreamer.h"
 25#include "MediaStreamTrackPrivate.h"
 26#include <wtf/ThreadSafeRefCounted.h>
 27
 28namespace WebCore {
 29
 30class RealtimeOutgoingMediaSourceGStreamer : public ThreadSafeRefCounted<RealtimeOutgoingMediaSourceGStreamer>, public MediaStreamTrackPrivate::Observer {
 31public:
 32 ~RealtimeOutgoingMediaSourceGStreamer();
 33
 34 void start();
 35 void stop();
 36 void setSource(Ref<MediaStreamTrackPrivate>&&);
 37 MediaStreamTrackPrivate& source() const { return m_source->get(); }
 38
 39 const GRefPtr<GstCaps>& allowedCaps() const { return m_allowedCaps; }
 40
 41 void link();
 42 const GRefPtr<GstPad>& pad() const { return m_webrtcSinkPad; }
 43 void setSinkPad(const GRefPtr<GstPad>&);
 44
 45 GRefPtr<GstWebRTCRTPSender> sender() const { return m_sender; }
 46 GRefPtr<GstElement> bin() const { return m_bin; }
 47
 48 virtual bool setPayloadType(const GRefPtr<GstCaps>&) { return false; }
 49
 50protected:
 51 explicit RealtimeOutgoingMediaSourceGStreamer();
 52
 53 void initializeFromTrack();
 54
 55 bool m_enabled { true };
 56 bool m_muted { false };
 57 bool m_isStopped { false };
 58 std::optional<Ref<MediaStreamTrackPrivate>> m_source;
 59 std::optional<RealtimeMediaSourceSettings> m_initialSettings;
 60 GRefPtr<GstElement> m_bin;
 61 GRefPtr<GstElement> m_outgoingSource;
 62 GRefPtr<GstElement> m_valve;
 63 GRefPtr<GstElement> m_preEncoderQueue;
 64 GRefPtr<GstElement> m_encoder;
 65 GRefPtr<GstElement> m_payloader;
 66 GRefPtr<GstElement> m_postEncoderQueue;
 67 GRefPtr<GstElement> m_capsFilter;
 68 GRefPtr<GstCaps> m_allowedCaps;
 69 GRefPtr<GstWebRTCRTPSender> m_sender;
 70 GRefPtr<GstPad> m_webrtcSinkPad;
 71
 72private:
 73 void sourceMutedChanged();
 74 void sourceEnabledChanged();
 75
 76 // MediaStreamTrackPrivate::Observer API
 77 void trackMutedChanged(MediaStreamTrackPrivate&) override { sourceMutedChanged(); }
 78 void trackEnabledChanged(MediaStreamTrackPrivate&) override { sourceEnabledChanged(); }
 79 void trackSettingsChanged(MediaStreamTrackPrivate&) override { initializeFromTrack(); }
 80 void trackEnded(MediaStreamTrackPrivate&) override { }
 81};
 82
 83} // namespace WebCore
 84
 85#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.cpp

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#include "config.h"
 21#include "RealtimeOutgoingVideoSourceGStreamer.h"
 22
 23#if USE(GSTREAMER_WEBRTC)
 24
 25#include "GStreamerVideoCaptureSource.h"
 26
 27GST_DEBUG_CATEGORY_EXTERN(webkit_webrtc_endpoint_debug);
 28#define GST_CAT_DEFAULT webkit_webrtc_endpoint_debug
 29
 30namespace WebCore {
 31
 32RealtimeOutgoingVideoSourceGStreamer::RealtimeOutgoingVideoSourceGStreamer(Ref<MediaStreamTrackPrivate>&& source)
 33 : RealtimeOutgoingMediaSourceGStreamer()
 34{
 35 registerWebKitGStreamerElements();
 36
 37 m_videoConvert = gst_element_factory_make("videoconvert", nullptr);
 38 m_encoder = gst_element_factory_make("webrtcvideoencoder", nullptr);
 39 gst_bin_add_many(GST_BIN_CAST(m_bin.get()), m_videoConvert.get(), m_encoder.get(), nullptr);
 40
 41 auto* padTemplate = gst_element_get_pad_template(m_encoder.get(), "src");
 42 auto caps = adoptGRef(gst_pad_template_get_caps(padTemplate));
 43 m_allowedCaps = adoptGRef(gst_caps_new_empty());
 44 gst_caps_foreach(caps.get(), reinterpret_cast<GstCapsForeachFunc>(+[](GstCapsFeatures*, GstStructure* structure, gpointer userData) {
 45 auto* source = reinterpret_cast<RealtimeOutgoingVideoSourceGStreamer*>(userData);
 46 const char* name = gst_structure_get_name(structure);
 47 const char* encodingName = nullptr;
 48 if (equal(name, "video/x-vp8"))
 49 encodingName = "VP8";
 50 else if (equal(name, "video/x-vp9"))
 51 encodingName = "VP9";
 52 else if (equal(name, "video/x-h264"))
 53 encodingName = "H264";
 54 if (encodingName)
 55 gst_caps_append_structure(source->m_allowedCaps.get(), gst_structure_new("application/x-rtp", "media", G_TYPE_STRING, "video", "encoding-name", G_TYPE_STRING, encodingName, "clock-rate", G_TYPE_INT, 90000, nullptr));
 56 }), this);
 57
 58 setSource(WTFMove(source));
 59}
 60
 61bool RealtimeOutgoingVideoSourceGStreamer::setPayloadType(const GRefPtr<GstCaps>& caps)
 62{
 63 GST_DEBUG_OBJECT(m_bin.get(), "Outgoing video source payload caps: %" GST_PTR_FORMAT, caps.get());
 64 auto* structure = gst_caps_get_structure(caps.get(), 0);
 65 GRefPtr<GstCaps> encoderCaps;
 66 if (const char* encodingName = gst_structure_get_string(structure, "encoding-name")) {
 67 if (equal(encodingName, "VP8")) {
 68 encoderCaps = adoptGRef(gst_caps_new_empty_simple("video/x-vp8"));
 69 m_payloader = makeGStreamerElement("rtpvp8pay", nullptr);
 70 } else if (equal(encodingName, "VP9")) {
 71 encoderCaps = adoptGRef(gst_caps_new_empty_simple("video/x-vp9"));
 72 m_payloader = makeGStreamerElement("rtpvp9pay", nullptr);
 73 } else if (equal(encodingName, "H264")) {
 74 encoderCaps = adoptGRef(gst_caps_new_empty_simple("video/x-h264"));
 75 m_payloader = makeGStreamerElement("rtph264pay", nullptr);
 76 // FIXME: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/893
 77 // gst_util_set_object_arg(G_OBJECT(m_payloader.get()), "aggregate-mode", "zero-latency");
 78 // g_object_set(m_payloader.get(), "config-interval", -1, nullptr);
 79 } else {
 80 GST_ERROR_OBJECT(m_bin.get(), "Unsupported outgoing video encoding: %s", encodingName);
 81 return false;
 82 }
 83 } else {
 84 GST_ERROR_OBJECT(m_bin.get(), "encoding-name not found");
 85 return false;
 86 }
 87
 88 if (!m_payloader)
 89 return false;
 90
 91 // FIXME: Re-enable this. Currently triggers caps negotiation error.
 92 g_object_set(m_payloader.get(), "auto-header-extension", FALSE, nullptr);
 93
 94 g_object_set(m_encoder.get(), "format", encoderCaps.get(), nullptr);
 95
 96 int payloadType;
 97 if (gst_structure_get_int(structure, "payload", &payloadType))
 98 g_object_set(m_payloader.get(), "pt", payloadType, nullptr);
 99
 100 auto filteredCaps = adoptGRef(gst_caps_new_full(gst_structure_copy(structure), nullptr));
 101 g_object_set(m_capsFilter.get(), "caps", filteredCaps.get(), nullptr);
 102
 103 gst_bin_add(GST_BIN_CAST(m_bin.get()), m_payloader.get());
 104 gst_element_link_many(m_outgoingSource.get(), m_valve.get(), m_videoConvert.get(), m_preEncoderQueue.get(),
 105 m_encoder.get(), m_payloader.get(), m_postEncoderQueue.get(), nullptr);
 106 return true;
 107}
 108
 109} // namespace WebCore
 110
 111#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/platform/mediastream/gstreamer/RealtimeOutgoingVideoSourceGStreamer.h

 1/*
 2 * Copyright (C) 2017-2022 Igalia S.L. All rights reserved.
 3 * Copyright (C) 2022 Metrological Group B.V.
 4 *
 5 * This library is free software; you can redistribute it and/or
 6 * modify it under the terms of the GNU Lesser General Public
 7 * License as published by the Free Software Foundation; either
 8 * version 2 of the License, or (at your option) any later version.
 9 *
 10 * This library is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13 * Lesser General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU Lesser General Public
 16 * License along with this library; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 18 */
 19
 20#pragma once
 21
 22#if USE(GSTREAMER_WEBRTC)
 23
 24#include "RealtimeOutgoingMediaSourceGStreamer.h"
 25
 26namespace WebCore {
 27
 28class RealtimeOutgoingVideoSourceGStreamer final : public RealtimeOutgoingMediaSourceGStreamer {
 29public:
 30 static Ref<RealtimeOutgoingVideoSourceGStreamer> create(Ref<MediaStreamTrackPrivate>&& source) { return adoptRef(*new RealtimeOutgoingVideoSourceGStreamer(WTFMove(source))); }
 31
 32 void setApplyRotation(bool shouldApplyRotation) { m_shouldApplyRotation = shouldApplyRotation; }
 33
 34 bool setPayloadType(const GRefPtr<GstCaps>&) final;
 35
 36protected:
 37 explicit RealtimeOutgoingVideoSourceGStreamer(Ref<MediaStreamTrackPrivate>&&);
 38
 39 bool m_shouldApplyRotation { false };
 40
 41private:
 42 GRefPtr<GstElement> m_videoConvert;
 43};
 44
 45} // namespace WebCore
 46
 47#endif // USE(GSTREAMER_WEBRTC)

Source/WebCore/testing/Internals.cpp

@@void Internals::resetToConsistentState(Page& page)
599599 rtcProvider.setH265Support(true);
600600 rtcProvider.setVP9Support(true, true);
601601 rtcProvider.clearFactory();
 602#elif USE(GSTREAMER_WEBRTC)
 603 page.settings().setWebRTCEncryptionEnabled(true);
 604 page.settings().setPeerConnectionEnabled(true);
602605#endif
603606
604607 page.setFullscreenAutoHideDuration(0_s);

@@void Internals::applyRotationForOutgoingVideoSources(RTCPeerConnection& connecti
16151618{
16161619 connection.applyRotationForOutgoingVideoSources();
16171620}
 1621
16181622void Internals::setWebRTCH265Support(bool value)
16191623{
16201624#if USE(LIBWEBRTC)

@@void Internals::setWebRTCH265Support(bool value)
16221626 page->libWebRTCProvider().setH265Support(value);
16231627 page->libWebRTCProvider().clearFactory();
16241628 }
 1629#else
 1630 UNUSED_PARAM(value);
16251631#endif
16261632}
16271633

@@void Internals::setWebRTCVP9Support(bool supportVP9Profile0, bool supportVP9Prof
16321638 page->libWebRTCProvider().setVP9Support(supportVP9Profile0, supportVP9Profile2);
16331639 page->libWebRTCProvider().clearFactory();
16341640 }
 1641#else
 1642 UNUSED_PARAM(supportVP9Profile0);
 1643 UNUSED_PARAM(supportVP9Profile2);
16351644#endif
16361645}
16371646

@@void Internals::setWebRTCVP9VTBSupport(bool value)
16421651 page->libWebRTCProvider().setVP9VTBSupport(value);
16431652 page->libWebRTCProvider().clearFactory();
16441653 }
 1654#else
 1655 UNUSED_PARAM(value);
16451656#endif
16461657}
16471658

@@void Internals::setEnableWebRTCEncryption(bool value)
16821693#if USE(LIBWEBRTC)
16831694 if (auto* page = contextDocument()->page())
16841695 page->settings().setWebRTCEncryptionEnabled(value);
 1696#else
 1697 UNUSED_PARAM(value);
16851698#endif
16861699}
16871700

@@void Internals::setUseDTLS10(bool useDTLS10)
16921705 if (!document || !document->page())
16931706 return;
16941707 document->page()->libWebRTCProvider().setUseDTLS10(useDTLS10);
 1708#else
 1709 UNUSED_PARAM(useDTLS10);
16951710#endif
16961711}
16971712

Source/cmake/FindGStreamer.cmake

2828# gstreamer-codecparser:GSTREAMER_CODECPARSERS_INCLUDE_DIRS and GSTREAMER_CODECPARSERS_LIBRARIES
2929# gstreamer-full: GSTREAMER_FULL_INCLUDE_DIRS and GSTREAMER_FULL_LIBRARIES
3030# gstreamer-transcoder: GSTREAMER_TRANSCODER_INCLUDE_DIRS and GSTREAMER_TRANSCODER_LIBRARIES
 31# gstreamer-rtp: GSTREAMER_RTP_INCLUDE_DIRS and GSTREAMER_RTP_LIBRARIES
 32# gstreamer-sdp: GSTREAMER_SDP_INCLUDE_DIRS and GSTREAMER_SDP_LIBRARIES
 33# gstreamer-webrtc: GSTREAMER_WEBRTC_INCLUDE_DIRS and GSTREAMER_WEBRTC_LIBRARIES
3134#
3235# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
3336#

@@FIND_GSTREAMER_COMPONENT(GSTREAMER_TAG gstreamer-tag-1.0 gsttag-1.0)
110113FIND_GSTREAMER_COMPONENT(GSTREAMER_VIDEO gstreamer-video-1.0 gstvideo-1.0)
111114FIND_GSTREAMER_COMPONENT(GSTREAMER_CODECPARSERS gstreamer-codecparsers-1.0 gstcodecparsers-1.0)
112115FIND_GSTREAMER_COMPONENT(GSTREAMER_TRANSCODER gstreamer-transcoder-1.0 gsttranscoder-1.0)
 116FIND_GSTREAMER_COMPONENT(GSTREAMER_RTP gstreamer-rtp-1.0 gstrtp-1.0)
 117FIND_GSTREAMER_COMPONENT(GSTREAMER_SDP gstreamer-sdp-1.0 gstsdp-1.0)
 118FIND_GSTREAMER_COMPONENT(GSTREAMER_WEBRTC gstreamer-webrtc-1.0 gstwebrtc-1.0)
113119
114120# ------------------------------------------------
115121# 3. Process the COMPONENTS passed to FIND_PACKAGE

@@mark_as_advanced(
154160 GSTREAMER_CODECPARSERS_LIBRARIES
155161 GSTREAMER_FULL_INCLUDE_DIRS
156162 GSTREAMER_FULL_LIBRARIES
 163 GSTREAMER_WEBRTC_INCLUDE_DIRS
 164 GSTREAMER_WEBRTC_LIBRARIES
157165)

Source/cmake/GStreamerChecks.cmake

@@if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
3232 list(APPEND GSTREAMER_COMPONENTS transcoder)
3333 endif ()
3434
 35 if (USE_GSTREAMER_WEB_RTC)
 36 list(APPEND GSTREAMER_COMPONENTS webrtc)
 37 endif ()
 38
3539 find_package(GStreamer 1.14.0 REQUIRED COMPONENTS ${GSTREAMER_COMPONENTS})
3640
3741 if (ENABLE_WEB_AUDIO)

@@if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
5862 message(FATAL_ERROR "GStreamerTranscoder >= 1.20 is needed for USE_GSTREAMER_TRANSCODER.")
5963 endif ()
6064
 65 if (USE_GSTREAMER_WEBRTC AND (PC_GSTREAMER_VERSION VERSION_LESS "1.20" OR NOT PC_GSTREAMER_WEBRTC_FOUND))
 66 message(FATAL_ERROR "GStreamerWebRTC >= 1.20 is needed for USE_GSTREAMER_WEBRTC.")
 67 endif ()
6168 endif ()
6269endif ()
6370
6471if (ENABLE_MEDIA_STREAM AND ENABLE_WEB_RTC)
65  SET_AND_EXPOSE_TO_BUILD(USE_LIBWEBRTC TRUE)
 72 if (USE_GSTREAMER_WEBRTC)
 73 SET_AND_EXPOSE_TO_BUILD(USE_LIBWEBRTC FALSE)
 74
 75 find_package(OpenSSL REQUIRED)
 76 else ()
 77 SET_AND_EXPOSE_TO_BUILD(USE_LIBWEBRTC TRUE)
 78 endif ()
6679else ()
6780 SET_AND_EXPOSE_TO_BUILD(USE_LIBWEBRTC FALSE)
6881endif ()

Source/cmake/GStreamerDefinitions.cmake

@@WEBKIT_OPTION_DEFINE(USE_GSTREAMER_NATIVE_VIDEO "Toggle native video support in
1111WEBKIT_OPTION_DEFINE(USE_GSTREAMER_NATIVE_AUDIO "Toggle native audio support in GStreamer media player" PRIVATE OFF)
1212WEBKIT_OPTION_DEFINE(USE_GSTREAMER_TEXT_SINK "Toggle text sink support in GStreamer media player" PRIVATE ON)
1313WEBKIT_OPTION_DEFINE(USE_GSTREAMER_TRANSCODER "Whether to enable support for GStreamer MediaRecorder backend" PRIVATE ON)
 14WEBKIT_OPTION_DEFINE(USE_GSTREAMER_WEBRTC "Whether to enable support for WebRTC" PRIVATE ON)

Source/cmake/GStreamerDependencies.cmake

@@WEBKIT_OPTION_DEPEND(USE_GSTREAMER_GL ENABLE_VIDEO)
22WEBKIT_OPTION_DEPEND(USE_GSTREAMER_MPEGTS ENABLE_VIDEO)
33WEBKIT_OPTION_DEPEND(USE_WPE_VIDEO_PLANE_DISPLAY_DMABUF USE_GSTREAMER_GL)
44WEBKIT_OPTION_DEPEND(USE_GSTREAMER_TRANSCODER ENABLE_MEDIA_RECORDER)
 5WEBKIT_OPTION_DEPEND(USE_GSTREAMER_WEBRTC ENABLE_WEB_RTC)

Tools/ChangeLog

 12022-02-12 Philippe Normand <pnormand@igalia.com>
 2
 3 [GStreamer] Initial import of the GstWebRTC backend
 4 https://bugs.webkit.org/show_bug.cgi?id=236540
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * flatpak/flatpakutils.py:
 9 (WebkitFlatpak.run_in_sandbox): Allow libnice debug log environment variable in runtime sandbox.
 10
1112022-02-25 Kimmo Kinnunen <kkinnunen@apple.com>
212
313 REGRESSION(r289580): [ iOS macOS ] TestWebKitAPI.IPCTestingAPI.CanReceiveSharedMemory is a constant timeout

Tools/flatpak/flatpakutils.py

@@class WebkitFlatpak:
838838 "MESA",
839839 "LIBGL",
840840 "PIPEWIRE",
 841 "NICE",
841842 "RUST",
842843 "SCCACHE",
843844 "SPA",

LayoutTests/ChangeLog

 12022-02-12 Philippe Normand <pnormand@igalia.com>
 2
 3 [GStreamer] Initial import of the GstWebRTC backend
 4 https://bugs.webkit.org/show_bug.cgi?id=236540
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * platform/glib/TestExpectations: Flag most WebRTC as failing. During this first development
 9 cycle I focused mostly on fixing crashes and only fixed a few failures. The remaining ones
 10 will be adressed in follow-up patches.
 11 * platform/glib/fast/mediastream/RTCPeerConnection-localDescription-expected.txt: Added.
 12 * platform/glib/fast/mediastream/RTCPeerConnection-remoteDescription-expected.txt: Added.
 13 * platform/glib/fast/mediastream/RTCPeerConnection-setRemoteDescription-offer-expected.txt: Added.
 14 * platform/glib/fast/mediastream/RTCPeerConnection-stable-expected.txt: Added.
 15
1162022-02-25 Kimmo Kinnunen <kkinnunen@apple.com>
217
318 REGRESSION(r289580): [ iOS macOS ] TestWebKitAPI.IPCTestingAPI.CanReceiveSharedMemory is a constant timeout

LayoutTests/platform/glib/TestExpectations

@@webkit.org/b/231811 media/video-concurrent-playback.html [ Failure ]
870870webkit.org/b/231811 media/video-interruption-with-resume-not-allowing-play.html [ Failure ]
871871webkit.org/b/231811 media/video-multiple-concurrent-playback.html [ Failure ]
872872webkit.org/b/231811 media/webaudio-background-playback.html [ Failure ]
873 webkit.org/b/231811 webrtc/concurrentVideoPlayback2.html [ Failure ]
 873webkit.org/b/231811 webkit.org/b/235885 webrtc/concurrentVideoPlayback2.html [ Failure Timeout ]
874874webkit.org/b/231811 media/media-session/callActionHandler.html [ Timeout ]
875875webkit.org/b/231811 media/media-session/play-after-seek.html [ Timeout ]
876876webkit.org/b/231811 media/remote-control-command-is-user-gesture.html [ Timeout ]

@@webkit.org/b/231811 media/video-system-sleep.html [ Timeout ]
883883webkit.org/b/231811 webaudio/audiocontext-state-interrupted.html [ Timeout ]
884884webkit.org/b/231811 webaudio/suspend-context-while-interrupted.html [ Timeout ]
885885
 886# rvfc related failures
886887imported/w3c/web-platform-tests/video-rvfc [ Pass ]
887888fast/mediastream/getUserMedia-rvfc.html [ Pass Failure ]
888889webrtc/peerConnection-rvfc.html [ Failure ]
889 webrtc/canvas-to-peer-connection.html [ Failure ]
890890imported/w3c/web-platform-tests/video-rvfc/request-video-frame-callback-webrtc.https.html [ Skip ]
891891imported/w3c/web-platform-tests/video-rvfc/request-video-frame-callback-before-xr-session.https.html [ Skip ]
892892imported/w3c/web-platform-tests/video-rvfc/request-video-frame-callback-during-xr-session.https.html [ Skip ]

@@webkit.org/b/234084 media/track/audio-track-configuration.html [ Failure ]
904904# bitrate estimation.
905905webkit.org/b/234084 media/track/video-track-configuration.html [ Failure ]
906906
 907# DataChannel GstWebRTC implementation incomplete
 908webkit.org/b/235885 webrtc/datachannel [ Skip ]
 909webkit.org/b/235885 http/wpt/webrtc/transfer-datachannel-service-worker.https.html [ Skip ]
 910
 911# The GstWebRTC backend doesn't support transforms yet.
 912webkit.org/b/235885 http/wpt/webrtc/audiovideo-script-transform.html [ Skip ]
 913webkit.org/b/235885 http/wpt/webrtc/video-script-transform-keyframe-only.html [ Skip ]
 914webkit.org/b/235885 http/wpt/webrtc/video-script-transform.html [ Skip ]
 915webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-encoded-transform/script-audio-transform.https.html [ Skip ]
 916webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-encoded-transform/script-change-transform.https.html [ Skip ]
 917webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-encoded-transform/script-metadata-transform.https.html [ Skip ]
 918webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-encoded-transform/script-transform.https.html [ Skip ]
 919webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-encoded-transform/script-write-twice-transform.https.html [ Skip ]
 920
 921webkit.org/b/235885 fast/mediastream/RTCPeerConnection-addIceCandidate.html [ Failure ]
 922webkit.org/b/235885 fast/mediastream/RTCPeerConnection-addTrack-reuse-sender.html [ Failure ]
 923webkit.org/b/235885 fast/mediastream/RTCPeerConnection-have-local-offer.html [ Crash ]
 924webkit.org/b/235885 fast/mediastream/RTCPeerConnection-have-local-pranswer.html [ Crash ]
 925webkit.org/b/235885 fast/mediastream/RTCPeerConnection-have-remote-offer.html [ Failure ]
 926webkit.org/b/235885 fast/mediastream/RTCPeerConnection-have-remote-pranswer.html [ Crash ]
 927webkit.org/b/235885 fast/mediastream/RTCPeerConnection-icecandidate-event.html [ Failure ]
 928webkit.org/b/235885 fast/mediastream/RTCPeerConnection-inspect-answer.html [ Failure ]
 929webkit.org/b/235885 fast/mediastream/RTCPeerConnection-inspect-offer.html [ Failure ]
 930webkit.org/b/235885 fast/mediastream/RTCPeerConnection-media-setup-callbacks-single-dialog.html [ Failure ]
 931webkit.org/b/235885 fast/mediastream/RTCPeerConnection-media-setup-single-dialog.html [ Failure ]
 932webkit.org/b/235885 fast/mediastream/RTCPeerConnection-media-setup-two-dialogs.html [ Crash ]
 933webkit.org/b/235885 fast/mediastream/RTCPeerConnection-page-cache.html [ Crash ]
 934webkit.org/b/235885 fast/mediastream/RTCPeerConnection-remotely-assigned-transceiver-mid.html [ Timeout ]
 935webkit.org/b/235885 fast/mediastream/RTCPeerConnection-setLocalDescription-offer.html [ Failure ]
 936webkit.org/b/235885 fast/mediastream/RTCPeerConnection-statsSelector.html [ Failure ]
 937webkit.org/b/235885 fast/mediastream/change-tracks-media-stream-being-played.html [ Timeout ]
 938webkit.org/b/235885 http/wpt/webrtc/third-party-frame-ice-candidate-filtering.html [ Failure ]
 939webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-extensions/RTCRtpParameters-maxFramerate.html [ Failure ]
 940webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp.html [ Failure ]
 941webkit.org/b/235885 imported/w3c/web-platform-tests/webrtc-priority/RTCRtpParameters-encodings.html [ Failure ]
 942webkit.org/b/235885 inspector/page/overrideSetting-ICECandidateFilteringEnabled.html [ Timeout ]
 943webkit.org/b/235885 imported/w3c/web-platform-tests/media-capabilities/decodingInfo.webrtc.html [ Failure ]
 944webkit.org/b/235885 imported/w3c/web-platform-tests/media-capabilities/encodingInfo.webrtc.html [ Failure ]
 945webkit.org/b/235885 webrtc/addTransceiver-then-addTrack.html [ Failure ]
 946webkit.org/b/235885 webrtc/audio-muted-stats.html [ Failure ]
 947webkit.org/b/235885 webrtc/audio-peer-connection-g722.html [ Failure ]
 948webkit.org/b/235885 webrtc/audio-peer-connection-webaudio.html [ Failure ]
 949webkit.org/b/235885 webrtc/audio-replace-track.html [ Failure ]
 950webkit.org/b/235885 webrtc/audio-samplerate-change.html [ Crash ]
 951webkit.org/b/235885 webrtc/audio-video-element-playing.html [ Timeout ]
 952webkit.org/b/235885 webrtc/candidate-stats.html [ Failure ]
 953webkit.org/b/235885 webrtc/canvas-to-peer-connection.html [ Timeout ]
 954webkit.org/b/235885 webrtc/captureCanvas-webrtc.html [ Failure ]
 955webkit.org/b/235885 webrtc/clone-audio-track.html [ Timeout ]
 956webkit.org/b/235885 webrtc/closing-peerconnection.html [ Timeout ]
 957webkit.org/b/235885 webrtc/direction-change.html [ Failure ]
 958webkit.org/b/235885 webrtc/disable-encryption.html [ Failure ]
 959webkit.org/b/235885 webrtc/ephemeral-certificates-and-cnames.html [ Failure ]
 960webkit.org/b/235885 webrtc/filtering-ice-candidate-after-reload.html [ Timeout ]
 961webkit.org/b/235885 webrtc/h264-packetization-mode.html [ Timeout ]
 962webkit.org/b/235885 webrtc/libwebrtc/setLocalDescriptionCrash.html [ Failure ]
 963webkit.org/b/235885 webrtc/multi-video.html [ Failure ]
 964webkit.org/b/235885 webrtc/no-port-zero-in-upd-candidates.html [ Failure ]
 965webkit.org/b/235885 webrtc/peer-connection-audio-mute.html [ Timeout ]
 966webkit.org/b/235885 webrtc/peer-connection-audio-mute2.html [ Timeout ]
 967webkit.org/b/235885 webrtc/peer-connection-audio-unmute.html [ Timeout ]
 968webkit.org/b/235885 webrtc/peer-connection-createMediaStreamDestination.html [ Failure ]
 969webkit.org/b/235885 webrtc/peer-connection-remote-audio-mute.html [ Timeout ]
 970webkit.org/b/235885 webrtc/peer-connection-remote-audio-mute2.html [ Timeout ]
 971webkit.org/b/235885 webrtc/peer-connection-track-end.html [ Failure ]
 972webkit.org/b/235885 webrtc/peerconnection-page-cache-long.html [ Timeout ]
 973webkit.org/b/235885 webrtc/peerconnection-page-cache.html [ Timeout ]
 974webkit.org/b/235885 webrtc/receiver-track-should-stay-live-even-if-receiver-is-inactive.html [ Timeout ]
 975webkit.org/b/235885 webrtc/release-after-getting-track.html [ Failure ]
 976webkit.org/b/235885 webrtc/remoteAudio-never-played.html [ Failure ]
 977webkit.org/b/235885 webrtc/remove-track.html [ Failure ]
 978webkit.org/b/235885 webrtc/utf8-sdp.html [ Failure ]
 979webkit.org/b/235885 webrtc/video-addTransceiver.html [ Failure ]
 980webkit.org/b/235885 webrtc/video-autoplay.html [ Failure ]
 981webkit.org/b/235885 webrtc/video-getParameters.html [ Failure ]
 982webkit.org/b/235885 webrtc/video-mediastreamtrack-stats.html [ Failure ]
 983webkit.org/b/235885 webrtc/video-mute-vp8.html [ Timeout ]
 984webkit.org/b/235885 webrtc/video-mute.html [ Timeout ]
 985webkit.org/b/235885 webrtc/video-receivers.html [ Failure ]
 986webkit.org/b/235885 webrtc/video-replace-track-to-null.html [ Failure ]
 987webkit.org/b/235885 webrtc/video-replace-track.html [ Failure ]
 988webkit.org/b/235885 webrtc/video-stats.html [ Failure ]
 989webkit.org/b/235885 webrtc/video-unmute.html [ Crash ]
 990webkit.org/b/235885 webrtc/video-vp8-videorange.html [ Failure ]
 991webkit.org/b/235885 webrtc/video.html [ Failure ]
 992webkit.org/b/235885 webrtc/vp8-then-h264.html [ Failure ]
 993webkit.org/b/235885 webrtc/vp9-svc.html [ Failure ]
 994webkit.org/b/235885 webrtc/vp9.html [ Failure ]
 995
907996#////////////////////////////////////////////////////////////////////////////////////////
908997# End of GStreamer-related bugs
909998#////////////////////////////////////////////////////////////////////////////////////////

@@webkit.org/b/79203 webkit.org/b/186678 fast/mediastream/MediaStream-video-elemen
14391528
14401529fast/mediastream/MediaDevices-addEventListener.html [ DumpJSConsoleLogInStdErr ]
14411530
1442 webkit.org/b/191006 webrtc/simulcast-h264.html [ Failure ]
 1531webkit.org/b/191006 webkit.org/b/235885 webrtc/simulcast-h264.html [ Failure Timeout ]
14431532
14441533webkit.org/b/193641 webrtc/video-setDirection.html [ Failure Pass ]
14451534
14461535webkit.org/b/194611 http/wpt/webrtc/getUserMedia-processSwapping.html [ Failure ]
14471536
14481537webkit.org/b/201267 [ Release ] webrtc/video-h264.html [ Timeout Failure ]
1449 webkit.org/b/222585 [ Debug ] webrtc/video-h264.html [ Crash ]
1450 
1451 webkit.org/b/210272 webrtc/datachannel/multiple-connections.html [ Timeout Pass ]
 1538webkit.org/b/222585 webkit.org/b/235885 [ Debug ] webrtc/video-h264.html [ Crash Failure ]
14521539
14531540webkit.org/b/215005 webkit.org/b/218787 webrtc/h264-baseline.html [ Crash Timeout ]
14541541# h264-high.html is marked as slow in the root expectation

@@webkit.org/b/215007 [ Debug ] webrtc/h264-high.html [ Slow Failure ]
14571544
14581545webkit.org/b/216538 webrtc/captureCanvas-webrtc-software-h264-baseline.html [ Slow Failure ]
14591546
1460 webkit.org/b/216763 webrtc/captureCanvas-webrtc-software-h264-high.html [ Crash Failure ]
 1547webkit.org/b/216763 webkit.org/b/235885 webrtc/captureCanvas-webrtc-software-h264-high.html [ Crash Failure Timeout ]
14611548
14621549webkit.org/b/218221 webrtc/vp9-profile2.html [ Timeout Failure ]
14631550

@@webkit.org/b/186100 css3/color-filters/color-filter-color-property-list-item.htm
22462333webkit.org/b/186100 fast/hidpi/filters-turbulence.html [ ImageOnlyFailure ]
22472334webkit.org/b/187044 webanimations/opacity-animation-yields-compositing-span.html [ Failure ]
22482335
2249 webkit.org/b/187064 webrtc/datachannel/mdns-ice-candidates.html [ Timeout ]
22502336webkit.org/b/187064 webrtc/video-addTrack.html [ Failure ]
2251 webkit.org/b/187064 webrtc/video-disabled-black.html [ Crash ]
2252 webkit.org/b/187064 webrtc/video-remote-mute.html [ Crash ]
2253 webkit.org/b/187064 webrtc/video-replace-muted-track.html [ Timeout ]
 2337webkit.org/b/187064 webkit.org/b/235885 webrtc/video-replace-muted-track.html [ Timeout Failure ]
 2338webkit.org/b/187064 webkit.org/b/235885 webrtc/video-disabled-black.html [ Crash Timeout ]
 2339webkit.org/b/187064 webkit.org/b/235885 webrtc/video-remote-mute.html [ Crash Failure ]
22542340webkit.org/b/187064 webrtc/video-rotation.html [ Failure ]
2255 webkit.org/b/187064 webrtc/video-rotation-no-cvo.html [ Failure ]
 2341webkit.org/b/187064 webkit.org/b/235885 webrtc/video-rotation-no-cvo.html [ Failure Crash ]
22562342webkit.org/b/187064 webrtc/video-with-data-channel.html [ Failure ]
22572343webkit.org/b/187064 imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html [ Failure Pass ]
22582344

@@media/video-remote-control-playpause.html [ Skip ]
25462632
25472633webkit.org/b/207062 imported/w3c/web-platform-tests/media-source/mediasource-replay.html [ Failure Pass ]
25482634
2549 webkit.org/b/229346 webrtc/multi-audio.html [ Timeout Pass ]
 2635webkit.org/b/229346 webkit.org/b/235885 webrtc/multi-audio.html [ Timeout Pass Failure ]
25502636
25512637webkit.org/b/229715 [ Debug ] fast/mediastream/getDisplayMedia-max-constraints3.html [ Timeout ]
25522638webkit.org/b/229715 [ Debug ] fast/mediastream/screencapture-user-gesture.html [ Timeout ]

LayoutTests/platform/glib/fast/mediastream/RTCPeerConnection-localDescription-expected.txt

 1Tests RTCPeerConnection localDescription.
 2
 3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 4
 5
 6PASS pc.setLocalDescription(sessionDescription).then(requestSucceeded1, requestFailed1); did not throw exception.
 7PASS requestSucceeded was called.
 8PASS pc.setLocalDescription(sessionDescription).then(requestSucceeded2, requestFailed2); did not throw exception.
 9PASS requestFailed was called.
 10PASS pc.localDescription.type is "offer"
 11FAIL pc.localDescription.sdp should be local. Was t=0 0
 12.
 13PASS pc.localDescription.type is "offer"
 14FAIL pc.localDescription.sdp should be local. Was t=0 0
 15.
 16PASS successfullyParsed is true
 17
 18TEST COMPLETE
 19

LayoutTests/platform/glib/fast/mediastream/RTCPeerConnection-remoteDescription-expected.txt

 1Tests RTCPeerConnection remoteDescription.
 2
 3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 4
 5
 6PASS pc.setRemoteDescription(sessionDescription).then(requestSucceeded1, requestFailed1); did not throw exception.
 7PASS requestSucceeded was called.
 8PASS pc.setRemoteDescription(sessionDescription).then(requestSucceeded2, requestFailed2); did not throw exception.
 9PASS requestFailed was called.
 10PASS pc.remoteDescription.type is "offer"
 11FAIL pc.remoteDescription.sdp should be remote. Was t=0 0
 12.
 13PASS pc.remoteDescription.type is "offer"
 14FAIL pc.remoteDescription.sdp should be remote. Was t=0 0
 15.
 16PASS successfullyParsed is true
 17
 18TEST COMPLETE
 19

LayoutTests/platform/glib/fast/mediastream/RTCPeerConnection-setRemoteDescription-offer-expected.txt

 1Test RTCPeerConnection.setRemoteDescription called with an RTCSessionDescription of type 'offer'
 2
 3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 4
 5
 6*** Create (remote) offer with audio (remoteOffer1)
 7*** Done, start testing with remoteOffer1
 8PASS pc.signalingState is 'stable'
 9PASS pc.remoteDescription is null
 10PASS pc.pendingRemoteDescription is null
 11PASS pc.currentRemoteDescription is null
 12
 13PASS remoteOffer1 set as remote description
 14PASS pc.signalingState is 'have-remote-offer'
 15FAIL pc.remoteDescription should be [object Object]. Was [object RTCSessionDescription].
 16FAIL pc.pendingRemoteDescription should be [object Object]. Was [object RTCSessionDescription].
 17PASS pc.currentRemoteDescription is null
 18
 19PASS remoteOffer1 set as remote description (again)
 20PASS pc.signalingState is 'have-remote-offer'
 21
 22*** Try setting local descriptions with bad types for the current state
 23PASS promise pc.setRemoteDescription({type:'answer', sdp:remoteOffer1.sdp}); rejected with OperationError: Unable to apply session remote description
 24PASS promise pc.setRemoteDescription({type:'pranswer', sdp:remoteOffer1.sdp}); rejected with OperationError: Unable to apply session remote description
 25
 26*** Create (remote) offer with video (remoteOffer2)
 27*** Done, start testing with remoteOffer2
 28PASS pc.signalingState is 'have-remote-offer'
 29
 30PASS remoteOffer2 set as remote description
 31PASS pc.signalingState is 'have-remote-offer'
 32FAIL pc.remoteDescription should be [object Object]. Was [object RTCSessionDescription].
 33FAIL pc.pendingRemoteDescription should be [object Object]. Was [object RTCSessionDescription].
 34PASS pc.currentRemoteDescription is null
 35
 36PASS successfullyParsed is true
 37
 38TEST COMPLETE
 39

LayoutTests/platform/glib/fast/mediastream/RTCPeerConnection-stable-expected.txt

 1Tests RTCPeerConnection in stable state.
 2
 3On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 4
 5
 6PASS pc.signalingState is "stable"
 7PASS pc.setLocalDescription(sessionDescription).then(finishIfSucceeded, requestFailed1); did not throw exception.
 8PASS setLocalDescription failed.
 9FAIL errorReason.name should be InvalidSessionDescriptionError. Was OperationError.
 10FAIL pc.localDescription should throw an exception. Was null.
 11FAIL pc.remoteDescription should throw an exception. Was null.
 12PASS pc.signalingState is "stable"
 13PASS pc.setLocalDescription(sessionDescription).then(finishIfSucceeded, requestFailed2); did not throw exception.
 14PASS setLocalDescription failed.
 15FAIL errorReason.name should be InvalidSessionDescriptionError. Was OperationError.
 16FAIL pc.localDescription should throw an exception. Was null.
 17FAIL pc.remoteDescription should throw an exception. Was null.
 18PASS pc.signalingState is "stable"
 19PASS pc.setRemoteDescription(sessionDescription).then(finishIfSucceeded, requestFailed3); did not throw exception.
 20PASS setRemoteDescription failed.
 21FAIL errorReason.name should be InvalidSessionDescriptionError. Was OperationError.
 22FAIL pc.localDescription should throw an exception. Was null.
 23FAIL pc.remoteDescription should throw an exception. Was null.
 24PASS pc.signalingState is "stable"
 25PASS pc.setRemoteDescription(sessionDescription).then(finishIfSucceeded, requestFailed4); did not throw exception.
 26PASS setRemoteDescription failed.
 27FAIL errorReason.name should be InvalidSessionDescriptionError. Was OperationError.
 28FAIL pc.localDescription should throw an exception. Was null.
 29FAIL pc.remoteDescription should throw an exception. Was null.
 30PASS pc.signalingState is "stable"
 31PASS pc.setLocalDescription(sessionDescription).then(requestSucceeded1, finishIfFailed); did not throw exception.
 32PASS setLocalDescription succeeded.
 33PASS pc.localDescription.type is "offer"
 34FAIL pc.localDescription.sdp should be local. Was t=0 0
 35.
 36FAIL pc.remoteDescription should throw an exception. Was null.
 37PASS pc.signalingState is "have-local-offer"
 38FAIL pc.localDescription should throw an exception. Was null.
 39FAIL pc.remoteDescription should throw an exception. Was null.
 40PASS pc.signalingState is "stable"
 41PASS pc.setRemoteDescription(sessionDescription).then(requestSucceeded2, finishIfFailed); did not throw exception.
 42PASS setRemoteDescription succeeded.
 43FAIL pc.localDescription should throw an exception. Was null.
 44PASS pc.remoteDescription.type is "offer"
 45FAIL pc.remoteDescription.sdp should be remote. Was t=0 0
 46.
 47PASS pc.signalingState is "have-remote-offer"
 48PASS successfullyParsed is true
 49
 50TEST COMPLETE
 51

ChangeLog

 12022-02-12 Philippe Normand <pnormand@igalia.com>
 2
 3 [GStreamer] Initial import of the GstWebRTC backend
 4 https://bugs.webkit.org/show_bug.cgi?id=236540
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Enable GstWebRTC by default if a recent-enough (>= 1.20) version is available.
 9
 10 * Source/cmake/FindGStreamer.cmake:
 11 * Source/cmake/GStreamerChecks.cmake:
 12 * Source/cmake/GStreamerDefinitions.cmake:
 13 * Source/cmake/GStreamerDependencies.cmake:
 14
1152022-02-25 Zan Dobersek <zdobersek@igalia.com>
216
317 [GTK][WPE] Uncouple libgbm, libdrm dependencies from ANGLE functionality