mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-14 18:57:07 -07:00
Expose DiscoveryService init/fini to JNI
This commit is contained in:
parent
65a497c585
commit
0a21b305b5
10 changed files with 241 additions and 13 deletions
|
@ -22,8 +22,12 @@
|
|||
#include <chiaki/common.h>
|
||||
#include <chiaki/log.h>
|
||||
#include <chiaki/session.h>
|
||||
#include <chiaki/discoveryservice.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "video-decoder.h"
|
||||
#include "audio-decoder.h"
|
||||
|
@ -286,7 +290,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J
|
|||
beach:
|
||||
free(host_str);
|
||||
E->SetIntField(env, result, E->GetFieldID(env, result_class, "errorCode", "I"), (jint)err);
|
||||
E->SetLongField(env, result, E->GetFieldID(env, result_class, "sessionPtr", "J"), (jlong)session);
|
||||
E->SetLongField(env, result, E->GetFieldID(env, result_class, "ptr", "J"), (jlong)session);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionFree(JNIEnv *env, jobject obj, jlong ptr)
|
||||
|
@ -352,3 +356,116 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionSetLogin
|
|||
chiaki_session_set_login_pin(&session->session, (const uint8_t *)pin, strlen(pin));
|
||||
E->ReleaseStringUTFChars(env, pin_java, pin);
|
||||
}
|
||||
|
||||
typedef struct android_discovery_service_t
|
||||
{
|
||||
ChiakiDiscoveryService service;
|
||||
jobject java_service;
|
||||
} AndroidDiscoveryService;
|
||||
|
||||
static void android_discovery_service_cb(ChiakiDiscoveryHost *hosts, size_t hosts_count, void *user)
|
||||
{
|
||||
AndroidDiscoveryService *service = user;
|
||||
// TODO
|
||||
CHIAKI_LOGD(&global_log, "Discovered %d hosts", (int)hosts_count);
|
||||
}
|
||||
|
||||
static ChiakiErrorCode sockaddr_from_java(JNIEnv *env, jobject /*InetSocketAddress*/ sockaddr_obj, struct sockaddr **addr, size_t *addr_size)
|
||||
{
|
||||
jclass sockaddr_class = E->GetObjectClass(env, sockaddr_obj);
|
||||
uint16_t port = (uint16_t)E->CallIntMethod(env, sockaddr_obj, E->GetMethodID(env, sockaddr_class, "getPort", "()I"));
|
||||
jobject addr_obj = E->CallObjectMethod(env, sockaddr_obj, E->GetMethodID(env, sockaddr_class, "getAddress", "()Ljava/net/InetAddress;"));
|
||||
jclass addr_class = E->GetObjectClass(env, addr_obj);
|
||||
jbyteArray addr_byte_array = E->CallObjectMethod(env, addr_obj, E->GetMethodID(env, addr_class, "getAddress", "()[B"));
|
||||
jsize addr_byte_array_len = E->GetArrayLength(env, addr_byte_array);
|
||||
|
||||
if(addr_byte_array_len == 4)
|
||||
{
|
||||
struct sockaddr_in *inaddr = CHIAKI_NEW(struct sockaddr_in);
|
||||
if(!inaddr)
|
||||
return CHIAKI_ERR_MEMORY;
|
||||
memset(inaddr, 0, sizeof(*inaddr));
|
||||
inaddr->sin_family = AF_INET;
|
||||
jbyte *bytes = E->GetByteArrayElements(env, addr_byte_array, NULL);
|
||||
memcpy(&inaddr->sin_addr.s_addr, bytes, sizeof(inaddr->sin_addr.s_addr));
|
||||
E->ReleaseByteArrayElements(env, addr_byte_array, bytes, JNI_ABORT);
|
||||
inaddr->sin_port = htons(port);
|
||||
|
||||
*addr = (struct sockaddr *)inaddr;
|
||||
*addr_size = sizeof(*inaddr);
|
||||
}
|
||||
else if(addr_byte_array_len == 0x10)
|
||||
{
|
||||
struct sockaddr_in6 *inaddr6 = CHIAKI_NEW(struct sockaddr_in6);
|
||||
if(!inaddr6)
|
||||
return CHIAKI_ERR_MEMORY;
|
||||
memset(inaddr6, 0, sizeof(*inaddr6));
|
||||
inaddr6->sin6_family = AF_INET6;
|
||||
jbyte *bytes = E->GetByteArrayElements(env, addr_byte_array, NULL);
|
||||
memcpy(&inaddr6->sin6_addr.in6_u, bytes, sizeof(inaddr6->sin6_addr.in6_u));
|
||||
E->ReleaseByteArrayElements(env, addr_byte_array, bytes, JNI_ABORT);
|
||||
inaddr6->sin6_port = htons(port);
|
||||
|
||||
*addr = (struct sockaddr *)inaddr6;
|
||||
*addr_size = sizeof(*inaddr6);
|
||||
}
|
||||
else
|
||||
return CHIAKI_ERR_INVALID_DATA;
|
||||
|
||||
return CHIAKI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_discoveryServiceCreate(JNIEnv *env, jobject obj, jobject result, jobject options_obj, jobject java_service)
|
||||
{
|
||||
jclass result_class = E->GetObjectClass(env, result);
|
||||
ChiakiErrorCode err = CHIAKI_ERR_SUCCESS;
|
||||
ChiakiDiscoveryServiceOptions options = { 0 };
|
||||
|
||||
AndroidDiscoveryService *service = CHIAKI_NEW(AndroidDiscoveryService);
|
||||
if(!service)
|
||||
{
|
||||
err = CHIAKI_ERR_MEMORY;
|
||||
goto beach;
|
||||
}
|
||||
|
||||
jclass options_class = E->GetObjectClass(env, options_obj);
|
||||
|
||||
options.hosts_max = (size_t)E->GetLongField(env, options_obj, E->GetFieldID(env, options_class, "hostsMax", "J"));
|
||||
options.host_drop_pings = (uint64_t)E->GetLongField(env, options_obj, E->GetFieldID(env, options_class, "hostDropPings", "J"));
|
||||
options.ping_ms = (uint64_t)E->GetLongField(env, options_obj, E->GetFieldID(env, options_class, "pingMs", "J"));
|
||||
options.cb = android_discovery_service_cb;
|
||||
options.cb_user = service;
|
||||
|
||||
err = sockaddr_from_java(env, E->GetObjectField(env, options_obj, E->GetFieldID(env, options_class, "sendAddr", "Ljava/net/InetSocketAddress;")), &options.send_addr, &options.send_addr_size);
|
||||
if(err != CHIAKI_ERR_SUCCESS)
|
||||
{
|
||||
CHIAKI_LOGE(&global_log, "Failed to get sockaddr from InetSocketAddress");
|
||||
goto beach;
|
||||
}
|
||||
|
||||
service->java_service = E->NewGlobalRef(env, java_service);
|
||||
// TODO: service->whatever = get id for callback method
|
||||
|
||||
err = chiaki_discovery_service_init(&service->service, &options, &global_log);
|
||||
if(err != CHIAKI_ERR_SUCCESS)
|
||||
{
|
||||
CHIAKI_LOGE(&global_log, "Failed to create discovery service (JNI)");
|
||||
E->DeleteGlobalRef(env, service->java_service);
|
||||
goto beach;
|
||||
}
|
||||
|
||||
beach:
|
||||
free(options.send_addr);
|
||||
E->SetIntField(env, result, E->GetFieldID(env, result_class, "errorCode", "I"), (jint)err);
|
||||
E->SetLongField(env, result, E->GetFieldID(env, result_class, "ptr", "J"), (jlong)service);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_discoveryServiceFree(JNIEnv *env, jobject obj, jlong ptr)
|
||||
{
|
||||
AndroidDiscoveryService *service = (AndroidDiscoveryService *)ptr;
|
||||
if(!service)
|
||||
return;
|
||||
chiaki_discovery_service_fini(&service->service);
|
||||
E->DeleteGlobalRef(env, service->java_service);
|
||||
free(service);
|
||||
}
|
||||
|
|
|
@ -25,13 +25,12 @@ import android.view.TextureView
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.metallic.chiaki.lib.*
|
||||
import java.util.stream.Stream
|
||||
|
||||
sealed class StreamState
|
||||
object StreamStateIdle: StreamState()
|
||||
object StreamStateConnecting: StreamState()
|
||||
object StreamStateConnected: StreamState()
|
||||
data class StreamStateCreateError(val error: SessionCreateError): StreamState()
|
||||
data class StreamStateCreateError(val error: CreateError): StreamState()
|
||||
data class StreamStateQuit(val reason: QuitReason, val reasonString: String?): StreamState()
|
||||
data class StreamStateLoginPinRequest(val pinIncorrect: Boolean): StreamState()
|
||||
|
||||
|
@ -77,7 +76,7 @@ class StreamSession(val connectInfo: ConnectInfo)
|
|||
session.setSurface(Surface(surfaceTexture))
|
||||
this.session = session
|
||||
}
|
||||
catch(e: SessionCreateError)
|
||||
catch(e: CreateError)
|
||||
{
|
||||
_state.value = StreamStateCreateError(e)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This file is part of Chiaki.
|
||||
*
|
||||
* Chiaki is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Chiaki is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.metallic.chiaki.discovery
|
||||
|
||||
import com.metallic.chiaki.lib.DiscoveryService
|
||||
import com.metallic.chiaki.lib.DiscoveryServiceOptions
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
class DiscoveryManager
|
||||
{
|
||||
companion object
|
||||
{
|
||||
const val HOSTS_MAX: ULong = 16U
|
||||
const val DROP_PINGS: ULong = 3U
|
||||
const val PING_MS: ULong = 500U
|
||||
const val PORT = 987
|
||||
}
|
||||
|
||||
private var discoveryService: DiscoveryService? = null
|
||||
|
||||
fun start()
|
||||
{
|
||||
if(discoveryService != null)
|
||||
return
|
||||
// TODO: catch CreateError
|
||||
discoveryService = DiscoveryService(DiscoveryServiceOptions(
|
||||
HOSTS_MAX, DROP_PINGS, PING_MS, InetSocketAddress("255.255.255.255", PORT)
|
||||
))
|
||||
}
|
||||
|
||||
fun stop()
|
||||
{
|
||||
val service = discoveryService ?: return
|
||||
service.dispose()
|
||||
discoveryService = null
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import android.os.Parcelable
|
|||
import android.view.Surface
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.lang.Exception
|
||||
import java.net.InetSocketAddress
|
||||
import kotlin.math.abs
|
||||
|
||||
@Parcelize
|
||||
|
@ -24,7 +25,7 @@ data class ConnectInfo(
|
|||
|
||||
private class ChiakiNative
|
||||
{
|
||||
data class SessionCreateResult(var errorCode: Int, var sessionPtr: Long)
|
||||
data class CreateResult(var errorCode: Int, var ptr: Long)
|
||||
companion object
|
||||
{
|
||||
init
|
||||
|
@ -34,7 +35,7 @@ private class ChiakiNative
|
|||
@JvmStatic external fun errorCodeToString(value: Int): String
|
||||
@JvmStatic external fun quitReasonToString(value: Int): String
|
||||
@JvmStatic external fun quitReasonIsStopped(value: Int): Boolean
|
||||
@JvmStatic external fun sessionCreate(result: SessionCreateResult, connectInfo: ConnectInfo, javaSession: Session)
|
||||
@JvmStatic external fun sessionCreate(result: CreateResult, connectInfo: ConnectInfo, javaSession: Session)
|
||||
@JvmStatic external fun sessionFree(ptr: Long)
|
||||
@JvmStatic external fun sessionStart(ptr: Long): Int
|
||||
@JvmStatic external fun sessionStop(ptr: Long): Int
|
||||
|
@ -42,6 +43,8 @@ private class ChiakiNative
|
|||
@JvmStatic external fun sessionSetSurface(ptr: Long, surface: Surface)
|
||||
@JvmStatic external fun sessionSetControllerState(ptr: Long, controllerState: ControllerState)
|
||||
@JvmStatic external fun sessionSetLoginPin(ptr: Long, pin: String)
|
||||
@JvmStatic external fun discoveryServiceCreate(result: CreateResult, options: DiscoveryServiceOptions, javaService: DiscoveryService)
|
||||
@JvmStatic external fun discoveryServiceFree(ptr: Long)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +111,7 @@ object ConnectedEvent: Event()
|
|||
data class LoginPinRequestEvent(val pinIncorrect: Boolean): Event()
|
||||
data class QuitEvent(val reason: QuitReason, val reasonString: String?): Event()
|
||||
|
||||
class SessionCreateError(val errorCode: ErrorCode): Exception("Failed to create Session: $errorCode")
|
||||
class CreateError(val errorCode: ErrorCode): Exception("Failed to create a native object: $errorCode")
|
||||
|
||||
class Session(connectInfo: ConnectInfo)
|
||||
{
|
||||
|
@ -122,12 +125,12 @@ class Session(connectInfo: ConnectInfo)
|
|||
|
||||
init
|
||||
{
|
||||
val result = ChiakiNative.SessionCreateResult(0, 0)
|
||||
val result = ChiakiNative.CreateResult(0, 0)
|
||||
ChiakiNative.sessionCreate(result, connectInfo, this)
|
||||
val errorCode = ErrorCode(result.errorCode)
|
||||
if(!errorCode.isSuccess)
|
||||
throw SessionCreateError(errorCode)
|
||||
nativePtr = result.sessionPtr
|
||||
throw CreateError(errorCode)
|
||||
nativePtr = result.ptr
|
||||
}
|
||||
|
||||
fun start() = ErrorCode(ChiakiNative.sessionStart(nativePtr))
|
||||
|
@ -196,4 +199,35 @@ data class DiscoveryHost(
|
|||
READY,
|
||||
STANDBY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class DiscoveryServiceOptions(
|
||||
val hostsMax: ULong,
|
||||
val hostDropPings: ULong,
|
||||
val pingMs: ULong,
|
||||
val sendAddr: InetSocketAddress
|
||||
)
|
||||
|
||||
class DiscoveryService(options: DiscoveryServiceOptions)
|
||||
{
|
||||
private var nativePtr: Long
|
||||
|
||||
init
|
||||
{
|
||||
val result = ChiakiNative.CreateResult(0, 0)
|
||||
ChiakiNative.discoveryServiceCreate(result, options, this)
|
||||
val errorCode = ErrorCode(result.errorCode)
|
||||
if(!errorCode.isSuccess)
|
||||
throw CreateError(errorCode)
|
||||
nativePtr = result.ptr
|
||||
}
|
||||
|
||||
fun dispose()
|
||||
{
|
||||
if(nativePtr == 0L)
|
||||
return
|
||||
ChiakiNative.discoveryServiceFree(nativePtr)
|
||||
nativePtr = 0L
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import androidx.lifecycle.ViewModel
|
|||
import com.metallic.chiaki.common.AppDatabase
|
||||
import com.metallic.chiaki.common.ManualDisplayHost
|
||||
import com.metallic.chiaki.common.ext.toLiveData
|
||||
import com.metallic.chiaki.discovery.DiscoveryManager
|
||||
|
||||
class MainViewModel(val database: AppDatabase): ViewModel()
|
||||
{
|
||||
|
@ -33,4 +34,12 @@ class MainViewModel(val database: AppDatabase): ViewModel()
|
|||
}
|
||||
.toLiveData()
|
||||
}
|
||||
|
||||
val discoveryManager = DiscoveryManager().also { it.start() }
|
||||
|
||||
override fun onCleared()
|
||||
{
|
||||
super.onCleared()
|
||||
discoveryManager.stop()
|
||||
}
|
||||
}
|
4
android/app/src/main/res/drawable/ic_discover_off.xml
Normal file
4
android/app/src/main/res/drawable/ic_discover_off.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="32dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnSurface" android:pathData="M22.99,9C19.15,5.16 13.8,3.76 8.84,4.78l2.52,2.52c3.47,-0.17 6.99,1.05 9.63,3.7l2,-2zM18.99,13c-1.29,-1.29 -2.84,-2.13 -4.49,-2.56l3.53,3.53 0.96,-0.97zM2,3.05L5.07,6.1C3.6,6.82 2.22,7.78 1,9l1.99,2c1.24,-1.24 2.67,-2.16 4.2,-2.77l2.24,2.24C7.81,10.89 6.27,11.73 5,13v0.01L6.99,15c1.36,-1.36 3.14,-2.04 4.92,-2.06L18.98,20l1.27,-1.26L3.29,1.79 2,3.05zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0z"/>
|
||||
</vector>
|
4
android/app/src/main/res/drawable/ic_discover_on.xml
Normal file
4
android/app/src/main/res/drawable/ic_discover_on.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="32dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnSurface" android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
|
||||
</vector>
|
|
@ -1,4 +1,4 @@
|
|||
<vector android:height="48dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<vector android:height="32dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnSurface" android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z"/>
|
||||
</vector>
|
|
@ -1,9 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_discover"
|
||||
android:icon="@drawable/ic_discover_on"
|
||||
android:title="@string/action_discover"
|
||||
android:checkable="true"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:icon="@drawable/ic_settings_48dp"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
|
@ -9,4 +9,5 @@
|
|||
<string name="action_quit_session">Quit</string>
|
||||
<string name="action_login_pin_connect">Connect</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="action_discover">Discover Consoles Automatically</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue