internal void UpdateReceiver() { if (_receiver != null) { var transceiver = Transceiver; Debug.Assert(transceiver != null); bool wasReceiving = _isReceiverPaired; bool hasRemoteTrack = (transceiver.RemoteTrack != null); // Note the extra "hasRemoteTrack" check, which ensures that when the remote track was // just removed by OnUnpaired(RemoteTrack) from the TrackRemoved event then it is not // immediately re-added by mistake. if (hasRemoteTrack && !wasReceiving) { // Transceiver started receiving, and user actually wants to receive _peer.InvokeOnAppThread(() => _receiver.OnPaired(transceiver.RemoteTrack)); _isReceiverPaired = true; } else if (!hasRemoteTrack && wasReceiving) { // Transceiver stopped receiving (user intent does not matter here) _peer.InvokeOnAppThread(() => _receiver.OnUnpaired(transceiver.RemoteTrack)); _isReceiverPaired = false; } } }
internal void OnUnpaired(MediaTrack track) { Debug.Assert(track != null); // This is called by the TrackRemoved event, which can be fired sometimes even // though we did not have any opportunity yet to pair. So only unpair if we did. // In details, the case is the answering peer being in sendonly mode, yet created // automatically by the implementation during SetRemoteDescription() in recvonly // mode (per the WebRTC spec). So the SetDirection(sendonly) triggers the TrackRemoved // event, but the pairing was never done because SetDirection() is called before // the receiver is updated. // Callbacks must be called on the main thread. _peer.InvokeOnAppThread(() => { if (_receiver != null) { bool wasReceiving = _remoteTrack != null; if (wasReceiving) { Debug.Assert(_remoteTrack == track); _receiver.OnUnpaired(_remoteTrack); } } _remoteTrack = null; }); }