@@ -4463,9 +4463,18 @@ async function _add(input, channel, userName) {
44634463 if ( state === 'stopped' ) {
44644464 logger . info ( 'Player stopped - ensuring queue is active source and flushing' ) ;
44654465 try {
4466- // Parallel stop and flush (flush is safe even if not stopped)
4466+ // Stop any active playback to force Sonos to use queue
4467+ try {
4468+ await sonos . stop ( ) ;
4469+ await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
4470+ } catch ( stopErr ) {
4471+ // Ignore stop errors (might already be stopped)
4472+ logger . debug ( 'Stop command result (may already be stopped): ' + stopErr . message ) ;
4473+ }
4474+
4475+ // Flush queue to start fresh
44674476 await sonos . flush ( ) ;
4468- await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ; // Reduced from 300ms
4477+ await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
44694478 logger . info ( 'Queue flushed and ready' ) ;
44704479 } catch ( flushErr ) {
44714480 logger . warn ( 'Could not flush queue: ' + flushErr . message ) ;
@@ -4493,8 +4502,9 @@ async function _add(input, channel, userName) {
44934502 // Try to queue the first valid candidate (most relevant result)
44944503 let result = null ;
44954504 try {
4505+ logger . info ( `Attempting to queue: ${ firstCandidate . name } by ${ firstCandidate . artist } (URI: ${ firstCandidate . uri } )` ) ;
44964506 await sonos . queue ( firstCandidate . uri ) ;
4497- logger . info ( 'Added track: ' + firstCandidate . name ) ;
4507+ logger . info ( 'Successfully queued track: ' + firstCandidate . name ) ;
44984508 result = firstCandidate ;
44994509 } catch ( e ) {
45004510 const errorDetails = e . message || String ( e ) ;
@@ -4540,7 +4550,72 @@ async function _add(input, channel, userName) {
45404550 // Start playback in background (don't await)
45414551 ( async ( ) => {
45424552 try {
4543- await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ; // Brief delay for queue to settle
4553+ // Ensure queue is the active source before starting playback
4554+ // Stop any active playback to force Sonos to use queue
4555+ try {
4556+ await sonos . stop ( ) ;
4557+ await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
4558+ } catch ( stopErr ) {
4559+ // Ignore stop errors (might already be stopped)
4560+ logger . debug ( 'Stop before play (may already be stopped): ' + stopErr . message ) ;
4561+ }
4562+
4563+ // Verify queue has items before trying to play (prevents UPnP error 701)
4564+ let queueReady = false ;
4565+ let retries = 0 ;
4566+ while ( ! queueReady && retries < 5 ) {
4567+ try {
4568+ const queue = await sonos . getQueue ( ) ;
4569+ if ( queue && queue . items && queue . items . length > 0 ) {
4570+ queueReady = true ;
4571+ logger . debug ( `Queue verified: ${ queue . items . length } items ready` ) ;
4572+ } else {
4573+ logger . debug ( `Queue not ready yet (attempt ${ retries + 1 } /5), waiting...` ) ;
4574+ await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
4575+ retries ++ ;
4576+ }
4577+ } catch ( queueErr ) {
4578+ logger . debug ( `Queue check failed (attempt ${ retries + 1 } /5): ${ queueErr . message } ` ) ;
4579+ await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
4580+ retries ++ ;
4581+ }
4582+ }
4583+
4584+ if ( ! queueReady ) {
4585+ logger . warn ( 'Queue not ready after 5 attempts, attempting playback anyway' ) ;
4586+ }
4587+
4588+ // Try to activate queue by seeking to position 1 (alternative to SetAVTransportURI)
4589+ // This should activate the queue as the transport source
4590+ try {
4591+ logger . debug ( 'Attempting to seek to queue position 1 to activate queue' ) ;
4592+ // Seek to track 1 in the queue to activate it
4593+ await sonos . avTransportService ( ) . Seek ( {
4594+ InstanceID : 0 ,
4595+ Unit : 'TRACK_NR' ,
4596+ Target : '1'
4597+ } ) ;
4598+ logger . debug ( 'Successfully sought to track 1, queue should be active' ) ;
4599+ // Wait for seek to complete
4600+ await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
4601+ } catch ( seekErr ) {
4602+ // If seek fails, try alternative: use next() to jump to first track
4603+ logger . debug ( 'Seek failed, trying next() to activate queue: ' + seekErr . message ) ;
4604+ try {
4605+ // Jump to first track in queue (this should activate the queue)
4606+ await sonos . next ( ) ;
4607+ logger . debug ( 'Used next() to activate queue' ) ;
4608+ await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
4609+ } catch ( nextErr ) {
4610+ logger . debug ( 'next() also failed: ' + nextErr . message ) ;
4611+ // Continue anyway - play() might still work
4612+ }
4613+ }
4614+
4615+ // Wait a moment to ensure queue is ready
4616+ await new Promise ( resolve => setTimeout ( resolve , 500 ) ) ;
4617+
4618+ // Start playback from queue
45444619 await sonos . play ( ) ;
45454620 logger . info ( 'Started playback from queue' ) ;
45464621 } catch ( playErr ) {
0 commit comments