Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/coroutine #35

Merged
merged 2 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ android {
}

dependencies {
implementation project(':srtdroid')
implementation project(':srtdroid-ktx')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.6.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ package io.github.thibaultbee.srtdroid.example

import android.app.Application
import android.content.Context
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import io.github.thibaultbee.srtdroid.example.tests.RecvFile
import io.github.thibaultbee.srtdroid.example.tests.SendFile
import io.github.thibaultbee.srtdroid.example.tests.TestClient
import io.github.thibaultbee.srtdroid.example.tests.TestServer
import java.util.concurrent.Executors
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.launch

class MainViewModel(application: Application) : AndroidViewModel(application) {
private val configuration = Configuration(getApplication())
private val sendFileName = "MyFileToSend"
private val recvFileName = "RecvFile"

private val executor = Executors.newFixedThreadPool(4)

val error = MutableLiveData<String>()
val success = MutableLiveData<String>()

Expand All @@ -26,68 +28,52 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
val sendFileCompletion = MutableLiveData<Boolean>()

private val testServer =
TestServer(executor,
{ msg ->
testServerCompletion.postValue(true)
success.postValue(msg)
},
{ msg ->
testClientCompletion.postValue(true)
error.postValue(msg)
}
)
TestServer()
private val testClient =
TestClient(
executor,
{ msg ->
testClientCompletion.postValue(true)
success.postValue(msg)
},
{ msg ->
testClientCompletion.postValue(true)
error.postValue(msg)
}
)
TestClient()

private val recvFile =
RecvFile(sendFileName,
RecvFile(
sendFileName,
recvFileName,
(getApplication() as Context).filesDir,
executor,
{ msg ->
recvFileCompletion.postValue(true)
success.postValue(msg)
},
{ msg ->
recvFileCompletion.postValue(true)
error.postValue(msg)
}
(getApplication() as Context).filesDir
)

private val sendFile =
SendFile((getApplication() as Context).filesDir,
executor,
{ msg ->
sendFileCompletion.postValue(true)
success.postValue(msg)
},
{ msg ->
sendFileCompletion.postValue(true)
error.postValue(msg)
}
)
SendFile((getApplication() as Context).filesDir)


private var testClientJob: Job? = null
private var testServerJob: Job? = null
private var recvFileJob: Job? = null
private var sendFileJob: Job? = null

/**
* Sends multiple messages to a SRT server.
*
* Same as SRT examples/test-c-client.c
*/
fun launchTestClient() {
testClient.launch(configuration.clientIP, configuration.clientPort)
if (testClientJob?.isActive == true) {
Log.w(TAG, "Test client job is already running")
return
}
testClientJob = viewModelScope.launch {
try {
testClient.run(configuration.clientIP, configuration.clientPort)
success.postValue("Client success!")
} catch (e: Exception) {
Log.e(TAG, "Client error: ${e.message}", e)
error.postValue(e.message)
} finally {
testClientCompletion.postValue(true)
}
}
}

fun cancelTestClient() {
testClient.cancel()
Log.i(TAG, "Canceling test client job")
testClientJob?.cancelChildren()
testClientJob = null
}

/**
Expand All @@ -96,11 +82,27 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
* Same as SRT examples/test-c-server.c
*/
fun launchTestServer() {
testServer.launch(configuration.serverIP, configuration.serverPort)
if (testServerJob?.isActive == true) {
Log.w(TAG, "Test server job is already running")
return
}
testServerJob = viewModelScope.launch {
try {
testServer.run(configuration.serverIP, configuration.serverPort)
success.postValue("Server success!")
} catch (e: Exception) {
Log.e(TAG, "Server error: ${e.message}", e)
error.postValue(e.message)
} finally {
testServerCompletion.postValue(true)
}
}
}

fun cancelTestServer() {
testServer.cancel()
Log.i(TAG, "Canceling test server job")
testServerJob?.cancel()
testServerJob = null
}

/**
Expand All @@ -109,11 +111,27 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
* Same as SRT examples/recvfile.cpp
*/
fun launchRecvFile() {
recvFile.launch(configuration.clientIP, configuration.clientPort)
if (recvFileJob?.isActive == true) {
Log.w(TAG, "Recv file job is already running")
return
}
recvFileJob = viewModelScope.launch {
try {
recvFile.run(configuration.clientIP, configuration.clientPort)
success.postValue("RecvFile success!")
} catch (e: Exception) {
Log.e(TAG, "RecvFile error: ${e.message}", e)
error.postValue(e.message)
} finally {
recvFileCompletion.postValue(true)
}
}
}

fun cancelRecvFile() {
recvFile.cancel()
Log.i(TAG, "Canceling recv file job")
recvFileJob?.cancel()
recvFileJob = null
}

/**
Expand All @@ -123,10 +141,30 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
* Same as SRT examples/sendfile.cpp
*/
fun launchSendFile() {
sendFile.launch(configuration.serverIP, configuration.serverPort)
if (sendFileJob?.isActive == true) {
Log.w(TAG, "Send file job is already running")
return
}
sendFileJob = viewModelScope.launch {
try {
sendFile.run(configuration.serverIP, configuration.serverPort)
success.postValue("SendFile success!")
} catch (e: Exception) {
Log.e(TAG, "SendFile error: ${e.message}", e)
error.postValue(e.message)
} finally {
sendFileCompletion.postValue(true)
}
}
}

fun cancelSendFile() {
sendFile.cancel()
Log.i(TAG, "Canceling send file job")
sendFileJob?.cancel()
sendFileJob = null
}

companion object {
private val TAG = MainViewModel::class.simpleName
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,4 @@ object Utils {
Error.clearLastError()
return message
}

fun writeFile(file: File, text: String) {
FileOutputStream(file).use {
it.write(text.toByteArray())
}
}
}
Original file line number Diff line number Diff line change
@@ -1,56 +1,63 @@
package io.github.thibaultbee.srtdroid.example.tests

import android.util.Log
import com.google.common.primitives.Ints
import com.google.common.primitives.Longs
import io.github.thibaultbee.srtdroid.enums.SockOpt
import io.github.thibaultbee.srtdroid.enums.Transtype
import io.github.thibaultbee.srtdroid.example.Utils
import io.github.thibaultbee.srtdroid.models.Socket
import com.google.common.primitives.Ints
import com.google.common.primitives.Longs
import io.github.thibaultbee.srtdroid.ktx.CoroutineSocket
import io.github.thibaultbee.srtdroid.ktx.extensions.connect
import io.github.thibaultbee.srtdroid.ktx.extensions.recvFile
import io.github.thibaultbee.srtdroid.ktx.extensions.send
import kotlinx.coroutines.delay
import java.io.File
import java.util.concurrent.ExecutorService

class RecvFile(
private val sendFileName: String,
private val recvFileName: String,
private val recvFileDir: File,
executorService: ExecutorService,
onSuccess: (String) -> Unit,
onError: (String) -> Unit
) : Test(executorService, onSuccess, onError) {
) : Test {
companion object {
private val TAG = RecvFile::class.simpleName
}

override val testName: String = this::class.simpleName!!
override val name: String = this::class.simpleName!!

override fun launchImpl(ip: String, port: Int, socket: Socket) {
override suspend fun run(ip: String, port: Int) {
Log.i(TAG, "Will get file $sendFileName from server")

if (!socket.isValid) {
throw Exception("Invalid socket")
}

socket.setSockFlag(SockOpt.TRANSTYPE, Transtype.FILE)
socket.connect(ip, port)

// Request server file
socket.send(Ints.toByteArray(sendFileName.length).reversedArray())

socket.send(sendFileName)

val fileSize = Longs.fromByteArray(socket.recv(Longs.BYTES).reversedArray())

// Where file will be written
val recvFile = File(recvFileDir, recvFileName)
if (fileSize != socket.recvFile(recvFile, 0, fileSize)) {
throw Exception("Failed to recv file: ${Utils.getErrorMessage()}")
val socket = CoroutineSocket()

try {
socket.setSockFlag(SockOpt.TRANSTYPE, Transtype.FILE)
socket.connect(ip, port)
Log.i(
TAG,
"Is connected: ${socket.isConnected}"
)

// Request server file
socket.send(Ints.toByteArray(sendFileName.length).reversedArray())

socket.send(sendFileName)

val array = socket.recv(Longs.BYTES)
val fileSize = Longs.fromByteArray(array.reversedArray())

// Where file will be written
val recvFile = File(recvFileDir, recvFileName)
Log.i(TAG, "Receiving file ${recvFile.path}")
if (fileSize != socket.recvFile(recvFile, 0, fileSize)) {
throw Exception("Failed to recv file: ${Utils.getErrorMessage()}")
}

// If session is close too early, last msg will not be receive by server
delay(1000)
Log.i(TAG, "Received file $recvFile")
} catch (e: Exception) {
throw e
} finally {
socket.close()
}

// If session is close too early, last msg will not be receive by server
Thread.sleep(1000)

successMsg = "Recv file is in $recvFile"
}

}
Loading
Loading