1
0
mirror of https://git.sr.ht/~thestr4ng3r/chiaki synced 2025-03-12 05:25:23 -07:00

Show Stream States nicely on Android

This commit is contained in:
Florian Märkl 2019-09-29 22:24:36 +02:00
parent 37e5de2b0f
commit 88db8c8840
No known key found for this signature in database
GPG Key ID: 125BC8A5A6A1E857
12 changed files with 185 additions and 12 deletions

@ -104,6 +104,7 @@ typedef struct android_chiaki_session_t
ChiakiSession session;
jobject java_session;
jclass java_session_class;
jmethodID java_session_event_connected_meth;
jmethodID java_session_event_login_pin_request_meth;
jmethodID java_session_event_quit_meth;
jfieldID java_controller_state_buttons;
@ -143,6 +144,10 @@ static void android_chiaki_event_cb(ChiakiEvent *event, void *user)
switch(event->type)
{
case CHIAKI_EVENT_CONNECTED:
E->CallVoidMethod(env, session->java_session,
session->java_session_event_connected_meth);
break;
case CHIAKI_EVENT_LOGIN_PIN_REQUEST:
E->CallVoidMethod(env, session->java_session,
session->java_session_event_login_pin_request_meth,
@ -253,6 +258,7 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionCreate(J
session->java_session = E->NewGlobalRef(env, java_session);
session->java_session_class = E->GetObjectClass(env, session->java_session);
session->java_session_event_connected_meth = E->GetMethodID(env, session->java_session_class, "eventConnected", "()V");
session->java_session_event_login_pin_request_meth = E->GetMethodID(env, session->java_session_class, "eventLoginPinRequest", "(Z)V");
session->java_session_event_quit_meth = E->GetMethodID(env, session->java_session_class, "eventQuit", "(ILjava/lang/String;)V");
@ -332,4 +338,12 @@ JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionSetContr
controller_state.right_x = (int16_t)E->GetShortField(env, controller_state_java, session->java_controller_state_right_x);
controller_state.right_y = (int16_t)E->GetShortField(env, controller_state_java, session->java_controller_state_right_y);
chiaki_session_set_controller_state(&session->session, &controller_state);
}
}
JNIEXPORT void JNICALL Java_com_metallic_chiaki_lib_ChiakiNative_sessionSetLoginPin(JNIEnv *env, jobject obj, jlong ptr, jstring pin_java)
{
AndroidChiakiSession *session = (AndroidChiakiSession *)ptr;
const char *pin = E->GetStringUTFChars(env, pin_java, NULL);
chiaki_session_set_login_pin(&session->session, (const uint8_t *)pin, strlen(pin));
E->ReleaseStringUTFChars(env, pin_java, pin);
}

@ -25,9 +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 StreamStateQuit(val reason: QuitReason, val reasonString: String?): StreamState()
data class StreamStateLoginPinRequest(val pinIncorrect: Boolean): StreamState()
@ -51,6 +54,7 @@ class StreamSession(val connectInfo: ConnectInfo)
session?.stop()
session?.dispose()
session = null
_state.value = StreamStateIdle
//surfaceTexture?.release()
}
@ -66,6 +70,7 @@ class StreamSession(val connectInfo: ConnectInfo)
try
{
val session = Session(connectInfo)
_state.value = StreamStateConnecting
session.eventCallback = this::eventCallback
session.start()
val surfaceTexture = surfaceTexture
@ -83,6 +88,7 @@ class StreamSession(val connectInfo: ConnectInfo)
{
when(event)
{
is ConnectedEvent -> _state.postValue(StreamStateConnected)
is QuitEvent -> _state.postValue(StreamStateQuit(event.reason, event.reasonString))
is LoginPinRequestEvent -> _state.postValue(StreamStateLoginPinRequest(event.pinIncorrect))
}
@ -114,6 +120,11 @@ class StreamSession(val connectInfo: ConnectInfo)
textureView.surfaceTexture = surfaceTexture
}
fun setLoginPin(pin: String)
{
session?.setLoginPin(pin)
}
@ExperimentalUnsignedTypes
fun dispatchKeyEvent(event: KeyEvent): Boolean
{

@ -40,6 +40,7 @@ class ChiakiNative
@JvmStatic external fun sessionJoin(ptr: Long): Int
@JvmStatic external fun sessionSetSurface(ptr: Long, surface: Surface)
@JvmStatic external fun sessionSetControllerState(ptr: Long, controllerState: ControllerState)
@JvmStatic external fun sessionSetLoginPin(ptr: Long, pin: String)
}
}
@ -98,6 +99,7 @@ class QuitReason(val value: Int)
}
sealed class Event
object ConnectedEvent: Event()
data class LoginPinRequestEvent(val pinIncorrect: Boolean): Event()
data class QuitEvent(val reason: QuitReason, val reasonString: String?): Event()
@ -140,6 +142,11 @@ class Session(connectInfo: ConnectInfo)
eventCallback?.let { it(event) }
}
private fun eventConnected()
{
event(ConnectedEvent)
}
private fun eventLoginPinRequest(pinIncorrect: Boolean)
{
event(LoginPinRequestEvent(pinIncorrect))
@ -159,4 +166,9 @@ class Session(connectInfo: ConnectInfo)
{
ChiakiNative.sessionSetControllerState(nativePtr, controllerState)
}
fun setLoginPin(pin: String)
{
ChiakiNative.sessionSetLoginPin(nativePtr, pin)
}
}

