--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -269,16 +269,18 @@ WebrtcVideoConduit::WebrtcVideoConduit(R
, mDenoising(false)
, mLockScaling(false)
, mSpatialLayers(1)
, mTemporalLayers(1)
, mCodecMode(webrtc::kRealtimeVideo)
, mCall(aCall) // refcounted store of the call object
, mSendStreamConfig(this) // 'this' is stored but not dereferenced in the constructor.
, mRecvStreamConfig(this) // 'this' is stored but not dereferenced in the constructor.
+ , mAllowSsrcChange(true)
+ , mWaitingForInitialSsrc(true)
, mRecvSSRC(0)
, mRecvSSRCSetInProgress(false)
, mSendCodecPlugin(nullptr)
, mRecvCodecPlugin(nullptr)
, mVideoStatsTimer(NS_NewTimer())
{
mRecvStreamConfig.renderer = this;
@@ -873,33 +875,34 @@ WebrtcVideoConduit::ConfigureSendMediaCo
}
return condError;
}
bool
WebrtcVideoConduit::SetRemoteSSRC(unsigned int ssrc)
{
- CSFLogDebug(LOGTAG, "%s: SSRC %u (0x%x)", __FUNCTION__, ssrc, ssrc);
- mRecvStreamConfig.rtp.remote_ssrc = ssrc;
-
unsigned int current_ssrc;
if (!GetRemoteSSRC(¤t_ssrc)) {
return false;
}
if (current_ssrc == ssrc) {
return true;
}
bool wasReceiving = mEngineReceiving;
if (StopReceiving() != kMediaConduitNoError) {
return false;
}
+ CSFLogDebug(LOGTAG, "%s: SSRC %u (0x%x)", __FUNCTION__, ssrc, ssrc);
+ mRecvStreamConfig.rtp.remote_ssrc = ssrc;
+ mWaitingForInitialSsrc = false;
+
// This will destroy mRecvStream and create a new one (argh, why can't we change
// it without a full destroy?)
// We're going to modify mRecvStream, we must lock. Only modified on MainThread.
// All non-MainThread users must lock before reading/using
{
MutexAutoLock lock(mCodecMutex);
// On the next StartReceiving() or ConfigureRecvMediaCodec, force
// building a new RecvStream to switch SSRCs.
@@ -1964,86 +1967,88 @@ WebrtcVideoConduit::DeliverPacket(const
}
return kMediaConduitNoError;
}
MediaConduitErrorCode
WebrtcVideoConduit::ReceivedRTPPacket(const void* data, int len, uint32_t ssrc)
{
- // Handle the unknown ssrc (and ssrc-not-signaled case).
- // We can't just do this here; it has to happen on MainThread :-(
- // We also don't want to drop the packet, nor stall this thread, so we hold
- // the packet (and any following) for inserting once the SSRC is set.
- bool queue = mRecvSSRCSetInProgress;
- if (queue || mRecvSSRC != ssrc) {
- // capture packet for insertion after ssrc is set -- do this before
- // sending the runnable, since it may pull from this. Since it
- // dispatches back to us, it's less critial to do this here, but doesn't
- // hurt.
- UniquePtr<QueuedPacket> packet((QueuedPacket*) malloc(sizeof(QueuedPacket) + len-1));
- packet->mLen = len;
- memcpy(packet->mData, data, len);
- CSFLogDebug(LOGTAG, "queuing packet: seq# %u, Len %d ",
- (uint16_t)ntohs(((uint16_t*) packet->mData)[1]), packet->mLen);
- if (queue) {
+ if (mAllowSsrcChange || mWaitingForInitialSsrc) {
+ // Handle the unknown ssrc (and ssrc-not-signaled case).
+ // We can't just do this here; it has to happen on MainThread :-(
+ // We also don't want to drop the packet, nor stall this thread, so we hold
+ // the packet (and any following) for inserting once the SSRC is set.
+ bool queue = mRecvSSRCSetInProgress;
+ if (queue || mRecvSSRC != ssrc) {
+ // capture packet for insertion after ssrc is set -- do this before
+ // sending the runnable, since it may pull from this. Since it
+ // dispatches back to us, it's less critial to do this here, but doesn't
+ // hurt.
+ UniquePtr<QueuedPacket> packet((QueuedPacket*) malloc(sizeof(QueuedPacket) + len-1));
+ packet->mLen = len;
+ memcpy(packet->mData, data, len);
+ CSFLogDebug(LOGTAG, "queuing packet: seq# %u, Len %d ",
+ (uint16_t)ntohs(((uint16_t*) packet->mData)[1]), packet->mLen);
+ if (queue) {
+ mQueuedPackets.AppendElement(Move(packet));
+ return kMediaConduitNoError;
+ }
+ // a new switch needs to be done
+ // any queued packets are from a previous switch that hasn't completed
+ // yet; drop them and only process the latest SSRC
+ mQueuedPackets.Clear();
mQueuedPackets.AppendElement(Move(packet));
+
+ CSFLogDebug(LOGTAG, "%s: switching from SSRC %u to %u", __FUNCTION__,
+ mRecvSSRC, ssrc);
+ // we "switch" here immediately, but buffer until the queue is released
+ mRecvSSRC = ssrc;
+ mRecvSSRCSetInProgress = true;
+ queue = true;
+
+ // Ensure lamba captures refs
+ RefPtr<WebrtcVideoConduit> self = this;
+ nsCOMPtr<nsIThread> thread;
+ if (NS_WARN_IF(NS_FAILED(NS_GetCurrentThread(getter_AddRefs(thread))))) {
+ return kMediaConduitRTPProcessingFailed;
+ }
+ NS_DispatchToMainThread(media::NewRunnableFrom([self, thread, ssrc]() mutable {
+ // Normally this is done in CreateOrUpdateMediaPipeline() for
+ // initial creation and renegotiation, but here we're rebuilding the
+ // Receive channel at a lower level. This is needed whenever we're
+ // creating a GMPVideoCodec (in particular, H264) so it can communicate
+ // errors to the PC.
+ WebrtcGmpPCHandleSetter setter(self->mPCHandle);
+ self->SetRemoteSSRC(ssrc); // this will likely re-create the VideoReceiveStream
+ // We want to unblock the queued packets on the original thread
+ thread->Dispatch(media::NewRunnableFrom([self, ssrc]() mutable {
+ if (ssrc == self->mRecvSSRC) {
+ // SSRC is set; insert queued packets
+ for (auto& packet : self->mQueuedPackets) {
+ CSFLogDebug(LOGTAG, "Inserting queued packets: seq# %u, Len %d ",
+ (uint16_t)ntohs(((uint16_t*) packet->mData)[1]), packet->mLen);
+
+ if (self->DeliverPacket(packet->mData, packet->mLen) != kMediaConduitNoError) {
+ CSFLogError(LOGTAG, "%s RTP Processing Failed", __FUNCTION__);
+ // Keep delivering and then clear the queue
+ }
+ }
+ self->mQueuedPackets.Clear();
+ // we don't leave inprogress until there are no changes in-flight
+ self->mRecvSSRCSetInProgress = false;
+ }
+ // else this is an intermediate switch; another is in-flight
+
+ return NS_OK;
+ }), NS_DISPATCH_NORMAL);
+ return NS_OK;
+ }));
return kMediaConduitNoError;
}
- // a new switch needs to be done
- // any queued packets are from a previous switch that hasn't completed
- // yet; drop them and only process the latest SSRC
- mQueuedPackets.Clear();
- mQueuedPackets.AppendElement(Move(packet));
-
- CSFLogDebug(LOGTAG, "%s: switching from SSRC %u to %u", __FUNCTION__,
- mRecvSSRC, ssrc);
- // we "switch" here immediately, but buffer until the queue is released
- mRecvSSRC = ssrc;
- mRecvSSRCSetInProgress = true;
- queue = true;
-
- // Ensure lamba captures refs
- RefPtr<WebrtcVideoConduit> self = this;
- nsCOMPtr<nsIThread> thread;
- if (NS_WARN_IF(NS_FAILED(NS_GetCurrentThread(getter_AddRefs(thread))))) {
- return kMediaConduitRTPProcessingFailed;
- }
- NS_DispatchToMainThread(media::NewRunnableFrom([self, thread, ssrc]() mutable {
- // Normally this is done in CreateOrUpdateMediaPipeline() for
- // initial creation and renegotiation, but here we're rebuilding the
- // Receive channel at a lower level. This is needed whenever we're
- // creating a GMPVideoCodec (in particular, H264) so it can communicate
- // errors to the PC.
- WebrtcGmpPCHandleSetter setter(self->mPCHandle);
- self->SetRemoteSSRC(ssrc); // this will likely re-create the VideoReceiveStream
- // We want to unblock the queued packets on the original thread
- thread->Dispatch(media::NewRunnableFrom([self, ssrc]() mutable {
- if (ssrc == self->mRecvSSRC) {
- // SSRC is set; insert queued packets
- for (auto& packet : self->mQueuedPackets) {
- CSFLogDebug(LOGTAG, "Inserting queued packets: seq# %u, Len %d ",
- (uint16_t)ntohs(((uint16_t*) packet->mData)[1]), packet->mLen);
-
- if (self->DeliverPacket(packet->mData, packet->mLen) != kMediaConduitNoError) {
- CSFLogError(LOGTAG, "%s RTP Processing Failed", __FUNCTION__);
- // Keep delivering and then clear the queue
- }
- }
- self->mQueuedPackets.Clear();
- // we don't leave inprogress until there are no changes in-flight
- self->mRecvSSRCSetInProgress = false;
- }
- // else this is an intermediate switch; another is in-flight
-
- return NS_OK;
- }), NS_DISPATCH_NORMAL);
- return NS_OK;
- }));
- return kMediaConduitNoError;
}
CSFLogVerbose(LOGTAG, "%s: seq# %u, Len %d, SSRC %u (0x%x) ", __FUNCTION__,
(uint16_t)ntohs(((uint16_t*) data)[1]), len,
(uint32_t) ntohl(((uint32_t*) data)[2]),
(uint32_t) ntohl(((uint32_t*) data)[2]));
if (DeliverPacket(data, len) != kMediaConduitNoError) {