@@ -2,6 +2,10 @@ import {
22 SessionInfo ,
33 BinaryMessageType ,
44 SessionEndMessage ,
5+ Metadata ,
6+ MetadataUpdateMessage ,
7+ ClientMessages ,
8+ ServerMessages ,
59} from "../messages.js" ;
610import type { Logger } from "../logging.js" ;
711import { ServerClient } from "./server-client.js" ;
@@ -11,22 +15,57 @@ const HEADER_SIZE = 13;
1115export class ServerSession {
1216 sessionActive : Set < string > = new Set ( ) ;
1317
18+ private _lastReportedMetadata : Metadata | null = null ;
19+
1420 constructor (
1521 private readonly sessionInfo : SessionInfo ,
1622 private readonly clients : Map < string , ServerClient > ,
1723 private readonly logger : Logger ,
1824 private readonly onSessionEnd : ( ) => void ,
1925 ) { }
2026
21- end ( ) {
22- // Send session end message
27+ public sendMetadata ( metadata : Metadata ) {
28+ // we are going to send the whole metadata object if we didn't share one yet
29+ // otherwise only include the keys that are different from the last reported metadata
30+ let payload : Partial < Metadata > ;
31+
32+ if ( ! this . _lastReportedMetadata ) {
33+ payload = metadata ;
34+ } else {
35+ payload = { } ;
36+ // Find updated fields
37+ for ( const key in metadata ) {
38+ // @ts -ignore
39+ if ( this . _lastReportedMetadata [ key ] !== metadata [ key ] ) {
40+ // @ts -ignore
41+ payload [ key ] = metadata [ key ] ;
42+ }
43+ }
44+ if ( Object . keys ( payload ) . length === 0 ) {
45+ return ;
46+ }
47+ }
48+ this . sendMessage ( {
49+ type : "metadata/update" ,
50+ payload,
51+ } ) ;
52+ this . _lastReportedMetadata = this . _lastReportedMetadata
53+ ? {
54+ ...this . _lastReportedMetadata ,
55+ ...payload ,
56+ }
57+ : metadata ;
58+ }
59+
60+ public end ( ) {
2361 const sessionEndMessage : SessionEndMessage = {
2462 type : "session/end" ,
2563 payload : {
2664 sessionId : this . sessionInfo . session_id ,
2765 } ,
2866 } ;
29-
67+ // Send session end message to all active clients
68+ // Avoid sendMessage as it can activate clients
3069 for ( const clientId of this . sessionActive ) {
3170 const client = this . clients . get ( clientId ) ;
3271 if ( client && client . isReady ( ) ) {
@@ -37,7 +76,7 @@ export class ServerSession {
3776 this . onSessionEnd ( ) ;
3877 }
3978
40- writeAudioPacketHeader (
79+ public writeAudioPacketHeader (
4180 data : DataView ,
4281 timestamp : number ,
4382 sampleCount : number ,
@@ -47,13 +86,7 @@ export class ServerSession {
4786 data . setUint32 ( 9 , sampleCount , false ) ; // Sample count (big-endian)
4887 }
4988
50- // Broadcast a binary message to all clients
51- sendBinary ( buffer : ArrayBuffer ) {
52- if ( ! this . clients . size ) {
53- this . logger . log ( "No active clients, skipping audio chunk" ) ;
54- return ;
55- }
56-
89+ private * _readyClients ( ) {
5790 for ( const client of this . clients . values ( ) ) {
5891 if ( ! client . isReady ( ) ) {
5992 this . logger . log ( `Client ${ client . clientId } not ready, skipping` ) ;
@@ -67,8 +100,26 @@ export class ServerSession {
67100 type : "session/start" as const ,
68101 payload : this . sessionInfo ,
69102 } ) ;
103+ if ( this . _lastReportedMetadata ) {
104+ client . send ( {
105+ type : "metadata/update" as const ,
106+ payload : this . _lastReportedMetadata ,
107+ } ) ;
108+ }
70109 this . sessionActive . add ( client . clientId ) ;
71110 }
111+ yield client ;
112+ }
113+ }
114+
115+ public sendMessage ( message : ServerMessages ) {
116+ for ( const client of this . _readyClients ( ) ) {
117+ client . send ( message ) ;
118+ }
119+ }
120+
121+ sendBinary ( buffer : ArrayBuffer ) {
122+ for ( const client of this . _readyClients ( ) ) {
72123 client . sendBinary ( buffer ) ;
73124 }
74125 }
0 commit comments