Skip to content

Commit 9caeba7

Browse files
authored
feat: AudioStream | expose frame-activity oracle (LastFrameReceivedAt) (#69)
Add a cheap monotonic timestamp on every AudioStream that ticks inside the FFI callback whenever a media frame is decoded. This is the foundation for the NearbyVoiceChat single-active-sid resolver (stream deduplication): a stream that's alive is decoding frames; a ghost never decodes. - AudioStreamInternal: private `lastFrameReceivedAt` (init -1), Volatile.Read/Write around Environment.TickCount, set right before the buffer write under the existing channel/sampleRate guards. - AudioStream: pass-through `LastFrameReceivedAt`. - IAudioStreams.GetLastFrameReceivedAt(StreamKey): returns -1 when the stream is missing or has never emitted (sentinel chosen over 0 because TickCount is signed and can legitimately be 0/negative). explorer consumer - decentraland/unity-explorer#8817
1 parent dc6e479 commit 9caeba7

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

Runtime/Scripts/Rooms/Streaming/Audio/AudioStream.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class AudioStream : IDisposable
2828

2929
public WavTeeControl WavTeeControl => currentInternal.WavTeeControl;
3030

31+
public Option<int> LastFrameReceivedAt => currentInternal.LastFrameReceivedAt;
32+
3133
public AudioStream(StreamKey streamKey, LiveKit.Rooms.Tracks.ITrack track)
3234
{
3335
this.streamKey = streamKey;
@@ -106,11 +108,21 @@ public class AudioStreamInternal : IDisposable
106108
);
107109

108110
private bool disposed;
111+
private int volatileLastFrameReceivedAt = -1;
109112

110113
public readonly AudioStreamInfo audioStreamInfo;
111114
private readonly uint internalChannels;
112115
private readonly uint internalSampleRate;
113116

117+
public Option<int> LastFrameReceivedAt
118+
{
119+
get
120+
{
121+
int value = Volatile.Read(ref volatileLastFrameReceivedAt);
122+
return value == -1 ? Option<int>.None : Option<int>.Some(value);
123+
}
124+
}
125+
114126
public WavTeeControl WavTeeControl
115127
{
116128
get
@@ -222,6 +234,8 @@ private void OnAudioStreamEvent(AudioStreamEvent e)
222234
return;
223235
}
224236

237+
Volatile.Write(ref volatileLastFrameReceivedAt, Environment.TickCount);
238+
225239
using var guard = buffer.Lock();
226240
guard.Value.Write(frame);
227241
guard.Value.TryWriteWavTee(frame, frame);

Runtime/Scripts/Rooms/Streaming/Audio/IAudioStreams.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
#if !UNITY_WEBGL || UNITY_EDITOR
1+
#if !UNITY_WEBGL || UNITY_EDITOR
2+
3+
using RichTypes;
24

35
namespace LiveKit.Rooms.Streaming.Audio
46
{
57
public interface IAudioStreams : IStreams<AudioStream, AudioStreamInfo>
68
{
7-
9+
}
10+
11+
public static class AudioStreamsExtensions
12+
{
13+
public static Option<int> GetLastFrameReceivedAt(this IAudioStreams streams, StreamKey streamKey)
14+
{
15+
var weak = streams.ActiveStream(streamKey);
16+
return weak.Resource.Has ? weak.Resource.Value.LastFrameReceivedAt : Option<int>.None;
17+
}
818
}
919
}
1020

0 commit comments

Comments
 (0)