scanDlnaMediaServerDevices function
Future<List<DiscoveredDevice> >
scanDlnaMediaServerDevices({
- Duration scanDuration = const Duration(seconds: 3),
- dynamic onDeviceFound()?,
Scan for DLNA Media Server devices in the local network (using SSDP/UPnP)
onDeviceFound
回調函數,當找到新裝置時調用
Implementation
Future<List<DiscoveredDevice>> scanDlnaMediaServerDevices({
Duration scanDuration = const Duration(seconds: 3),
Function(DiscoveredDevice)? onDeviceFound,
}) async {
final logger = AppLogger();
await logger.info('info.start_dlna_server_scan', tag: 'SSDP');
final List<DiscoveredDevice> devices = [];
RawDatagramSocket socket;
try {
socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);
} catch (e) {
return [];
}
// SSDP discovery message specifically for Media Server
const String ssdpRequest =
'M-SEARCH * HTTP/1.1\r\n'
'HOST: 239.255.255.250:1900\r\n'
'MAN: "ssdp:discover"\r\n'
'MX: 2\r\n'
'ST: urn:schemas-upnp-org:device:MediaServer:1\r\n'
'\r\n';
final data = utf8.encode(ssdpRequest);
// 定期發送 SSDP discovery message
final interval = Duration(seconds: 2);
final periodic = Timer.periodic(interval, (_) {
socket.send(data, InternetAddress('239.255.255.250'), 1900);
});
// 啟動時立即發送一次
socket.send(data, InternetAddress('239.255.255.250'), 1900);
final responses = <String, DiscoveredDevice>{};
final completer = Completer<void>();
socket.listen(
(RawSocketEvent event) async {
if (event == RawSocketEvent.read) {
final datagram = socket.receive();
if (datagram != null) {
final resp = utf8.decode(datagram.data);
final ip = datagram.address.address;
if (resp.contains('MediaServer')) {
// Parse device information
final nameMatch = RegExp(r'\nSERVER: (.+)').firstMatch(resp);
final name = nameMatch?.group(1) ?? 'DLNA Media Server';
// Parse LOCATION field
final locationMatch = RegExp(
r'LOCATION:\s*(.+)\r?\n',
caseSensitive: false,
).firstMatch(resp);
final location = locationMatch?.group(1)?.trim();
// Parse model information (if available)
final modelMatch = RegExp(
r'MODEL: (.+?)\r?\n',
caseSensitive: false,
).firstMatch(resp);
final model = modelMatch?.group(1)?.trim();
if (!responses.containsKey(ip) && location != null) {
final device = DiscoveredDevice.fromDlnaMediaServer(
name: name,
ip: ip,
location: location,
model: model,
);
await logger.info(
'info.found_dlna_server',
tag: 'SSDP',
params: {
'name': device.name,
'ip': device.ip,
'model': device.model ?? 'unknown',
'location': device.location,
},
);
responses[ip] = device;
if (onDeviceFound != null) {
onDeviceFound(device);
}
}
}
}
}
},
onDone: () {
if (!completer.isCompleted) {
completer.complete();
}
},
onError: (_) {
if (!completer.isCompleted) {
completer.complete();
}
},
);
// Wait for scanDuration to complete
Future.delayed(scanDuration, () {
periodic.cancel();
socket.close();
if (!completer.isCompleted) {
completer.complete();
}
});
await completer.future;
devices.addAll(responses.values);
await logger.info(
'info.dlna_server_scan_complete',
tag: 'SSDP',
params: {'count': devices.length},
);
return devices;
}