feat: animate local speaker ring from MoQ frame transmission
Wire the local user's avatar into the existing speaking-ring animation so the host/speaker sees the same green ring + amplitude glow on their own cell that remote speakers already get. Ground truth is the broadcaster's `publisher.send(opus)` success: the new `onLevel` callback fires only after a frame actually leaves on the wire, computed from the raw PCM peak (shared `peakAmplitude` util used by both the player decode loop and the broadcaster capture loop). This means the animation reflects what the relay sees, not any UI-side mute / role state that could be stale or buggy — if frames are flowing, the ring plays. Plumbing: `NestsSpeaker.startBroadcasting` gains an optional `onLevel` that the moq-lite + IETF broadcasters both honour, the reconnecting wrapper replays it on every session reissue (alongside the existing mute-intent replay), and `NestViewModel.startBroadcast` hands it a lambda that calls the existing `onSpeakerActivity` / `onAudioLevel` plumbing keyed on the local pubkey. The 250 ms speaking-timeout fades the ring naturally when the user mutes or stops broadcasting.
This commit is contained in:
+15
-1
@@ -479,7 +479,21 @@ class NestViewModel(
|
||||
}
|
||||
speaker = s
|
||||
observeSpeakerState(s)
|
||||
val handle = s.startBroadcasting()
|
||||
// The speaker-side `onLevel` callback is the ground
|
||||
// truth for the local-speaking ring: it fires only
|
||||
// after a frame actually reaches the wire (see
|
||||
// NestMoqLiteBroadcaster.start). Reusing the same
|
||||
// `onSpeakerActivity` / `onAudioLevel` plumbing the
|
||||
// remote speakers use means the local avatar gets
|
||||
// the same ring + glow + 250 ms timeout fade as
|
||||
// any other speaker — no separate UI branch needed.
|
||||
val handle =
|
||||
s.startBroadcasting(
|
||||
onLevel = { level ->
|
||||
onSpeakerActivity(speakerPubkeyHex)
|
||||
onAudioLevel(speakerPubkeyHex, level)
|
||||
},
|
||||
)
|
||||
broadcastHandle = handle
|
||||
_uiState.update { it.copy(broadcast = BroadcastUiState.Broadcasting(isMuted = false)) }
|
||||
} catch (ce: CancellationException) {
|
||||
|
||||
Reference in New Issue
Block a user