livekit-client 2.18.8 → 2.18.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/livekit-client.esm.mjs +26 -9
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts +2 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +2 -2
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +2 -1
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +2 -1
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +2 -2
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/room/data-track/LocalDataTrack.ts +15 -7
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +350 -198
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +9 -3
- package/src/room/data-track/outgoing/types.ts +1 -1
|
@@ -603,237 +603,389 @@ describe('DataTrackOutgoingManager', () => {
|
|
|
603
603
|
await shutdownPromise;
|
|
604
604
|
});
|
|
605
605
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
[
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
606
|
+
describe('localDataTrack.flush()', () => {
|
|
607
|
+
it('should resolve flush() after a single tryPush once the packet is acknowledged', async () => {
|
|
608
|
+
const pubHandle = 5;
|
|
609
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
610
|
+
new Map([
|
|
611
|
+
[
|
|
612
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
613
|
+
Descriptor.active(
|
|
614
|
+
{
|
|
615
|
+
sid: 'bogus-sid',
|
|
616
|
+
pubHandle,
|
|
617
|
+
name: 'test',
|
|
618
|
+
usesE2ee: false,
|
|
619
|
+
},
|
|
620
|
+
null,
|
|
621
|
+
),
|
|
622
|
+
],
|
|
623
|
+
]),
|
|
624
|
+
);
|
|
625
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
626
|
+
'packetAvailable',
|
|
627
|
+
'packetsFlushedChange',
|
|
628
|
+
]);
|
|
629
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
630
|
+
{ name: 'track name' },
|
|
631
|
+
manager,
|
|
632
|
+
pubHandle,
|
|
633
|
+
);
|
|
633
634
|
|
|
634
|
-
|
|
635
|
-
|
|
635
|
+
// 1. Push a single-packet payload
|
|
636
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05]) });
|
|
637
|
+
|
|
638
|
+
// 2. The packet should have been emitted to be sent over the data channel
|
|
639
|
+
const packetEvent = await managerEvents.waitFor('packetAvailable');
|
|
640
|
+
expect(packetEvent.handle).toStrictEqual(pubHandle);
|
|
641
|
+
|
|
642
|
+
// 3. A event should be sent indicating that the data track is no longer "flushed"
|
|
643
|
+
const noLongerFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
644
|
+
expect(noLongerFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
645
|
+
expect(noLongerFlushedEvent.isFlushed).toStrictEqual(false);
|
|
646
|
+
|
|
647
|
+
// 3. Calling flush() right after tryPush() should not resolve until the packet
|
|
648
|
+
// is acknowledged via handlePacketSendComplete
|
|
649
|
+
let flushed = false;
|
|
650
|
+
const flushPromise = localDataTrack.flush().then(() => {
|
|
651
|
+
flushed = true;
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
655
|
+
expect(flushed).toStrictEqual(false);
|
|
656
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
636
657
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
expect(packetEvent.handle).toStrictEqual(pubHandle);
|
|
658
|
+
// 4. Acknowledge that the packet has been sent over the data channel
|
|
659
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
640
660
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
661
|
+
// 5. The packetsFlushed event fires once the in-flight packet counter reaches 0
|
|
662
|
+
const flushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
663
|
+
expect(flushedEvent.handle).toStrictEqual(pubHandle);
|
|
664
|
+
expect(flushedEvent.isFlushed).toStrictEqual(true);
|
|
665
|
+
|
|
666
|
+
// 6. The flush() promise resolves
|
|
667
|
+
await flushPromise;
|
|
668
|
+
expect(flushed).toStrictEqual(true);
|
|
646
669
|
});
|
|
647
670
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
671
|
+
it('should resolve flush() only after all packets in a multi-packet payload are acknowledged', async () => {
|
|
672
|
+
const pubHandle = 5;
|
|
673
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
674
|
+
new Map([
|
|
675
|
+
[
|
|
676
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
677
|
+
Descriptor.active(
|
|
678
|
+
{
|
|
679
|
+
sid: 'bogus-sid',
|
|
680
|
+
pubHandle,
|
|
681
|
+
name: 'test',
|
|
682
|
+
usesE2ee: false,
|
|
683
|
+
},
|
|
684
|
+
null,
|
|
685
|
+
),
|
|
686
|
+
],
|
|
687
|
+
]),
|
|
688
|
+
);
|
|
689
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
690
|
+
'packetAvailable',
|
|
691
|
+
'packetsFlushedChange',
|
|
692
|
+
]);
|
|
693
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
694
|
+
{ name: 'track name' },
|
|
695
|
+
manager,
|
|
696
|
+
pubHandle,
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
// 1. Push a payload large enough to span multiple packets (24k > single packet mtu)
|
|
700
|
+
await localDataTrack.tryPush({ payload: new Uint8Array(24_000).fill(0xbe) });
|
|
651
701
|
|
|
652
|
-
|
|
653
|
-
|
|
702
|
+
// 2. A event should be sent indicating that the data track is no longer "flushed"
|
|
703
|
+
const noLongerFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
704
|
+
expect(noLongerFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
705
|
+
expect(noLongerFlushedEvent.isFlushed).toStrictEqual(false);
|
|
654
706
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
707
|
+
// 3. Two packetAvailable events should be emitted for this payload
|
|
708
|
+
await managerEvents.waitFor('packetAvailable');
|
|
709
|
+
await managerEvents.waitFor('packetAvailable');
|
|
658
710
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
711
|
+
// 4. Call flush() before any of the packets have been acknowledged
|
|
712
|
+
let flushed = false;
|
|
713
|
+
const flushPromise = localDataTrack.flush().then(() => {
|
|
714
|
+
flushed = true;
|
|
715
|
+
});
|
|
663
716
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
DataTrackHandle.fromNumber(pubHandle),
|
|
670
|
-
Descriptor.active(
|
|
671
|
-
{
|
|
672
|
-
sid: 'bogus-sid',
|
|
673
|
-
pubHandle,
|
|
674
|
-
name: 'test',
|
|
675
|
-
usesE2ee: false,
|
|
676
|
-
},
|
|
677
|
-
null,
|
|
678
|
-
),
|
|
679
|
-
],
|
|
680
|
-
]),
|
|
681
|
-
);
|
|
682
|
-
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
683
|
-
'packetAvailable',
|
|
684
|
-
'packetsFlushed',
|
|
685
|
-
]);
|
|
686
|
-
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
687
|
-
{ name: 'track name' },
|
|
688
|
-
manager,
|
|
689
|
-
pubHandle,
|
|
690
|
-
);
|
|
717
|
+
// 5. Acknowledge the first packet -- flush should not resolve yet, in-flight counter still > 0
|
|
718
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
719
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
720
|
+
expect(flushed).toStrictEqual(false);
|
|
721
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
691
722
|
|
|
692
|
-
|
|
693
|
-
|
|
723
|
+
// 6. Acknowledge the second packet -- flush resolves once the counter reaches 0
|
|
724
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
694
725
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
726
|
+
const flushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
727
|
+
expect(flushedEvent.handle).toStrictEqual(pubHandle);
|
|
728
|
+
expect(flushedEvent.isFlushed).toStrictEqual(true);
|
|
698
729
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
const flushPromise = localDataTrack.flush().then(() => {
|
|
702
|
-
flushed = true;
|
|
730
|
+
await flushPromise;
|
|
731
|
+
expect(flushed).toStrictEqual(true);
|
|
703
732
|
});
|
|
704
733
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
734
|
+
it('should resolve any pending flush() calls when the manager is reset', async () => {
|
|
735
|
+
const pubHandle = 5;
|
|
736
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
737
|
+
new Map([
|
|
738
|
+
[
|
|
739
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
740
|
+
Descriptor.active(
|
|
741
|
+
{
|
|
742
|
+
sid: 'bogus-sid',
|
|
743
|
+
pubHandle,
|
|
744
|
+
name: 'test',
|
|
745
|
+
usesE2ee: false,
|
|
746
|
+
},
|
|
747
|
+
null,
|
|
748
|
+
),
|
|
749
|
+
],
|
|
750
|
+
]),
|
|
751
|
+
);
|
|
752
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
753
|
+
'packetAvailable',
|
|
754
|
+
'packetsFlushedChange',
|
|
755
|
+
'reset',
|
|
756
|
+
]);
|
|
757
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
758
|
+
{ name: 'track name' },
|
|
759
|
+
manager,
|
|
760
|
+
pubHandle,
|
|
761
|
+
);
|
|
710
762
|
|
|
711
|
-
|
|
712
|
-
|
|
763
|
+
// 1. Push a single-packet payload
|
|
764
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05]) });
|
|
713
765
|
|
|
714
|
-
|
|
715
|
-
|
|
766
|
+
// 2. A event should be sent indicating that the data track is no longer "flushed"
|
|
767
|
+
const noLongerFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
768
|
+
expect(noLongerFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
769
|
+
expect(noLongerFlushedEvent.isFlushed).toStrictEqual(false);
|
|
716
770
|
|
|
717
|
-
|
|
718
|
-
expect(flushed).toStrictEqual(true);
|
|
719
|
-
});
|
|
771
|
+
await managerEvents.waitFor('packetAvailable');
|
|
720
772
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
Descriptor.active(
|
|
728
|
-
{
|
|
729
|
-
sid: 'bogus-sid',
|
|
730
|
-
pubHandle,
|
|
731
|
-
name: 'test',
|
|
732
|
-
usesE2ee: false,
|
|
733
|
-
},
|
|
734
|
-
null,
|
|
735
|
-
),
|
|
736
|
-
],
|
|
737
|
-
]),
|
|
738
|
-
);
|
|
739
|
-
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
740
|
-
'packetAvailable',
|
|
741
|
-
'packetsFlushed',
|
|
742
|
-
'reset',
|
|
743
|
-
]);
|
|
744
|
-
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
745
|
-
{ name: 'track name' },
|
|
746
|
-
manager,
|
|
747
|
-
pubHandle,
|
|
748
|
-
);
|
|
773
|
+
// 3. Call flush() before the in-flight packet is acknowledged -- it should remain
|
|
774
|
+
// pending because the in-flight counter is still > 0
|
|
775
|
+
let flushed = false;
|
|
776
|
+
const flushPromise = localDataTrack.flush().then(() => {
|
|
777
|
+
flushed = true;
|
|
778
|
+
});
|
|
749
779
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
780
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
781
|
+
expect(flushed).toStrictEqual(false);
|
|
782
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
783
|
+
|
|
784
|
+
// 4. Reset the manager. This simulates a RTCEngine disconnect and should resolve
|
|
785
|
+
// the pending flush() even though the packet was never acknowledged.
|
|
786
|
+
await manager.reset();
|
|
787
|
+
await managerEvents.waitFor('reset');
|
|
788
|
+
|
|
789
|
+
// 5. The flush() promise resolves
|
|
790
|
+
await flushPromise;
|
|
791
|
+
expect(flushed).toStrictEqual(true);
|
|
753
792
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const flushPromise = localDataTrack.flush().then(() => {
|
|
758
|
-
flushed = true;
|
|
793
|
+
// 6. No packetsFlushed event was emitted -- reset short-circuits the flush directly
|
|
794
|
+
// on the LocalDataTrack rather than going through the in-flight counter.
|
|
795
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
759
796
|
});
|
|
760
797
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
798
|
+
it('should resolve flush() at the end of a batch of tryPush calls after all packets are later acknowledged as "sent"', async () => {
|
|
799
|
+
const pubHandle = 5;
|
|
800
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
801
|
+
new Map([
|
|
802
|
+
[
|
|
803
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
804
|
+
Descriptor.active(
|
|
805
|
+
{
|
|
806
|
+
sid: 'bogus-sid',
|
|
807
|
+
pubHandle,
|
|
808
|
+
name: 'test',
|
|
809
|
+
usesE2ee: false,
|
|
810
|
+
},
|
|
811
|
+
null,
|
|
812
|
+
),
|
|
813
|
+
],
|
|
814
|
+
]),
|
|
815
|
+
);
|
|
816
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
817
|
+
'packetAvailable',
|
|
818
|
+
'packetsFlushedChange',
|
|
819
|
+
]);
|
|
820
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
821
|
+
{ name: 'track name' },
|
|
822
|
+
manager,
|
|
823
|
+
pubHandle,
|
|
824
|
+
);
|
|
764
825
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
826
|
+
// 1. Run a batch of tryPush calls
|
|
827
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x01]) });
|
|
828
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x02]) });
|
|
829
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x03]) });
|
|
830
|
+
|
|
831
|
+
// 2. A event should have been sent indicating that the data track is no longer "flushed"
|
|
832
|
+
const noLongerFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
833
|
+
expect(noLongerFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
834
|
+
expect(noLongerFlushedEvent.isFlushed).toStrictEqual(false);
|
|
835
|
+
|
|
836
|
+
// 3. Three packetAvailable events should be emitted, one per pushed frame
|
|
837
|
+
await managerEvents.waitFor('packetAvailable');
|
|
838
|
+
await managerEvents.waitFor('packetAvailable');
|
|
839
|
+
await managerEvents.waitFor('packetAvailable');
|
|
840
|
+
|
|
841
|
+
// 4. After the batch is enqueued, call flush() to wait for the SFU to drain them
|
|
842
|
+
let flushed = false;
|
|
843
|
+
const flushPromise = localDataTrack.flush().then(() => {
|
|
844
|
+
flushed = true;
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// 5. Acknowledge two of the three packets -- flush should not resolve yet
|
|
848
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
849
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
850
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
851
|
+
expect(flushed).toStrictEqual(false);
|
|
852
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
853
|
+
|
|
854
|
+
// 6. Acknowledge the last packet -- flush resolves once the counter reaches 0
|
|
855
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
856
|
+
|
|
857
|
+
const flushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
858
|
+
expect(flushedEvent.handle).toStrictEqual(pubHandle);
|
|
859
|
+
|
|
860
|
+
await flushPromise;
|
|
861
|
+
expect(flushed).toStrictEqual(true);
|
|
862
|
+
});
|
|
769
863
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
864
|
+
it('should resolve flush() if there are no tryPush calls in flight', async () => {
|
|
865
|
+
const pubHandle = 5;
|
|
866
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
867
|
+
new Map([
|
|
868
|
+
[
|
|
869
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
870
|
+
Descriptor.active(
|
|
871
|
+
{
|
|
872
|
+
sid: 'bogus-sid',
|
|
873
|
+
pubHandle,
|
|
874
|
+
name: 'test',
|
|
875
|
+
usesE2ee: false,
|
|
876
|
+
},
|
|
877
|
+
null,
|
|
878
|
+
),
|
|
879
|
+
],
|
|
880
|
+
]),
|
|
881
|
+
);
|
|
882
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
883
|
+
{ name: 'track name' },
|
|
884
|
+
manager,
|
|
885
|
+
pubHandle,
|
|
886
|
+
);
|
|
773
887
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
});
|
|
888
|
+
// Call flush, make sure it resolves on its own
|
|
889
|
+
await localDataTrack.flush();
|
|
890
|
+
});
|
|
778
891
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
);
|
|
892
|
+
it('should resolve flush() at the end of a batch of tryPush calls which have all fully sent their data', async () => {
|
|
893
|
+
const pubHandle = 5;
|
|
894
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
895
|
+
new Map([
|
|
896
|
+
[
|
|
897
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
898
|
+
Descriptor.active(
|
|
899
|
+
{
|
|
900
|
+
sid: 'bogus-sid',
|
|
901
|
+
pubHandle,
|
|
902
|
+
name: 'test',
|
|
903
|
+
usesE2ee: false,
|
|
904
|
+
},
|
|
905
|
+
null,
|
|
906
|
+
),
|
|
907
|
+
],
|
|
908
|
+
]),
|
|
909
|
+
);
|
|
910
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
911
|
+
'packetAvailable',
|
|
912
|
+
]);
|
|
913
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
914
|
+
{ name: 'track name' },
|
|
915
|
+
manager,
|
|
916
|
+
pubHandle,
|
|
917
|
+
);
|
|
806
918
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
919
|
+
// 1. Run a batch of tryPush calls
|
|
920
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x01]) });
|
|
921
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x02]) });
|
|
922
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x03]) });
|
|
811
923
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
924
|
+
// 2. Three packetAvailable events should be emitted, one per pushed frame
|
|
925
|
+
await managerEvents.waitFor('packetAvailable');
|
|
926
|
+
await managerEvents.waitFor('packetAvailable');
|
|
927
|
+
await managerEvents.waitFor('packetAvailable');
|
|
928
|
+
|
|
929
|
+
// 3. Acknowledge all three packets
|
|
930
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
931
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
932
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
816
933
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const flushPromise = localDataTrack.flush().then(() => {
|
|
820
|
-
flushed = true;
|
|
934
|
+
// 4. Call flush and ensure that it resolves immediately
|
|
935
|
+
await localDataTrack.flush();
|
|
821
936
|
});
|
|
822
937
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
938
|
+
it('should send packetsFlushedChange events in between tryPush / handlePacketSendComplete calls', async () => {
|
|
939
|
+
const pubHandle = 5;
|
|
940
|
+
const manager = OutgoingDataTrackManager.withDescriptors(
|
|
941
|
+
new Map([
|
|
942
|
+
[
|
|
943
|
+
DataTrackHandle.fromNumber(pubHandle),
|
|
944
|
+
Descriptor.active(
|
|
945
|
+
{
|
|
946
|
+
sid: 'bogus-sid',
|
|
947
|
+
pubHandle,
|
|
948
|
+
name: 'test',
|
|
949
|
+
usesE2ee: false,
|
|
950
|
+
},
|
|
951
|
+
null,
|
|
952
|
+
),
|
|
953
|
+
],
|
|
954
|
+
]),
|
|
955
|
+
);
|
|
956
|
+
const managerEvents = subscribeToEvents<DataTrackOutgoingManagerCallbacks>(manager, [
|
|
957
|
+
'packetsFlushedChange',
|
|
958
|
+
]);
|
|
959
|
+
const localDataTrack = LocalDataTrack.withExplicitHandle(
|
|
960
|
+
{ name: 'track name' },
|
|
961
|
+
manager,
|
|
962
|
+
pubHandle,
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
// 1. Send a single packet frame
|
|
966
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x01]) });
|
|
829
967
|
|
|
830
|
-
|
|
831
|
-
|
|
968
|
+
// 2. Ensure the data track is no longer "flushed"
|
|
969
|
+
const noLongerFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
970
|
+
expect(noLongerFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
971
|
+
expect(noLongerFlushedEvent.isFlushed).toStrictEqual(false);
|
|
832
972
|
|
|
833
|
-
|
|
834
|
-
|
|
973
|
+
// 3. Send more single packet frames
|
|
974
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x02]) });
|
|
975
|
+
await localDataTrack.tryPush({ payload: new Uint8Array([0x03]) });
|
|
835
976
|
|
|
836
|
-
|
|
837
|
-
|
|
977
|
+
// 3. Acknowledge the first two packets
|
|
978
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
979
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
980
|
+
expect(managerEvents.areThereBufferedEvents('packetsFlushedChange')).toBe(false);
|
|
981
|
+
|
|
982
|
+
// 4. Acknowledge the last packet
|
|
983
|
+
manager.handlePacketSendComplete(DataTrackHandle.fromNumber(pubHandle));
|
|
984
|
+
|
|
985
|
+
// 4. The data track should now be "flushed" again
|
|
986
|
+
const isFlushedEvent = await managerEvents.waitFor('packetsFlushedChange');
|
|
987
|
+
expect(isFlushedEvent.handle).toStrictEqual(pubHandle);
|
|
988
|
+
expect(isFlushedEvent.isFlushed).toStrictEqual(true);
|
|
989
|
+
});
|
|
838
990
|
});
|
|
839
991
|
});
|
|
@@ -18,7 +18,7 @@ import DataTrackOutgoingPipeline from './pipeline';
|
|
|
18
18
|
import {
|
|
19
19
|
type DataTrackOptions,
|
|
20
20
|
type EventPacketAvailable,
|
|
21
|
-
type
|
|
21
|
+
type EventPacketsFlushedChange,
|
|
22
22
|
type EventSfuPublishRequest,
|
|
23
23
|
type EventSfuUnpublishRequest,
|
|
24
24
|
type EventTrackPublished,
|
|
@@ -76,7 +76,7 @@ export type DataTrackOutgoingManagerCallbacks = {
|
|
|
76
76
|
/** A {@link LocalDataTrack} has been unpublished */
|
|
77
77
|
trackUnpublished: (event: EventTrackUnpublished) => void;
|
|
78
78
|
/** A {@link LocalDataTrack} has had all of its in flight packets sent via the rtc data channel. */
|
|
79
|
-
|
|
79
|
+
packetsFlushedChange: (event: EventPacketsFlushedChange) => void;
|
|
80
80
|
/** The manager has been reset and all state has been cleared in preparation for the next room
|
|
81
81
|
* connection. */
|
|
82
82
|
reset: () => void;
|
|
@@ -167,6 +167,12 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
167
167
|
for await (const packet of descriptor.pipeline.processFrame(frame)) {
|
|
168
168
|
const prev = this.inFlightPacketCounter.get(handle) ?? 0;
|
|
169
169
|
this.inFlightPacketCounter.set(handle, prev + 1);
|
|
170
|
+
if (prev === 0) {
|
|
171
|
+
// A new packet has been sent, so there are now packets in the rtc data channel buffer for
|
|
172
|
+
// this data track frame
|
|
173
|
+
this.emit('packetsFlushedChange', { handle, isFlushed: false });
|
|
174
|
+
}
|
|
175
|
+
|
|
170
176
|
this.emit('packetAvailable', { handle, bytes: packet.toBinary() });
|
|
171
177
|
}
|
|
172
178
|
} catch (err) {
|
|
@@ -193,7 +199,7 @@ export default class OutgoingDataTrackManager extends (EventEmitter as new () =>
|
|
|
193
199
|
this.inFlightPacketCounter.set(handle, counter);
|
|
194
200
|
|
|
195
201
|
if (counter === 0) {
|
|
196
|
-
this.emit('
|
|
202
|
+
this.emit('packetsFlushedChange', { handle, isFlushed: true });
|
|
197
203
|
}
|
|
198
204
|
}
|
|
199
205
|
|
|
@@ -47,4 +47,4 @@ export type EventTrackPublished = { track: LocalDataTrack };
|
|
|
47
47
|
export type EventTrackUnpublished = { sid: DataTrackSid };
|
|
48
48
|
|
|
49
49
|
/** A track has had all of its in flight packets sent via the rtc data channel. */
|
|
50
|
-
export type
|
|
50
|
+
export type EventPacketsFlushedChange = { handle: DataTrackHandle; isFlushed: boolean };
|