removePublishedTrack method
Implementation
Future<void> removePublishedTrack(String trackSid, {bool notify = true}) async {
logger.finer('Unpublish track sid: $trackSid, notify: $notify');
final pub = trackPublications.remove(trackSid);
if (pub == null) {
logger.warning('Publication not found $trackSid');
return;
}
final track = pub.track;
if (track != null) {
if (room.roomOptions.stopLocalTrackOnUnpublish) {
await track.stop();
}
final sender = track.transceiver?.sender;
var didRemoveSender = false;
if (sender != null) {
try {
await room.engine.publisher?.pc.removeTrack(sender);
} catch (e) {
logger.warning('[$objectId] rtc.removeTrack() did throw $e');
}
didRemoveSender = true;
}
// not gated on the primary sender, stale backup codec state must not
// survive unpublish even when the track never got a live sender
if (track is LocalVideoTrack) {
// remove each backup sender on its own, one failure should not
// prevent removal of the others
for (final simulcastTrack in track.simulcastCodecs.values.toList()) {
final simulcastSender = simulcastTrack.sender;
if (simulcastSender == null) {
continue;
}
try {
await room.engine.publisher?.pc.removeTrack(simulcastSender);
} catch (e) {
logger.warning('[$objectId] rtc.removeTrack() did throw $e');
}
simulcastTrack.sender = null;
didRemoveSender = true;
}
track.clearSimulcastState();
}
// doesn't make sense to negotiate if already disposed
if (didRemoveSender && !isDisposed) {
// manual negotiation since track changed
await room.engine.negotiate();
}
// did unpublish
await track.onUnpublish();
if (track.processor != null) {
await track.processor?.onUnpublish();
await track.stopProcessor();
}
}
if (notify) {
[events, room.events].emit(
LocalTrackUnpublishedEvent(
participant: this,
publication: pub,
),
);
}
await pub.dispose();
}