@@ -95,6 +95,7 @@ interface ILayercodeClient {
9595 triggerUserTurnFinished ( ) : Promise < void > ;
9696 getStream ( ) : MediaStream | null ;
9797 setInputDevice ( deviceId : string ) : Promise < void > ;
98+ listDevices ( ) : Promise < Array < MediaDeviceInfo & { default : boolean } > > ;
9899 mute ( ) : void ;
99100 unmute ( ) : void ;
100101 readonly status : string ;
@@ -126,6 +127,8 @@ interface LayercodeClientOptions {
126127 onError ?: ( error : Error ) => void ;
127128 /** Callback when a device is switched */
128129 onDeviceSwitched ?: ( deviceId : string ) => void ;
130+ /** Callback when available devices change (devices added/removed) */
131+ onDevicesChanged ?: ( devices : Array < MediaDeviceInfo & { default : boolean } > ) => void ;
129132 /** Callback for data messages */
130133 onDataMessage ?: ( message : any ) => void ;
131134 /** Callback for other messages (excluding audio msgs) */
@@ -192,6 +195,7 @@ class LayercodeClient implements ILayercodeClient {
192195 onDisconnect : options . onDisconnect ?? NOOP ,
193196 onError : options . onError ?? NOOP ,
194197 onDeviceSwitched : options . onDeviceSwitched ?? NOOP ,
198+ onDevicesChanged : options . onDevicesChanged ?? NOOP ,
195199 onDataMessage : options . onDataMessage ?? NOOP ,
196200 onMessage : options . onMessage ?? NOOP ,
197201 onUserAmplitudeChange : options . onUserAmplitudeChange ?? NOOP ,
@@ -562,7 +566,6 @@ class LayercodeClient implements ILayercodeClient {
562566 // Reset turn tracking for clean start
563567 this . _resetTurnTracking ( ) ;
564568 this . _stopAmplitudeMonitoring ( ) ;
565- this . _setupDeviceChangeListener ( ) ;
566569
567570 // Get conversation key from server
568571 let authorizeSessionRequestBody = {
@@ -588,6 +591,9 @@ class LayercodeClient implements ILayercodeClient {
588591 this . conversationId = authorizeSessionResponseBody . conversation_id ; // Save the conversation_id for use in future reconnects
589592 this . options . conversationId = this . conversationId ;
590593
594+ await this . wavRecorder . requestPermission ( ) ;
595+ this . _setupDeviceChangeListener ( ) ;
596+
591597 // Connect WebSocket
592598 this . ws = new WebSocket (
593599 `${ this . _websocketUrl } ?${ new URLSearchParams ( {
@@ -645,7 +651,6 @@ class LayercodeClient implements ILayercodeClient {
645651 console . error ( 'Error connecting to Layercode agent:' , error ) ;
646652 this . _setStatus ( 'error' ) ;
647653 this . options . onError ( error instanceof Error ? error : new Error ( String ( error ) ) ) ;
648- throw error ;
649654 }
650655 }
651656
@@ -679,6 +684,14 @@ class LayercodeClient implements ILayercodeClient {
679684 return this . wavRecorder . getStream ( ) ;
680685 }
681686
687+ /**
688+ * List all available audio input devices
689+ * @returns {Promise<Array<MediaDeviceInfo & {default: boolean}>> }
690+ */
691+ async listDevices ( ) : Promise < Array < MediaDeviceInfo & { default : boolean } > > {
692+ return this . wavRecorder . listDevices ( ) ;
693+ }
694+
682695 /**
683696 * Switches the input device for the microphone and restarts recording
684697 * @param {string } deviceId - The deviceId of the new microphone
@@ -778,6 +791,9 @@ class LayercodeClient implements ILayercodeClient {
778791 if ( ! this . deviceChangeListener ) {
779792 this . deviceChangeListener = async ( devices : any [ ] ) => {
780793 try {
794+ // Notify user that devices have changed
795+ this . options . onDevicesChanged ( devices ) ;
796+
781797 const defaultDevice = devices . find ( ( device : any ) => device . default ) ;
782798 const usingDefaultDevice = this . useSystemDefaultDevice ;
783799 const previousDefaultDeviceKey = this . lastKnownSystemDefaultDeviceKey ;
0 commit comments