@ -17,19 +17,30 @@
package com.metallic.chiaki.stream
import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Matrix
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import com.metallic.chiaki.*
import com.metallic.chiaki.R
import com.metallic.chiaki.StreamStateIdle
import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.lib.LoginPinRequestEvent
import com.metallic.chiaki.touchcontrols.TouchControlsFragment
import kotlinx.android.synthetic.main.activity_stream.*
private sealed class DialogContents
private object StreamQuitDialog: DialogContents()
private object CreateErrorDialog: DialogContents()
private object PinRequestDialog: DialogContents()
@ExperimentalUnsignedTypes
class StreamActivity : AppCompatActivity()
{
@ -60,9 +71,7 @@ class StreamActivity : AppCompatActivity()
viewModel.session.attachToTextureView(textureView)
viewModel.session.state.observe(this, Observer {
stateTextView.text = if(it != StreamStateIdle) "$it" else ""
})
viewModel.session.state.observe(this, Observer { this.stateChanged(it) })
textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
adjustTextureViewAspect()
@ -89,6 +98,12 @@ class StreamActivity : AppCompatActivity()
viewModel.session.pause()
}
private fun reconnect()
{
viewModel.session.shutdown()
viewModel.session.resume()
}
override fun onWindowFocusChanged(hasFocus: Boolean)
{
super.onWindowFocusChanged(hasFocus)
@ -106,6 +121,92 @@ class StreamActivity : AppCompatActivity()
or View.SYSTEM_UI_FLAG_FULLSCREEN)
}
private var dialogContents: DialogContents? = null
private var dialog: AlertDialog? = null
set(value)
{
field = value
if(value == null)
dialogContents = null
}
private fun stateChanged(state: StreamState)
{
progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE
when(state)
{
is StreamStateQuit ->
{
if(dialogContents != StreamQuitDialog)
{
dialog?.dismiss()
val reasonStr = state.reasonString
val dialog = AlertDialog.Builder(this)
.setMessage(getString(R.string.alert_message_session_quit, state.reason.toString())
+ (if(reasonStr != null) "\n$reasonStr" else ""))
.setPositiveButton(R.string.action_reconnect) { _, _ ->
dialog = null
reconnect()
}
.setNegativeButton(R.string.action_quit_session) { _, _ ->
dialog = null
finish()
}
.create()
dialogContents = StreamQuitDialog
dialog.show()
}
}
is StreamStateCreateError ->
{
if(dialogContents != CreateErrorDialog)
{
dialog?.dismiss()
val dialog = AlertDialog.Builder(this)
.setMessage(getString(R.string.alert_message_session_create_error, state.error.errorCode.toString()))
.setNegativeButton(R.string.action_quit_session) { _, _ ->
dialog = null
finish()
}
.create()
dialogContents = CreateErrorDialog
dialog.show()
}
}
is StreamStateLoginPinRequest ->
{
if(dialogContents != PinRequestDialog)
{
dialog?.dismiss()
val view = layoutInflater.inflate(R.layout.dialog_login_pin, null)
val pinEditText = view.findViewById<EditText>(R.id.pinEditText)
val dialog = AlertDialog.Builder(this)
.setMessage(
if(state.pinIncorrect)
R.string.alert_message_login_pin_request_incorrect
else
R.string.alert_message_login_pin_request)
.setView(view)
.setPositiveButton(R.string.action_login_pin_connect) { _, _ ->
this.dialog = null
viewModel.session.setLoginPin(pinEditText.text.toString())
}
.setNegativeButton(R.string.action_quit_session) { _, _ ->
this.dialog = null
finish()
}
.create()
dialogContents = PinRequestDialog
dialog.show()
}
}
}
}
private fun adjustTextureViewAspect()
{

@ -21,6 +21,7 @@ import androidx.lifecycle.ViewModel
import com.metallic.chiaki.StreamSession
import com.metallic.chiaki.lib.*
@ExperimentalUnsignedTypes
class StreamViewModel: ViewModel()
{
private var connectInfo: ConnectInfo? = null

@ -11,10 +11,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/stateTextView"
android:layout_width="match_parent"
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<EditText
android:id="@+id/pinEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberPassword"
android:singleLine="false" />
</LinearLayout>

@ -1,3 +1,10 @@
<resources>
<string name="app_name">Chiaki</string>
<string name="alert_message_session_quit">Session has quit: %s</string>
<string name="alert_message_session_create_error">Failed to create Session: %s</string>
<string name="alert_message_login_pin_request">Login PIN:</string>
<string name="alert_message_login_pin_request_incorrect">Entered PIN was incorrect!\nLogin PIN:</string>
<string name="action_reconnect">Reconnect</string>
<string name="action_quit_session">Quit</string>
<string name="action_login_pin_connect">Connect</string>
</resources>

@ -10,6 +10,5 @@
<item name="colorPrimaryDark">@color/primary_dark</item>
<item name="colorAccent">@color/accent</item>
<item name="android:windowBackground">@color/stream_background</item>
<item name="android:textColor">@color/stream_text</item>
</style>
</resources>

@ -111,6 +111,7 @@ typedef struct chiaki_audio_stream_info_event_t
typedef enum {
CHIAKI_EVENT_CONNECTED,
CHIAKI_EVENT_LOGIN_PIN_REQUEST,
CHIAKI_EVENT_QUIT
} ChiakiEventType;

@ -276,7 +276,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_set_login_pin(ChiakiSession *sessio
return CHIAKI_ERR_SUCCESS;
}
static void session_send_event(ChiakiSession *session, ChiakiEvent *event)
void chiaki_session_send_event(ChiakiSession *session, ChiakiEvent *event)
{
if(!session->event_cb)
return;
@ -376,7 +376,7 @@ static void *session_thread_func(void *arg)
ChiakiEvent event = { 0 };
event.type = CHIAKI_EVENT_LOGIN_PIN_REQUEST;
event.login_pin_request.pin_incorrect = pin_incorrect;
session_send_event(session, &event);
chiaki_session_send_event(session, &event);
pin_incorrect = true;
chiaki_cond_timedwait_pred(&session->state_cond, &session->state_mutex, UINT64_MAX, session_check_state_pred_pin, session);
@ -502,7 +502,7 @@ quit:
quit_event.type = CHIAKI_EVENT_QUIT;
quit_event.quit.reason = session->quit_reason;
quit_event.quit.reason_str = session->quit_reason_str;
session_send_event(session, &quit_event);
chiaki_session_send_event(session, &quit_event);
return NULL;
#undef CHECK_STOP

@ -55,6 +55,7 @@ typedef enum {
STATE_EXPECT_STREAMINFO
} StreamConnectionState;
void chiaki_session_send_event(ChiakiSession *session, ChiakiEvent *event);
static void stream_connection_takion_cb(ChiakiTakionEvent *event, void *user);
static void stream_connection_takion_data(ChiakiStreamConnection *stream_connection, ChiakiTakionMessageDataType data_type, uint8_t *buf, size_t buf_size);
@ -243,6 +244,14 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio
stream_connection->state = STATE_IDLE;
stream_connection->state_finished = false;
stream_connection->state_failed = false;
ChiakiEvent event = { 0 };
event.type = CHIAKI_EVENT_CONNECTED;
chiaki_mutex_unlock(&stream_connection->state_mutex);
chiaki_session_send_event(session, &event);
err = chiaki_mutex_lock(&stream_connection->state_mutex);
assert(err == CHIAKI_ERR_SUCCESS);
while(true)
{
err = chiaki_cond_timedwait_pred(&stream_connection->state_cond, &stream_connection->state_mutex, HEARTBEAT_INTERVAL_MS, state_finished_cond_check, stream_connection);