|
1 | 1 | import log, { LoggerNames, type StructuredLogger, getLogger } from '../../logger'; |
| 2 | +import { Future } from '../utils'; |
2 | 3 | import { type DataTrackFrame, DataTrackFrameInternal } from './frame'; |
3 | 4 | import type { DataTrackHandle } from './handle'; |
4 | 5 | import type OutgoingDataTrackManager from './outgoing/OutgoingDataTrackManager'; |
@@ -28,14 +29,35 @@ export default class LocalDataTrack implements ILocalTrack, IDataTrack { |
28 | 29 |
|
29 | 30 | protected log: StructuredLogger = log; |
30 | 31 |
|
| 32 | + /** Resolves once the data track has sent all pending packets the rtc data channel buffer. */ |
| 33 | + protected flushedFuture = new Future<void, never>(); |
| 34 | + |
31 | 35 | /** @internal */ |
32 | 36 | constructor(options: DataTrackOptions, manager: OutgoingDataTrackManager) { |
33 | 37 | this.options = options; |
34 | 38 | this.manager = manager; |
35 | 39 |
|
36 | 40 | this.log = getLogger(LoggerNames.DataTracks); |
| 41 | + |
| 42 | + this.manager.on('packetsFlushed', this.handleManagerPacketsFlushed); |
| 43 | + this.manager.on('reset', this.handleManagerReset); |
37 | 44 | } |
38 | 45 |
|
| 46 | + private handleManagerReset = () => { |
| 47 | + // When the associated manager resets, mark any in flight flushes as complete |
| 48 | + // There's nothing actionable a user can do to get these to complete so no |
| 49 | + // error is being thrown. |
| 50 | + this.handleManagerPacketsFlushed(); |
| 51 | + |
| 52 | + this.manager.off('packetsFlushed', this.handleManagerReset); |
| 53 | + this.manager.off('reset', this.handleManagerReset); |
| 54 | + }; |
| 55 | + |
| 56 | + private handleManagerPacketsFlushed = () => { |
| 57 | + this.flushedFuture.resolve?.(); |
| 58 | + this.flushedFuture = new Future(); |
| 59 | + }; |
| 60 | + |
39 | 61 | /** @internal */ |
40 | 62 | static withExplicitHandle( |
41 | 63 | options: DataTrackOptions, |
@@ -104,6 +126,35 @@ export default class LocalDataTrack implements ILocalTrack, IDataTrack { |
104 | 126 | } |
105 | 127 | } |
106 | 128 |
|
| 129 | + /** |
| 130 | + * When called, waits for all in flight packets to be sent before resolving. |
| 131 | + * |
| 132 | + * Use this to: |
| 133 | + * |
| 134 | + * 1. Send frames exactly in order: |
| 135 | + * ```ts |
| 136 | + * await track.tryPush(/* ... *\/); |
| 137 | + * await track.flush(); |
| 138 | + * await track.tryPush(/* ... *\/); |
| 139 | + * await track.flush(); |
| 140 | + * // ... etc ... |
| 141 | + * ``` |
| 142 | + * |
| 143 | + * 2. Wait for frames to all be delivered before unpublishing a local data track: |
| 144 | + * |
| 145 | + * ```ts |
| 146 | + * await track.tryPush(/* ... *\/); |
| 147 | + * await track.tryPush(/* ... *\/); |
| 148 | + * await track.tryPush(/* ... *\/); |
| 149 | + * // ... etc ... |
| 150 | + * await track.flush(); |
| 151 | + * await track.unpublish(); |
| 152 | + * ``` |
| 153 | + **/ |
| 154 | + async flush(): Promise<void> { |
| 155 | + return this.flushedFuture.promise; |
| 156 | + } |
| 157 | + |
107 | 158 | /** |
108 | 159 | * Unpublish the track from the SFU. Once this is called, any further calls to {@link tryPush} |
109 | 160 | * will fail. |
|
0 commit comments