Skip to content

Commit

Permalink
feat(*): add SrtUrl support for CoroutineSocket
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibaultBee committed Jul 9, 2024
1 parent d9c096c commit b537ee2
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.github.thibaultbee.srtdroid.enums.EpollOpt
import io.github.thibaultbee.srtdroid.enums.ErrorType
import io.github.thibaultbee.srtdroid.enums.SockOpt
import io.github.thibaultbee.srtdroid.enums.SockStatus
import io.github.thibaultbee.srtdroid.interfaces.ConfigurableSocket
import io.github.thibaultbee.srtdroid.models.Epoll
import io.github.thibaultbee.srtdroid.models.Error
import io.github.thibaultbee.srtdroid.models.MsgCtrl
Expand Down Expand Up @@ -48,7 +49,7 @@ class CoroutineSocket
private constructor(
private val socket: Socket
) :
CoroutineScope {
ConfigurableSocket, CoroutineScope {
constructor() : this(Socket())

init {
Expand Down Expand Up @@ -292,7 +293,7 @@ private constructor(
* @throws IOException if can't get [SockOpt]
* @see [setSockFlag]
*/
fun getSockFlag(opt: SockOpt): Any {
override fun getSockFlag(opt: SockOpt): Any {
return socket.getSockFlag(opt)
}

Expand All @@ -306,7 +307,7 @@ private constructor(
* @throws IOException if can't set [SockOpt]
* @see [getSockFlag]
*/
fun setSockFlag(opt: SockOpt, value: Any) {
override fun setSockFlag(opt: SockOpt, value: Any) {
if ((opt == SockOpt.RCVSYN) || (opt == SockOpt.SNDSYN)) {
throw IllegalArgumentException("Options not supported")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.github.thibaultbee.srtdroid.ktx.extensions

import io.github.thibaultbee.srtdroid.enums.SockStatus
import io.github.thibaultbee.srtdroid.ktx.CoroutineSocket
import io.github.thibaultbee.srtdroid.models.SrtUrl
import java.io.File
import java.net.BindException
import java.net.ConnectException
Expand All @@ -10,15 +10,36 @@ import java.net.InetSocketAddress
import java.net.SocketException
import java.net.SocketTimeoutException

/**
* Binds the socket to a local address.
*
* **See Also:** [srt_bind](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_bind)
*
* @param url the URL to bind to in FFmpeg format srt://hostname:port[?options]
*
* @throws BindException if bind has failed
*/
suspend fun CoroutineSocket.bind(url: String) = bind(SrtUrl(url))

/**
* Tests if the SRT socket is connected.
* Binds the socket to a local address.
*
* **See Also:** [srt_bind](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_bind)
*
* @param srtUrl the URL to bind to in FFmpeg format srt://hostname:port[?options]
*
* @return true if the SRT socket is connected, otherwise false
* @throws BindException if bind has failed
*/
val CoroutineSocket.isConnected: Boolean
get() = sockState == SockStatus.CONNECTED
suspend fun CoroutineSocket.bind(srtUrl: SrtUrl) {
if (srtUrl.mode != null) {
require(srtUrl.mode != SrtUrl.Mode.CALLER) { "Bind is only for `listener` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
srtUrl.preBindApplyTo(this)
bind(srtUrl.hostname, srtUrl.port)
srtUrl.postApplyTo(this)
}

/**
* Binds the socket to a local address.
Expand All @@ -45,6 +66,35 @@ suspend fun CoroutineSocket.bind(address: String, port: Int) =
suspend fun CoroutineSocket.bind(address: InetAddress, port: Int) =
bind(InetSocketAddress(address, port))


/**
* Connects a socket to an URL.
*
* **See Also:** [srt_connect](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_connect)
*
* @param url the URL to connect to in FFmpeg format srt://hostname:port[?options]
* @throws ConnectException if connection has failed
*/
suspend fun CoroutineSocket.connect(url: String) = connect(SrtUrl(url))

/**
* Connects a socket to an URL.
*
* **See Also:** [srt_connect](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_connect)
*
* @param srtUrl the URL to connect to in FFmpeg format srt://hostname:port[?options]
* @throws ConnectException if connection has failed
*/
suspend fun CoroutineSocket.connect(srtUrl: SrtUrl) {
if (srtUrl.mode != null) {
require(srtUrl.mode != SrtUrl.Mode.LISTENER) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
connect(srtUrl.hostname, srtUrl.port)
srtUrl.postApplyTo(this)
}

/**
* Connects a socket to a specified address and port.
*
Expand All @@ -69,6 +119,35 @@ suspend fun CoroutineSocket.connect(address: String, port: Int) =
suspend fun CoroutineSocket.connect(address: InetAddress, port: Int) =
connect(InetSocketAddress(address, port))

/**
* Performs a rendezvous connection.
*
* **See Also:** [srt_rendezvous](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_rendezvous)
*
* @param url the URL to rendezvous to in FFmpeg format srt://hostname:port[?options]
* @throws SocketException if rendezvous connection has failed
*/
suspend fun CoroutineSocket.rendezVous(url: String) = rendezVous(SrtUrl(url))

/**
* Performs a rendezvous connection.
*
* **See Also:** [srt_rendezvous](https://github.com/Haivision/srt/blob/master/docs/API/API-functions.md#srt_rendezvous)
*
* @param srtUrl the URL to rendezvous to in FFmpeg format srt://hostname:port[?options]
* @throws SocketException if rendezvous connection has failed
*/
suspend fun CoroutineSocket.rendezVous(
srtUrl: SrtUrl
) {
if (srtUrl.mode != null) {
require(srtUrl.mode == SrtUrl.Mode.RENDEZ_VOUS) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
rendezVous(srtUrl.hostname, srtUrl.hostname, srtUrl.port)
srtUrl.postApplyTo(this)
}

/**
* Performs a rendezvous connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fun Socket.bind(url: String) = bind(SrtUrl(url))
*/
fun Socket.bind(srtUrl: SrtUrl) {
if (srtUrl.mode != null) {
require(srtUrl.mode != SrtUrl.Mode.CALLER) { "Bind is only for `listener` or `rendezvous` mode but ${srtUrl.mode.value}" }
require(srtUrl.mode != SrtUrl.Mode.CALLER) { "Bind is only for `listener` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
Expand Down Expand Up @@ -57,7 +57,7 @@ fun Socket.connect(url: String) = connect(SrtUrl(url))
*/
fun Socket.connect(srtUrl: SrtUrl) {
if (srtUrl.mode != null) {
require(srtUrl.mode != SrtUrl.Mode.LISTENER) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode.value}" }
require(srtUrl.mode != SrtUrl.Mode.LISTENER) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
Expand Down Expand Up @@ -87,7 +87,7 @@ fun Socket.rendezVous(
srtUrl: SrtUrl
) {
if (srtUrl.mode != null) {
require(srtUrl.mode == SrtUrl.Mode.RENDEZ_VOUS) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode.value}" }
require(srtUrl.mode == SrtUrl.Mode.RENDEZ_VOUS) { "Connect is only for `caller` or `rendezvous` mode but ${srtUrl.mode}" }
}

srtUrl.preApplyTo(this)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.thibaultbee.srtdroid.interfaces

import io.github.thibaultbee.srtdroid.enums.SockOpt

/**
* A convenient interface to get and set socket options
*/
interface ConfigurableSocket {
fun getSockFlag(opt: SockOpt): Any
fun setSockFlag(opt: SockOpt, value: Any)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.github.thibaultbee.srtdroid.enums.ErrorType
import io.github.thibaultbee.srtdroid.enums.RejectReasonCode
import io.github.thibaultbee.srtdroid.enums.SockOpt
import io.github.thibaultbee.srtdroid.enums.SockStatus
import io.github.thibaultbee.srtdroid.interfaces.ConfigurableSocket
import io.github.thibaultbee.srtdroid.models.rejectreason.InternalRejectReason
import io.github.thibaultbee.srtdroid.models.rejectreason.PredefinedRejectReason
import io.github.thibaultbee.srtdroid.models.rejectreason.RejectReason
Expand All @@ -45,7 +46,7 @@ import java.nio.ByteBuffer
* Once it has been called, you must release Srt context with [Srt.cleanUp] when application leaves.
*/
class Socket
private constructor(private val srtsocket: Int) : Closeable {
private constructor(private val srtsocket: Int) : ConfigurableSocket, Closeable {
companion object {
@JvmStatic
private external fun nativeCreateSocket(): Int
Expand Down Expand Up @@ -412,7 +413,7 @@ private constructor(private val srtsocket: Int) : Closeable {
* @throws IOException if can't get [SockOpt]
* @see [setSockFlag]
*/
fun getSockFlag(opt: SockOpt): Any {
override fun getSockFlag(opt: SockOpt): Any {
return nativeGetSockFlag(opt) ?: throw IOException(Error.lastErrorMessage)
}

Expand All @@ -428,7 +429,7 @@ private constructor(private val srtsocket: Int) : Closeable {
* @throws IOException if can't set [SockOpt]
* @see [getSockFlag]
*/
fun setSockFlag(opt: SockOpt, value: Any) {
override fun setSockFlag(opt: SockOpt, value: Any) {
if (nativeSetSockFlag(opt, value) != 0) {
throw IOException(Error.lastErrorMessage)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.github.thibaultbee.srtdroid.Srt
import io.github.thibaultbee.srtdroid.enums.SockOpt
import io.github.thibaultbee.srtdroid.enums.Transtype
import io.github.thibaultbee.srtdroid.extensions.toBoolean
import io.github.thibaultbee.srtdroid.interfaces.ConfigurableSocket
import java.security.InvalidParameterException

/**
Expand Down Expand Up @@ -197,7 +198,11 @@ data class SrtUrl(
}
}

internal fun preBindApplyTo(socket: Socket) {
/**
* Sets pre configuration for binding socket.
* Internal purpose only.
*/
fun preBindApplyTo(socket: ConfigurableSocket) {
iptos?.let { socket.setSockFlag(SockOpt.IPTOS, it) }
ipttl?.let { socket.setSockFlag(SockOpt.IPTTL, it) }
maxSegmentSize?.let { socket.setSockFlag(SockOpt.MSS, it) }
Expand All @@ -207,7 +212,11 @@ data class SrtUrl(
recvBufferSize?.let { socket.setSockFlag(SockOpt.RCVBUF, it) }
}

internal fun preApplyTo(socket: Socket) {
/**
* Sets pre configuration for socket.
* Internal purpose only.
*/
fun preApplyTo(socket: ConfigurableSocket) {
connectTimeoutInMs?.let { socket.setSockFlag(SockOpt.CONNTIMEO, it) }
flightFlagSize?.let { socket.setSockFlag(SockOpt.FC, it) }

Expand Down Expand Up @@ -236,7 +245,11 @@ data class SrtUrl(
enableTimestampBasedPacketDelivery?.let { socket.setSockFlag(SockOpt.TSBPDMODE, it) }
}

internal fun postApplyTo(socket: Socket) {
/**
* Sets post configuration for socket.
* Internal purpose only.
*/
fun postApplyTo(socket: ConfigurableSocket) {
inputBandwidth?.let { socket.setSockFlag(SockOpt.INPUTBW, it) }
maxBandwidth?.let { socket.setSockFlag(SockOpt.MAXBW, it) }
overheadBandwidth?.let { socket.setSockFlag(SockOpt.OHEADBW, it) }
Expand Down

0 comments on commit b537ee2

Please sign in to comment.