public async Task DiscoverDevicesAsync(Func <HttpDiscoveredDeviceContext, Task <bool> > onDeviceDiscovered, CancellationToken cancellationToken = default(CancellationToken)) { string discoverRequest = "M-SEARCH * HTTP/1.1\n" + "Host: 239.255.255.250:1900\n" + "Man: \"ssdp:discover\"\n" + "ST: roku:ecp\n" + ""; var bytes = Encoding.UTF8.GetBytes(discoverRequest); using (var udpClient = new UdpClient(endPoint)) { await udpClient.SendAsync(bytes, bytes.Length, "239.255.255.250", 1900).ConfigureAwait(false); while (!cancellationToken.IsCancellationRequested) { var receiveTask = Task.Run( async() => { try { return(await udpClient.ReceiveAsync().ConfigureAwait(false)); } catch (ObjectDisposedException) { // NOTE: We assume that a disposal exception is an attempt to cancel an // outstanding ReceiveAsync() by closing the socket (disposing the // UdpClient). throw new OperationCanceledException(); } }); var cancellationTask = Task.Delay(TimeSpan.FromMilliseconds(-1), cancellationToken); var completedTask = await Task.WhenAny(receiveTask, cancellationTask).ConfigureAwait(false); if (completedTask == cancellationTask) { // NOTE: We allow the OperationCanceledException to bubble up, causing disposal of the // UdpClient which would force any pending ReceiveAsync() to throw an // ObjectDisposedException. await cancellationTask.ConfigureAwait(false); return; } var rawResponse = await receiveTask.ConfigureAwait(false); var response = await ParseResponseAsync(rawResponse.Buffer).ConfigureAwait(false); if (response.StatusCode == 200 && response.Headers.TryGetValue("ST", out string stHeader) && stHeader == "roku:ecp" && response.Headers.TryGetValue("LOCATION", out string location) && Uri.TryCreate(location, UriKind.Absolute, out Uri locationUri) && response.Headers.TryGetValue("USN", out string usn)) { var serialNumber = usn.StartsWith("uuid:roku:ecp:") ? usn.Substring("uuid:roku:ecp:".Length) : usn; var device = new HttpRokuDevice(serialNumber, locationUri, this.handler); bool cancelDiscovery = false; var context = new HttpDiscoveredDeviceContext(device, serialNumber); if (onDeviceDiscovered != null) { cancelDiscovery = await onDeviceDiscovered(context).ConfigureAwait(false); } var args = new HttpDeviceDiscoveredEventArgs(context) { CancelDiscovery = cancelDiscovery }; this.DeviceDiscovered?.Invoke(this, args); cancelDiscovery = args.CancelDiscovery; var baseArgs = new DeviceDiscoveredEventArgs(context) { CancelDiscovery = cancelDiscovery }; this.baseDeviceDiscovered?.Invoke(this, baseArgs); cancelDiscovery = baseArgs.CancelDiscovery; if (cancelDiscovery) { return; } } } } }
public HttpDeviceDiscoveredEventArgs(HttpDiscoveredDeviceContext context) : base(context) { this.Context = context; }