package com.srtk.airlink import android.content.Context import android.net.nsd.NsdManager import android.net.nsd.NsdServiceInfo import android.util.Log import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import java.net.InetAddress data class ServerInfo( val name: String, val ip: InetAddress, val port: Int ) { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is ServerInfo) return false return ip == other.ip && port == other.port } override fun hashCode(): Int { return 31 * ip.hashCode() + port } } class DiscoveryManager(context: Context) { private val TAG = "DiscoveryManager" private val nsdManager = context.getSystemService( Context.NSD_SERVICE ) as NsdManager private val SERVICE_TYPE = "_procam._udp." fun discover(): Flow = callbackFlow { val discoveryListener = object : NsdManager.DiscoveryListener { override fun onDiscoveryStarted(regType: String) { Log.d(TAG, "Discovery started") } override fun onServiceFound(service: NsdServiceInfo) { if (service.serviceType.contains("_procam")) { try { nsdManager.resolveService( service, object : NsdManager.ResolveListener { override fun onResolveFailed( serviceInfo: NsdServiceInfo, errorCode: Int ) { Log.w(TAG, "Resolve failed: $errorCode") } override fun onServiceResolved( serviceInfo: NsdServiceInfo ) { try { val server = ServerInfo( name = serviceInfo.serviceName, ip = serviceInfo.host, port = serviceInfo.port ) trySend(server) } catch (e: Exception) { Log.e( TAG, "Error creating ServerInfo: ${e.message}" ) } } } ) } catch (e: Exception) { Log.e(TAG, "Resolve error: ${e.message}") } } } override fun onServiceLost(service: NsdServiceInfo) { Log.d(TAG, "Service lost: ${service.serviceName}") } override fun onDiscoveryStopped(serviceType: String) { Log.d(TAG, "Discovery stopped") } override fun onStartDiscoveryFailed( serviceType: String, errorCode: Int ) { Log.e(TAG, "Start discovery failed: $errorCode") try { nsdManager.stopServiceDiscovery(this) } catch (e: Exception) { Log.e(TAG, "Stop discovery error: ${e.message}") } } override fun onStopDiscoveryFailed( serviceType: String, errorCode: Int ) { Log.e(TAG, "Stop discovery failed: $errorCode") } } try { nsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener ) } catch (e: Exception) { Log.e(TAG, "Discovery start error: ${e.message}") } awaitClose { try { nsdManager.stopServiceDiscovery(discoveryListener) } catch (e: Exception) { Log.e(TAG, "Discovery cleanup error: ${e.message}") } } } }