@@ -53,49 +53,110 @@ public MdnsChromecastLocator(ILogger<MdnsChromecastLocator>? logger = null)
53
53
}
54
54
55
55
/// <summary>
56
- /// Find the available chromecast receivers (async, no events)
56
+ /// Find the available chromecast receivers using progressive discovery (async, no events)
57
+ /// Performs quick scan first, then medium, then full timeout if needed
58
+ /// Returns early if devices are found at any stage
57
59
/// </summary>
58
- /// <param name="timeout">Discovery timeout (default 2 seconds)</param>
60
+ /// <param name="quickTimeout">First scan timeout (default 400ms)</param>
61
+ /// <param name="mediumTimeout">Second scan timeout (default 800ms)</param>
62
+ /// <param name="fullTimeout">Final scan timeout (default 2 seconds)</param>
59
63
/// <returns>Collection of chromecast receivers</returns>
60
- public async Task < IEnumerable < ChromecastReceiver > > FindReceiversAsync ( TimeSpan ? timeout = null )
64
+ public async Task < IEnumerable < ChromecastReceiver > > FindReceiversAsync (
65
+ TimeSpan ? quickTimeout = null ,
66
+ TimeSpan ? mediumTimeout = null ,
67
+ TimeSpan ? fullTimeout = null )
61
68
{
62
- var discoveryTimeout = timeout ?? TimeSpan . FromSeconds ( 2 ) ;
63
69
var devices = new List < ChromecastReceiver > ( ) ;
64
70
65
- _mdnsDiscoveryStarted ( _logger , discoveryTimeout . TotalMilliseconds , null ) ;
71
+ // Progressive scan timeouts: quick -> medium -> full
72
+ var scanTimeouts = new [ ]
73
+ {
74
+ quickTimeout ?? TimeSpan . FromMilliseconds ( 400 ) , // 1st scan: very quick
75
+ mediumTimeout ?? TimeSpan . FromMilliseconds ( 800 ) , // 2nd scan: medium speed
76
+ fullTimeout ?? TimeSpan . FromSeconds ( 2 ) // 3rd scan: full timeout
77
+ } ;
66
78
67
- try
79
+ _progressiveDiscoveryStarted ( _logger , scanTimeouts . Length , scanTimeouts [ scanTimeouts . Length - 1 ] . TotalMilliseconds , null ) ;
80
+
81
+ for ( int scanIndex = 0 ; scanIndex < scanTimeouts . Length ; scanIndex ++ )
68
82
{
69
- var responses = await ZeroconfResolver . ResolveAsync (
70
- "_googlecast._tcp.local." ,
71
- scanTime : discoveryTimeout ) . ConfigureAwait ( false ) ;
72
-
73
- var responsesList = responses . ToList ( ) ;
74
- _mdnsDiscoveryResponsesFound ( _logger , responsesList . Count , null ) ;
83
+ var currentTimeout = scanTimeouts [ scanIndex ] ;
84
+ var scanNumber = scanIndex + 1 ;
75
85
76
- foreach ( var response in responsesList )
86
+ _progressiveCheckStarted ( _logger , scanNumber , currentTimeout . TotalMilliseconds , null ) ;
87
+
88
+ try
77
89
{
78
- var chromecast = CreateChromecastReceiver ( response ) ;
79
- if ( chromecast != null )
90
+ var responses = await ZeroconfResolver . ResolveAsync (
91
+ "_googlecast._tcp.local." ,
92
+ scanTime : currentTimeout ) . ConfigureAwait ( false ) ;
93
+
94
+ var responsesList = responses . ToList ( ) ;
95
+
96
+ var scanDevices = new List < ChromecastReceiver > ( ) ;
97
+ foreach ( var response in responsesList )
98
+ {
99
+ var chromecast = CreateChromecastReceiver ( response ) ;
100
+ if ( chromecast != null )
101
+ {
102
+ // Avoid duplicates from previous scans
103
+ if ( ! devices . Any ( d => d . DeviceUri . ToString ( ) == chromecast . DeviceUri . ToString ( ) && d . Port == chromecast . Port ) )
104
+ {
105
+ devices . Add ( chromecast ) ;
106
+ scanDevices . Add ( chromecast ) ;
107
+ _chromecastDiscovered ( _logger , chromecast . Name , chromecast . DeviceUri . ToString ( ) , chromecast . Port , null ) ;
108
+ }
109
+ }
110
+ }
111
+
112
+ _progressiveCheckCompleted ( _logger , scanNumber , scanDevices . Count , devices . Count , null ) ;
113
+
114
+ // If we found devices in this scan, stop here (early exit optimization)
115
+ if ( scanDevices . Count > 0 )
80
116
{
81
- devices . Add ( chromecast ) ;
82
- _chromecastDiscovered ( _logger , chromecast . Name , chromecast . DeviceUri . ToString ( ) , chromecast . Port , null ) ;
117
+ _progressiveDiscoveryCompletedEarly ( _logger , scanNumber , devices . Count , null ) ;
118
+ break ;
83
119
}
120
+
121
+ _progressiveCheckWaiting ( _logger , scanNumber , null ) ;
122
+ }
123
+ catch ( OperationCanceledException )
124
+ {
125
+ _progressiveCheckCancelled ( _logger , scanNumber , devices . Count , null ) ;
126
+ break ;
127
+ }
128
+ catch ( TimeoutException ex )
129
+ {
130
+ _progressiveDiscoveryError ( _logger , devices . Count , ex ) ;
131
+ // Continue to next scan on timeout
132
+ }
133
+ catch ( Exception ex )
134
+ {
135
+ _progressiveCheckError ( _logger , scanNumber , devices . Count , ex ) ;
136
+ // Continue to next scan on error
84
137
}
85
-
86
- _mdnsDiscoveryCompleted ( _logger , devices . Count , null ) ;
87
- }
88
- catch ( OperationCanceledException ex )
89
- {
90
- _mdnsDiscoveryCancelled ( _logger , devices . Count , ex ) ;
91
- }
92
- catch ( TimeoutException ex )
93
- {
94
- _mdnsDiscoveryTimedOut ( _logger , devices . Count , ex ) ;
95
138
}
96
- catch ( Exception ex )
139
+
140
+ _progressiveDiscoveryCompleted ( _logger , devices . Count , null ) ;
141
+ return devices ;
142
+ }
143
+
144
+ /// <summary>
145
+ /// Process discovery responses and convert to ChromecastReceiver objects
146
+ /// </summary>
147
+ private List < ChromecastReceiver > ProcessResponses ( IEnumerable < IZeroconfHost > responses , ILogger logger )
148
+ {
149
+ var devices = new List < ChromecastReceiver > ( ) ;
150
+ var responsesList = responses . ToList ( ) ;
151
+
152
+ foreach ( var response in responsesList )
97
153
{
98
- _mdnsDiscoveryError ( _logger , devices . Count , ex ) ;
154
+ var chromecast = CreateChromecastReceiver ( response ) ;
155
+ if ( chromecast != null )
156
+ {
157
+ devices . Add ( chromecast ) ;
158
+ _chromecastDiscovered ( logger , chromecast . Name , chromecast . DeviceUri . ToString ( ) , chromecast . Port , null ) ;
159
+ }
99
160
}
100
161
101
162
return devices ;
@@ -104,9 +165,13 @@ public async Task<IEnumerable<ChromecastReceiver>> FindReceiversAsync(TimeSpan?
104
165
/// <summary>
105
166
/// Start continuous discovery that raises events for found devices
106
167
/// </summary>
107
- /// <param name="scanInterval">Time between scans (default 5 seconds)</param>
168
+ /// <param name="scanInterval">Time between scans (default and minimium is 5 seconds)</param>
108
169
public void StartContinuousDiscovery ( TimeSpan ? scanInterval = null )
109
170
{
171
+ if ( scanInterval . HasValue && scanInterval . Value . TotalSeconds < 5 )
172
+ {
173
+ throw new ArgumentException ( "Scan interval must be at least 5 seconds" , nameof ( scanInterval ) ) ;
174
+ }
110
175
StopContinuousDiscovery ( ) ;
111
176
112
177
var interval = scanInterval ?? TimeSpan . FromSeconds ( 5 ) ;
@@ -382,6 +447,67 @@ public void StopContinuousDiscovery()
382
447
LogLevel . Warning ,
383
448
new EventId ( 1022 , nameof ( _unexpectedErrorDuringContinuousDiscoveryScan ) ) ,
384
449
"Unexpected error during continuous discovery scan, retrying in 1 second" ) ;
450
+
451
+ // Progressive discovery logging delegates
452
+ private static readonly Action < ILogger , int , double , Exception ? > _progressiveDiscoveryStarted =
453
+ LoggerMessage . Define < int , double > (
454
+ LogLevel . Information ,
455
+ new EventId ( 1023 , nameof ( _progressiveDiscoveryStarted ) ) ,
456
+ "Starting progressive mDNS discovery with {CheckCount} check intervals (max timeout: {MaxTimeout}ms)" ) ;
457
+
458
+ private static readonly Action < ILogger , int , double , Exception ? > _progressiveCheckStarted =
459
+ LoggerMessage . Define < int , double > (
460
+ LogLevel . Debug ,
461
+ new EventId ( 1024 , nameof ( _progressiveCheckStarted ) ) ,
462
+ "Progressive check {CheckNumber} at {Interval}ms - monitoring discovery progress" ) ;
463
+
464
+ private static readonly Action < ILogger , int , int , int , Exception ? > _progressiveCheckCompleted =
465
+ LoggerMessage . Define < int , int , int > (
466
+ LogLevel . Debug ,
467
+ new EventId ( 1025 , nameof ( _progressiveCheckCompleted ) ) ,
468
+ "Progressive check {CheckNumber} completed. Discovery finished with {NewDevices} devices ({TotalDevices} total)" ) ;
469
+
470
+ private static readonly Action < ILogger , int , int , Exception ? > _progressiveDiscoveryCompletedEarly =
471
+ LoggerMessage . Define < int , int > (
472
+ LogLevel . Information ,
473
+ new EventId ( 1026 , nameof ( _progressiveDiscoveryCompletedEarly ) ) ,
474
+ "Progressive discovery completed early at check {CheckNumber}. Found {DeviceCount} devices" ) ;
475
+
476
+ private static readonly Action < ILogger , int , Exception ? > _progressiveCheckWaiting =
477
+ LoggerMessage . Define < int > (
478
+ LogLevel . Debug ,
479
+ new EventId ( 1027 , nameof ( _progressiveCheckWaiting ) ) ,
480
+ "Progressive check {CheckNumber} - discovery still in progress, continuing to next interval" ) ;
481
+
482
+ private static readonly Action < ILogger , int , int , Exception ? > _progressiveCheckCancelled =
483
+ LoggerMessage . Define < int , int > (
484
+ LogLevel . Warning ,
485
+ new EventId ( 1028 , nameof ( _progressiveCheckCancelled ) ) ,
486
+ "Progressive check {CheckNumber} was cancelled. Returning {DeviceCount} devices found so far" ) ;
487
+
488
+ private static readonly Action < ILogger , int , int , Exception ? > _progressiveCheckError =
489
+ LoggerMessage . Define < int , int > (
490
+ LogLevel . Warning ,
491
+ new EventId ( 1029 , nameof ( _progressiveCheckError ) ) ,
492
+ "Error during progressive check {CheckNumber}. Continuing to next interval. Found {DeviceCount} devices so far" ) ;
493
+
494
+ private static readonly Action < ILogger , int , Exception ? > _progressiveDiscoveryCancelled =
495
+ LoggerMessage . Define < int > (
496
+ LogLevel . Warning ,
497
+ new EventId ( 1030 , nameof ( _progressiveDiscoveryCancelled ) ) ,
498
+ "Progressive discovery was cancelled. Returning {DeviceCount} devices found" ) ;
499
+
500
+ private static readonly Action < ILogger , int , Exception ? > _progressiveDiscoveryError =
501
+ LoggerMessage . Define < int > (
502
+ LogLevel . Warning ,
503
+ new EventId ( 1031 , nameof ( _progressiveDiscoveryError ) ) ,
504
+ "Error during progressive discovery final wait. Returning {DeviceCount} devices found" ) ;
505
+
506
+ private static readonly Action < ILogger , int , Exception ? > _progressiveDiscoveryCompleted =
507
+ LoggerMessage . Define < int > (
508
+ LogLevel . Information ,
509
+ new EventId ( 1032 , nameof ( _progressiveDiscoveryCompleted ) ) ,
510
+ "Progressive mDNS discovery completed. Found {DeviceCount} Chromecast devices total" ) ;
385
511
#endregion
386
512
387
513
#region IDisposable Implementation
0 commit comments