diff --git a/voice/src/commonMain/kotlin/VoiceConnectionBuilder.kt b/voice/src/commonMain/kotlin/VoiceConnectionBuilder.kt index f9aa30990d7b..c0fd221612cf 100644 --- a/voice/src/commonMain/kotlin/VoiceConnectionBuilder.kt +++ b/voice/src/commonMain/kotlin/VoiceConnectionBuilder.kt @@ -25,6 +25,8 @@ import kotlinx.coroutines.flow.first import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +internal expect val isSupported: Boolean + @KordVoice public class VoiceConnectionBuilder( public var gateway: Gateway, @@ -32,6 +34,14 @@ public class VoiceConnectionBuilder( public var channelId: Snowflake, public var guildId: Snowflake ) { + init { + if(!isSupported) { + throw UnsupportedOperationException(""" + Voice is currently not supported on Windows, if you're developing on Windows we recommend using + WSL: https://aka.ms/wsl + """.trimIndent()) + } + } /** * The amount in milliseconds to wait for the events required to create a [VoiceConnection]. Default is 5000, or 5 seconds. */ diff --git a/voice/src/jsMain/kotlin/VoiceConnectionBuilder.js.kt b/voice/src/jsMain/kotlin/VoiceConnectionBuilder.js.kt new file mode 100644 index 000000000000..df8eacf9fe9e --- /dev/null +++ b/voice/src/jsMain/kotlin/VoiceConnectionBuilder.js.kt @@ -0,0 +1,3 @@ +package dev.kord.voice + +internal actual val isSupported: Boolean = true diff --git a/voice/src/ktorMain/kotlin/VoiceConnectionBuilder.ktor.kt b/voice/src/ktorMain/kotlin/VoiceConnectionBuilder.ktor.kt new file mode 100644 index 000000000000..df8eacf9fe9e --- /dev/null +++ b/voice/src/ktorMain/kotlin/VoiceConnectionBuilder.ktor.kt @@ -0,0 +1,3 @@ +package dev.kord.voice + +internal actual val isSupported: Boolean = true diff --git a/voice/src/ktorMain/kotlin/udp/VoiceUdpSocket.ktor.kt b/voice/src/ktorMain/kotlin/udp/VoiceUdpSocket.ktor.kt new file mode 100644 index 000000000000..8289998c890e --- /dev/null +++ b/voice/src/ktorMain/kotlin/udp/VoiceUdpSocket.ktor.kt @@ -0,0 +1,46 @@ +package dev.kord.voice.udp + +import dev.kord.common.annotation.KordVoice +import dev.kord.voice.io.ByteArrayView +import io.ktor.network.sockets.* +import io.ktor.network.selector.* +import io.ktor.network.sockets.Datagram +import io.ktor.utils.io.core.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import io.ktor.network.sockets.Datagram as KtorDatagram + +@KordVoice +public actual typealias SocketAddress = InetSocketAddress + +@KordVoice +public actual val GlobalVoiceUdpSocket: VoiceUdpSocket = object : VoiceUdpSocket { + private val socketScope = + CoroutineScope(Dispatchers.Default + SupervisorJob() + CoroutineName("kord-voice-global-socket")) + + private val socket = aSocket(SelectorManager(socketScope.coroutineContext)).udp().bind() + + private val incoming: MutableSharedFlow = MutableSharedFlow() + + init { + socket.incoming + .consumeAsFlow() + .onEach { incoming.emit(it) } + .launchIn(socketScope) + } + + override fun all(address: SocketAddress): Flow { + return incoming + .filter { it.address == address } + .map { it.packet } + } + + override suspend fun send(address: SocketAddress, packet: ByteArrayView) { + val brp = ByteReadPacket(packet.data, packet.dataStart, packet.viewSize) + socket.send(KtorDatagram(brp, address)) + } + + override suspend fun stop() { + } +} + diff --git a/voice/src/mingwMain/kotlin/VoiceConnectionBuilder.mingw.kt b/voice/src/mingwMain/kotlin/VoiceConnectionBuilder.mingw.kt new file mode 100644 index 000000000000..b6b6d633f6f5 --- /dev/null +++ b/voice/src/mingwMain/kotlin/VoiceConnectionBuilder.mingw.kt @@ -0,0 +1,3 @@ +package dev.kord.voice + +internal actual val isSupported: Boolean = false \ No newline at end of file diff --git a/voice/src/mingwMain/kotlin/udp/VoiceUdpSocket.nonJs.kt b/voice/src/mingwMain/kotlin/udp/VoiceUdpSocket.nonJs.kt new file mode 100644 index 000000000000..39d77fa91102 --- /dev/null +++ b/voice/src/mingwMain/kotlin/udp/VoiceUdpSocket.nonJs.kt @@ -0,0 +1,18 @@ +package dev.kord.voice.udp + +import dev.kord.common.annotation.KordVoice +import dev.kord.voice.io.ByteArrayView +import io.ktor.utils.io.core.* +import kotlinx.coroutines.flow.Flow + +@KordVoice +public actual val GlobalVoiceUdpSocket: VoiceUdpSocket = object : VoiceUdpSocket { + override fun all(address: SocketAddress): Flow = unsupported() + + override suspend fun send(address: SocketAddress, packet: ByteArrayView) = unsupported() + + override suspend fun stop() = unsupported() +} + +private fun unsupported(): Nothing = TODO("Voice is not supported on windows") + diff --git a/voice/src/nonKtorMain/kotlin/VoiceUdpSocket.js.kt b/voice/src/nonKtorMain/kotlin/VoiceUdpSocket.js.kt new file mode 100644 index 000000000000..3c5972f67201 --- /dev/null +++ b/voice/src/nonKtorMain/kotlin/VoiceUdpSocket.js.kt @@ -0,0 +1,9 @@ +package dev.kord.voice.udp + +import dev.kord.common.annotation.KordVoice + +@KordVoice +public actual data class SocketAddress actual constructor( + public actual val hostname: String, + public actual val port: Int, +)