diff --git a/.appveyor.yml b/.appveyor.yml index db3c3a0..933f517 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,7 +5,6 @@ image: branches: only: - master - - develop - /^v\d.*$/ - /^deploy-test(-.*)?$/ @@ -37,14 +36,14 @@ for: install: - git submodule update --init --recursive - sudo pip3 install protobuf - - HOMEBREW_NO_AUTO_UPDATE=1 brew install qt@5 opus openssl@1.1 nasm sdl2 protobuf + - brew install qt opus openssl@1.1 nasm sdl2 protobuf - scripts/build-ffmpeg.sh build_script: - - export CMAKE_PREFIX_PATH="`pwd`/ffmpeg-prefix;/usr/local/opt/openssl@1.1;/usr/local/opt/qt@5" + - export CMAKE_PREFIX_PATH="`pwd`/ffmpeg-prefix;/usr/local/opt/openssl@1.1;/usr/local/opt/qt" - scripts/build-common.sh - cp -a build/gui/chiaki.app Chiaki.app - - /usr/local/opt/qt@5/bin/macdeployqt Chiaki.app -dmg + - /usr/local/opt/qt/bin/macdeployqt Chiaki.app -dmg artifacts: - path: Chiaki.dmg diff --git a/.builds/android.yml b/.builds/android.yml index 20cd88b..7b64ab4 100644 --- a/.builds/android.yml +++ b/.builds/android.yml @@ -22,7 +22,7 @@ tasks: sudo docker run \ -v /home/build:/home/build \ -u $(id -u):$(id -g) \ - thestr4ng3r/android:90d826e \ + thestr4ng3r/android:f064ea6 \ /bin/bash -c "cd /home/build/chiaki/android && ./gradlew assembleRelease bundleRelease" cp chiaki/android/app/build/outputs/apk/release/app-release*.apk Chiaki.apk cp chiaki/android/app/build/outputs/bundle/release/app-release*.aab Chiaki.aab diff --git a/.builds/common.yml b/.builds/common.yml index b692b08..46b754f 100644 --- a/.builds/common.yml +++ b/.builds/common.yml @@ -9,47 +9,38 @@ packages: - ninja - protoc - py3-protobuf - - py3-setuptools - opus-dev - qt5-qtbase-dev - qt5-qtsvg-dev - qt5-qtmultimedia-dev - ffmpeg-dev - sdl2-dev - - podman + - sdl2-static # this is gone on alpine edge so might be necessary to remove later + - docker - fuse - - udev - - argp-standalone artifacts: - chiaki.nro - Chiaki.AppImage tasks: - - setup_podman: | - sudo rc-service udev start - sudo rc-service cgroups start - sudo rc-service fuse start # Fuse for AppImages - echo build:100000:65536 | sudo tee /etc/subuid - echo build:100000:65536 | sudo tee /etc/subgid - # https://www.kernel.org/doc/Documentation/networking/tuntap.txt - # for slirp4netns - sudo mkdir -p /dev/net - sudo mknod /dev/net/tun c 10 200 - sudo chmod 0666 /dev/net/tun + - start_docker: | + sudo service docker start + sudo chmod +s /usr/bin/docker # Yes, I know what I am doing + sudo service fuse start # Fuse for AppImages - local_build_and_test: | cd chiaki - cmake -Bbuild -GNinja -DCHIAKI_ENABLE_CLI=ON -DCHIAKI_ENABLE_GUI=ON -DCHIAKI_CLI_ARGP_STANDALONE=ON + cmake -Bbuild -GNinja ninja -C build build/test/chiaki-unit - appimage: | cd chiaki - scripts/run-podman-build-appimage.sh + scripts/run-docker-build-appimage.sh cp appimage/Chiaki.AppImage ../Chiaki.AppImage - switch: | cd chiaki - scripts/switch/run-podman-build-chiaki.sh + scripts/switch/run-docker-build-chiaki.sh cp build_switch/switch/chiaki.nro ../chiaki.nro - bullseye: | cd chiaki - scripts/run-podman-build-bullseye.sh + scripts/run-docker-build-bullseye.sh diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 72109b5..caa9016 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,5 +1,5 @@ -image: freebsd/14.x +image: freebsd/latest sources: - https://git.sr.ht/~thestr4ng3r/chiaki @@ -7,8 +7,7 @@ sources: packages: - cmake - protobuf - - py311-setuptools # should not be needed with nanopb >= 0.4.9 - - py311-protobuf + - py37-protobuf - opus - qt5-core - qt5-qmake diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml index e1595ac..b8785ef 100644 --- a/.builds/openbsd.yml +++ b/.builds/openbsd.yml @@ -1,5 +1,5 @@ -image: openbsd/latest +image: openbsd/6.7 sources: - https://git.sr.ht/~thestr4ng3r/chiaki @@ -7,7 +7,6 @@ sources: packages: - cmake - protobuf - - py3-setuptools # should not be needed with nanopb >= 0.4.9 - py3-protobuf - opus - qtbase diff --git a/.gitignore b/.gitignore index f30ef42..0b9eccd 100644 --- a/.gitignore +++ b/.gitignore @@ -29,5 +29,3 @@ compile_commands.json chiaki.conf /appimage .cache/ -/*.app -/*.dmg diff --git a/.gitmodules b/.gitmodules index 250f8fe..ac87125 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,4 +15,4 @@ url = https://github.com/google/oboe [submodule "switch/borealis"] path = switch/borealis - url = https://git.sr.ht/~thestr4ng3r/borealis + url = https://github.com/natinusala/borealis.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 64caaee..3bddb7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,6 @@ endif() tri_option(CHIAKI_ENABLE_FFMPEG_DECODER "Enable FFMPEG video decoder" ${CHIAKI_FFMPEG_DEFAULT}) tri_option(CHIAKI_ENABLE_PI_DECODER "Enable Raspberry Pi-specific video decoder (requires libraspberrypi0 and libraspberrypi-doc)" AUTO) option(CHIAKI_LIB_ENABLE_MBEDTLS "Use mbedtls instead of OpenSSL as part of Chiaki Lib" OFF) -option(CHIAKI_LIB_MBEDTLS_EXTERNAL_PROJECT "Fetch Mbed TLS instead of using system-provided libs" OFF) option(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT "Use OpenSSL as CMake external project" OFF) option(CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER "Use SDL Gamecontroller for Input" ON) option(CHIAKI_CLI_ARGP_STANDALONE "Search for standalone argp lib for CLI" OFF) @@ -32,7 +31,7 @@ tri_option(CHIAKI_USE_SYSTEM_JERASURE "Use system-provided jerasure instead of s tri_option(CHIAKI_USE_SYSTEM_NANOPB "Use system-provided nanopb instead of submodule" AUTO) set(CHIAKI_VERSION_MAJOR 2) -set(CHIAKI_VERSION_MINOR 2) +set(CHIAKI_VERSION_MINOR 0) set(CHIAKI_VERSION_PATCH 0) set(CHIAKI_VERSION ${CHIAKI_VERSION_MAJOR}.${CHIAKI_VERSION_MINOR}.${CHIAKI_VERSION_PATCH}) @@ -90,20 +89,6 @@ endif() if(CHIAKI_LIB_ENABLE_MBEDTLS) add_definitions(-DCHIAKI_LIB_ENABLE_MBEDTLS) - if(CHIAKI_LIB_MBEDTLS_EXTERNAL_PROJECT) - set(FETCHCONTENT_QUIET CACHE BOOL FALSE) - include(FetchContent) - set(ENABLE_TESTING CACHE INTERNAL OFF) - set(ENABLE_PROGRAMS CACHE INTERNAL OFF) - set(USE_SHARED_MBEDTLS_LIBRARY CACHE INTERNAL OFF) - FetchContent_Declare( - mbedtls - GIT_REPOSITORY https://github.com/Mbed-TLS/mbedtls.git - GIT_TAG 8b3f26a5ac38d4fdccbc5c5366229f3e01dafcc0 # v2.28.0 - GIT_PROGRESS TRUE - ) - FetchContent_MakeAvailable(mbedtls) - endif() endif() if(CHIAKI_ENABLE_FFMPEG_DECODER) @@ -150,30 +135,21 @@ if(CHIAKI_ENABLE_CLI) add_subdirectory(cli) endif() -if(CHIAKI_ENABLE_GUI AND CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER) - find_package(SDL2 MODULE REQUIRED) -endif() - if(CHIAKI_ENABLE_SETSU) - if(CHIAKI_ENABLE_SETSU STREQUAL AUTO AND SDL2_FOUND AND (SDL2_VERSION_MINOR GREATER 0 OR SDL2_VERSION_PATCH GREATER_EQUAL 14)) - message(STATUS "SDL version ${SDL2_VERSION} is >= 2.0.14, disabling Setsu") - set(CHIAKI_ENABLE_SETSU OFF) + find_package(Udev QUIET) + find_package(Evdev QUIET) + if(Udev_FOUND AND Evdev_FOUND) + set(CHIAKI_ENABLE_SETSU ON) else() - find_package(Udev QUIET) - find_package(Evdev QUIET) - if(Udev_FOUND AND Evdev_FOUND) - set(CHIAKI_ENABLE_SETSU ON) - else() - if(NOT CHIAKI_ENABLE_SETSU STREQUAL AUTO) - message(FATAL_ERROR " - CHIAKI_ENABLE_SETSU is set to ON, but its dependencies (udev and evdev) could not be resolved. - Keep in mind that setsu is only supported on Linux!") - endif() - set(CHIAKI_ENABLE_SETSU OFF) - endif() - if(CHIAKI_ENABLE_SETSU) - add_subdirectory(setsu) + if(NOT CHIAKI_ENABLE_SETSU STREQUAL AUTO) + message(FATAL_ERROR " +CHIAKI_ENABLE_SETSU is set to ON, but its dependencies (udev and evdev) could not be resolved. +Keep in mind that setsu is only supported on Linux!") endif() + set(CHIAKI_ENABLE_SETSU OFF) + endif() + if(CHIAKI_ENABLE_SETSU) + add_subdirectory(setsu) endif() endif() @@ -184,6 +160,7 @@ else() endif() if(CHIAKI_ENABLE_GUI) + #add_subdirectory(setsu) add_subdirectory(gui) endif() diff --git a/README.md b/README.md index 1a94b66..b84b73d 100644 --- a/README.md +++ b/README.md @@ -8,35 +8,33 @@ [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/c81ogebvsmo43dd3?svg=true)](https://ci.appveyor.com/project/thestr4ng3r/chiaki) [![builds.sr.ht Status](https://builds.sr.ht/~thestr4ng3r/chiaki.svg)](https://builds.sr.ht/~thestr4ng3r/chiaki?) Chiaki is a Free and Open Source Software Client for PlayStation 4 and PlayStation 5 Remote Play -for Linux, FreeBSD, OpenBSD, NetBSD, Android, macOS, Windows, Nintendo Switch and potentially even more platforms. - -## Project Status and Contributing - -As all relevant features are implemented, this project is considered to be finished and in maintenance mode only. -No major updates are planned and contributions are only accepted in special cases such as security issues. -The objective is to keep a stable base and not break existing support for less mainstream platforms such as BSDs. - -**For a more active, fast moving and community-oriented project, refer -to [chiaki-ng](https://streetpea.github.io/chiaki-ng/) ("next generation"). -If you would like to contribute, this will likely also be the best place to do so.** +for Linux, FreeBSD, OpenBSD, Android, macOS, Windows, Nintendo Switch and potentially even more platforms. ![Screenshot](assets/screenshot.png) +## Features + +Everything necessary for a full streaming session, including the initial +registration and wakeup of the console, is supported. +The following features however are yet to be implemented: +* Rumble +* Accelerometer/Gyroscope + ## Installing -You can either download a pre-built release or build Chiaki from source. +You can either download a pre-built release (easier) or build Chiaki from source. ### Downloading a Release -Builds are provided for Linux, Android, macOS, Nintendo Switch and Windows. +Builds are provided for Linux, Android, macOS and Windows. You can download them [here](https://git.sr.ht/~thestr4ng3r/chiaki/refs). * **Linux**: The provided file is an [AppImage](https://appimage.org/). Simply make it executable (`chmod +x .AppImage`) and run it. -* **Android**: Install from [F-Droid](https://f-droid.org/packages/com.metallic.chiaki/) or download the APK from Sourcehut. +* **Android**: Install from [Google Play](https://play.google.com/store/apps/details?id=com.metallic.chiaki), [F-Droid](https://f-droid.org/packages/com.metallic.chiaki/) or download the APK from Sourcehut. * **macOS**: Drag the application from the `.dmg` into your Applications folder. * **Windows**: Extract the `.zip` file and execute `chiaki.exe`. -* **Switch**: Download the `.nro` file and copy it into the `switch/` directory on your SD card. +* **Switch**: Follow README specific [instructions](./switch/README.md) ### Building from Source @@ -49,8 +47,8 @@ cmake .. make ``` -For more detailed platform-specific instructions, see [doc/platform-build.md](doc/platform-build.md) or [switch/](./switch/README.md) for Nintendo Switch. - +For more detailed platform-specific instructions, see [doc/platform-build.md](doc/platform-build.md). +in ## Usage If your Console is on your local network, is turned on or in standby mode and does not have Discovery explicitly disabled, Chiaki should find it. @@ -73,6 +71,13 @@ Settings -> Remote Play -> Add Device, or on a PS5: Settings -> System -> Remote You can now double-click your Console in Chiaki's main window to start Remote Play. +## Joining the Community or Getting Help + +There are official groups for Chiaki on Telegram and IRC. They are bridged so you can join whichever you like: + +- **Telegram:** https://t.me/chiakitg +- **IRC:** #chiaki on irc.freenode.net + ## Acknowledgements This project has only been made possible because of the following Open Source projects: diff --git a/android/app/build.gradle b/android/app/build.gradle index 21a89f3..ee70e84 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-parcelize' +apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' def rootCMakeLists = "../../CMakeLists.txt" @@ -18,12 +18,13 @@ def chiakiVersion = "$chiakiVersionMajor.$chiakiVersionMinor.$chiakiVersionPatch println("Determined Chiaki Version: $chiakiVersion") android { - compileSdkVersion 33 + compileSdkVersion 30 + buildToolsVersion "30.0.2" defaultConfig { applicationId "com.metallic.chiaki" minSdkVersion 21 - targetSdkVersion 33 - versionCode 12 + targetSdkVersion 30 + versionCode 8 versionName chiakiVersion externalNativeBuild { cmake { @@ -32,16 +33,11 @@ android { "-DCHIAKI_ENABLE_GUI=OFF", "-DCHIAKI_ENABLE_SETSU=OFF", "-DCHIAKI_ENABLE_ANDROID=ON", - "-DCHIAKI_ENABLE_FFMPEG_DECODER=OFF", - "-DCHIAKI_ENABLE_PI_DECODER=OFF", "-DCHIAKI_LIB_ENABLE_OPUS=OFF", "-DCHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT=ON" } } } - buildFeatures { - viewBinding true - } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -51,7 +47,7 @@ android { } externalNativeBuild { cmake { - version "3.22.1" + version "3.10.2+" path rootCMakeLists } } @@ -65,7 +61,6 @@ android { } } - Properties properties = new Properties() def propertiesFile = file("../local.properties") if (propertiesFile.exists()) { @@ -91,26 +86,31 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { } } +androidExtensions { + // for @Parcelize + experimental = true +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.6.0' - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation 'androidx.preference:preference:1.2.0' - implementation 'com.google.android.material:material:1.8.0' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.preference:preference:1.1.0' + implementation 'com.google.android.material:material:1.1.0-beta02' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' - implementation 'androidx.lifecycle:lifecycle-reactivestreams:2.5.1' - implementation "io.reactivex.rxjava2:rxjava:2.2.20" + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' + implementation 'androidx.lifecycle:lifecycle-reactivestreams:2.2.0' + implementation "io.reactivex.rxjava2:rxjava:2.2.12" implementation "io.reactivex.rxjava2:rxkotlin:2.4.0" implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' - def room_version = "2.5.0" + def room_version = "2.2.4" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-rxjava2:$room_version" - implementation "com.squareup.moshi:moshi:1.14.0" - kapt "com.squareup.moshi:moshi-kotlin-codegen:1.14.0" + implementation "com.squareup.moshi:moshi:1.9.2" + kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.2" } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a0d28cb..14b0466 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,8 +5,6 @@ - - + android:configChanges="keyboard|keyboardHidden|orientation|screenSize"> diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index 9b14b60..35543ad 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -110,9 +110,9 @@ JNIEXPORT jstring JNICALL JNI_FCN(quitReasonToString)(JNIEnv *env, jobject obj, return E->NewStringUTF(env, chiaki_quit_reason_string((ChiakiQuitReason)value)); } -JNIEXPORT jboolean JNICALL JNI_FCN(quitReasonIsError)(JNIEnv *env, jobject obj, jint value) +JNIEXPORT jboolean JNICALL JNI_FCN(quitReasonIsStopped)(JNIEnv *env, jobject obj, jint value) { - return chiaki_quit_reason_is_error(value); + return value == CHIAKI_QUIT_REASON_STOPPED; } JNIEXPORT jobject JNICALL JNI_FCN(videoProfilePreset)(JNIEnv *env, jobject obj, jint resolution_preset, jint fps_preset, jobject codec) @@ -133,7 +133,6 @@ typedef struct android_chiaki_session_t jmethodID java_session_event_connected_meth; jmethodID java_session_event_login_pin_request_meth; jmethodID java_session_event_quit_meth; - jmethodID java_session_event_rumble_meth; jfieldID java_controller_state_buttons; jfieldID java_controller_state_l2_state; jfieldID java_controller_state_r2_state; @@ -141,20 +140,6 @@ typedef struct android_chiaki_session_t jfieldID java_controller_state_left_y; jfieldID java_controller_state_right_x; jfieldID java_controller_state_right_y; - jfieldID java_controller_state_touches; - jfieldID java_controller_state_gyro_x; - jfieldID java_controller_state_gyro_y; - jfieldID java_controller_state_gyro_z; - jfieldID java_controller_state_accel_x; - jfieldID java_controller_state_accel_y; - jfieldID java_controller_state_accel_z; - jfieldID java_controller_state_orient_x; - jfieldID java_controller_state_orient_y; - jfieldID java_controller_state_orient_z; - jfieldID java_controller_state_orient_w; - jfieldID java_controller_touch_x; - jfieldID java_controller_touch_y; - jfieldID java_controller_touch_id; AndroidChiakiVideoDecoder video_decoder; AndroidChiakiAudioDecoder audio_decoder; @@ -193,14 +178,6 @@ static void android_chiaki_event_cb(ChiakiEvent *event, void *user) free(reason_str); break; } - case CHIAKI_EVENT_RUMBLE: - E->CallVoidMethod(env, session->java_session, - session->java_session_event_rumble_meth, - (jint)event->rumble.left, - (jint)event->rumble.right); - break; - default: - break; } (*global_vm)->DetachCurrentThread(global_vm); @@ -319,7 +296,6 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject 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"); - session->java_session_event_rumble_meth = E->GetMethodID(env, session->java_session_class, "eventRumble", "(II)V"); jclass controller_state_class = E->FindClass(env, BASE_PACKAGE"/ControllerState"); session->java_controller_state_buttons = E->GetFieldID(env, controller_state_class, "buttons", "I"); @@ -329,22 +305,6 @@ JNIEXPORT void JNICALL JNI_FCN(sessionCreate)(JNIEnv *env, jobject obj, jobject session->java_controller_state_left_y = E->GetFieldID(env, controller_state_class, "leftY", "S"); session->java_controller_state_right_x = E->GetFieldID(env, controller_state_class, "rightX", "S"); session->java_controller_state_right_y = E->GetFieldID(env, controller_state_class, "rightY", "S"); - session->java_controller_state_touches = E->GetFieldID(env, controller_state_class, "touches", "[L"BASE_PACKAGE"/ControllerTouch;"); - session->java_controller_state_gyro_x = E->GetFieldID(env, controller_state_class, "gyroX", "F"); - session->java_controller_state_gyro_y = E->GetFieldID(env, controller_state_class, "gyroY", "F"); - session->java_controller_state_gyro_z = E->GetFieldID(env, controller_state_class, "gyroZ", "F"); - session->java_controller_state_accel_x = E->GetFieldID(env, controller_state_class, "accelX", "F"); - session->java_controller_state_accel_y = E->GetFieldID(env, controller_state_class, "accelY", "F"); - session->java_controller_state_accel_z = E->GetFieldID(env, controller_state_class, "accelZ", "F"); - session->java_controller_state_orient_x = E->GetFieldID(env, controller_state_class, "orientX", "F"); - session->java_controller_state_orient_y = E->GetFieldID(env, controller_state_class, "orientY", "F"); - session->java_controller_state_orient_z = E->GetFieldID(env, controller_state_class, "orientZ", "F"); - session->java_controller_state_orient_w = E->GetFieldID(env, controller_state_class, "orientW", "F"); - - jclass controller_touch_class = E->FindClass(env, BASE_PACKAGE"/ControllerTouch"); - session->java_controller_touch_x = E->GetFieldID(env, controller_touch_class, "x", "S"); - session->java_controller_touch_y = E->GetFieldID(env, controller_touch_class, "y", "S"); - session->java_controller_touch_id = E->GetFieldID(env, controller_touch_class, "id", "B"); chiaki_session_set_event_cb(&session->session, android_chiaki_event_cb, session); chiaki_session_set_video_sample_cb(&session->session, android_chiaki_video_decoder_video_sample, &session->video_decoder); @@ -413,8 +373,7 @@ JNIEXPORT void JNICALL JNI_FCN(sessionSetSurface)(JNIEnv *env, jobject obj, jlon JNIEXPORT void JNICALL JNI_FCN(sessionSetControllerState)(JNIEnv *env, jobject obj, jlong ptr, jobject controller_state_java) { AndroidChiakiSession *session = (AndroidChiakiSession *)ptr; - ChiakiControllerState controller_state; - chiaki_controller_state_set_idle(&controller_state); + ChiakiControllerState controller_state = { 0 }; controller_state.buttons = (uint32_t)E->GetIntField(env, controller_state_java, session->java_controller_state_buttons); controller_state.l2_state = (uint8_t)E->GetByteField(env, controller_state_java, session->java_controller_state_l2_state); controller_state.r2_state = (uint8_t)E->GetByteField(env, controller_state_java, session->java_controller_state_r2_state); @@ -422,34 +381,6 @@ JNIEXPORT void JNICALL JNI_FCN(sessionSetControllerState)(JNIEnv *env, jobject o controller_state.left_y = (int16_t)E->GetShortField(env, controller_state_java, session->java_controller_state_left_y); 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); - jobjectArray touch_array = E->GetObjectField(env, controller_state_java, session->java_controller_state_touches); - size_t touch_array_len = (size_t)E->GetArrayLength(env, touch_array); - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) - { - if(i < touch_array_len) - { - jobject touch = E->GetObjectArrayElement(env, touch_array, i); - controller_state.touches[i].x = (uint16_t)E->GetShortField(env, touch, session->java_controller_touch_x); - controller_state.touches[i].y = (uint16_t)E->GetShortField(env, touch, session->java_controller_touch_y); - controller_state.touches[i].id = (int8_t)E->GetByteField(env, touch, session->java_controller_touch_id); - } - else - { - controller_state.touches[i].x = 0; - controller_state.touches[i].y = 0; - controller_state.touches[i].id = -1; - } - } - controller_state.gyro_x = E->GetFloatField(env, controller_state_java, session->java_controller_state_gyro_x); - controller_state.gyro_y = E->GetFloatField(env, controller_state_java, session->java_controller_state_gyro_y); - controller_state.gyro_z = E->GetFloatField(env, controller_state_java, session->java_controller_state_gyro_z); - controller_state.accel_x = E->GetFloatField(env, controller_state_java, session->java_controller_state_accel_x); - controller_state.accel_y = E->GetFloatField(env, controller_state_java, session->java_controller_state_accel_y); - controller_state.accel_z = E->GetFloatField(env, controller_state_java, session->java_controller_state_accel_z); - controller_state.orient_x = E->GetFloatField(env, controller_state_java, session->java_controller_state_orient_x); - controller_state.orient_y = E->GetFloatField(env, controller_state_java, session->java_controller_state_orient_y); - controller_state.orient_z = E->GetFloatField(env, controller_state_java, session->java_controller_state_orient_z); - controller_state.orient_w = E->GetFloatField(env, controller_state_java, session->java_controller_state_orient_w); chiaki_session_set_controller_state(&session->session, &controller_state); } diff --git a/android/app/src/main/cpp/oboe b/android/app/src/main/cpp/oboe index 8740d0f..0ab5b12 160000 --- a/android/app/src/main/cpp/oboe +++ b/android/app/src/main/cpp/oboe @@ -1 +1 @@ -Subproject commit 8740d0fc321a55489dbbf6067298201b7d2e106d +Subproject commit 0ab5b12a5bc3630a3d6c83b20eed2a669ebf7a24 diff --git a/android/app/src/main/cpp/video-decoder.c b/android/app/src/main/cpp/video-decoder.c index 1146ad8..d57623d 100644 --- a/android/app/src/main/cpp/video-decoder.c +++ b/android/app/src/main/cpp/video-decoder.c @@ -26,34 +26,29 @@ ChiakiErrorCode android_chiaki_video_decoder_init(AndroidChiakiVideoDecoder *dec return chiaki_mutex_init(&decoder->codec_mutex, false); } -static void kill_decoder(AndroidChiakiVideoDecoder *decoder) -{ - chiaki_mutex_lock(&decoder->codec_mutex); - decoder->shutdown_output = true; - ssize_t codec_buf_index = AMediaCodec_dequeueInputBuffer(decoder->codec, 1000); - if(codec_buf_index >= 0) - { - CHIAKI_LOGI(decoder->log, "Video Decoder sending EOS buffer"); - AMediaCodec_queueInputBuffer(decoder->codec, (size_t)codec_buf_index, 0, 0, decoder->timestamp_cur++, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); - AMediaCodec_stop(decoder->codec); - chiaki_mutex_unlock(&decoder->codec_mutex); - chiaki_thread_join(&decoder->output_thread, NULL); - } - else - { - CHIAKI_LOGE(decoder->log, "Failed to get input buffer for shutting down Video Decoder!"); - AMediaCodec_stop(decoder->codec); - chiaki_mutex_unlock(&decoder->codec_mutex); - } - AMediaCodec_delete(decoder->codec); - decoder->codec = NULL; - decoder->shutdown_output = false; -} - void android_chiaki_video_decoder_fini(AndroidChiakiVideoDecoder *decoder) { if(decoder->codec) - kill_decoder(decoder); + { + chiaki_mutex_lock(&decoder->codec_mutex); + decoder->shutdown_output = true; + ssize_t codec_buf_index = AMediaCodec_dequeueInputBuffer(decoder->codec, -1); + if(codec_buf_index >= 0) + { + CHIAKI_LOGI(decoder->log, "Video Decoder sending EOS buffer"); + AMediaCodec_queueInputBuffer(decoder->codec, (size_t)codec_buf_index, 0, 0, decoder->timestamp_cur++, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + AMediaCodec_stop(decoder->codec); + chiaki_mutex_unlock(&decoder->codec_mutex); + chiaki_thread_join(&decoder->output_thread, NULL); + } + else + { + CHIAKI_LOGE(decoder->log, "Failed to get input buffer for shutting down Video Decoder!"); + AMediaCodec_stop(decoder->codec); + chiaki_mutex_unlock(&decoder->codec_mutex); + } + AMediaCodec_delete(decoder->codec); + } chiaki_mutex_fini(&decoder->codec_mutex); } @@ -61,16 +56,6 @@ void android_chiaki_video_decoder_set_surface(AndroidChiakiVideoDecoder *decoder { chiaki_mutex_lock(&decoder->codec_mutex); - if(!surface) - { - if(decoder->codec) - { - kill_decoder(decoder); - CHIAKI_LOGI(decoder->log, "Decoder shut down after surface was removed"); - } - return; - } - if(decoder->codec) { #if __ANDROID_API__ >= 23 diff --git a/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt b/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt index 8398f62..4d4738c 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/AppDatabase.kt @@ -23,11 +23,9 @@ val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE registered_host RENAME ps4_mac TO server_mac") + database.execSQL("ALTER TABLE registered_host RENAME ps4_nickname TO server_nickname") database.execSQL("ALTER TABLE registered_host ADD target INTEGER NOT NULL DEFAULT 1000") - database.execSQL("CREATE TABLE `new_registered_host` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `target` INTEGER NOT NULL, `ap_ssid` TEXT, `ap_bssid` TEXT, `ap_key` TEXT, `ap_name` TEXT, `server_mac` INTEGER NOT NULL, `server_nickname` TEXT, `rp_regist_key` BLOB NOT NULL, `rp_key_type` INTEGER NOT NULL, `rp_key` BLOB NOT NULL)"); - database.execSQL("INSERT INTO `new_registered_host` SELECT `id`, `target`, `ap_ssid`, `ap_bssid`, `ap_key`, `ap_name`, `ps4_mac`, `ps4_nickname`, `rp_regist_key`, `rp_key_type`, `rp_key` FROM `registered_host`") - database.execSQL("DROP TABLE registered_host") - database.execSQL("ALTER TABLE new_registered_host RENAME TO registered_host") } } diff --git a/android/app/src/main/java/com/metallic/chiaki/common/ManualHost.kt b/android/app/src/main/java/com/metallic/chiaki/common/ManualHost.kt index 7065610..5825000 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/ManualHost.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/ManualHost.kt @@ -3,7 +3,7 @@ package com.metallic.chiaki.common import androidx.room.* -import androidx.room.ForeignKey.Companion.SET_NULL +import androidx.room.ForeignKey.SET_NULL import io.reactivex.Completable import io.reactivex.Flowable import io.reactivex.Single diff --git a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt index 3c4f2f9..c9691b5 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/Preferences.kt @@ -68,26 +68,11 @@ class Preferences(context: Context) get() = sharedPreferences.getBoolean(onScreenControlsEnabledKey, true) set(value) { sharedPreferences.edit().putBoolean(onScreenControlsEnabledKey, value).apply() } - val touchpadOnlyEnabledKey get() = resources.getString(R.string.preferences_touchpad_only_enabled_key) + val touchpadOnlyEnabledKey get() = resources.getString(R.string.preferences_touchpad_only_key) var touchpadOnlyEnabled get() = sharedPreferences.getBoolean(touchpadOnlyEnabledKey, false) set(value) { sharedPreferences.edit().putBoolean(touchpadOnlyEnabledKey, value).apply() } - val rumbleEnabledKey get() = resources.getString(R.string.preferences_rumble_enabled_key) - var rumbleEnabled - get() = sharedPreferences.getBoolean(rumbleEnabledKey, true) - set(value) { sharedPreferences.edit().putBoolean(rumbleEnabledKey, value).apply() } - - val motionEnabledKey get() = resources.getString(R.string.preferences_motion_enabled_key) - var motionEnabled - get() = sharedPreferences.getBoolean(motionEnabledKey, true) - set(value) { sharedPreferences.edit().putBoolean(motionEnabledKey, value).apply() } - - val buttonHapticEnabledKey get() = resources.getString(R.string.preferences_button_haptic_enabled_key) - var buttonHapticEnabled - get() = sharedPreferences.getBoolean(buttonHapticEnabledKey, true) - set(value) { sharedPreferences.edit().putBoolean(buttonHapticEnabledKey, value).apply() } - val logVerboseKey get() = resources.getString(R.string.preferences_log_verbose_key) var logVerbose get() = sharedPreferences.getBoolean(logVerboseKey, false) diff --git a/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt b/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt index d920a8c..b96d88d 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt @@ -3,7 +3,7 @@ package com.metallic.chiaki.common import androidx.room.* -import androidx.room.ColumnInfo.Companion.BLOB +import androidx.room.ColumnInfo.BLOB import com.metallic.chiaki.lib.RegistHost import com.metallic.chiaki.lib.Target import io.reactivex.Completable diff --git a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt index 74257ac..8334dc5 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/SerializedSettings.kt @@ -25,8 +25,6 @@ import io.reactivex.rxkotlin.addTo import io.reactivex.schedulers.Schedulers import okio.Buffer import okio.Okio -import okio.buffer -import okio.source import java.io.File import java.io.IOException @@ -166,7 +164,7 @@ fun importSettingsFromUri(activity: Activity, uri: Uri, disposable: CompositeDis try { val inputStream = activity.contentResolver.openInputStream(uri) ?: throw IOException() - val buffer = inputStream.source().buffer() + val buffer = Okio.buffer(Okio.source(inputStream)) val reader = JsonReader.of(buffer) val adapter = moshi().serializedSettingsAdapter() diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index bb0b0a6..d638cb2 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -3,7 +3,8 @@ package com.metallic.chiaki.lib import android.os.Parcelable import android.util.Log import android.view.Surface -import kotlinx.parcelize.Parcelize +import kotlinx.android.parcel.IgnoredOnParcel +import kotlinx.android.parcel.Parcelize import java.lang.Exception import java.net.InetSocketAddress import kotlin.math.abs @@ -83,14 +84,14 @@ private class ChiakiNative } @JvmStatic external fun errorCodeToString(value: Int): String @JvmStatic external fun quitReasonToString(value: Int): String - @JvmStatic external fun quitReasonIsError(value: Int): Boolean + @JvmStatic external fun quitReasonIsStopped(value: Int): Boolean @JvmStatic external fun videoProfilePreset(resolutionPreset: Int, fpsPreset: Int, codec: Codec): ConnectVideoProfile @JvmStatic external fun sessionCreate(result: CreateResult, connectInfo: ConnectInfo, logFile: String?, logVerbose: Boolean, javaSession: Session) @JvmStatic external fun sessionFree(ptr: Long) @JvmStatic external fun sessionStart(ptr: Long): Int @JvmStatic external fun sessionStop(ptr: Long): Int @JvmStatic external fun sessionJoin(ptr: Long): Int - @JvmStatic external fun sessionSetSurface(ptr: Long, surface: Surface?) + @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) @@ -149,14 +150,6 @@ class ChiakiLog(val levelMask: Int, val callback: (level: Int, text: String) -> private fun maxAbs(a: Short, b: Short) = if(abs(a.toInt()) > abs(b.toInt())) a else b -private val CONTROLLER_TOUCHES_MAX = 2 // must be the same as CHIAKI_CONTROLLER_TOUCHES_MAX - -data class ControllerTouch( - var x: UShort = 0U, - var y: UShort = 0U, - var id: Byte = -1 // -1 = up -) - data class ControllerState constructor( var buttons: UInt = 0U, var l2State: UByte = 0U, @@ -164,40 +157,26 @@ data class ControllerState constructor( var leftX: Short = 0, var leftY: Short = 0, var rightX: Short = 0, - var rightY: Short = 0, - private var touchIdNext: UByte = 0U, - var touches: Array = arrayOf(ControllerTouch(), ControllerTouch()), - var gyroX: Float = 0.0f, - var gyroY: Float = 0.0f, - var gyroZ: Float = 0.0f, - var accelX: Float = 0.0f, - var accelY: Float = 1.0f, - var accelZ: Float = 0.0f, - var orientX: Float = 0.0f, - var orientY: Float = 0.0f, - var orientZ: Float = 0.0f, - var orientW: Float = 1.0f + var rightY: Short = 0 ){ companion object { val BUTTON_CROSS = (1 shl 0).toUInt() val BUTTON_MOON = (1 shl 1).toUInt() - val BUTTON_BOX = (1 shl 2).toUInt() - val BUTTON_PYRAMID = (1 shl 3).toUInt() + val BUTTON_BOX = (1 shl 2).toUInt() + val BUTTON_PYRAMID = (1 shl 3).toUInt() val BUTTON_DPAD_LEFT = (1 shl 4).toUInt() val BUTTON_DPAD_RIGHT = (1 shl 5).toUInt() - val BUTTON_DPAD_UP = (1 shl 6).toUInt() + val BUTTON_DPAD_UP = (1 shl 6).toUInt() val BUTTON_DPAD_DOWN = (1 shl 7).toUInt() - val BUTTON_L1 = (1 shl 8).toUInt() - val BUTTON_R1 = (1 shl 9).toUInt() + val BUTTON_L1 = (1 shl 8).toUInt() + val BUTTON_R1 = (1 shl 9).toUInt() val BUTTON_L3 = (1 shl 10).toUInt() val BUTTON_R3 = (1 shl 11).toUInt() - val BUTTON_OPTIONS = (1 shl 12).toUInt() + val BUTTON_OPTIONS = (1 shl 12).toUInt() val BUTTON_SHARE = (1 shl 13).toUInt() - val BUTTON_TOUCHPAD = (1 shl 14).toUInt() + val BUTTON_TOUCHPAD = (1 shl 14).toUInt() val BUTTON_PS = (1 shl 15).toUInt() - val TOUCHPAD_WIDTH: UShort = 1920U - val TOUCHPAD_HEIGHT: UShort = 942U } infix fun or(o: ControllerState) = ControllerState( @@ -207,116 +186,24 @@ data class ControllerState constructor( leftX = maxAbs(leftX, o.leftX), leftY = maxAbs(leftY, o.leftY), rightX = maxAbs(rightX, o.rightX), - rightY = maxAbs(rightY, o.rightY), - touches = touches.zip(o.touches) { a, b -> if(a.id >= 0) a else b }.toTypedArray(), - gyroX = gyroX, - gyroY = gyroY, - gyroZ = gyroZ, - accelX = accelX, - accelY = accelY, - accelZ = accelZ, - orientX = orientX, - orientY = orientY, - orientZ = orientZ, - orientW = orientW + rightY = maxAbs(rightY, o.rightY) ) - - override fun equals(other: Any?): Boolean - { - if(this === other) return true - if(javaClass != other?.javaClass) return false - - other as ControllerState - - if(buttons != other.buttons) return false - if(l2State != other.l2State) return false - if(r2State != other.r2State) return false - if(leftX != other.leftX) return false - if(leftY != other.leftY) return false - if(rightX != other.rightX) return false - if(rightY != other.rightY) return false - if(touchIdNext != other.touchIdNext) return false - if(!touches.contentEquals(other.touches)) return false - if(gyroX != other.gyroX) return false - if(gyroY != other.gyroY) return false - if(gyroZ != other.gyroZ) return false - if(accelX != other.accelX) return false - if(accelY != other.accelY) return false - if(accelZ != other.accelZ) return false - if(orientX != other.orientX) return false - if(orientY != other.orientY) return false - if(orientZ != other.orientZ) return false - if(orientW != other.orientW) return false - - return true - } - - override fun hashCode(): Int - { - var result = buttons.hashCode() - result = 31 * result + l2State.hashCode() - result = 31 * result + r2State.hashCode() - result = 31 * result + leftX - result = 31 * result + leftY - result = 31 * result + rightX - result = 31 * result + rightY - result = 31 * result + touchIdNext.hashCode() - result = 31 * result + touches.contentHashCode() - result = 31 * result + gyroX.hashCode() - result = 31 * result + gyroY.hashCode() - result = 31 * result + gyroZ.hashCode() - result = 31 * result + accelX.hashCode() - result = 31 * result + accelY.hashCode() - result = 31 * result + accelZ.hashCode() - result = 31 * result + orientX.hashCode() - result = 31 * result + orientY.hashCode() - result = 31 * result + orientZ.hashCode() - result = 31 * result + orientW.hashCode() - return result - } - - fun startTouch(x: UShort, y: UShort): UByte? = - touches - .find { it.id < 0 } - ?.also { - it.id = touchIdNext.toByte() - it.x = x - it.y = y - touchIdNext = ((touchIdNext + 1U) and 0x7fU).toUByte() - }?.id?.toUByte() - - fun stopTouch(id: UByte) - { - touches.find { - it.id >= 0 && it.id == id.toByte() - }?.let { - it.id = -1 - } - } - - fun setTouchPos(id: UByte, x: UShort, y: UShort): Boolean - = touches.find { - it.id >= 0 && it.id == id.toByte() - }?.let { - val r = it.x != x || it.y != y - it.x = x - it.y = y - r - } ?: false } class QuitReason(val value: Int) { override fun toString() = ChiakiNative.quitReasonToString(value) - val isError = ChiakiNative.quitReasonIsError(value) + /** + * whether the reason is CHIAKI_QUIT_REASON_STOPPED + */ + val isStopped = ChiakiNative.quitReasonIsStopped(value) } sealed class Event object ConnectedEvent: Event() data class LoginPinRequestEvent(val pinIncorrect: Boolean): Event() data class QuitEvent(val reason: QuitReason, val reasonString: String?): Event() -data class RumbleEvent(val left: UByte, val right: UByte): Event() class CreateError(val errorCode: ErrorCode): Exception("Failed to create a native object: $errorCode") @@ -372,12 +259,7 @@ class Session(connectInfo: ConnectInfo, logFile: String?, logVerbose: Boolean) event(QuitEvent(QuitReason(reasonValue), reasonString)) } - private fun eventRumble(left: Int, right: Int) - { - event(RumbleEvent(left.toUByte(), right.toUByte())) - } - - fun setSurface(surface: Surface?) + fun setSurface(surface: Surface) { ChiakiNative.sessionSetSurface(nativePtr, surface) } diff --git a/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt index 465a2a7..0bd844e 100644 --- a/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/main/DisplayHostRecyclerViewAdapter.kt @@ -3,7 +3,6 @@ package com.metallic.chiaki.main import android.util.Log -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.animation.AnimationUtils @@ -17,8 +16,8 @@ import com.metallic.chiaki.common.DiscoveredDisplayHost import com.metallic.chiaki.common.DisplayHost import com.metallic.chiaki.common.ManualDisplayHost import com.metallic.chiaki.common.ext.inflate -import com.metallic.chiaki.databinding.ItemDisplayHostBinding import com.metallic.chiaki.lib.DiscoveryHost +import kotlinx.android.synthetic.main.item_display_host.view.* class DisplayHostDiffCallback(val old: List, val new: List): DiffUtil.Callback() { @@ -43,10 +42,10 @@ class DisplayHostRecyclerViewAdapter( diff.dispatchUpdatesTo(this) } - class ViewHolder(val binding: ItemDisplayHostBinding): RecyclerView.ViewHolder(binding.root) + class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) - = ViewHolder(ItemDisplayHostBinding.inflate(LayoutInflater.from(parent.context), parent, false)) + = ViewHolder(parent.inflate(R.layout.item_display_host)) override fun getItemCount() = hosts.count() @@ -54,7 +53,7 @@ class DisplayHostRecyclerViewAdapter( { val context = holder.itemView.context val host = hosts[position] - holder.binding.also { + holder.itemView.also { it.nameTextView.text = host.name it.hostTextView.text = context.getString(R.string.display_host_host, host.host) val id = host.id @@ -88,7 +87,7 @@ class DisplayHostRecyclerViewAdapter( else -> R.drawable.ic_console } ) - it.root.setOnClickListener { clickCallback(host) } + it.setOnClickListener { clickCallback(host) } val canWakeup = host.registeredHost != null val canEditDelete = host is ManualDisplayHost diff --git a/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt b/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt index 5bf1f49..4fd8178 100644 --- a/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/main/MainActivity.kt @@ -17,54 +17,52 @@ import com.metallic.chiaki.R import com.metallic.chiaki.common.* import com.metallic.chiaki.common.ext.putRevealExtra import com.metallic.chiaki.common.ext.viewModelFactory -import com.metallic.chiaki.databinding.ActivityMainBinding import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.DiscoveryHost import com.metallic.chiaki.manualconsole.EditManualConsoleActivity import com.metallic.chiaki.regist.RegistActivity import com.metallic.chiaki.settings.SettingsActivity import com.metallic.chiaki.stream.StreamActivity +import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel - private lateinit var binding: ActivityMainBinding private var discoveryMenuItem: MenuItem? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_main) title = "" - setSupportActionBar(binding.toolbar) + setSupportActionBar(toolbar) - binding.floatingActionButton.setOnClickListener { - expandFloatingActionButton(!binding.floatingActionButton.isExpanded) + floatingActionButton.setOnClickListener { + expandFloatingActionButton(!floatingActionButton.isExpanded) } - binding.floatingActionButtonDialBackground.setOnClickListener { + floatingActionButtonDialBackground.setOnClickListener { expandFloatingActionButton(false) } - binding.addManualButton.setOnClickListener { addManualConsole() } - binding.addManualLabelButton.setOnClickListener { addManualConsole() } + addManualButton.setOnClickListener { addManualConsole() } + addManualLabelButton.setOnClickListener { addManualConsole() } - binding.registerButton.setOnClickListener { showRegistration() } - binding.registerLabelButton.setOnClickListener { showRegistration() } + registerButton.setOnClickListener { showRegistration() } + registerLabelButton.setOnClickListener { showRegistration() } viewModel = ViewModelProvider(this, viewModelFactory { MainViewModel(getDatabase(this), Preferences(this)) }) .get(MainViewModel::class.java) val recyclerViewAdapter = DisplayHostRecyclerViewAdapter(this::hostTriggered, this::wakeupHost, this::editHost, this::deleteHost) - binding.hostsRecyclerView.adapter = recyclerViewAdapter - binding.hostsRecyclerView.layoutManager = LinearLayoutManager(this) + hostsRecyclerView.adapter = recyclerViewAdapter + hostsRecyclerView.layoutManager = LinearLayoutManager(this) viewModel.displayHosts.observe(this, Observer { - val top = binding.hostsRecyclerView.computeVerticalScrollOffset() == 0 + val top = hostsRecyclerView.computeVerticalScrollOffset() == 0 recyclerViewAdapter.hosts = it if(top) - binding.hostsRecyclerView.scrollToPosition(0) + hostsRecyclerView.scrollToPosition(0) updateEmptyInfo() }) @@ -78,19 +76,19 @@ class MainActivity : AppCompatActivity() { if(viewModel.displayHosts.value?.isEmpty() ?: true) { - binding.emptyInfoLayout.visibility = View.VISIBLE + emptyInfoLayout.visibility = View.VISIBLE val discoveryActive = viewModel.discoveryActive.value ?: false - binding.emptyInfoImageView.setImageResource(if(discoveryActive) R.drawable.ic_discover_on else R.drawable.ic_discover_off) - binding.emptyInfoTextView.setText(if(discoveryActive) R.string.display_hosts_empty_discovery_on_info else R.string.display_hosts_empty_discovery_off_info) + emptyInfoImageView.setImageResource(if(discoveryActive) R.drawable.ic_discover_on else R.drawable.ic_discover_off) + emptyInfoTextView.setText(if(discoveryActive) R.string.display_hosts_empty_discovery_on_info else R.string.display_hosts_empty_discovery_off_info) } else - binding.emptyInfoLayout.visibility = View.GONE + emptyInfoLayout.visibility = View.GONE } private fun expandFloatingActionButton(expand: Boolean) { - binding.floatingActionButton.isExpanded = expand - binding.floatingActionButton.isActivated = binding.floatingActionButton.isExpanded + floatingActionButton.isExpanded = expand + floatingActionButton.isActivated = floatingActionButton.isExpanded } override fun onStart() @@ -107,7 +105,7 @@ class MainActivity : AppCompatActivity() override fun onBackPressed() { - if(binding.floatingActionButton.isExpanded) + if(floatingActionButton.isExpanded) { expandFloatingActionButton(false) return @@ -153,7 +151,7 @@ class MainActivity : AppCompatActivity() private fun addManualConsole() { Intent(this, EditManualConsoleActivity::class.java).also { - it.putRevealExtra(binding.addManualButton, binding.rootLayout) + it.putRevealExtra(addManualButton, rootLayout) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } } @@ -161,7 +159,7 @@ class MainActivity : AppCompatActivity() private fun showRegistration() { Intent(this, RegistActivity::class.java).also { - it.putRevealExtra(binding.registerButton, binding.rootLayout) + it.putRevealExtra(registerButton, rootLayout) startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } } diff --git a/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt b/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt index bb64b87..49e5f4d 100644 --- a/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/manualconsole/EditManualConsoleActivity.kt @@ -16,10 +16,10 @@ import com.metallic.chiaki.common.RegisteredHost import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase -import com.metallic.chiaki.databinding.ActivityEditManualBinding import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo +import kotlinx.android.synthetic.main.activity_edit_manual.* class EditManualConsoleActivity: AppCompatActivity(), RevealActivity { @@ -28,20 +28,18 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity const val EXTRA_MANUAL_HOST_ID = "manual_host_id" } - private lateinit var viewModel: EditManualConsoleViewModel - private lateinit var binding: ActivityEditManualBinding - override val revealIntent: Intent get() = intent - override val revealRootLayout: View get() = binding.rootLayout + override val revealRootLayout: View get() = rootLayout override val revealWindow: Window get() = window + private lateinit var viewModel: EditManualConsoleViewModel + private val disposable = CompositeDisposable() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityEditManualBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_edit_manual) handleReveal() viewModel = ViewModelProvider(this, viewModelFactory { @@ -54,17 +52,17 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity .get(EditManualConsoleViewModel::class.java) viewModel.existingHost?.observe(this, Observer { - binding.hostEditText.setText(it.host) + hostEditText.setText(it.host) }) viewModel.selectedRegisteredHost.observe(this, Observer { - binding.registeredHostTextView.setText(titleForRegisteredHost(it)) + registeredHostTextView.setText(titleForRegisteredHost(it)) }) viewModel.registeredHosts.observe(this, Observer { hosts -> - binding.registeredHostTextView.setAdapter(ArrayAdapter(this, R.layout.dropdown_menu_popup_item, + registeredHostTextView.setAdapter(ArrayAdapter(this, R.layout.dropdown_menu_popup_item, hosts.map { titleForRegisteredHost(it) })) - binding.registeredHostTextView.onItemClickListener = object: AdapterView.OnItemClickListener { + registeredHostTextView.onItemClickListener = object: AdapterView.OnItemClickListener { override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { if(position >= hosts.size) @@ -75,7 +73,8 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity } }) - binding.saveButton.setOnClickListener { saveHost() } + + saveButton.setOnClickListener { saveHost() } } private fun titleForRegisteredHost(registeredHost: RegisteredHost?) = @@ -86,14 +85,14 @@ class EditManualConsoleActivity: AppCompatActivity(), RevealActivity private fun saveHost() { - val host = binding.hostEditText.text.toString().trim() + val host = hostEditText.text.toString().trim() if(host.isEmpty()) { - binding.hostEditText.error = getString(R.string.entered_host_invalid) + hostEditText.error = getString(R.string.entered_host_invalid) return } - binding.saveButton.isEnabled = false + saveButton.isEnabled = false viewModel.saveHost(host) .observeOn(AndroidSchedulers.mainThread()) .subscribe { diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt index 9190f9c..fb3ddaa 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt @@ -12,9 +12,9 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import com.metallic.chiaki.R import com.metallic.chiaki.common.ext.RevealActivity -import com.metallic.chiaki.databinding.ActivityRegistBinding import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.Target +import kotlinx.android.synthetic.main.activity_regist.* import java.lang.IllegalArgumentException class RegistActivity: AppCompatActivity(), RevealActivity @@ -30,35 +30,33 @@ class RegistActivity: AppCompatActivity(), RevealActivity private const val REQUEST_REGIST = 1 } - private lateinit var viewModel: RegistViewModel - private lateinit var binding: ActivityRegistBinding - override val revealWindow: Window get() = window override val revealIntent: Intent get() = intent - override val revealRootLayout: View get() = binding.rootLayout + override val revealRootLayout: View get() = rootLayout + + private lateinit var viewModel: RegistViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityRegistBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_regist) handleReveal() viewModel = ViewModelProvider(this).get(RegistViewModel::class.java) - binding.hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255") - binding.broadcastCheckBox.isChecked = intent.getBooleanExtra(EXTRA_BROADCAST, true) + hostEditText.setText(intent.getStringExtra(EXTRA_HOST) ?: "255.255.255.255") + broadcastCheckBox.isChecked = intent.getBooleanExtra(EXTRA_BROADCAST, true) - binding.registButton.setOnClickListener { doRegist() } + registButton.setOnClickListener { doRegist() } - binding.ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5) { + ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5) { RegistViewModel.ConsoleVersion.PS5 -> R.id.ps5RadioButton RegistViewModel.ConsoleVersion.PS4_GE_8 -> R.id.ps4VersionGE8RadioButton RegistViewModel.ConsoleVersion.PS4_GE_7 -> R.id.ps4VersionGE7RadioButton RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.id.ps4VersionLT7RadioButton }) - binding.ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> + ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> viewModel.ps4Version.value = when(checkedId) { R.id.ps5RadioButton -> RegistViewModel.ConsoleVersion.PS5 @@ -70,14 +68,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity } viewModel.ps4Version.observe(this, Observer { - binding.psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE - binding.psnIdTextInputLayout.hint = getString(when(it!!) + psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.ConsoleVersion.PS4_LT_7) View.GONE else View.VISIBLE + psnIdTextInputLayout.hint = getString(when(it!!) { RegistViewModel.ConsoleVersion.PS4_LT_7 -> R.string.hint_regist_psn_online_id else -> R.string.hint_regist_psn_account_id }) - binding.pinHelpBeforeTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_before else R.string.regist_pin_instructions_ps4_before) - binding.pinHelpNavigationTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_navigation else R.string.regist_pin_instructions_ps4_navigation) + pinHelpBeforeTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_before else R.string.regist_pin_instructions_ps4_before) + pinHelpNavigationTextView.setText(if(it.isPS5) R.string.regist_pin_instructions_ps5_navigation else R.string.regist_pin_instructions_ps4_navigation) }) } @@ -85,11 +83,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity { val ps4Version = viewModel.ps4Version.value ?: RegistViewModel.ConsoleVersion.PS5 - val host = binding.hostEditText.text.toString().trim() + val host = hostEditText.text.toString().trim() val hostValid = host.isNotEmpty() - val broadcast = binding.broadcastCheckBox.isChecked + val broadcast = broadcastCheckBox.isChecked - val psnId = binding.psnIdEditText.text.toString().trim() + val psnId = psnIdEditText.text.toString().trim() val psnOnlineId: String? = if(ps4Version == RegistViewModel.ConsoleVersion.PS4_LT_7) psnId else null val psnAccountId: ByteArray? = if(ps4Version != RegistViewModel.ConsoleVersion.PS4_LT_7) @@ -103,11 +101,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity } - val pin = binding.pinEditText.text.toString() + val pin = pinEditText.text.toString() val pinValid = pin.length == PIN_LENGTH - binding.hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null - binding.psnIdEditText.error = + hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null + psnIdEditText.error = if(!psnIdValid) getString(when(ps4Version) { @@ -116,7 +114,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity }) else null - binding.pinEditText.error = if(!pinValid) getString(R.string.regist_pin_invalid, PIN_LENGTH) else null + pinEditText.error = if(!pinValid) getString(R.string.regist_pin_invalid, PIN_LENGTH) else null if(!hostValid || !psnIdValid || !pinValid) return diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt index 16f545a..870b67e 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt @@ -16,8 +16,8 @@ import com.metallic.chiaki.R import com.metallic.chiaki.common.MacAddress import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase -import com.metallic.chiaki.databinding.ActivityRegistExecuteBinding import com.metallic.chiaki.lib.RegistInfo +import kotlinx.android.synthetic.main.activity_regist_execute.* import kotlin.math.max class RegistExecuteActivity: AppCompatActivity() @@ -31,57 +31,55 @@ class RegistExecuteActivity: AppCompatActivity() } private lateinit var viewModel: RegistExecuteViewModel - private lateinit var binding: ActivityRegistExecuteBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityRegistExecuteBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_regist_execute) viewModel = ViewModelProvider(this, viewModelFactory { RegistExecuteViewModel(getDatabase(this)) }) .get(RegistExecuteViewModel::class.java) - binding.logTextView.setHorizontallyScrolling(true) - binding.logTextView.movementMethod = ScrollingMovementMethod() + logTextView.setHorizontallyScrolling(true) + logTextView.movementMethod = ScrollingMovementMethod() viewModel.logText.observe(this, Observer { - val textLayout = binding.logTextView.layout ?: return@Observer + val textLayout = logTextView.layout ?: return@Observer val lineCount = textLayout.lineCount if(lineCount < 1) return@Observer - binding.logTextView.text = it - val scrollY = textLayout.getLineBottom(lineCount - 1) - binding.logTextView.height + binding.logTextView.paddingTop + binding.logTextView.paddingBottom - binding.logTextView.scrollTo(0, max(scrollY, 0)) + logTextView.text = it + val scrollY = textLayout.getLineBottom(lineCount - 1) - logTextView.height + logTextView.paddingTop + logTextView.paddingBottom + logTextView.scrollTo(0, max(scrollY, 0)) }) viewModel.state.observe(this, Observer { - binding.progressBar.visibility = if(it == RegistExecuteViewModel.State.RUNNING) View.VISIBLE else View.GONE + progressBar.visibility = if(it == RegistExecuteViewModel.State.RUNNING) View.VISIBLE else View.GONE when(it) { RegistExecuteViewModel.State.FAILED -> { - binding.infoTextView.visibility = View.VISIBLE - binding.infoTextView.setText(R.string.regist_info_failed) + infoTextView.visibility = View.VISIBLE + infoTextView.setText(R.string.regist_info_failed) setResult(RESULT_FAILED) } RegistExecuteViewModel.State.SUCCESSFUL, RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE -> { - binding.infoTextView.visibility = View.VISIBLE - binding.infoTextView.setText(R.string.regist_info_success) + infoTextView.visibility = View.VISIBLE + infoTextView.setText(R.string.regist_info_success) setResult(RESULT_OK) if(it == RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE) showDuplicateDialog() } RegistExecuteViewModel.State.STOPPED -> { - binding.infoTextView.visibility = View.GONE + infoTextView.visibility = View.GONE setResult(Activity.RESULT_CANCELED) } - else -> binding.infoTextView.visibility = View.GONE + else -> infoTextView.visibility = View.GONE } }) - binding.shareLogButton.setOnClickListener { + shareLogButton.setOnClickListener { val log = viewModel.logText.value ?: "" Intent(Intent.ACTION_SEND).also { it.type = "text/plain" diff --git a/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt b/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt index 822fe76..e96b7b5 100644 --- a/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt +++ b/android/app/src/main/java/com/metallic/chiaki/session/StreamInput.kt @@ -1,37 +1,19 @@ package com.metallic.chiaki.session -import android.content.Context -import android.hardware.* -import android.view.* -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.OnLifecycleEvent +import android.util.Log +import android.view.InputDevice +import android.view.KeyEvent +import android.view.MotionEvent import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.lib.ControllerState -class StreamInput(val context: Context, val preferences: Preferences) +class StreamInput(val preferences: Preferences) { var controllerStateChangedCallback: ((ControllerState) -> Unit)? = null val controllerState: ControllerState get() { - val controllerState = sensorControllerState or keyControllerState or motionControllerState - - val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager - @Suppress("DEPRECATION") - when(windowManager.defaultDisplay.rotation) - { - Surface.ROTATION_90 -> { - controllerState.accelX *= -1.0f - controllerState.accelZ *= -1.0f - controllerState.gyroX *= -1.0f - controllerState.gyroZ *= -1.0f - controllerState.orientX *= -1.0f - controllerState.orientZ *= -1.0f - } - else -> {} - } + val controllerState = keyControllerState or motionControllerState // prioritize motion controller's l2 and r2 over key // (some controllers send only key, others both but key earlier than full press) @@ -43,7 +25,6 @@ class StreamInput(val context: Context, val preferences: Preferences) return controllerState or touchControllerState } - private val sensorControllerState = ControllerState() // from Motion Sensors private val keyControllerState = ControllerState() // from KeyEvents private val motionControllerState = ControllerState() // from MotionEvents var touchControllerState = ControllerState() @@ -55,66 +36,6 @@ class StreamInput(val context: Context, val preferences: Preferences) private val swapCrossMoon = preferences.swapCrossMoon - private val sensorEventListener = object: SensorEventListener { - override fun onSensorChanged(event: SensorEvent) - { - when(event.sensor.type) - { - Sensor.TYPE_ACCELEROMETER -> { - sensorControllerState.accelX = event.values[1] / SensorManager.GRAVITY_EARTH - sensorControllerState.accelY = event.values[2] / SensorManager.GRAVITY_EARTH - sensorControllerState.accelZ = event.values[0] / SensorManager.GRAVITY_EARTH - } - Sensor.TYPE_GYROSCOPE -> { - sensorControllerState.gyroX = event.values[1] - sensorControllerState.gyroY = event.values[2] - sensorControllerState.gyroZ = event.values[0] - } - Sensor.TYPE_ROTATION_VECTOR -> { - val q = floatArrayOf(0f, 0f, 0f, 0f) - SensorManager.getQuaternionFromVector(q, event.values) - sensorControllerState.orientX = q[2] - sensorControllerState.orientY = q[3] - sensorControllerState.orientZ = q[1] - sensorControllerState.orientW = q[0] - } - else -> return - } - controllerStateUpdated() - } - - override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} - } - - private val motionLifecycleObserver = object: LifecycleObserver { - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - fun onResume() - { - val samplingPeriodUs = 4000 - val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager - listOfNotNull( - sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), - sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), - sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) - ).forEach { - sensorManager.registerListener(sensorEventListener, it, samplingPeriodUs) - } - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - fun onPause() - { - val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager - sensorManager.unregisterListener(sensorEventListener) - } - } - - fun observe(lifecycleOwner: LifecycleOwner) - { - if(preferences.motionEnabled) - lifecycleOwner.lifecycle.addObserver(motionLifecycleObserver) - } - private fun controllerStateUpdated() { controllerStateChangedCallback?.let { it(controllerState) } @@ -177,7 +98,7 @@ class StreamInput(val context: Context, val preferences: Preferences) { if(event.source and InputDevice.SOURCE_CLASS_JOYSTICK != InputDevice.SOURCE_CLASS_JOYSTICK) return false - fun Float.signedAxis() = (this * Short.MAX_VALUE).toInt().toShort() + fun Float.signedAxis() = (this * Short.MAX_VALUE).toShort() fun Float.unsignedAxis() = (this * UByte.MAX_VALUE.toFloat()).toUInt().toUByte() motionControllerState.leftX = event.getAxisValue(MotionEvent.AXIS_X).signedAxis() motionControllerState.leftY = event.getAxisValue(MotionEvent.AXIS_Y).signedAxis() diff --git a/android/app/src/main/java/com/metallic/chiaki/session/StreamSession.kt b/android/app/src/main/java/com/metallic/chiaki/session/StreamSession.kt index dd32a40..059840c 100644 --- a/android/app/src/main/java/com/metallic/chiaki/session/StreamSession.kt +++ b/android/app/src/main/java/com/metallic/chiaki/session/StreamSession.kt @@ -25,11 +25,8 @@ class StreamSession(val connectInfo: ConnectInfo, val logManager: LogManager, va private val _state = MutableLiveData(StreamStateIdle) val state: LiveData get() = _state - private val _rumbleState = MutableLiveData(RumbleEvent(0U, 0U)) - val rumbleState: LiveData get() = _rumbleState - private var surfaceTexture: SurfaceTexture? = null - private var surface: Surface? = null + var surfaceTexture: SurfaceTexture? = null init { @@ -62,9 +59,9 @@ class StreamSession(val connectInfo: ConnectInfo, val logManager: LogManager, va _state.value = StreamStateConnecting session.eventCallback = this::eventCallback session.start() - val surface = surface - if(surface != null) - session.setSurface(surface) + val surfaceTexture = surfaceTexture + if(surfaceTexture != null) + session.setSurface(Surface(surfaceTexture)) this.session = session } catch(e: CreateError) @@ -89,30 +86,9 @@ class StreamSession(val connectInfo: ConnectInfo, val logManager: LogManager, va event.pinIncorrect ) ) - is RumbleEvent -> _rumbleState.postValue(event) } } - fun attachToSurfaceView(surfaceView: SurfaceView) - { - surfaceView.holder.addCallback(object: SurfaceHolder.Callback { - override fun surfaceCreated(holder: SurfaceHolder) { } - - override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) - { - val surface = holder.surface - this@StreamSession.surface = surface - session?.setSurface(surface) - } - - override fun surfaceDestroyed(holder: SurfaceHolder) - { - this@StreamSession.surface = null - session?.setSurface(null) - } - }) - } - fun attachToTextureView(textureView: TextureView) { textureView.surfaceTextureListener = object: TextureView.SurfaceTextureListener { @@ -121,7 +97,6 @@ class StreamSession(val connectInfo: ConnectInfo, val logManager: LogManager, va if(surfaceTexture != null) return surfaceTexture = surface - this@StreamSession.surface = Surface(surfaceTexture) session?.setSurface(Surface(surface)) } diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt index 1cf224f..3a87e1b 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsActivity.kt @@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.metallic.chiaki.R -import com.metallic.chiaki.databinding.ActivitySettingsBinding +import kotlinx.android.synthetic.main.activity_settings.* interface TitleFragment { @@ -18,23 +18,20 @@ interface TitleFragment class SettingsActivity: AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { - private lateinit var binding: ActivitySettingsBinding - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivitySettingsBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_settings) title = "" - setSupportActionBar(binding.toolbar) + setSupportActionBar(toolbar) val rootFragment = SettingsFragment() replaceFragment(rootFragment, false) supportFragmentManager.addOnBackStackChangedListener { val titleFragment = supportFragmentManager.findFragmentById(R.id.settingsFragment) as? TitleFragment ?: return@addOnBackStackChangedListener - binding.titleTextView.text = titleFragment.getTitle(resources) + titleTextView.text = titleFragment.getTitle(resources) } - binding.titleTextView.text = rootFragment.getTitle(resources) + titleTextView.text = rootFragment.getTitle(resources) } override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference) = when(pref.fragment) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt index f574d09..f38f619 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsFragment.kt @@ -16,6 +16,7 @@ import com.metallic.chiaki.common.exportAndShareAllSettings import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.importSettingsFromUri +import com.metallic.chiaki.lib.Codec import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo @@ -25,9 +26,6 @@ class DataStore(val preferences: Preferences): PreferenceDataStore() { preferences.logVerboseKey -> preferences.logVerbose preferences.swapCrossMoonKey -> preferences.swapCrossMoon - preferences.rumbleEnabledKey -> preferences.rumbleEnabled - preferences.motionEnabledKey -> preferences.motionEnabled - preferences.buttonHapticEnabledKey -> preferences.buttonHapticEnabled else -> defValue } @@ -37,9 +35,6 @@ class DataStore(val preferences: Preferences): PreferenceDataStore() { preferences.logVerboseKey -> preferences.logVerbose = value preferences.swapCrossMoonKey -> preferences.swapCrossMoon = value - preferences.rumbleEnabledKey -> preferences.rumbleEnabled = value - preferences.motionEnabledKey -> preferences.motionEnabled = value - preferences.buttonHapticEnabledKey -> preferences.buttonHapticEnabled = value } } diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt index 6acf547..46c8904 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsAdapter.kt @@ -2,13 +2,13 @@ package com.metallic.chiaki.settings -import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.metallic.chiaki.R import com.metallic.chiaki.common.LogFile import com.metallic.chiaki.common.ext.inflate -import com.metallic.chiaki.databinding.ItemLogFileBinding +import kotlinx.android.synthetic.main.item_log_file.view.* import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* @@ -20,7 +20,7 @@ class SettingsLogsAdapter: RecyclerView.Adapter( private val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT) private val timeFormat = SimpleDateFormat("HH:mm:ss:SSS", Locale.getDefault()) - class ViewHolder(val binding: ItemLogFileBinding): RecyclerView.ViewHolder(binding.root) + class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) var logFiles: List = listOf() set(value) @@ -29,16 +29,16 @@ class SettingsLogsAdapter: RecyclerView.Adapter( notifyDataSetChanged() } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = - ViewHolder(ItemLogFileBinding.inflate(LayoutInflater.from(parent.context), parent, false)) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_log_file)) override fun getItemCount() = logFiles.size override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val view = holder.itemView val logFile = logFiles[position] - holder.binding.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}" - holder.binding.summaryTextView.text = logFile.filename - holder.binding.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } } + view.nameTextView.text = "${dateFormat.format(logFile.date)} ${timeFormat.format(logFile.date)}" + view.summaryTextView.text = logFile.filename + view.shareButton.setOnClickListener { shareCallback?.let { it(logFile) } } } } \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt index 0397172..07e1e3f 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsLogsFragment.kt @@ -21,35 +21,29 @@ import com.metallic.chiaki.common.LogFile import com.metallic.chiaki.common.LogManager import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.fileProviderAuthority -import com.metallic.chiaki.databinding.FragmentSettingsLogsBinding +import kotlinx.android.synthetic.main.fragment_settings_logs.* class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment { private lateinit var viewModel: SettingsLogsViewModel - private var _binding: FragmentSettingsLogsBinding? = null - private val binding get() = _binding!! - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - FragmentSettingsLogsBinding.inflate(inflater, container, false).let { - _binding = it - it.root - } + inflater.inflate(R.layout.fragment_settings_logs, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val context = requireContext() + val context = context!! viewModel = ViewModelProvider(this, viewModelFactory { SettingsLogsViewModel(LogManager(context)) }) .get(SettingsLogsViewModel::class.java) val adapter = SettingsLogsAdapter() - binding.logsRecyclerView.layoutManager = LinearLayoutManager(context) - binding.logsRecyclerView.adapter = adapter + logsRecyclerView.layoutManager = LinearLayoutManager(context) + logsRecyclerView.adapter = adapter adapter.shareCallback = this::shareLogFile viewModel.sessionLogs.observe(viewLifecycleOwner, Observer { adapter.logFiles = it - binding.emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE + emptyInfoGroup.visibility = if(it.isEmpty()) View.VISIBLE else View.GONE }) val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context) @@ -61,7 +55,7 @@ class SettingsLogsFragment: AppCompatDialogFragment(), TitleFragment viewModel.deleteLog(file) } } - ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(binding.logsRecyclerView) + ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(logsRecyclerView) } override fun getTitle(resources: Resources): String = resources.getString(R.string.preferences_logs_title) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt index 509d594..57a06ce 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt @@ -2,15 +2,17 @@ package com.metallic.chiaki.settings -import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.metallic.chiaki.R import com.metallic.chiaki.common.RegisteredHost -import com.metallic.chiaki.databinding.ItemRegisteredHostBinding +import com.metallic.chiaki.common.ext.inflate +import kotlinx.android.synthetic.main.item_registered_host.view.* class SettingsRegisteredHostsAdapter: RecyclerView.Adapter() { - class ViewHolder(val binding: ItemRegisteredHostBinding): RecyclerView.ViewHolder(binding.root) + class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) var hosts: List = listOf() set(value) @@ -19,15 +21,15 @@ class SettingsRegisteredHostsAdapter: RecyclerView.Adapter - if(aspectDeformation > 0) - width = (height * aspectRatio).toInt() - else - height = (width / aspectRatio).toInt() - TransformMode.FIT -> - if(aspectDeformation > 0) - height = (width / aspectRatio).toInt() - else - width = (height * aspectRatio).toInt() - TransformMode.STRETCH -> {} - } - super.onMeasure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) - ) - } -} diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt index bd77e0c..67d425b 100644 --- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamActivity.kt @@ -6,8 +6,12 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.app.AlertDialog import android.graphics.Matrix -import android.os.* -import android.view.* +import android.os.Bundle +import android.os.Handler +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.TextureView +import android.view.View import android.widget.EditText import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isGone @@ -16,18 +20,15 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.* import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.metallic.chiaki.R +import com.metallic.chiaki.common.LogManager import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.common.ext.viewModelFactory -import com.metallic.chiaki.databinding.ActivityStreamBinding import com.metallic.chiaki.lib.ConnectInfo import com.metallic.chiaki.lib.ConnectVideoProfile import com.metallic.chiaki.session.* -import com.metallic.chiaki.touchcontrols.DefaultTouchControlsFragment -import com.metallic.chiaki.touchcontrols.TouchControlsFragment import com.metallic.chiaki.touchcontrols.TouchpadOnlyFragment -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.addTo -import kotlin.math.min +import com.metallic.chiaki.touchcontrols.TouchControlsFragment +import kotlinx.android.synthetic.main.activity_stream.* private sealed class DialogContents private object StreamQuitDialog: DialogContents() @@ -43,8 +44,6 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe } private lateinit var viewModel: StreamViewModel - private lateinit var binding: ActivityStreamBinding - private val uiVisibilityHandler = Handler() override fun onCreate(savedInstanceState: Bundle?) @@ -59,76 +58,64 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe } viewModel = ViewModelProvider(this, viewModelFactory { - StreamViewModel(application, connectInfo) + StreamViewModel(Preferences(this), LogManager(this), connectInfo) })[StreamViewModel::class.java] - viewModel.input.observe(this) - - binding = ActivityStreamBinding.inflate(layoutInflater) - setContentView(binding.root) + setContentView(R.layout.activity_stream) window.decorView.setOnSystemUiVisibilityChangeListener(this) viewModel.onScreenControlsEnabled.observe(this, Observer { - if(binding.onScreenControlsSwitch.isChecked != it) - binding.onScreenControlsSwitch.isChecked = it - if(binding.onScreenControlsSwitch.isChecked) - binding.touchpadOnlySwitch.isChecked = false + if(onScreenControlsSwitch.isChecked != it) + onScreenControlsSwitch.isChecked = it + if(onScreenControlsSwitch.isChecked) + touchpadOnlySwitch.isChecked = false }) - binding.onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked -> + onScreenControlsSwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.setOnScreenControlsEnabled(isChecked) showOverlay() } viewModel.touchpadOnlyEnabled.observe(this, Observer { - if(binding.touchpadOnlySwitch.isChecked != it) - binding.touchpadOnlySwitch.isChecked = it - if(binding.touchpadOnlySwitch.isChecked) - binding.onScreenControlsSwitch.isChecked = false + if(touchpadOnlySwitch.isChecked != it) + touchpadOnlySwitch.isChecked = it + if(touchpadOnlySwitch.isChecked) + onScreenControlsSwitch.isChecked = false }) - binding.touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked -> + touchpadOnlySwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.setTouchpadOnlyEnabled(isChecked) showOverlay() } - binding.displayModeToggle.addOnButtonCheckedListener { _, _, _ -> - adjustStreamViewAspect() + displayModeToggle.addOnButtonCheckedListener { _, checkedId, _ -> + // following 'if' is a workaround until selectionRequired for MaterialButtonToggleGroup + // comes out of alpha. + // See https://stackoverflow.com/questions/56164004/required-single-selection-on-materialbuttontogglegroup + if (displayModeToggle.checkedButtonId == -1) + displayModeToggle.check(checkedId) + + adjustTextureViewAspect() showOverlay() } - //viewModel.session.attachToTextureView(textureView) - viewModel.session.attachToSurfaceView(binding.surfaceView) + viewModel.session.attachToTextureView(textureView) viewModel.session.state.observe(this, Observer { this.stateChanged(it) }) - adjustStreamViewAspect() - - if(Preferences(this).rumbleEnabled) - { - val vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator - viewModel.session.rumbleState.observe(this, Observer { - val amplitude = min(255, (it.left.toInt() + it.right.toInt()) / 2) - vibrator.cancel() - if(amplitude == 0) - return@Observer - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - vibrator.vibrate(VibrationEffect.createOneShot(1000, amplitude)) - else - vibrator.vibrate(1000) - }) + textureView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + adjustTextureViewAspect() } } - private val controlsDisposable = CompositeDisposable() - override fun onAttachFragment(fragment: Fragment) { super.onAttachFragment(fragment) if(fragment is TouchControlsFragment) { - fragment.controllerState - .subscribe { viewModel.input.touchControllerState = it } - .addTo(controlsDisposable) + fragment.controllerStateCallback = { viewModel.input.touchControllerState = it } fragment.onScreenControlsEnabled = viewModel.onScreenControlsEnabled - if(fragment is TouchpadOnlyFragment) - fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled + } + if(fragment is TouchpadOnlyFragment) + { + fragment.controllerStateCallback = { viewModel.input.touchControllerState = it } + fragment.touchpadOnlyEnabled = viewModel.touchpadOnlyEnabled } } @@ -145,12 +132,6 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe viewModel.session.pause() } - override fun onDestroy() - { - super.onDestroy() - controlsDisposable.dispose() - } - private fun reconnect() { viewModel.session.shutdown() @@ -169,14 +150,14 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun showOverlay() { - binding.overlay.isVisible = true - binding.overlay.animate() + overlay.isVisible = true + overlay.animate() .alpha(1.0f) .setListener(object: AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) + override fun onAnimationEnd(animation: Animator?) { - binding.overlay.alpha = 1.0f + overlay.alpha = 1.0f } }) uiVisibilityHandler.removeCallbacks(hideSystemUIRunnable) @@ -185,13 +166,13 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun hideOverlay() { - binding.overlay.animate() + overlay.animate() .alpha(0.0f) .setListener(object: AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) + override fun onAnimationEnd(animation: Animator?) { - binding.overlay.isGone = true + overlay.isGone = true } }) } @@ -224,39 +205,34 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe private fun stateChanged(state: StreamState) { - binding.progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE + progressBar.visibility = if(state == StreamStateConnecting) View.VISIBLE else View.GONE when(state) { is StreamStateQuit -> { - if(dialogContents != StreamQuitDialog) + if(!state.reason.isStopped && dialogContents != StreamQuitDialog) { - if(state.reason.isError) - { - dialog?.dismiss() - val reasonStr = state.reasonString - val dialog = MaterialAlertDialogBuilder(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() - } - .setOnCancelListener { - dialog = null - finish() - } - .setNegativeButton(R.string.action_quit_session) { _, _ -> - dialog = null - finish() - } - .create() - dialogContents = StreamQuitDialog - dialog.show() - } - else - finish() + dialog?.dismiss() + val reasonStr = state.reasonString + val dialog = MaterialAlertDialogBuilder(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() + } + .setOnCancelListener { + dialog = null + finish() + } + .setNegativeButton(R.string.action_quit_session) { _, _ -> + dialog = null + finish() + } + .create() + dialogContents = StreamQuitDialog + dialog.show() } } @@ -311,89 +287,77 @@ class StreamActivity : AppCompatActivity(), View.OnSystemUiVisibilityChangeListe dialog.show() } } - - else -> {} } } - private fun adjustTextureViewAspect(textureView: TextureView) + private fun adjustTextureViewAspect() { - val trans = TextureViewTransform(viewModel.session.connectInfo.videoProfile, textureView) - val resolution = trans.resolutionFor(TransformMode.fromButton(binding.displayModeToggle.checkedButtonId)) + val displayInfo = DisplayInfo(viewModel.session.connectInfo.videoProfile, textureView) + val resolution = displayInfo.computeResolutionFor(displayModeToggle.checkedButtonId) + Matrix().also { textureView.getTransform(it) - it.setScale(resolution.width / trans.viewWidth, resolution.height / trans.viewHeight) - it.postTranslate((trans.viewWidth - resolution.width) * 0.5f, (trans.viewHeight - resolution.height) * 0.5f) + it.setScale(resolution.width / displayInfo.viewWidth, resolution.height / displayInfo.viewHeight) + it.postTranslate((displayInfo.viewWidth - resolution.width) * 0.5f, (displayInfo.viewHeight - resolution.height) * 0.5f) textureView.setTransform(it) } } - private fun adjustSurfaceViewAspect() - { - val videoProfile = viewModel.session.connectInfo.videoProfile - binding.aspectRatioLayout.aspectRatio = videoProfile.width.toFloat() / videoProfile.height.toFloat() - binding.aspectRatioLayout.mode = TransformMode.fromButton(binding.displayModeToggle.checkedButtonId) - } - - private fun adjustStreamViewAspect() = adjustSurfaceViewAspect() - override fun dispatchKeyEvent(event: KeyEvent) = viewModel.input.dispatchKeyEvent(event) || super.dispatchKeyEvent(event) override fun onGenericMotionEvent(event: MotionEvent) = viewModel.input.onGenericMotionEvent(event) || super.onGenericMotionEvent(event) + } -enum class TransformMode -{ - FIT, - STRETCH, - ZOOM; - companion object - { - fun fromButton(displayModeButtonId: Int) - = when (displayModeButtonId) - { - R.id.display_mode_stretch_button -> STRETCH - R.id.display_mode_zoom_button -> ZOOM - else -> FIT - } - } -} - -class TextureViewTransform(private val videoProfile: ConnectVideoProfile, private val textureView: TextureView) +class DisplayInfo constructor(val videoProfile: ConnectVideoProfile, val textureView: TextureView) { - private val contentWidth : Float get() = videoProfile.width.toFloat() - private val contentHeight : Float get() = videoProfile.height.toFloat() + val contentWidth : Float get() = videoProfile.width.toFloat() + val contentHeight : Float get() = videoProfile.height.toFloat() val viewWidth : Float get() = textureView.width.toFloat() val viewHeight : Float get() = textureView.height.toFloat() - private val contentAspect : Float get() = contentHeight / contentWidth + val contentAspect : Float get() = contentHeight / contentWidth - fun resolutionFor(mode: TransformMode): Resolution - = when(mode) + fun computeResolutionFor(displayModeButtonId: Int) : Resolution + { + when (displayModeButtonId) { - TransformMode.STRETCH -> strechedResolution - TransformMode.ZOOM -> zoomedResolution - TransformMode.FIT -> normalResolution + R.id.display_mode_stretch_button -> return computeStrechedResolution() + R.id.display_mode_zoom_button -> return computeZoomedResolution() + else -> return computeNormalResolution() } + } - private val strechedResolution get() = Resolution(viewWidth, viewHeight) + private fun computeStrechedResolution(): Resolution + { + return Resolution(viewWidth, viewHeight) + } - private val zoomedResolution get() = - if(viewHeight > viewWidth * contentAspect) + private fun computeZoomedResolution(): Resolution + { + if (viewHeight > viewWidth * contentAspect) { val zoomFactor = viewHeight / contentHeight - Resolution(contentWidth * zoomFactor, viewHeight) + return Resolution(contentWidth * zoomFactor, viewHeight) } else { val zoomFactor = viewWidth / contentWidth - Resolution(viewWidth, contentHeight * zoomFactor) + return Resolution(viewWidth, contentHeight * zoomFactor) } + } - private val normalResolution get() = - if(viewHeight > viewWidth * contentAspect) - Resolution(viewWidth, viewWidth * contentAspect) + private fun computeNormalResolution(): Resolution + { + if (viewHeight > viewWidth * contentAspect) + { + return Resolution(viewWidth, viewWidth * contentAspect) + } else - Resolution(viewHeight / contentAspect, viewHeight) + { + return Resolution(viewHeight / contentAspect, viewHeight) + } + } + } diff --git a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt index df69378..ebaaf80 100644 --- a/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/stream/StreamViewModel.kt @@ -2,22 +2,19 @@ package com.metallic.chiaki.stream -import android.app.Application -import android.content.Context -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import com.metallic.chiaki.common.LogManager import com.metallic.chiaki.session.StreamSession import com.metallic.chiaki.common.Preferences import com.metallic.chiaki.lib.* import com.metallic.chiaki.session.StreamInput -class StreamViewModel(val application: Application, val connectInfo: ConnectInfo): ViewModel() +class StreamViewModel(val preferences: Preferences, val logManager: LogManager, val connectInfo: ConnectInfo): ViewModel() { - val preferences = Preferences(application) - val logManager = LogManager(application) - private var _session: StreamSession? = null - val input = StreamInput(application, preferences) + val input = StreamInput(preferences) val session = StreamSession(connectInfo, logManager, preferences.logVerbose, input) private var _onScreenControlsEnabled = MutableLiveData(preferences.onScreenControlsEnabled) diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonHaptics.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonHaptics.kt deleted file mode 100644 index 909eab4..0000000 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonHaptics.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.metallic.chiaki.touchcontrols - -import android.content.Context -import android.os.Build -import android.os.VibrationEffect -import android.os.Vibrator -import androidx.appcompat.app.AppCompatActivity -import com.metallic.chiaki.common.Preferences - -class ButtonHaptics(val context: Context) -{ - private val enabled = Preferences(context).buttonHapticEnabled - - fun trigger(harder: Boolean = false) - { - if(!enabled) - return - val vibrator = context.getSystemService(AppCompatActivity.VIBRATOR_SERVICE) as Vibrator - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - vibrator.vibrate( - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) - VibrationEffect.createPredefined(if(harder) VibrationEffect.EFFECT_CLICK else VibrationEffect.EFFECT_TICK) - else - VibrationEffect.createOneShot(10, if(harder) 200 else 100) - ) - else - vibrator.vibrate(10) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonView.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonView.kt index 66a9afe..b2eba6b 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonView.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/ButtonView.kt @@ -6,19 +6,14 @@ import android.content.Context import android.graphics.Canvas import android.graphics.drawable.Drawable import android.util.AttributeSet -import android.util.Log import android.view.MotionEvent import android.view.View -import android.view.ViewGroup -import androidx.core.view.children import com.metallic.chiaki.R class ButtonView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - private val haptics = ButtonHaptics(context) - var buttonPressed = false private set(value) { @@ -26,8 +21,6 @@ class ButtonView @JvmOverloads constructor( field = value if(diff) { - if(value) - haptics.trigger() invalidate() buttonPressedCallback?.let { it(field) } } @@ -53,39 +46,16 @@ class ButtonView @JvmOverloads constructor( { super.onDraw(canvas) val drawable = if(buttonPressed) drawablePressed else drawableIdle - drawable?.setBounds(paddingLeft, paddingTop, width - paddingRight, height - paddingBottom) + drawable?.setBounds(0, 0, width, height) drawable?.draw(canvas) } - /** - * If this button overlaps with others in the same layout, - * let the one whose center is closest to the touch handle it. - */ - private fun bestFittingTouchView(x: Float, y: Float): View - { - val loc = locationOnScreen + Vector(x, y) - return (parent as? ViewGroup)?.children?.filter { - it is ButtonView - }?.filter { - val pos = it.locationOnScreen - loc.x >= pos.x && loc.x < pos.x + it.width && loc.y >= pos.y && loc.y < pos.y + it.height - }?.sortedBy { - (loc - (it.locationOnScreen + Vector(it.width.toFloat(), it.height.toFloat()) * 0.5f)).lengthSq - }?.firstOrNull() ?: this - } - override fun onTouchEvent(event: MotionEvent): Boolean { - when(event.actionMasked) + when(event.action) { - MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> { - if(bestFittingTouchView(event.getX(event.actionIndex), event.getY(event.actionIndex)) != this) - return false - buttonPressed = true - } - MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> { - buttonPressed = false - } + MotionEvent.ACTION_DOWN -> buttonPressed = true + MotionEvent.ACTION_UP -> buttonPressed = false } return true } diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/DPadView.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/DPadView.kt index 9c359d8..9386e8f 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/DPadView.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/DPadView.kt @@ -16,8 +16,6 @@ class DPadView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - private val haptics = ButtonHaptics(context) - enum class Direction { LEFT, RIGHT, @@ -73,7 +71,7 @@ class DPadView @JvmOverloads constructor( else drawable = dpadIdleDrawable - drawable?.setBounds(paddingLeft, paddingTop, width - paddingRight, height - paddingBottom) + drawable?.setBounds(0, 0, width, height) //drawable?.alpha = 127 drawable?.draw(canvas) } @@ -115,8 +113,6 @@ class DPadView @JvmOverloads constructor( if(state != newState) { - if(newState != null) - haptics.trigger() state = newState invalidate() stateChangeCallback?.let { it(state) } diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt index b1ecfbe..9c4ca51 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchControlsFragment.kt @@ -3,97 +3,74 @@ package com.metallic.chiaki.touchcontrols import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import com.metallic.chiaki.databinding.FragmentControlsBinding +import com.metallic.chiaki.R import com.metallic.chiaki.lib.ControllerState -import io.reactivex.Observable -import io.reactivex.rxkotlin.Observables.combineLatest -import io.reactivex.subjects.BehaviorSubject -import io.reactivex.subjects.Subject +import kotlinx.android.synthetic.main.fragment_controls.* -abstract class TouchControlsFragment : Fragment() +class TouchControlsFragment : Fragment() { - protected var ownControllerState = ControllerState() - set(value) + private var controllerState = ControllerState() + private set(value) { val diff = field != value field = value if(diff) - ownControllerStateSubject.onNext(ownControllerState) + controllerStateCallback?.let { it(value) } } - protected val ownControllerStateSubject: Subject - = BehaviorSubject.create().also { it.onNext(ownControllerState) } - - // to delay attaching to the touchpadView until it's available - protected val controllerStateProxy: Subject> - = BehaviorSubject.create>().also { it.onNext(ownControllerStateSubject) } - val controllerState: Observable get() = - controllerStateProxy.flatMap { it } - + var controllerStateCallback: ((ControllerState) -> Unit)? = null var onScreenControlsEnabled: LiveData? = null -} -class DefaultTouchControlsFragment : TouchControlsFragment() -{ - private var _binding: FragmentControlsBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - FragmentControlsBinding.inflate(inflater, container, false).let { - _binding = it - controllerStateProxy.onNext( - combineLatest(ownControllerStateSubject, binding.touchpadView.controllerState) { a, b -> a or b } - ) - it.root - } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View + = inflater.inflate(R.layout.fragment_controls, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.dpadView.stateChangeCallback = this::dpadStateChanged - binding.crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS) - binding.moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON) - binding.pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID) - binding.boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX) - binding.l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1) - binding.r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1) - binding.l3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L3) - binding.r3ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R3) - binding.optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS) - binding.shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE) - binding.psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) + dpadView.stateChangeCallback = this::dpadStateChanged + crossButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_CROSS) + moonButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_MOON) + pyramidButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PYRAMID) + boxButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_BOX) + l1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_L1) + r1ButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_R1) + optionsButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_OPTIONS) + shareButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_SHARE) + psButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_PS) + touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) - binding.l2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { l2State = if(it) 255U else 0U } } - binding.r2ButtonView.buttonPressedCallback = { ownControllerState = ownControllerState.copy().apply { r2State = if(it) 255U else 0U } } + l2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { l2State = if(it) 255U else 0U } } + r2ButtonView.buttonPressedCallback = { controllerState = controllerState.copy().apply { r2State = if(it) 255U else 0U } } val quantizeStick = { f: Float -> - (Short.MAX_VALUE * f).toInt().toShort() + (Short.MAX_VALUE * f).toShort() } - binding.leftAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply { + leftAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { leftX = quantizeStick(it.x) leftY = quantizeStick(it.y) }} - binding.rightAnalogStickView.stateChangedCallback = { ownControllerState = ownControllerState.copy().apply { + rightAnalogStickView.stateChangedCallback = { controllerState = controllerState.copy().apply { rightX = quantizeStick(it.x) rightY = quantizeStick(it.y) }} - onScreenControlsEnabled?.observe(viewLifecycleOwner, Observer { + onScreenControlsEnabled?.observe(this, Observer { view.visibility = if(it) View.VISIBLE else View.GONE }) } private fun dpadStateChanged(direction: DPadView.Direction?) { - ownControllerState = ownControllerState.copy().apply { + controllerState = controllerState.copy().apply { buttons = ((buttons and ControllerState.BUTTON_DPAD_LEFT.inv() and ControllerState.BUTTON_DPAD_RIGHT.inv() @@ -115,7 +92,7 @@ class DefaultTouchControlsFragment : TouchControlsFragment() } private fun buttonStateChanged(buttonMask: UInt) = { pressed: Boolean -> - ownControllerState = ownControllerState.copy().apply { + controllerState = controllerState.copy().apply { buttons = if(pressed) buttons or buttonMask diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchTracker.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchTracker.kt index a1ead71..01d6869 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchTracker.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchTracker.kt @@ -26,7 +26,7 @@ class TouchTracker if(pointerId == null) { pointerId = event.getPointerId(event.actionIndex) - currentPosition = Vector(event.getX(event.actionIndex), event.getY(event.actionIndex)) + currentPosition = Vector(event.x, event.y) } } diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt index 8910ef7..610c099 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadOnlyFragment.kt @@ -6,42 +6,49 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import com.metallic.chiaki.databinding.FragmentTouchpadOnlyBinding -import io.reactivex.rxkotlin.Observables.combineLatest +import com.metallic.chiaki.R +import com.metallic.chiaki.lib.ControllerState +import kotlinx.android.synthetic.main.fragment_controls.* -class TouchpadOnlyFragment : TouchControlsFragment() +class TouchpadOnlyFragment : Fragment() { + private var controllerState = ControllerState() + private set(value) + { + val diff = field != value + field = value + if(diff) + controllerStateCallback?.let { it(value) } + } + + var controllerStateCallback: ((ControllerState) -> Unit)? = null var touchpadOnlyEnabled: LiveData? = null - private var _binding: FragmentTouchpadOnlyBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = - FragmentTouchpadOnlyBinding.inflate(inflater, container, false).let { - _binding = it - controllerStateProxy.onNext( - combineLatest(ownControllerStateSubject, binding.touchpadView.controllerState) { a, b -> a or b } - ) - it.root - } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View + = inflater.inflate(R.layout.fragment_touchpad_only, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - touchpadOnlyEnabled?.observe(viewLifecycleOwner, Observer { + + touchpadButtonView.buttonPressedCallback = buttonStateChanged(ControllerState.BUTTON_TOUCHPAD) + + touchpadOnlyEnabled?.observe(this, Observer { view.visibility = if(it) View.VISIBLE else View.GONE }) } private fun buttonStateChanged(buttonMask: UInt) = { pressed: Boolean -> - ownControllerState = ownControllerState.copy().apply { + controllerState = controllerState.copy().apply { buttons = if(pressed) buttons or buttonMask else buttons and buttonMask.inv() + } } } \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt deleted file mode 100644 index a7e7b85..0000000 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/TouchpadView.kt +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL - -package com.metallic.chiaki.touchcontrols - -import android.content.Context -import android.graphics.Canvas -import android.graphics.drawable.Drawable -import android.util.AttributeSet -import android.view.MotionEvent -import android.view.View -import com.metallic.chiaki.R -import com.metallic.chiaki.lib.ControllerState -import io.reactivex.Observable -import io.reactivex.subjects.BehaviorSubject -import io.reactivex.subjects.Subject -import kotlin.math.max - -class TouchpadView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : View(context, attrs, defStyleAttr) -{ - companion object - { - private const val BUTTON_PRESS_MAX_MOVE_DIST_DP = 32.0f - private const val SHORT_BUTTON_PRESS_DURATION_MS = 200L - private const val BUTTON_HOLD_DELAY_MS = 500L - } - - private val haptics = ButtonHaptics(context) - - private val drawableIdle: Drawable? - private val drawablePressed: Drawable? - - private val state: ControllerState = ControllerState() - - inner class Touch( - val stateId: UByte, - private val startX: Float, - private val startY: Float) - { - var lifted = false // will be true but touch still in list when only relevant for short touch - private var maxDist: Float = 0.0f - val moveInsignificant: Boolean get() = maxDist < BUTTON_PRESS_MAX_MOVE_DIST_DP - - fun onMove(x: Float, y: Float) - { - val d = (Vector(x, y) - Vector(startX, startY)).length / resources.displayMetrics.density - maxDist = max(d, maxDist) - } - - val startButtonHoldRunnable = Runnable { - if(!moveInsignificant || buttonHeld) - return@Runnable - haptics.trigger(true) - state.buttons = state.buttons or ControllerState.BUTTON_TOUCHPAD - buttonHeld = true - triggerStateChanged() - } - } - private val pointerTouches = mutableMapOf() - - private val stateSubject: Subject - = BehaviorSubject.create().also { it.onNext(state) } - val controllerState: Observable get() = stateSubject - - private var shortPressingTouches = listOf() - private val shortButtonPressLiftRunnable = Runnable { - state.buttons = state.buttons and ControllerState.BUTTON_TOUCHPAD.inv() - shortPressingTouches.forEach { - state.stopTouch(it.stateId) - } - shortPressingTouches = listOf() - triggerStateChanged() - } - - private var buttonHeld = false - - init - { - context.theme.obtainStyledAttributes(attrs, R.styleable.TouchpadView, 0, 0).apply { - drawableIdle = getDrawable(R.styleable.TouchpadView_drawableIdle) - drawablePressed = getDrawable(R.styleable.TouchpadView_drawablePressed) - recycle() - } - isClickable = true - } - - override fun onDraw(canvas: Canvas) - { - super.onDraw(canvas) - if(pointerTouches.values.find { !it.lifted } == null) - return - val drawable = if(state.buttons and ControllerState.BUTTON_TOUCHPAD != 0U) drawablePressed else drawableIdle - drawable?.setBounds(paddingLeft, paddingTop, width - paddingRight, height - paddingBottom) - drawable?.draw(canvas) - } - - private fun touchX(event: MotionEvent, index: Int): UShort = - maxOf(0U.toUShort(), minOf((ControllerState.TOUCHPAD_WIDTH - 1u).toUShort(), - (ControllerState.TOUCHPAD_WIDTH.toFloat() * event.getX(index) / width.toFloat()).toUInt().toUShort())) - - private fun touchY(event: MotionEvent, index: Int): UShort = - maxOf(0U.toUShort(), minOf((ControllerState.TOUCHPAD_HEIGHT - 1u).toUShort(), - (ControllerState.TOUCHPAD_HEIGHT.toFloat() * event.getY(index) / height.toFloat()).toUInt().toUShort())) - - override fun onTouchEvent(event: MotionEvent): Boolean - { - when(event.actionMasked) - { - MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> { - state.startTouch(touchX(event, event.actionIndex), touchY(event, event.actionIndex))?.let { - haptics.trigger() - val touch = Touch(it, event.getX(event.actionIndex), event.getY(event.actionIndex)) - pointerTouches[event.getPointerId(event.actionIndex)] = touch - if(!buttonHeld) - postDelayed(touch.startButtonHoldRunnable, BUTTON_HOLD_DELAY_MS) - triggerStateChanged() - } - } - MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> { - pointerTouches.remove(event.getPointerId(event.actionIndex))?.let { - removeCallbacks(it.startButtonHoldRunnable) - when - { - buttonHeld -> - { - buttonHeld = false - state.buttons = state.buttons and ControllerState.BUTTON_TOUCHPAD.inv() - state.stopTouch(it.stateId) - } - it.moveInsignificant -> triggerShortButtonPress(it) - else -> state.stopTouch(it.stateId) - } - triggerStateChanged() - } - } - MotionEvent.ACTION_MOVE -> { - val changed = pointerTouches.entries.fold(false) { acc, it -> - val index = event.findPointerIndex(it.key) - if(index < 0) - acc - else - { - it.value.onMove(event.getX(event.actionIndex), event.getY(event.actionIndex)) - acc || state.setTouchPos(it.value.stateId, touchX(event, index), touchY(event, index)) - } - } - if(changed) - triggerStateChanged() - } - } - return true - } - - private fun triggerShortButtonPress(touch: Touch) - { - shortPressingTouches = shortPressingTouches + listOf(touch) - removeCallbacks(shortButtonPressLiftRunnable) - state.buttons = state.buttons or ControllerState.BUTTON_TOUCHPAD - postDelayed(shortButtonPressLiftRunnable, SHORT_BUTTON_PRESS_DURATION_MS) - } - - private fun triggerStateChanged() - { - invalidate() - stateSubject.onNext(state) - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/Vector.kt b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/Vector.kt index 208c41a..36216e8 100644 --- a/android/app/src/main/java/com/metallic/chiaki/touchcontrols/Vector.kt +++ b/android/app/src/main/java/com/metallic/chiaki/touchcontrols/Vector.kt @@ -2,7 +2,6 @@ package com.metallic.chiaki.touchcontrols -import android.view.View import kotlin.math.sqrt data class Vector(val x: Float, val y: Float) @@ -19,10 +18,4 @@ data class Vector(val x: Float, val y: Float) val lengthSq get() = x*x + y*y val length get() = sqrt(lengthSq) val normalized get() = this / length -} - -val View.locationOnScreen: Vector get() { - val v = intArrayOf(0, 0) - this.getLocationOnScreen(v) - return Vector(v[0].toFloat(), v[1].toFloat()) } \ No newline at end of file diff --git a/android/app/src/main/res/drawable/control_button_l1.xml b/android/app/src/main/res/drawable/control_button_l1.xml index 17f9594..a709f25 100644 --- a/android/app/src/main/res/drawable/control_button_l1.xml +++ b/android/app/src/main/res/drawable/control_button_l1.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_l1_pressed.xml b/android/app/src/main/res/drawable/control_button_l1_pressed.xml index 0267190..b8bcce0 100644 --- a/android/app/src/main/res/drawable/control_button_l1_pressed.xml +++ b/android/app/src/main/res/drawable/control_button_l1_pressed.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_l2.xml b/android/app/src/main/res/drawable/control_button_l2.xml index 8e75f40..6867aa0 100644 --- a/android/app/src/main/res/drawable/control_button_l2.xml +++ b/android/app/src/main/res/drawable/control_button_l2.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_l2_pressed.xml b/android/app/src/main/res/drawable/control_button_l2_pressed.xml index b120891..e4df2de 100644 --- a/android/app/src/main/res/drawable/control_button_l2_pressed.xml +++ b/android/app/src/main/res/drawable/control_button_l2_pressed.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_l3.xml b/android/app/src/main/res/drawable/control_button_l3.xml deleted file mode 100644 index 34c3382..0000000 --- a/android/app/src/main/res/drawable/control_button_l3.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/control_button_l3_pressed.xml b/android/app/src/main/res/drawable/control_button_l3_pressed.xml deleted file mode 100644 index 43f239a..0000000 --- a/android/app/src/main/res/drawable/control_button_l3_pressed.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/control_button_r1.xml b/android/app/src/main/res/drawable/control_button_r1.xml index d614419..a0b3262 100644 --- a/android/app/src/main/res/drawable/control_button_r1.xml +++ b/android/app/src/main/res/drawable/control_button_r1.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_r1_pressed.xml b/android/app/src/main/res/drawable/control_button_r1_pressed.xml index 8d51983..5cadcb6 100644 --- a/android/app/src/main/res/drawable/control_button_r1_pressed.xml +++ b/android/app/src/main/res/drawable/control_button_r1_pressed.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_r2.xml b/android/app/src/main/res/drawable/control_button_r2.xml index dd16994..c6a625d 100644 --- a/android/app/src/main/res/drawable/control_button_r2.xml +++ b/android/app/src/main/res/drawable/control_button_r2.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_r2_pressed.xml b/android/app/src/main/res/drawable/control_button_r2_pressed.xml index 7cc84b1..260e60b 100644 --- a/android/app/src/main/res/drawable/control_button_r2_pressed.xml +++ b/android/app/src/main/res/drawable/control_button_r2_pressed.xml @@ -1,12 +1,13 @@ + android:viewportHeight="33.86667"> diff --git a/android/app/src/main/res/drawable/control_button_r3.xml b/android/app/src/main/res/drawable/control_button_r3.xml deleted file mode 100644 index 0f2bcfd..0000000 --- a/android/app/src/main/res/drawable/control_button_r3.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/control_button_r3_pressed.xml b/android/app/src/main/res/drawable/control_button_r3_pressed.xml deleted file mode 100644 index 08635e8..0000000 --- a/android/app/src/main/res/drawable/control_button_r3_pressed.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/control_button_touchpad.xml b/android/app/src/main/res/drawable/control_button_touchpad.xml new file mode 100644 index 0000000..40c0465 --- /dev/null +++ b/android/app/src/main/res/drawable/control_button_touchpad.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/app/src/main/res/drawable/control_button_touchpad_pressed.xml b/android/app/src/main/res/drawable/control_button_touchpad_pressed.xml new file mode 100644 index 0000000..8255860 --- /dev/null +++ b/android/app/src/main/res/drawable/control_button_touchpad_pressed.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/app/src/main/res/drawable/control_touchpad.xml b/android/app/src/main/res/drawable/control_touchpad.xml deleted file mode 100644 index 509b8a3..0000000 --- a/android/app/src/main/res/drawable/control_touchpad.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/control_touchpad_pressed.xml b/android/app/src/main/res/drawable/control_touchpad_pressed.xml deleted file mode 100644 index b4f3f16..0000000 --- a/android/app/src/main/res/drawable/control_touchpad_pressed.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/ic_button_haptic.xml b/android/app/src/main/res/drawable/ic_button_haptic.xml deleted file mode 100644 index fea4c99..0000000 --- a/android/app/src/main/res/drawable/ic_button_haptic.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/ic_motion.xml b/android/app/src/main/res/drawable/ic_motion.xml deleted file mode 100644 index c5a4ea1..0000000 --- a/android/app/src/main/res/drawable/ic_motion.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android/app/src/main/res/drawable/ic_rumble.xml b/android/app/src/main/res/drawable/ic_rumble.xml deleted file mode 100644 index 4ecdb61..0000000 --- a/android/app/src/main/res/drawable/ic_rumble.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android/app/src/main/res/layout/activity_stream.xml b/android/app/src/main/res/layout/activity_stream.xml index 6a7f9a3..255ccde 100644 --- a/android/app/src/main/res/layout/activity_stream.xml +++ b/android/app/src/main/res/layout/activity_stream.xml @@ -1,24 +1,16 @@ - - - - + android:layout_height="match_parent"/> @@ -42,6 +34,7 @@ android:id="@+id/overlay" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_gravity="bottom" android:fitsSystemWindows="true"> + android:clipChildren="false"> - - + app:layout_constraintBottom_toBottomOf="parent"/> - - - - - + + + app:layout_constraintTop_toBottomOf="@id/l2ButtonView"/> + app:layout_constraintTop_toBottomOf="@id/r2ButtonView"/> - - + app:layout_constraintEnd_toEndOf="parent" /> \ No newline at end of file diff --git a/android/app/src/main/res/values/attrs.xml b/android/app/src/main/res/values/attrs.xml index 04f738a..b0a1170 100644 --- a/android/app/src/main/res/values/attrs.xml +++ b/android/app/src/main/res/values/attrs.xml @@ -1,11 +1,8 @@ - - - - - + + @@ -14,9 +11,4 @@ - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml index 9ee2e9b..543f0f4 100644 --- a/android/app/src/main/res/values/dimens.xml +++ b/android/app/src/main/res/values/dimens.xml @@ -1,10 +1,6 @@ - 88dp - 176dp - 24dp - 16dp - 64dp + 48dp 48dp 32dp 48dp diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 254042b..0f54522 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -88,12 +88,6 @@ H265 (PS5 only) Swap Cross/Moon and Box/Pyramid Buttons Swap face buttons if default mapping is incorrect (e.g. for 8BitDo controllers) - Rumble - Use phone vibration motor for rumble - Motion - Use device\'s motion sensors for controller motion - Touch Haptics - Use phone vibration motor for short haptic feedback on button touches Are you sure you want to delete the registered console %s with ID %s? Are you sure you want to delete the console entry for %s? Keep @@ -107,10 +101,7 @@ discovery_enabled on_screen_controls_enabled - touchpad_only_enabled - rumble_enabled - motion_enabled - button_haptic_enabled + touchpad_only_enabled log_verbose import_settings export_settings diff --git a/android/app/src/main/res/xml/preferences.xml b/android/app/src/main/res/xml/preferences.xml index 49989db..0416f6e 100644 --- a/android/app/src/main/res/xml/preferences.xml +++ b/android/app/src/main/res/xml/preferences.xml @@ -19,24 +19,6 @@ app:summary="@string/preferences_swap_cross_moon_summary" app:icon="@drawable/ic_gamepad" /> - - - - - - - - - diff --git a/assets/chiaki_macos_simple.svg b/assets/chiaki_macos_simple.svg deleted file mode 100644 index 7f1359d..0000000 --- a/assets/chiaki_macos_simple.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - diff --git a/assets/controls/l1.svg b/assets/controls/l1.svg index 9d3c3f9..ce67e89 100644 --- a/assets/controls/l1.svg +++ b/assets/controls/l1.svg @@ -5,13 +5,37 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="l1.svg" + inkscape:version="1.0beta1 (5c3063637d, 2019-10-15)" id="svg8" version="1.1" - viewBox="0 0 67.733332 67.733336" - height="256" + viewBox="0 0 67.733332 33.866668" + height="128" width="256"> + @@ -25,12 +49,28 @@ + style="display:inline" + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1"> + diff --git a/assets/controls/l2.svg b/assets/controls/l2.svg index 4d561e0..01e886f 100644 --- a/assets/controls/l2.svg +++ b/assets/controls/l2.svg @@ -5,13 +5,37 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="l2.svg" + inkscape:version="1.0beta1 (5c3063637d, 2019-10-15)" id="svg8" version="1.1" - viewBox="0 0 67.733332 67.733336" - height="256" + viewBox="0 0 67.733332 33.866668" + height="128" width="256"> + @@ -25,12 +49,28 @@ + style="display:inline" + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1"> + diff --git a/assets/controls/l3.svg b/assets/controls/l3.svg deleted file mode 100644 index 464e440..0000000 --- a/assets/controls/l3.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - diff --git a/assets/controls/l3_raw.svg b/assets/controls/l3_raw.svg deleted file mode 100644 index f04135f..0000000 --- a/assets/controls/l3_raw.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - L3 - - diff --git a/assets/controls/lr12.svg b/assets/controls/lr12.svg deleted file mode 100644 index 874475f..0000000 --- a/assets/controls/lr12.svg +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - L1 - - - - R1 - - - - L2 - - - - R2 - - diff --git a/assets/controls/r1.svg b/assets/controls/r1.svg index 70f881c..ef51bc2 100644 --- a/assets/controls/r1.svg +++ b/assets/controls/r1.svg @@ -5,13 +5,37 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="r1.svg" + inkscape:version="1.0beta1 (5c3063637d, 2019-10-15)" id="svg8" version="1.1" - viewBox="0 0 67.733332 67.733336" - height="256" + viewBox="0 0 67.733332 33.866668" + height="128" width="256"> + @@ -25,12 +49,28 @@ + style="display:inline" + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1"> + diff --git a/assets/controls/r2.svg b/assets/controls/r2.svg index c32639d..350ffaa 100644 --- a/assets/controls/r2.svg +++ b/assets/controls/r2.svg @@ -5,13 +5,37 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="r2.svg" + inkscape:version="1.0beta1 (5c3063637d, 2019-10-15)" id="svg8" version="1.1" - viewBox="0 0 67.733332 67.733336" - height="256" + viewBox="0 0 67.733332 33.866668" + height="128" width="256"> + @@ -25,13 +49,28 @@ + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Ebene 1"> + diff --git a/assets/controls/r3.svg b/assets/controls/r3.svg deleted file mode 100644 index b5f1fa7..0000000 --- a/assets/controls/r3.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - diff --git a/assets/controls/r3_raw.svg b/assets/controls/r3_raw.svg deleted file mode 100644 index 5f47c8e..0000000 --- a/assets/controls/r3_raw.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - R3 - - diff --git a/assets/controls/touchpad_surface.svg b/assets/controls/touchpad_surface.svg deleted file mode 100644 index 7476128..0000000 --- a/assets/controls/touchpad_surface.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 83de1f9..83c37a9 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -15,4 +15,3 @@ endif() add_executable(chiaki-cli src/main.c) target_link_libraries(chiaki-cli chiaki-cli-lib) -install(TARGETS chiaki-cli) diff --git a/cli/src/discover.c b/cli/src/discover.c index cf9319f..503b53a 100644 --- a/cli/src/discover.c +++ b/cli/src/discover.c @@ -142,19 +142,13 @@ CHIAKI_EXPORT int chiaki_cli_cmd_discover(ChiakiLog *log, int argc, char *argv[] return 1; } + ((struct sockaddr_in *)host_addr)->sin_port = htons(CHIAKI_DISCOVERY_PORT_PS4); // TODO: IPv6, PS5, should probably use the service + ChiakiDiscoveryPacket packet; memset(&packet, 0, sizeof(packet)); packet.cmd = CHIAKI_DISCOVERY_CMD_SRCH; - packet.protocol_version = CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS4; - ((struct sockaddr_in *)host_addr)->sin_port = htons(CHIAKI_DISCOVERY_PORT_PS4); - err = chiaki_discovery_send(&discovery, &packet, host_addr, host_addr_len); - if(err != CHIAKI_ERR_SUCCESS) - CHIAKI_LOGE(log, "Failed to send discovery packet for PS4: %s", chiaki_error_string(err)); - packet.protocol_version = CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS5; - ((struct sockaddr_in *)host_addr)->sin_port = htons(CHIAKI_DISCOVERY_PORT_PS5); - err = chiaki_discovery_send(&discovery, &packet, host_addr, host_addr_len); - if(err != CHIAKI_ERR_SUCCESS) - CHIAKI_LOGE(log, "Failed to send discovery packet for PS5: %s", chiaki_error_string(err)); + + chiaki_discovery_send(&discovery, &packet, host_addr, host_addr_len); while(1) sleep(1); // TODO: wtf diff --git a/cli/src/wakeup.c b/cli/src/wakeup.c index cea2792..cf5ab45 100644 --- a/cli/src/wakeup.c +++ b/cli/src/wakeup.c @@ -11,14 +11,10 @@ static char doc[] = "Send a PS4 wakeup packet."; #define ARG_KEY_HOST 'h' #define ARG_KEY_REGISTKEY 'r' -#define ARG_KEY_PS4 '4' -#define ARG_KEY_PS5 '5' static struct argp_option options[] = { { "host", ARG_KEY_HOST, "Host", 0, "Host to send wakeup packet to", 0 }, - { "registkey", ARG_KEY_REGISTKEY, "RegistKey", 0, "Remote Play registration key (plaintext)", 0 }, - { "ps4", ARG_KEY_PS4, NULL, 0, "PlayStation 4", 0 }, - { "ps5", ARG_KEY_PS5, NULL, 0, "PlayStation 5 (default)", 0 }, + { "registkey", ARG_KEY_REGISTKEY, "RegistKey", 0, "PS4 registration key", 0 }, { 0 } }; @@ -26,7 +22,6 @@ typedef struct arguments { const char *host; const char *registkey; - bool ps5; } Arguments; static int parse_opt(int key, char *arg, struct argp_state *state) @@ -44,12 +39,6 @@ static int parse_opt(int key, char *arg, struct argp_state *state) case ARGP_KEY_ARG: argp_usage(state); break; - case ARG_KEY_PS4: - arguments->ps5 = false; - break; - case ARG_KEY_PS5: - arguments->ps5 = true; - break; default: return ARGP_ERR_UNKNOWN; } @@ -62,7 +51,6 @@ static struct argp argp = { options, parse_opt, 0, doc, 0, 0, 0 }; CHIAKI_EXPORT int chiaki_cli_cmd_wakeup(ChiakiLog *log, int argc, char *argv[]) { Arguments arguments = { 0 }; - arguments.ps5 = true; error_t argp_r = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &arguments); if(argp_r != 0) return 1; @@ -85,5 +73,5 @@ CHIAKI_EXPORT int chiaki_cli_cmd_wakeup(ChiakiLog *log, int argc, char *argv[]) uint64_t credential = (uint64_t)strtoull(arguments.registkey, NULL, 16); - return chiaki_discovery_wakeup(log, NULL, arguments.host, credential, arguments.ps5); + return chiaki_discovery_wakeup(log, NULL, arguments.host, credential, false); } diff --git a/cmake/FindFFMPEG.cmake b/cmake/FindFFMPEG.cmake index bdb66aa..32e8ac0 100644 --- a/cmake/FindFFMPEG.cmake +++ b/cmake/FindFFMPEG.cmake @@ -49,11 +49,7 @@ function (_ffmpeg_find component headername) # Try pkg-config first if(PKG_CONFIG_FOUND) - if(CMAKE_VERSION VERSION_LESS "3.6") - pkg_check_modules(FFMPEG_${component} lib${component}) - else() - pkg_check_modules(FFMPEG_${component} lib${component} IMPORTED_TARGET) - endif() + pkg_check_modules(FFMPEG_${component} lib${component} IMPORTED_TARGET) if(FFMPEG_${component}_FOUND) if((TARGET PkgConfig::FFMPEG_${component}) AND (NOT CMAKE_VERSION VERSION_LESS "3.11.0")) if(APPLE) @@ -73,9 +69,6 @@ function (_ffmpeg_find component headername) add_library(FFMPEG::${component} ALIAS PkgConfig::FFMPEG_${component}) else() add_library("FFMPEG::${component}" INTERFACE IMPORTED) - if(CMAKE_VERSION VERSION_LESS "3.6") - link_directories("${FFMPEG_${component}_LIBRARY_DIRS}") - endif() set_target_properties("FFMPEG::${component}" PROPERTIES INTERFACE_LINK_DIRECTORIES "${FFMPEG_${component}_LIBRARY_DIRS}" INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_${component}_INCLUDE_DIRS}" @@ -231,14 +224,10 @@ foreach (_ffmpeg_component IN LISTS FFMPEG_FIND_COMPONENTS) list(APPEND _ffmpeg_required_vars "FFMPEG_${_ffmpeg_component}_LIBRARIES") else() - if(NOT FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS) - set(FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS - "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIR}") - endif() - if(NOT FFMPEG_${_ffmpeg_component}_LIBRARIES) - set(FFMPEG_${_ffmpeg_component}_LIBRARIES - "${FFMPEG_${_ffmpeg_component}_LIBRARY}") - endif() + set(FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS + "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIR}") + set(FFMPEG_${_ffmpeg_component}_LIBRARIES + "${FFMPEG_${_ffmpeg_component}_LIBRARY}") list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS}") list(APPEND FFMPEG_LIBRARIES diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 03717b0..a0b9ebd 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -1,26 +1,6 @@ find_package(SDL2 NO_MODULE QUIET) -# Adapted from libsdl-org/SDL_ttf: https://github.com/libsdl-org/SDL_ttf/blob/main/cmake/FindPrivateSDL2.cmake#L19-L31 -# Copyright (C) 1997-2022 Sam Lantinga -# Licensed under the zlib license (https://github.com/libsdl-org/SDL_ttf/blob/main/LICENSE.txt) -set(SDL2_VERSION_MAJOR) -set(SDL2_VERSION_MINOR) -set(SDL2_VERSION_PATCH) -set(SDL2_VERSION) -if(SDL2_INCLUDE_DIR) - file(READ "${SDL2_INCLUDE_DIR}/SDL_version.h" _sdl_version_h) - string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl2_major_re "${_sdl_version_h}") - set(SDL2_VERSION_MAJOR "${CMAKE_MATCH_1}") - string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl2_minor_re "${_sdl_version_h}") - set(SDL2_VERSION_MINOR "${CMAKE_MATCH_1}") - string(REGEX MATCH "#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)" _sdl2_patch_re "${_sdl_version_h}") - set(SDL2_VERSION_PATCH "${CMAKE_MATCH_1}") - if(_sdl2_major_re AND _sdl2_minor_re AND _sdl2_patch_re) - set(SDL2_VERSION "${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}") - endif() -endif() - if(SDL2_FOUND AND (NOT TARGET SDL2::SDL2)) add_library(SDL2::SDL2 UNKNOWN IMPORTED GLOBAL) if(NOT SDL2_LIBDIR) diff --git a/cmake/OpenSSLExternalProject.cmake b/cmake/OpenSSLExternalProject.cmake index 1e1370d..0538d48 100644 --- a/cmake/OpenSSLExternalProject.cmake +++ b/cmake/OpenSSLExternalProject.cmake @@ -33,8 +33,8 @@ endif() find_program(MAKE_EXE NAMES gmake make) ExternalProject_Add(OpenSSL-ExternalProject - URL https://www.openssl.org/source/openssl-1.1.1s.tar.gz - URL_HASH SHA256=c5ac01e760ee6ff0dab61d6b2bbd30146724d063eb322180c6f18a6f74e4b6aa + URL https://www.openssl.org/source/openssl-1.1.1d.tar.gz + URL_HASH SHA256=1e3a91bc1f9dfce01af26026f856e064eab4c8ee0a8f457b5ae30b40b8b711f2 INSTALL_DIR "${OPENSSL_INSTALL_DIR}" CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env ${OPENSSL_BUILD_ENV} "/Configure" "--prefix=" no-shared ${OPENSSL_CONFIG_EXTRA_ARGS} "${OPENSSL_OS_COMPILER}" diff --git a/cmake/switch.cmake b/cmake/switch.cmake index 7e600be..6046d67 100644 --- a/cmake/switch.cmake +++ b/cmake/switch.cmake @@ -1,15 +1,34 @@ # Find DEVKITPRO set(DEVKITPRO "$ENV{DEVKITPRO}" CACHE PATH "Path to DevKitPro") -if(NOT DEVKITPRO) - message(FATAL_ERROR "Please set DEVKITPRO env before calling cmake. https://devkitpro.org/wiki/Getting_Started") +set(PORTLIBS_PREFIX "$ENV{PORTLIBS_PREFIX}" CACHE PATH "Path to portlibs inside DevKitPro") +if(NOT DEVKITPRO OR NOT PORTLIBS_PREFIX) + message(FATAL_ERROR "Please set DEVKITPRO & PORTLIBS_PREFIX env before calling cmake. https://devkitpro.org/wiki/Getting_Started") endif() # include devkitpro toolchain -include("${DEVKITPRO}/cmake/Switch.cmake") +include("${DEVKITPRO}/switch.cmake") set(NSWITCH TRUE) +# Enable gcc -g, to use +# /opt/devkitpro/devkitA64/bin/aarch64-none-elf-addr2line -e build_switch/switch/chiaki -f -p -C -a 0xCCB5C +# set(CMAKE_BUILD_TYPE Debug) +# set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available" ) + +# FIXME rework this file to use the toolchain only +# https://github.com/diasurgical/devilutionX/pull/764 +set(ARCH "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -ftls-model=local-exec") +# set(CMAKE_C_FLAGS "-O2 -ffunction-sections ${ARCH}") +set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") +# workaroud force -fPIE to avoid +# aarch64-none-elf/bin/ld: read-only segment has dynamic relocations +set(CMAKE_EXE_LINKER_FLAGS "-specs=${DEVKITPRO}/libnx/switch.specs ${ARCH} -fPIE -Wl,-Map,Output.map") + +# add portlibs to the list of include dir +include_directories("${PORTLIBS_PREFIX}/include") + # troubleshoot message(STATUS "CMAKE_FIND_ROOT_PATH = ${CMAKE_FIND_ROOT_PATH}") message(STATUS "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}") @@ -60,3 +79,4 @@ function(add_nro_target output_name target title author version icon romfs) endfunction() set(CMAKE_USE_SYSTEM_ENVIRONMENT_PATH OFF) +set(CMAKE_PREFIX_PATH "/") diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 443150f..5f44908 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -6,6 +6,9 @@ find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Concurrent Multimedia Open if(APPLE) find_package(Qt5 REQUIRED COMPONENTS MacExtras) endif() +if(CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER) + find_package(SDL2 MODULE REQUIRED) +endif() if(WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN) @@ -67,12 +70,12 @@ if(CHIAKI_ENABLE_CLI) endif() target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Concurrent Qt5::Multimedia Qt5::OpenGL Qt5::Svg) -target_link_libraries(chiaki SDL2::SDL2) if(APPLE) target_link_libraries(chiaki Qt5::MacExtras) target_compile_definitions(chiaki PRIVATE CHIAKI_GUI_ENABLE_QT_MACEXTRAS) endif() if(CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER) + target_link_libraries(chiaki SDL2::SDL2) target_compile_definitions(chiaki PRIVATE CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER) endif() if(CHIAKI_ENABLE_SETSU) diff --git a/gui/chiaki.icns b/gui/chiaki.icns index e51fa65..13613ff 100644 Binary files a/gui/chiaki.icns and b/gui/chiaki.icns differ diff --git a/gui/include/avopenglwidget.h b/gui/include/avopenglwidget.h index 19bd287..6f234e9 100644 --- a/gui/include/avopenglwidget.h +++ b/gui/include/avopenglwidget.h @@ -3,8 +3,6 @@ #ifndef CHIAKI_AVOPENGLWIDGET_H #define CHIAKI_AVOPENGLWIDGET_H -#include "transformmode.h" - #include #include @@ -76,24 +74,21 @@ class AVOpenGLWidget: public QOpenGLWidget public: static QSurfaceFormat CreateSurfaceFormat(); - explicit AVOpenGLWidget(StreamSession *session, QWidget *parent = nullptr, TransformMode transform_mode = TransformMode::Fit); + explicit AVOpenGLWidget(StreamSession *session, QWidget *parent = nullptr); ~AVOpenGLWidget() override; void SwapFrames(); AVOpenGLFrame *GetBackgroundFrame() { return &frames[1 - frame_fg]; } - void SetTransformMode(TransformMode mode) { transform_mode = mode; } - TransformMode GetTransformMode() const { return transform_mode; } - protected: - TransformMode transform_mode; void mouseMoveEvent(QMouseEvent *event) override; void initializeGL() override; void paintGL() override; - public slots: + private slots: void ResetMouseTimeout(); + public slots: void HideMouse(); }; diff --git a/gui/include/controllermanager.h b/gui/include/controllermanager.h index eee0120..6ec6efb 100644 --- a/gui/include/controllermanager.h +++ b/gui/include/controllermanager.h @@ -12,12 +12,8 @@ #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER #include -#include #endif -#define PS_TOUCHPAD_MAX_X 1920 -#define PS_TOUCHPAD_MAX_Y 1079 - class Controller; class ControllerManager : public QObject @@ -37,9 +33,7 @@ class ControllerManager : public QObject private slots: void UpdateAvailableControllers(); void HandleEvents(); -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER - void ControllerEvent(SDL_Event evt); -#endif + void ControllerEvent(int device_id); public: static ControllerManager *GetInstance(); @@ -63,24 +57,12 @@ class Controller : public QObject private: Controller(int device_id, ControllerManager *manager); -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER - void UpdateState(SDL_Event event); - bool HandleButtonEvent(SDL_ControllerButtonEvent event); - bool HandleAxisEvent(SDL_ControllerAxisEvent event); -#if SDL_VERSION_ATLEAST(2, 0, 14) - bool HandleSensorEvent(SDL_ControllerSensorEvent event); - bool HandleTouchpadEvent(SDL_ControllerTouchpadEvent event); -#endif -#endif + void UpdateState(); ControllerManager *manager; int id; - ChiakiOrientationTracker orientation_tracker; - ChiakiControllerState state; - bool is_dualsense; #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER - QMap, uint8_t> touch_ids; SDL_GameController *controller; #endif @@ -91,44 +73,9 @@ class Controller : public QObject int GetDeviceID(); QString GetName(); ChiakiControllerState GetState(); - void SetRumble(uint8_t left, uint8_t right); - void SetTriggerEffects(uint8_t type_left, const uint8_t *data_left, uint8_t type_right, const uint8_t *data_right); - bool IsDualSense(); signals: void StateChanged(); }; -/* PS5 trigger effect documentation: - https://controllers.fandom.com/wiki/Sony_DualSense#FFB_Trigger_Modes - - Taken from SDL2, licensed under the zlib license, - Copyright (C) 1997-2022 Sam Lantinga - https://github.com/libsdl-org/SDL/blob/release-2.24.1/test/testgamecontroller.c#L263-L289 -*/ -typedef struct -{ - Uint8 ucEnableBits1; /* 0 */ - Uint8 ucEnableBits2; /* 1 */ - Uint8 ucRumbleRight; /* 2 */ - Uint8 ucRumbleLeft; /* 3 */ - Uint8 ucHeadphoneVolume; /* 4 */ - Uint8 ucSpeakerVolume; /* 5 */ - Uint8 ucMicrophoneVolume; /* 6 */ - Uint8 ucAudioEnableBits; /* 7 */ - Uint8 ucMicLightMode; /* 8 */ - Uint8 ucAudioMuteBits; /* 9 */ - Uint8 rgucRightTriggerEffect[11]; /* 10 */ - Uint8 rgucLeftTriggerEffect[11]; /* 21 */ - Uint8 rgucUnknown1[6]; /* 32 */ - Uint8 ucLedFlags; /* 38 */ - Uint8 rgucUnknown2[2]; /* 39 */ - Uint8 ucLedAnim; /* 41 */ - Uint8 ucLedBrightness; /* 42 */ - Uint8 ucPadLights; /* 43 */ - Uint8 ucLedRed; /* 44 */ - Uint8 ucLedGreen; /* 45 */ - Uint8 ucLedBlue; /* 46 */ -} DS5EffectsState_t; - #endif // CHIAKI_CONTROLLERMANAGER_H diff --git a/gui/include/mainwindow.h b/gui/include/mainwindow.h index 4112c19..f1190de 100644 --- a/gui/include/mainwindow.h +++ b/gui/include/mainwindow.h @@ -55,7 +55,6 @@ class MainWindow : public QMainWindow void UpdateDiscoveryEnabled(); void ShowSettings(); - void Quit(); void UpdateDisplayServers(); void UpdateServerWidgets(); diff --git a/gui/include/settings.h b/gui/include/settings.h index 00f38ab..c2320b8 100644 --- a/gui/include/settings.h +++ b/gui/include/settings.h @@ -63,9 +63,6 @@ class Settings : public QObject void SetLogVerbose(bool enabled) { settings.setValue("settings/log_verbose", enabled); } uint32_t GetLogLevelMask(); - bool GetDualSenseEnabled() const { return settings.value("settings/dualsense_enabled", false).toBool(); } - void SetDualSenseEnabled(bool enabled) { settings.setValue("settings/dualsense_enabled", enabled); } - ChiakiVideoResolutionPreset GetResolution() const; void SetResolution(ChiakiVideoResolutionPreset resolution); diff --git a/gui/include/settingsdialog.h b/gui/include/settingsdialog.h index 00af648..d564bef 100644 --- a/gui/include/settingsdialog.h +++ b/gui/include/settingsdialog.h @@ -20,7 +20,6 @@ class SettingsDialog : public QDialog QCheckBox *log_verbose_check_box; QComboBox *disconnect_action_combo_box; - QCheckBox *dualsense_check_box; QComboBox *resolution_combo_box; QComboBox *fps_combo_box; @@ -38,7 +37,6 @@ class SettingsDialog : public QDialog private slots: void LogVerboseChanged(); - void DualSenseChanged(); void DisconnectActionSelected(); void ResolutionSelected(); diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h index 4b0ba01..c98758e 100644 --- a/gui/include/streamsession.h +++ b/gui/include/streamsession.h @@ -13,14 +13,12 @@ #if CHIAKI_GUI_ENABLE_SETSU #include -#include #endif #include "exception.h" #include "sessionlog.h" #include "controllermanager.h" #include "settings.h" -#include "transformmode.h" #include #include @@ -54,18 +52,9 @@ struct StreamSessionConnectInfo ChiakiConnectVideoProfile video_profile; unsigned int audio_buffer_size; bool fullscreen; - TransformMode transform_mode; bool enable_keyboard; - bool enable_dualsense; - StreamSessionConnectInfo( - Settings *settings, - ChiakiTarget target, - QString host, - QByteArray regist_key, - QByteArray morning, - bool fullscreen, - TransformMode transform_mode); + StreamSessionConnectInfo(Settings *settings, ChiakiTarget target, QString host, QByteArray regist_key, QByteArray morning, bool fullscreen); }; class StreamSession : public QObject @@ -85,9 +74,6 @@ class StreamSession : public QObject Setsu *setsu; QMap, uint8_t> setsu_ids; ChiakiControllerState setsu_state; - SetsuDevice *setsu_motion_device; - ChiakiOrientationTracker orient_tracker; - bool orient_dirty; #endif ChiakiControllerState keyboard_state; @@ -102,23 +88,17 @@ class StreamSession : public QObject unsigned int audio_buffer_size; QAudioOutput *audio_output; QIODevice *audio_io; - SDL_AudioDeviceID haptics_output; - uint8_t *haptics_resampler_buf; QMap key_map; void PushAudioFrame(int16_t *buf, size_t samples_count); - void PushHapticsFrame(uint8_t *buf, size_t buf_size); + void Event(ChiakiEvent *event); #if CHIAKI_GUI_ENABLE_SETSU void HandleSetsuEvent(SetsuEvent *event); #endif private slots: void InitAudio(unsigned int channels, unsigned int rate); - void InitHaptics(); - void Event(ChiakiEvent *event); - void DisconnectHaptics(); - void ConnectHaptics(); public: explicit StreamSession(const StreamSessionConnectInfo &connect_info, QObject *parent = nullptr); @@ -140,7 +120,7 @@ class StreamSession : public QObject #endif void HandleKeyboardEvent(QKeyEvent *event); - bool HandleMouseEvent(QMouseEvent *event); + void HandleMouseEvent(QMouseEvent *event); signals: void FfmpegFrameAvailable(); diff --git a/gui/include/streamwindow.h b/gui/include/streamwindow.h index f3bd8bb..5c526b0 100644 --- a/gui/include/streamwindow.h +++ b/gui/include/streamwindow.h @@ -22,14 +22,10 @@ class StreamWindow: public QMainWindow const StreamSessionConnectInfo connect_info; StreamSession *session; - QAction *fullscreen_action; - QAction *stretch_action; - QAction *zoom_action; AVOpenGLWidget *av_widget; void Init(); void UpdateVideoTransform(); - void UpdateTransformModeActions(); protected: void keyPressEvent(QKeyEvent *event) override; @@ -46,9 +42,6 @@ class StreamWindow: public QMainWindow void SessionQuit(ChiakiQuitReason reason, const QString &reason_str); void LoginPINRequested(bool incorrect); void ToggleFullscreen(); - void ToggleStretch(); - void ToggleZoom(); - void Quit(); }; #endif // CHIAKI_GUI_STREAMWINDOW_H diff --git a/gui/include/transformmode.h b/gui/include/transformmode.h deleted file mode 100644 index 5c01d87..0000000 --- a/gui/include/transformmode.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL - -#ifndef CHIAKI_TRANSFORMMODE_H -#define CHIAKI_TRANSFORMMODE_H - -enum class TransformMode { - Fit, - Zoom, - Stretch -}; - -#endif diff --git a/gui/res/chiaki_macos.svg b/gui/res/chiaki_macos.svg deleted file mode 100644 index 7f1359d..0000000 --- a/gui/res/chiaki_macos.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - diff --git a/gui/res/resources.qrc b/gui/res/resources.qrc index b89bee7..86efda9 100644 --- a/gui/res/resources.qrc +++ b/gui/res/resources.qrc @@ -5,7 +5,6 @@ discover-24px.svg discover-off-24px.svg chiaki.svg - chiaki_macos.svg console-ps4.svg console-ps5.svg diff --git a/gui/src/avopenglwidget.cpp b/gui/src/avopenglwidget.cpp index bfd184a..3d1d8eb 100644 --- a/gui/src/avopenglwidget.cpp +++ b/gui/src/avopenglwidget.cpp @@ -109,6 +109,7 @@ static const float vert_pos[] = { 1.0f, 1.0f }; + QSurfaceFormat AVOpenGLWidget::CreateSurfaceFormat() { QSurfaceFormat format; @@ -122,13 +123,13 @@ QSurfaceFormat AVOpenGLWidget::CreateSurfaceFormat() return format; } -AVOpenGLWidget::AVOpenGLWidget(StreamSession *session, QWidget *parent, TransformMode transform_mode) +AVOpenGLWidget::AVOpenGLWidget(StreamSession *session, QWidget *parent) : QOpenGLWidget(parent), - session(session), transform_mode(transform_mode) + session(session) { enum AVPixelFormat pixel_format = chiaki_ffmpeg_decoder_get_pixel_format(session->GetFfmpegDecoder()); conversion_config = nullptr; - for(auto &cc : conversion_configs) + for(auto &cc: conversion_configs) { if(pixel_format == cc.pixel_format) { @@ -381,10 +382,10 @@ void AVOpenGLWidget::paintGL() vp_width = widget_width; vp_height = widget_height; } - else if(transform_mode == TransformMode::Fit) + else { float aspect = (float)frame->width / (float)frame->height; - if(widget_height && aspect < (float)widget_width / (float)widget_height) + if(aspect < (float)widget_width / (float)widget_height) { vp_height = widget_height; vp_width = (GLsizei)(vp_height * aspect); @@ -395,34 +396,6 @@ void AVOpenGLWidget::paintGL() vp_height = (GLsizei)(vp_width / aspect); } } - else if(transform_mode == TransformMode::Zoom) - { - float aspect = (float)frame->width / (float)frame->height; - if(widget_height && aspect < (float)widget_width / (float)widget_height) - { - vp_width = widget_width; - vp_height = (GLsizei)(vp_width / aspect); - } - else - { - vp_height = widget_height; - vp_width = (GLsizei)(vp_height * aspect); - } - } - else // transform_mode == TransformMode::Stretch - { - float aspect = (float)frame->width / (float)frame->height; - if(widget_height && aspect < (float)widget_width / (float)widget_height) - { - vp_height = widget_height; - vp_width = widget_width; - } - else - { - vp_width = widget_width; - vp_height = widget_height; - } - } f->glViewport((widget_width - vp_width) / 2, (widget_height - vp_height) / 2, vp_width, vp_height); diff --git a/gui/src/controllermanager.cpp b/gui/src/controllermanager.cpp index 8cc501f..2f9a2aa 100644 --- a/gui/src/controllermanager.cpp +++ b/gui/src/controllermanager.cpp @@ -68,11 +68,6 @@ static QSet chiaki_motion_controller_guids({ "030000008f0e00001431000000000000", }); -static QSet> chiaki_dualsense_controller_ids({ - // in format (vendor id, product id) - QPair(0x054c, 0x0ce6), // DualSense controller - QPair(0x054c, 0x0df2), // DualSense Edge controller -}); static ControllerManager *instance = nullptr; @@ -90,15 +85,6 @@ ControllerManager::ControllerManager(QObject *parent) { #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER SDL_SetMainReady(); -#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); -#endif -#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); -#endif -#ifdef SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS - SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); -#endif if(SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { const char *err = SDL_GetError(); @@ -171,51 +157,22 @@ void ControllerManager::HandleEvents() break; case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONDOWN: + ControllerEvent(event.cbutton.which); + break; case SDL_CONTROLLERAXISMOTION: -#if not defined(CHIAKI_ENABLE_SETSU) and SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_CONTROLLERSENSORUPDATE: - case SDL_CONTROLLERTOUCHPADDOWN: - case SDL_CONTROLLERTOUCHPADMOTION: - case SDL_CONTROLLERTOUCHPADUP: -#endif - ControllerEvent(event); + ControllerEvent(event.caxis.which); break; } } #endif } -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER -void ControllerManager::ControllerEvent(SDL_Event event) +void ControllerManager::ControllerEvent(int device_id) { - int device_id; - switch(event.type) - { - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - device_id = event.cbutton.which; - break; - case SDL_CONTROLLERAXISMOTION: - device_id = event.caxis.which; - break; -#if SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_CONTROLLERSENSORUPDATE: - device_id = event.csensor.which; - break; - case SDL_CONTROLLERTOUCHPADDOWN: - case SDL_CONTROLLERTOUCHPADMOTION: - case SDL_CONTROLLERTOUCHPADUP: - device_id = event.ctouchpad.which; - break; -#endif - default: - return; - } if(!open_controllers.contains(device_id)) return; - open_controllers[device_id]->UpdateState(event); + open_controllers[device_id]->UpdateState(); } -#endif QSet ControllerManager::GetAvailableControllers() { @@ -240,13 +197,10 @@ void ControllerManager::ControllerClosed(Controller *controller) open_controllers.remove(controller->GetDeviceID()); } -Controller::Controller(int device_id, ControllerManager *manager) - : QObject(manager), is_dualsense(false) +Controller::Controller(int device_id, ControllerManager *manager) : QObject(manager) { this->id = device_id; this->manager = manager; - chiaki_orientation_tracker_init(&this->orientation_tracker); - chiaki_controller_state_set_idle(&this->state); #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER controller = nullptr; @@ -255,14 +209,6 @@ Controller::Controller(int device_id, ControllerManager *manager) if(SDL_JoystickGetDeviceInstanceID(i) == device_id) { controller = SDL_GameControllerOpen(i); -#if SDL_VERSION_ATLEAST(2, 0, 14) - if(SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL)) - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); - if(SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO)) - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); -#endif - auto controller_id = QPair(SDL_GameControllerGetVendor(controller), SDL_GameControllerGetProduct(controller)); - is_dualsense = chiaki_dualsense_controller_ids.contains(controller_id); break; } } @@ -273,197 +219,16 @@ Controller::~Controller() { #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER if(controller) - { - // Clear trigger effects, SDL doesn't do it automatically - const uint8_t clear_effect[10] = { 0 }; - this->SetTriggerEffects(0x05, clear_effect, 0x05, clear_effect); SDL_GameControllerClose(controller); - } #endif manager->ControllerClosed(this); } -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER -void Controller::UpdateState(SDL_Event event) +void Controller::UpdateState() { - switch(event.type) - { - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - if(!HandleButtonEvent(event.cbutton)) - return; - break; - case SDL_CONTROLLERAXISMOTION: - if(!HandleAxisEvent(event.caxis)) - return; - break; -#if SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_CONTROLLERSENSORUPDATE: - if(!HandleSensorEvent(event.csensor)) - return; - break; - case SDL_CONTROLLERTOUCHPADDOWN: - case SDL_CONTROLLERTOUCHPADMOTION: - case SDL_CONTROLLERTOUCHPADUP: - if(!HandleTouchpadEvent(event.ctouchpad)) - return; - break; -#endif - default: - return; - - } emit StateChanged(); } -inline bool Controller::HandleButtonEvent(SDL_ControllerButtonEvent event) { - ChiakiControllerButton ps_btn; - switch(event.button) - { - case SDL_CONTROLLER_BUTTON_A: - ps_btn = CHIAKI_CONTROLLER_BUTTON_CROSS; - break; - case SDL_CONTROLLER_BUTTON_B: - ps_btn = CHIAKI_CONTROLLER_BUTTON_MOON; - break; - case SDL_CONTROLLER_BUTTON_X: - ps_btn = CHIAKI_CONTROLLER_BUTTON_BOX; - break; - case SDL_CONTROLLER_BUTTON_Y: - ps_btn = CHIAKI_CONTROLLER_BUTTON_PYRAMID; - break; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: - ps_btn = CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT; - break; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: - ps_btn = CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT; - break; - case SDL_CONTROLLER_BUTTON_DPAD_UP: - ps_btn = CHIAKI_CONTROLLER_BUTTON_DPAD_UP; - break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: - ps_btn = CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN; - break; - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: - ps_btn = CHIAKI_CONTROLLER_BUTTON_L1; - break; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: - ps_btn = CHIAKI_CONTROLLER_BUTTON_R1; - break; - case SDL_CONTROLLER_BUTTON_LEFTSTICK: - ps_btn = CHIAKI_CONTROLLER_BUTTON_L3; - break; - case SDL_CONTROLLER_BUTTON_RIGHTSTICK: - ps_btn = CHIAKI_CONTROLLER_BUTTON_R3; - break; - case SDL_CONTROLLER_BUTTON_START: - ps_btn = CHIAKI_CONTROLLER_BUTTON_OPTIONS; - break; - case SDL_CONTROLLER_BUTTON_BACK: - ps_btn = CHIAKI_CONTROLLER_BUTTON_SHARE; - break; - case SDL_CONTROLLER_BUTTON_GUIDE: - ps_btn = CHIAKI_CONTROLLER_BUTTON_PS; - break; -#if SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_CONTROLLER_BUTTON_TOUCHPAD: - ps_btn = CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; - break; -#endif - default: - return false; - } - if(event.type == SDL_CONTROLLERBUTTONDOWN) - state.buttons |= ps_btn; - else - state.buttons &= ~ps_btn; - return true; -} - -inline bool Controller::HandleAxisEvent(SDL_ControllerAxisEvent event) { - switch(event.axis) - { - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: - state.l2_state = (uint8_t)(event.value >> 7); - break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - state.r2_state = (uint8_t)(event.value >> 7); - break; - case SDL_CONTROLLER_AXIS_LEFTX: - state.left_x = event.value; - break; - case SDL_CONTROLLER_AXIS_LEFTY: - state.left_y = event.value; - break; - case SDL_CONTROLLER_AXIS_RIGHTX: - state.right_x = event.value; - break; - case SDL_CONTROLLER_AXIS_RIGHTY: - state.right_y = event.value; - break; - default: - return false; - } - return true; -} - -#if SDL_VERSION_ATLEAST(2, 0, 14) -inline bool Controller::HandleSensorEvent(SDL_ControllerSensorEvent event) -{ - switch(event.sensor) - { - case SDL_SENSOR_ACCEL: - state.accel_x = event.data[0] / SDL_STANDARD_GRAVITY; - state.accel_y = event.data[1] / SDL_STANDARD_GRAVITY; - state.accel_z = event.data[2] / SDL_STANDARD_GRAVITY; - break; - case SDL_SENSOR_GYRO: - state.gyro_x = event.data[0]; - state.gyro_y = event.data[1]; - state.gyro_z = event.data[2]; - break; - default: - return false; - } - chiaki_orientation_tracker_update( - &orientation_tracker, state.gyro_x, state.gyro_y, state.gyro_z, - state.accel_x, state.accel_y, state.accel_z, event.timestamp * 1000); - chiaki_orientation_tracker_apply_to_controller_state(&orientation_tracker, &state); - return true; -} - -inline bool Controller::HandleTouchpadEvent(SDL_ControllerTouchpadEvent event) -{ - auto key = qMakePair(event.touchpad, event.finger); - bool exists = touch_ids.contains(key); - uint8_t chiaki_id; - switch(event.type) - { - case SDL_CONTROLLERTOUCHPADDOWN: - if(touch_ids.size() >= CHIAKI_CONTROLLER_TOUCHES_MAX) - return false; - chiaki_id = chiaki_controller_state_start_touch(&state, event.x * PS_TOUCHPAD_MAX_X, event.y * PS_TOUCHPAD_MAX_Y); - touch_ids.insert(key, chiaki_id); - break; - case SDL_CONTROLLERTOUCHPADMOTION: - if(!exists) - return false; - chiaki_controller_state_set_touch_pos(&state, touch_ids[key], event.x * PS_TOUCHPAD_MAX_X, event.y * PS_TOUCHPAD_MAX_Y); - break; - case SDL_CONTROLLERTOUCHPADUP: - if(!exists) - return false; - chiaki_controller_state_stop_touch(&state, touch_ids[key]); - touch_ids.remove(key); - break; - default: - return false; - } - return true; -} -#endif -#endif - bool Controller::IsConnected() { #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER @@ -487,11 +252,7 @@ QString Controller::GetName() #ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER if(!controller) return QString(); - SDL_Joystick *js = SDL_GameControllerGetJoystick(controller); - SDL_JoystickGUID guid = SDL_JoystickGetGUID(js); - char guid_str[256]; - SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); - return QString("%1 (%2)").arg(SDL_JoystickName(js), guid_str); + return SDL_GameControllerName(controller); #else return QString(); #endif @@ -499,39 +260,34 @@ QString Controller::GetName() ChiakiControllerState Controller::GetState() { + ChiakiControllerState state; + chiaki_controller_state_set_idle(&state); +#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER + if(!controller) + return state; + + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A) ? CHIAKI_CONTROLLER_BUTTON_CROSS : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_B) ? CHIAKI_CONTROLLER_BUTTON_MOON : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X) ? CHIAKI_CONTROLLER_BUTTON_BOX : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_Y) ? CHIAKI_CONTROLLER_BUTTON_PYRAMID : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT) ? CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT) ? CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP) ? CHIAKI_CONTROLLER_BUTTON_DPAD_UP : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN) ? CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER) ? CHIAKI_CONTROLLER_BUTTON_L1 : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) ? CHIAKI_CONTROLLER_BUTTON_R1 : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSTICK) ? CHIAKI_CONTROLLER_BUTTON_L3 : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK) ? CHIAKI_CONTROLLER_BUTTON_R3 : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START) ? CHIAKI_CONTROLLER_BUTTON_OPTIONS : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_BACK) ? CHIAKI_CONTROLLER_BUTTON_SHARE : 0; + state.buttons |= SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_GUIDE) ? CHIAKI_CONTROLLER_BUTTON_PS : 0; + state.l2_state = (uint8_t)(SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) >> 7); + state.r2_state = (uint8_t)(SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) >> 7); + state.left_x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); + state.left_y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + state.right_x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); + state.right_y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); + +#endif return state; } - -void Controller::SetRumble(uint8_t left, uint8_t right) -{ -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER - if(!controller) - return; - SDL_GameControllerRumble(controller, (uint16_t)left << 8, (uint16_t)right << 8, 5000); -#endif -} - -void Controller::SetTriggerEffects(uint8_t type_left, const uint8_t *data_left, uint8_t type_right, const uint8_t *data_right) -{ -#if defined(CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER) && SDL_VERSION_ATLEAST(2, 0, 16) - if(!is_dualsense || !controller) - return; - DS5EffectsState_t state; - SDL_zero(state); - state.ucEnableBits1 |= (0x04 /* left trigger */ | 0x08 /* right trigger */); - state.rgucLeftTriggerEffect[0] = type_left; - SDL_memcpy(state.rgucLeftTriggerEffect + 1, data_left, 10); - state.rgucRightTriggerEffect[0] = type_right; - SDL_memcpy(state.rgucRightTriggerEffect + 1, data_right, 10); - SDL_GameControllerSendEffect(controller, &state, sizeof(state)); -#endif -} - -bool Controller::IsDualSense() -{ -#ifdef CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER - if(!controller) - return false; - return is_dualsense; -#endif -} diff --git a/gui/src/main.cpp b/gui/src/main.cpp index 5f2aad7..56a85f2 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -71,11 +71,7 @@ int real_main(int argc, char *argv[]) QApplication app(argc, argv); -#ifdef Q_OS_MACOS - QApplication::setWindowIcon(QIcon(":/icons/chiaki_macos.svg")); -#else QApplication::setWindowIcon(QIcon(":/icons/chiaki.svg")); -#endif QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); @@ -103,15 +99,9 @@ int real_main(int argc, char *argv[]) QCommandLineOption morning_option("morning", "", "morning"); parser.addOption(morning_option); - QCommandLineOption fullscreen_option("fullscreen", "Start window in fullscreen mode [maintains aspect ratio, adds black bars to fill unsused parts of screen if applicable] (only for use with stream command)"); + QCommandLineOption fullscreen_option("fullscreen", "Start window in fullscreen (only for use with stream command)"); parser.addOption(fullscreen_option); - QCommandLineOption zoom_option("zoom", "Start window in fullscreen zoomed in to fit screen [maintains aspect ratio, cutting off edges of image to fill screen] (only for use with stream command)"); - parser.addOption(zoom_option); - - QCommandLineOption stretch_option("stretch", "Start window in fullscreen stretched to fit screen [distorts aspect ratio to fill screen] (only for use with stream command)"); - parser.addOption(stretch_option); - parser.process(app); QStringList args = parser.positionalArguments(); @@ -121,7 +111,7 @@ int real_main(int argc, char *argv[]) if(args[0] == "list") { for(const auto &host : settings.GetRegisteredHosts()) - printf("Host: %s \n", host.GetServerNickname().toLocal8Bit().constData()); + printf("Host: %s \n", host.GetServerNickname().toLocal8Bit().constData()); return 0; } if(args[0] == "stream") @@ -133,34 +123,25 @@ int real_main(int argc, char *argv[]) QString host = args[args.size()-1]; QByteArray morning; QByteArray regist_key; - ChiakiTarget target = CHIAKI_TARGET_PS4_10; if(parser.value(regist_key_option).isEmpty() && parser.value(morning_option).isEmpty()) { if(args.length() < 3) parser.showHelp(1); - - bool found = false; for(const auto &temphost : settings.GetRegisteredHosts()) { if(temphost.GetServerNickname() == args[1]) { - found = true; morning = temphost.GetRPKey(); regist_key = temphost.GetRPRegistKey(); - target = temphost.GetTarget(); break; } - } - if(!found) - { printf("No configuration found for '%s'\n", args[1].toLocal8Bit().constData()); return 1; } } else { - // TODO: explicit option for target regist_key = parser.value(regist_key_option).toUtf8(); if(regist_key.length() > sizeof(ChiakiConnectInfo::regist_key)) { @@ -180,21 +161,8 @@ int real_main(int argc, char *argv[]) return 1; } } - if ((parser.isSet(stretch_option) && (parser.isSet(zoom_option) || parser.isSet(fullscreen_option))) || (parser.isSet(zoom_option) && parser.isSet(fullscreen_option))) - { - printf("Must choose between fullscreen, zoom or stretch option."); - return 1; - } - - StreamSessionConnectInfo connect_info( - &settings, - target, - host, - regist_key, - morning, - parser.isSet(fullscreen_option), - parser.isSet(zoom_option) ? TransformMode::Zoom : parser.isSet(stretch_option) ? TransformMode::Stretch : TransformMode::Fit); - + // TODO: target here + StreamSessionConnectInfo connect_info(&settings, CHIAKI_TARGET_PS4_10, host, regist_key, morning, parser.isSet(fullscreen_option)); return RunStream(app, connect_info); } #ifdef CHIAKI_ENABLE_CLI diff --git a/gui/src/mainwindow.cpp b/gui/src/mainwindow.cpp index 0912b2e..296626d 100644 --- a/gui/src/mainwindow.cpp +++ b/gui/src/mainwindow.cpp @@ -146,11 +146,6 @@ MainWindow::MainWindow(Settings *settings, QWidget *parent) AddToolBarAction(settings_action); connect(settings_action, &QAction::triggered, this, &MainWindow::ShowSettings); - auto quit_action = new QAction(tr("Quit"), this); - quit_action->setShortcut(Qt::CTRL + Qt::Key_Q); - addAction(quit_action); - connect(quit_action, &QAction::triggered, this, &MainWindow::Quit); - auto scroll_area = new QScrollArea(this); scroll_area->setWidgetResizable(true); scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -172,7 +167,7 @@ MainWindow::MainWindow(Settings *settings, QWidget *parent) grid_widget->setContentsMargins(0, 0, 0, 0); resize(800, 600); - + connect(&discovery_manager, &DiscoveryManager::HostsUpdated, this, &MainWindow::UpdateDisplayServers); connect(settings, &Settings::RegisteredHostsUpdated, this, &MainWindow::UpdateDisplayServers); connect(settings, &Settings::ManualHostsUpdated, this, &MainWindow::UpdateDisplayServers); @@ -254,14 +249,7 @@ void MainWindow::ServerItemWidgetTriggered() } QString host = server.GetHostAddr(); - StreamSessionConnectInfo info( - settings, - server.registered_host.GetTarget(), - host, - server.registered_host.GetRPRegistKey(), - server.registered_host.GetRPKey(), - false, - TransformMode::Fit); + StreamSessionConnectInfo info(settings, server.registered_host.GetTarget(), host, server.registered_host.GetRPRegistKey(), server.registered_host.GetRPKey(), false); new StreamWindow(info); } else @@ -310,11 +298,6 @@ void MainWindow::ShowSettings() dialog.exec(); } -void MainWindow::Quit() -{ - qApp->exit(); -} - void MainWindow::UpdateDisplayServers() { display_servers.clear(); @@ -347,7 +330,7 @@ void MainWindow::UpdateDisplayServers() display_servers.append(server); } - + UpdateServerWidgets(); } diff --git a/gui/src/settings.cpp b/gui/src/settings.cpp index 6d296d1..17f7d83 100644 --- a/gui/src/settings.cpp +++ b/gui/src/settings.cpp @@ -88,10 +88,10 @@ uint32_t Settings::GetLogLevelMask() } static const QMap resolutions = { - { CHIAKI_VIDEO_RESOLUTION_PRESET_360p, "360p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_540p, "540p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_720p, "720p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_1080p, "1080p" } + { CHIAKI_VIDEO_RESOLUTION_PRESET_360p, "360p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_540p, "540p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_720p, "720p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_1080p, "1080p"} }; static const ChiakiVideoResolutionPreset resolution_default = CHIAKI_VIDEO_RESOLUTION_PRESET_720p; @@ -136,8 +136,8 @@ void Settings::SetBitrate(unsigned int bitrate) } static const QMap codecs = { - { CHIAKI_CODEC_H264, "h264" }, - { CHIAKI_CODEC_H265, "h265" } + { CHIAKI_CODEC_H264, "h264"}, + { CHIAKI_CODEC_H265, "h265"} }; static const ChiakiCodec codec_default = CHIAKI_CODEC_H265; diff --git a/gui/src/settingsdialog.cpp b/gui/src/settingsdialog.cpp index 1770932..b8bd412 100644 --- a/gui/src/settingsdialog.cpp +++ b/gui/src/settingsdialog.cpp @@ -69,11 +69,6 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa log_verbose_check_box->setChecked(settings->GetLogVerbose()); connect(log_verbose_check_box, &QCheckBox::stateChanged, this, &SettingsDialog::LogVerboseChanged); - dualsense_check_box = new QCheckBox(this); - general_layout->addRow(tr("Extended DualSense Support:\nEnable haptics and adaptive triggers\nfor attached DualSense controllers.\nThis is currently experimental."), dualsense_check_box); - dualsense_check_box->setChecked(settings->GetDualSenseEnabled()); - connect(dualsense_check_box, &QCheckBox::stateChanged, this, &SettingsDialog::DualSenseChanged); - auto log_directory_label = new QLineEdit(GetLogBaseDir(), this); log_directory_label->setReadOnly(true); general_layout->addRow(tr("Log Directory:"), log_directory_label); @@ -94,7 +89,7 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa connect(disconnect_action_combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(DisconnectActionSelected())); general_layout->addRow(tr("Action on Disconnect:"), disconnect_action_combo_box); - + audio_device_combo_box = new QComboBox(this); audio_device_combo_box->addItem(tr("Auto")); auto current_audio_device = settings->GetAudioOutDevice(); @@ -117,7 +112,7 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa auto available_devices = audio_devices_future_watcher->result(); while(audio_device_combo_box->count() > 1) // remove all but "Auto" audio_device_combo_box->removeItem(1); - for(QAudioDeviceInfo di : available_devices) + for (QAudioDeviceInfo di : available_devices) audio_device_combo_box->addItem(di.deviceName(), di.deviceName()); int audio_out_device_index = audio_device_combo_box->findData(settings->GetAudioOutDevice()); audio_device_combo_box->setCurrentIndex(audio_out_device_index < 0 ? 0 : audio_out_device_index); @@ -141,10 +136,10 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa resolution_combo_box = new QComboBox(this); static const QList> resolution_strings = { - { CHIAKI_VIDEO_RESOLUTION_PRESET_360p, "360p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_540p, "540p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_720p, "720p" }, - { CHIAKI_VIDEO_RESOLUTION_PRESET_1080p, "1080p (PS5 and PS4 Pro only)" } + { CHIAKI_VIDEO_RESOLUTION_PRESET_360p, "360p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_540p, "540p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_720p, "720p"}, + { CHIAKI_VIDEO_RESOLUTION_PRESET_1080p, "1080p (PS5 and PS4 Pro only)"} }; auto current_res = settings->GetResolution(); for(const auto &p : resolution_strings) @@ -327,11 +322,6 @@ void SettingsDialog::LogVerboseChanged() settings->SetLogVerbose(log_verbose_check_box->isChecked()); } -void SettingsDialog::DualSenseChanged() -{ - settings->SetDualSenseEnabled(dualsense_check_box->isChecked()); -} - void SettingsDialog::FPSSelected() { settings->SetFPS((ChiakiVideoFPSPreset)fps_combo_box->currentData().toInt()); diff --git a/gui/src/settingskeycapturedialog.cpp b/gui/src/settingskeycapturedialog.cpp index a631444..3339813 100644 --- a/gui/src/settingskeycapturedialog.cpp +++ b/gui/src/settingskeycapturedialog.cpp @@ -7,7 +7,7 @@ #include #include -SettingsKeyCaptureDialog::SettingsKeyCaptureDialog(QWidget *parent) +SettingsKeyCaptureDialog::SettingsKeyCaptureDialog(QWidget* parent) { setWindowTitle(tr("Key Capture")); @@ -23,7 +23,7 @@ SettingsKeyCaptureDialog::SettingsKeyCaptureDialog(QWidget *parent) connect(button, &QPushButton::clicked, this, &QDialog::accept); } -void SettingsKeyCaptureDialog::keyReleaseEvent(QKeyEvent *event) +void SettingsKeyCaptureDialog::keyReleaseEvent(QKeyEvent* event) { KeyCaptured(Qt::Key(event->key())); accept(); diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp index 42c9959..fedae10 100644 --- a/gui/src/streamsession.cpp +++ b/gui/src/streamsession.cpp @@ -14,20 +14,7 @@ #define SETSU_UPDATE_INTERVAL_MS 4 -#ifdef Q_OS_LINUX -#define DUALSENSE_AUDIO_DEVICE_NEEDLE "DualSense" -#else -#define DUALSENSE_AUDIO_DEVICE_NEEDLE "Wireless Controller" -#endif - -StreamSessionConnectInfo::StreamSessionConnectInfo( - Settings *settings, - ChiakiTarget target, - QString host, - QByteArray regist_key, - QByteArray morning, - bool fullscreen, - TransformMode transform_mode) +StreamSessionConnectInfo::StreamSessionConnectInfo(Settings *settings, ChiakiTarget target, QString host, QByteArray regist_key, QByteArray morning, bool fullscreen) : settings(settings) { key_map = settings->GetControllerMappingForDecoding(); @@ -43,14 +30,11 @@ StreamSessionConnectInfo::StreamSessionConnectInfo( this->morning = morning; audio_buffer_size = settings->GetAudioBufferSize(); this->fullscreen = fullscreen; - this->transform_mode = transform_mode; this->enable_keyboard = false; // TODO: from settings - this->enable_dualsense = settings->GetDualSenseEnabled(); } static void AudioSettingsCb(uint32_t channels, uint32_t rate, void *user); static void AudioFrameCb(int16_t *buf, size_t samples_count, void *user); -static void HapticsFrameCb(uint8_t *buf, size_t buf_size, void *user); static void EventCb(ChiakiEvent *event, void *user); #if CHIAKI_GUI_ENABLE_SETSU static void SessionSetsuCb(SetsuEvent *event, void *user); @@ -65,12 +49,9 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje pi_decoder(nullptr), #endif audio_output(nullptr), - audio_io(nullptr), - haptics_output(0), - haptics_resampler_buf(nullptr) + audio_io(nullptr) { connected = false; - ChiakiErrorCode err; #if CHIAKI_LIB_ENABLE_PI_DECODER if(connect_info.decoder == Decoder::Pi) @@ -85,7 +66,7 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje ffmpeg_decoder = new ChiakiFfmpegDecoder; ChiakiLogSniffer sniffer; chiaki_log_sniffer_init(&sniffer, CHIAKI_LOG_ALL, GetChiakiLog()); - err = chiaki_ffmpeg_decoder_init(ffmpeg_decoder, + ChiakiErrorCode err = chiaki_ffmpeg_decoder_init(ffmpeg_decoder, chiaki_log_sniffer_get_log(&sniffer), chiaki_target_is_ps5(connect_info.target) ? connect_info.video_profile.codec : CHIAKI_CODEC_H264, connect_info.hw_decoder.isEmpty() ? NULL : connect_info.hw_decoder.toUtf8().constData(), @@ -120,21 +101,11 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje QByteArray host_str = connect_info.host.toUtf8(); - ChiakiConnectInfo chiaki_connect_info = {}; + ChiakiConnectInfo chiaki_connect_info; chiaki_connect_info.ps5 = chiaki_target_is_ps5(connect_info.target); chiaki_connect_info.host = host_str.constData(); chiaki_connect_info.video_profile = connect_info.video_profile; chiaki_connect_info.video_profile_auto_downgrade = true; - chiaki_connect_info.enable_keyboard = false; - chiaki_connect_info.enable_dualsense = connect_info.enable_dualsense; - -#if CHIAKI_LIB_ENABLE_PI_DECODER - if(connect_info.decoder == Decoder::Pi && chiaki_connect_info.video_profile.codec != CHIAKI_CODEC_H264) - { - CHIAKI_LOGW(GetChiakiLog(), "A codec other than H264 was requested for Pi Decoder. Falling back to it."); - chiaki_connect_info.video_profile.codec = CHIAKI_CODEC_H264; - } -#endif if(connect_info.regist_key.size() != sizeof(chiaki_connect_info.regist_key)) throw ChiakiException("RegistKey invalid"); @@ -155,14 +126,6 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje chiaki_opus_decoder_get_sink(&opus_decoder, &audio_sink); chiaki_session_set_audio_sink(&session, &audio_sink); - if(connect_info.enable_dualsense) - { - ChiakiAudioSink haptics_sink; - haptics_sink.user = this; - haptics_sink.frame_cb = HapticsFrameCb; - chiaki_session_set_haptics_sink(&session, &haptics_sink); - } - #if CHIAKI_LIB_ENABLE_PI_DECODER if(pi_decoder) chiaki_session_set_video_sample_cb(&session, chiaki_pi_decoder_video_sample_cb, pi_decoder); @@ -181,29 +144,16 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje #endif #if CHIAKI_GUI_ENABLE_SETSU - setsu_motion_device = nullptr; chiaki_controller_state_set_idle(&setsu_state); - orient_dirty = true; - chiaki_orientation_tracker_init(&orient_tracker); setsu = setsu_new(); auto timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [this]{ setsu_poll(setsu, SessionSetsuCb, this); - if(orient_dirty) - { - chiaki_orientation_tracker_apply_to_controller_state(&orient_tracker, &setsu_state); - SendFeedbackState(); - orient_dirty = false; - } }); timer->start(SETSU_UPDATE_INTERVAL_MS); #endif key_map = connect_info.key_map; - if(connect_info.enable_dualsense) - { - InitHaptics(); - } UpdateGamepads(); } @@ -231,16 +181,6 @@ StreamSession::~StreamSession() chiaki_ffmpeg_decoder_fini(ffmpeg_decoder); delete ffmpeg_decoder; } - if(haptics_output > 0) - { - SDL_CloseAudioDevice(haptics_output); - haptics_output = 0; - } - if(haptics_resampler_buf) - { - free(haptics_resampler_buf); - haptics_resampler_buf = nullptr; - } } void StreamSession::Start() @@ -269,16 +209,13 @@ void StreamSession::SetLoginPIN(const QString &pin) chiaki_session_set_login_pin(&session, (const uint8_t *)data.constData(), data.size()); } -bool StreamSession::HandleMouseEvent(QMouseEvent *event) +void StreamSession::HandleMouseEvent(QMouseEvent *event) { - if(event->button() != Qt::MouseButton::LeftButton) - return false; if(event->type() == QEvent::MouseButtonPress) keyboard_state.buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; else keyboard_state.buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; SendFeedbackState(); - return true; } void StreamSession::HandleKeyboardEvent(QKeyEvent *event) @@ -345,8 +282,6 @@ void StreamSession::UpdateGamepads() { CHIAKI_LOGI(log.GetChiakiLog(), "Controller %d disconnected", controller->GetDeviceID()); controllers.remove(controller_id); - if(controller->IsDualSense()) - DisconnectHaptics(); delete controller; } } @@ -365,11 +300,6 @@ void StreamSession::UpdateGamepads() CHIAKI_LOGI(log.GetChiakiLog(), "Controller %d opened: \"%s\"", controller_id, controller->GetName().toLocal8Bit().constData()); connect(controller, &Controller::StateChanged, this, &StreamSession::SendFeedbackState); controllers[controller_id] = controller; - if(controller->IsDualSense()) - { - // Connect haptics audio device with a delay to give the sound system time to set up - QTimer::singleShot(1000, this, &StreamSession::ConnectHaptics); - } } } @@ -382,16 +312,17 @@ void StreamSession::SendFeedbackState() ChiakiControllerState state; chiaki_controller_state_set_idle(&state); -#if CHIAKI_GUI_ENABLE_SETSU - // setsu is the one that potentially has gyro/accel/orient so copy that directly first - state = setsu_state; -#endif - +#if CHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER for(auto controller : controllers) { auto controller_state = controller->GetState(); chiaki_controller_state_or(&state, &state, &controller_state); } +#endif + +#if CHIAKI_GUI_ENABLE_SETSU + chiaki_controller_state_or(&state, &state, &setsu_state); +#endif chiaki_controller_state_or(&state, &state, &keyboard_state); chiaki_session_set_controller_state(&session, &state); @@ -428,82 +359,6 @@ void StreamSession::InitAudio(unsigned int channels, unsigned int rate) channels, rate, audio_output->bufferSize()); } -void StreamSession::InitHaptics() -{ - haptics_output = 0; - haptics_resampler_buf = nullptr; -#ifdef Q_OS_LINUX - // Haptics work most reliably with Pipewire, so try to use that if available - SDL_SetHint("SDL_AUDIODRIVER", "pipewire"); -#endif - - if(SDL_Init(SDL_INIT_AUDIO) < 0) - { - CHIAKI_LOGE(log.GetChiakiLog(), "Could not initialize SDL Audio for haptics output: %s", SDL_GetError()); - return; - } - -#ifdef Q_OS_LINUX - if(!strstr(SDL_GetCurrentAudioDriver(), "pipewire")) - { - CHIAKI_LOGW( - log.GetChiakiLog(), - "Haptics output is not using Pipewire, this may not work reliably. (was: '%s')", - SDL_GetCurrentAudioDriver()); - } -#endif - - SDL_AudioCVT cvt; - SDL_BuildAudioCVT(&cvt, AUDIO_S16LSB, 4, 3000, AUDIO_S16LSB, 4, 48000); - cvt.len = 240; // 10 16bit stereo samples - haptics_resampler_buf = (uint8_t*) calloc(cvt.len * cvt.len_mult, sizeof(uint8_t)); -} - -void StreamSession::DisconnectHaptics() -{ - if(this->haptics_output > 0) - { - SDL_CloseAudioDevice(haptics_output); - this->haptics_output = 0; - } -} - -void StreamSession::ConnectHaptics() -{ - if(this->haptics_output > 0) - { - CHIAKI_LOGW(this->log.GetChiakiLog(), "Haptics already connected to an attached DualSense controller, ignoring additional controllers."); - return; - } - - SDL_AudioSpec want, have; - SDL_zero(want); - want.freq = 48000; - want.format = AUDIO_S16LSB; - want.channels = 4; - want.samples = 480; // 10ms buffer - want.callback = NULL; - - const char *device_name = nullptr; - for(int i=0; i < SDL_GetNumAudioDevices(0); i++) - { - device_name = SDL_GetAudioDeviceName(i, 0); - if(!device_name || !strstr(device_name, DUALSENSE_AUDIO_DEVICE_NEEDLE)) - continue; - haptics_output = SDL_OpenAudioDevice(device_name, 0, &want, &have, 0); - if(haptics_output == 0) - { - CHIAKI_LOGE(log.GetChiakiLog(), "Could not open SDL Audio Device %s for haptics output: %s", device_name, SDL_GetError()); - continue; - } - SDL_PauseAudioDevice(haptics_output, 0); - CHIAKI_LOGI(log.GetChiakiLog(), "Haptics Audio Device '%s' opened with %d channels @ %d Hz, buffer size %u (driver=%s)", device_name, have.channels, have.freq, have.size, SDL_GetCurrentAudioDriver()); - return; - } - CHIAKI_LOGW(log.GetChiakiLog(), "DualSense features were enabled and a DualSense is connected, but could not find the DualSense audio device!"); - return; -} - void StreamSession::PushAudioFrame(int16_t *buf, size_t samples_count) { if(!audio_io) @@ -511,35 +366,6 @@ void StreamSession::PushAudioFrame(int16_t *buf, size_t samples_count) audio_io->write((const char *)buf, static_cast(samples_count * 2 * 2)); } -void StreamSession::PushHapticsFrame(uint8_t *buf, size_t buf_size) -{ - if(haptics_output == 0) - return; - SDL_AudioCVT cvt; - // Haptics samples are coming in at 3KHZ, but the DualSense expects 48KHZ - SDL_BuildAudioCVT(&cvt, AUDIO_S16LSB, 4, 3000, AUDIO_S16LSB, 4, 48000); - cvt.len = buf_size * 2; - cvt.buf = haptics_resampler_buf; - // Remix to 4 channels - for (int i=0; i < buf_size; i+=4) - { - SDL_memset(haptics_resampler_buf + i * 2, 0, 4); - SDL_memcpy(haptics_resampler_buf + (i * 2) + 4, buf + i, 4); - } - // Resample to 48kHZ - if(SDL_ConvertAudio(&cvt) != 0) - { - CHIAKI_LOGE(log.GetChiakiLog(), "Failed to resample haptics audio: %s", SDL_GetError()); - return; - } - - if(SDL_QueueAudio(haptics_output, cvt.buf, cvt.len_cvt) < 0) - { - CHIAKI_LOGE(log.GetChiakiLog(), "Failed to submit haptics audio to device: %s", SDL_GetError()); - return; - } -} - void StreamSession::Event(ChiakiEvent *event) { switch(event->type) @@ -554,30 +380,6 @@ void StreamSession::Event(ChiakiEvent *event) case CHIAKI_EVENT_LOGIN_PIN_REQUEST: emit LoginPINRequested(event->login_pin_request.pin_incorrect); break; - case CHIAKI_EVENT_RUMBLE: { - uint8_t left = event->rumble.left; - uint8_t right = event->rumble.right; - QMetaObject::invokeMethod(this, [this, left, right]() { - for(auto controller : controllers) - controller->SetRumble(left, right); - }); - break; - } - case CHIAKI_EVENT_TRIGGER_EFFECTS: { - uint8_t type_left = event->trigger_effects.type_left; - uint8_t data_left[10]; - memcpy(data_left, event->trigger_effects.left, 10); - uint8_t data_right[10]; - memcpy(data_right, event->trigger_effects.right, 10); - uint8_t type_right = event->trigger_effects.type_right; - QMetaObject::invokeMethod(this, [this, type_left, data_left, type_right, data_right]() { - for(auto controller : controllers) - controller->SetTriggerEffects(type_left, data_left, type_right, data_right); - }); - break; - } - default: - break; } } @@ -589,64 +391,27 @@ void StreamSession::HandleSetsuEvent(SetsuEvent *event) switch(event->type) { case SETSU_EVENT_DEVICE_ADDED: - switch(event->dev_type) - { - case SETSU_DEVICE_TYPE_TOUCHPAD: - // connect all the touchpads! - if(setsu_connect(setsu, event->path, event->dev_type)) - CHIAKI_LOGI(GetChiakiLog(), "Connected Setsu Touchpad Device %s", event->path); - else - CHIAKI_LOGE(GetChiakiLog(), "Failed to connect to Setsu Touchpad Device %s", event->path); - break; - case SETSU_DEVICE_TYPE_MOTION: - // connect only one motion since multiple make no sense - if(setsu_motion_device) - { - CHIAKI_LOGI(GetChiakiLog(), "Setsu Motion Device %s detected there is already one connected", - event->path); - break; - } - setsu_motion_device = setsu_connect(setsu, event->path, event->dev_type); - if(setsu_motion_device) - CHIAKI_LOGI(GetChiakiLog(), "Connected Setsu Motion Device %s", event->path); - else - CHIAKI_LOGE(GetChiakiLog(), "Failed to connect to Setsu Motion Device %s", event->path); - break; - } + setsu_connect(setsu, event->path); break; case SETSU_EVENT_DEVICE_REMOVED: - switch(event->dev_type) + for(auto it=setsu_ids.begin(); it!=setsu_ids.end();) { - case SETSU_DEVICE_TYPE_TOUCHPAD: - CHIAKI_LOGI(GetChiakiLog(), "Setsu Touchpad Device %s disconnected", event->path); - for(auto it=setsu_ids.begin(); it!=setsu_ids.end();) - { - if(it.key().first == event->path) - { - chiaki_controller_state_stop_touch(&setsu_state, it.value()); - setsu_ids.erase(it++); - } - else - it++; - } - SendFeedbackState(); - break; - case SETSU_DEVICE_TYPE_MOTION: - if(!setsu_motion_device || strcmp(setsu_device_get_path(setsu_motion_device), event->path)) - break; - CHIAKI_LOGI(GetChiakiLog(), "Setsu Motion Device %s disconnected", event->path); - setsu_motion_device = nullptr; - chiaki_orientation_tracker_init(&orient_tracker); - orient_dirty = true; - break; + if(it.key().first == event->path) + { + chiaki_controller_state_stop_touch(&setsu_state, it.value()); + setsu_ids.erase(it++); + } + else + it++; } + SendFeedbackState(); break; case SETSU_EVENT_TOUCH_DOWN: break; case SETSU_EVENT_TOUCH_UP: for(auto it=setsu_ids.begin(); it!=setsu_ids.end(); it++) { - if(it.key().first == setsu_device_get_path(event->dev) && it.key().second == event->touch.tracking_id) + if(it.key().first == setsu_device_get_path(event->dev) && it.key().second == event->tracking_id) { chiaki_controller_state_stop_touch(&setsu_state, it.value()); setsu_ids.erase(it); @@ -656,18 +421,18 @@ void StreamSession::HandleSetsuEvent(SetsuEvent *event) SendFeedbackState(); break; case SETSU_EVENT_TOUCH_POSITION: { - QPair k = { setsu_device_get_path(event->dev), event->touch.tracking_id }; + QPair k = { setsu_device_get_path(event->dev), event->tracking_id }; auto it = setsu_ids.find(k); if(it == setsu_ids.end()) { - int8_t cid = chiaki_controller_state_start_touch(&setsu_state, event->touch.x, event->touch.y); + int8_t cid = chiaki_controller_state_start_touch(&setsu_state, event->x, event->y); if(cid >= 0) setsu_ids[k] = (uint8_t)cid; else break; } else - chiaki_controller_state_set_touch_pos(&setsu_state, it.value(), event->touch.x, event->touch.y); + chiaki_controller_state_set_touch_pos(&setsu_state, it.value(), event->x, event->y); SendFeedbackState(); break; } @@ -677,13 +442,6 @@ void StreamSession::HandleSetsuEvent(SetsuEvent *event) case SETSU_EVENT_BUTTON_UP: setsu_state.buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; break; - case SETSU_EVENT_MOTION: - chiaki_orientation_tracker_update(&orient_tracker, - event->motion.gyro_x, event->motion.gyro_y, event->motion.gyro_z, - event->motion.accel_x, event->motion.accel_y, event->motion.accel_z, - event->motion.timestamp); - orient_dirty = true; - break; } } #endif @@ -702,7 +460,6 @@ class StreamSessionPrivate } static void PushAudioFrame(StreamSession *session, int16_t *buf, size_t samples_count) { session->PushAudioFrame(buf, samples_count); } - static void PushHapticsFrame(StreamSession *session, uint8_t *buf, size_t buf_size) { session->PushHapticsFrame(buf, buf_size); } static void Event(StreamSession *session, ChiakiEvent *event) { session->Event(event); } #if CHIAKI_GUI_ENABLE_SETSU static void HandleSetsuEvent(StreamSession *session, SetsuEvent *event) { session->HandleSetsuEvent(event); } @@ -722,12 +479,6 @@ static void AudioFrameCb(int16_t *buf, size_t samples_count, void *user) StreamSessionPrivate::PushAudioFrame(session, buf, samples_count); } -static void HapticsFrameCb(uint8_t *buf, size_t buf_size, void *user) -{ - auto session = reinterpret_cast(user); - StreamSessionPrivate::PushHapticsFrame(session, buf, buf_size); -} - static void EventCb(ChiakiEvent *event, void *user) { auto session = reinterpret_cast(user); diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp index a2337d7..feff758 100644 --- a/gui/src/streamwindow.cpp +++ b/gui/src/streamwindow.cpp @@ -10,7 +10,6 @@ #include #include #include -#include StreamWindow::StreamWindow(const StreamSessionConnectInfo &connect_info, QWidget *parent) : QMainWindow(parent), @@ -24,6 +23,8 @@ StreamWindow::StreamWindow(const StreamSessionConnectInfo &connect_info, QWidget try { + if(connect_info.fullscreen) + showFullScreen(); Init(); } catch(const Exception &e) @@ -39,8 +40,6 @@ StreamWindow::~StreamWindow() delete av_widget; } -#include - void StreamWindow::Init() { session = new StreamSession(connect_info, this); @@ -48,36 +47,10 @@ void StreamWindow::Init() connect(session, &StreamSession::SessionQuit, this, &StreamWindow::SessionQuit); connect(session, &StreamSession::LoginPINRequested, this, &StreamWindow::LoginPINRequested); - const QKeySequence fullscreen_shortcut = Qt::Key_F11; - const QKeySequence stretch_shortcut = Qt::CTRL + Qt::Key_S; - const QKeySequence zoom_shortcut = Qt::CTRL + Qt::Key_Z; - - fullscreen_action = new QAction(tr("Fullscreen"), this); - fullscreen_action->setCheckable(true); - fullscreen_action->setShortcut(fullscreen_shortcut); - addAction(fullscreen_action); - connect(fullscreen_action, &QAction::triggered, this, &StreamWindow::ToggleFullscreen); - if(session->GetFfmpegDecoder()) { - av_widget = new AVOpenGLWidget(session, this, connect_info.transform_mode); + av_widget = new AVOpenGLWidget(session, this); setCentralWidget(av_widget); - - av_widget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(av_widget, &QWidget::customContextMenuRequested, this, [this](const QPoint &pos) { - av_widget->ResetMouseTimeout(); - - QMenu menu(av_widget); - menu.addAction(fullscreen_action); - menu.addSeparator(); - menu.addAction(stretch_action); - menu.addAction(zoom_action); - releaseKeyboard(); - connect(&menu, &QMenu::aboutToHide, this, [this] { - grabKeyboard(); - }); - menu.exec(av_widget->mapToGlobal(pos)); - }); } else { @@ -90,34 +63,13 @@ void StreamWindow::Init() session->Start(); - stretch_action = new QAction(tr("Stretch"), this); - stretch_action->setCheckable(true); - stretch_action->setShortcut(stretch_shortcut); - addAction(stretch_action); - connect(stretch_action, &QAction::triggered, this, &StreamWindow::ToggleStretch); - - zoom_action = new QAction(tr("Zoom"), this); - zoom_action->setCheckable(true); - zoom_action->setShortcut(zoom_shortcut); - addAction(zoom_action); - connect(zoom_action, &QAction::triggered, this, &StreamWindow::ToggleZoom); - - auto quit_action = new QAction(tr("Quit"), this); - quit_action->setShortcut(Qt::CTRL + Qt::Key_Q); - addAction(quit_action); - connect(quit_action, &QAction::triggered, this, &StreamWindow::Quit); + auto fullscreen_action = new QAction(tr("Fullscreen"), this); + fullscreen_action->setShortcut(Qt::Key_F11); + addAction(fullscreen_action); + connect(fullscreen_action, &QAction::triggered, this, &StreamWindow::ToggleFullscreen); resize(connect_info.video_profile.width, connect_info.video_profile.height); - - if(connect_info.fullscreen) - { - showFullScreen(); - fullscreen_action->setChecked(true); - } - else - show(); - - UpdateTransformModeActions(); + show(); } void StreamWindow::keyPressEvent(QKeyEvent *event) @@ -132,32 +84,22 @@ void StreamWindow::keyReleaseEvent(QKeyEvent *event) session->HandleKeyboardEvent(event); } -void StreamWindow::Quit() -{ - close(); -} - void StreamWindow::mousePressEvent(QMouseEvent *event) { - if(session && session->HandleMouseEvent(event)) - return; - QMainWindow::mousePressEvent(event); + if(session) + session->HandleMouseEvent(event); } void StreamWindow::mouseReleaseEvent(QMouseEvent *event) { - if(session && session->HandleMouseEvent(event)) - return; - QMainWindow::mouseReleaseEvent(event); + if(session) + session->HandleMouseEvent(event); } void StreamWindow::mouseDoubleClickEvent(QMouseEvent *event) { - if(event->button() == Qt::MouseButton::LeftButton) - { - ToggleFullscreen(); - return; - } + ToggleFullscreen(); + QMainWindow::mouseDoubleClickEvent(event); } @@ -201,7 +143,7 @@ void StreamWindow::closeEvent(QCloseEvent *event) void StreamWindow::SessionQuit(ChiakiQuitReason reason, const QString &reason_str) { - if(chiaki_quit_reason_is_error(reason)) + if(reason != CHIAKI_QUIT_REASON_STOPPED) { QString m = tr("Chiaki Session has quit") + ":\n" + chiaki_quit_reason_string(reason); if(!reason_str.isEmpty()) @@ -233,48 +175,15 @@ void StreamWindow::LoginPINRequested(bool incorrect) void StreamWindow::ToggleFullscreen() { if(isFullScreen()) - { showNormal(); - fullscreen_action->setChecked(false); - } else { showFullScreen(); if(av_widget) av_widget->HideMouse(); - fullscreen_action->setChecked(true); } } -void StreamWindow::UpdateTransformModeActions() -{ - TransformMode tm = av_widget ? av_widget->GetTransformMode() : TransformMode::Fit; - stretch_action->setChecked(tm == TransformMode::Stretch); - zoom_action->setChecked(tm == TransformMode::Zoom); -} - -void StreamWindow::ToggleStretch() -{ - if(!av_widget) - return; - av_widget->SetTransformMode( - av_widget->GetTransformMode() == TransformMode::Stretch - ? TransformMode::Fit - : TransformMode::Stretch); - UpdateTransformModeActions(); -} - -void StreamWindow::ToggleZoom() -{ - if(!av_widget) - return; - av_widget->SetTransformMode( - av_widget->GetTransformMode() == TransformMode::Zoom - ? TransformMode::Fit - : TransformMode::Zoom); - UpdateTransformModeActions(); -} - void StreamWindow::resizeEvent(QResizeEvent *event) { UpdateVideoTransform(); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cbfd6b0..e2a79d3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -35,8 +35,7 @@ set(HEADER_FILES include/chiaki/time.h include/chiaki/fec.h include/chiaki/regist.h - include/chiaki/opusdecoder.h - include/chiaki/orientation.h) + include/chiaki/opusdecoder.h) set(SOURCE_FILES src/common.c @@ -72,10 +71,9 @@ set(SOURCE_FILES src/controller.c src/takionsendbuffer.c src/time.c - src/fec.c + src/fec src/regist.c - src/opusdecoder.c - src/orientation.c) + src/opusdecoder.c) if(CHIAKI_ENABLE_FFMPEG_DECODER) list(APPEND HEADER_FILES include/chiaki/ffmpegdecoder.h) @@ -119,15 +117,11 @@ find_package(Threads REQUIRED) target_link_libraries(chiaki-lib Threads::Threads) if(CHIAKI_LIB_ENABLE_MBEDTLS) - if(CHIAKI_LIB_MBEDTLS_EXTERNAL_PROJECT) - target_link_libraries(chiaki-lib mbedtls mbedx509 mbedcrypto) - else() - # provided by mbedtls-static (mbedtls-devel) - find_library(MBEDTLS mbedtls) - find_library(MBEDX509 mbedx509) - find_library(MBEDCRYPTO mbedcrypto) - target_link_libraries(chiaki-lib ${MBEDTLS} ${MBEDX509} ${MBEDCRYPTO}) - endif() + # provided by mbedtls-static (mbedtls-devel) + find_library(MBEDTLS mbedtls) + find_library(MBEDX509 mbedx509) + find_library(MBEDCRYPTO mbedcrypto) + target_link_libraries(chiaki-lib ${MBEDTLS} ${MBEDX509} ${MBEDCRYPTO}) elseif(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT) target_link_libraries(chiaki-lib OpenSSL_Crypto) else() diff --git a/lib/include/chiaki/controller.h b/lib/include/chiaki/controller.h index 24e86a9..e8f2e7c 100644 --- a/lib/include/chiaki/controller.h +++ b/lib/include/chiaki/controller.h @@ -66,10 +66,6 @@ typedef struct chiaki_controller_state_t uint8_t touch_id_next; ChiakiControllerTouch touches[CHIAKI_CONTROLLER_TOUCHES_MAX]; - - float gyro_x, gyro_y, gyro_z; - float accel_x, accel_y, accel_z; - float orient_x, orient_y, orient_z, orient_w; } ChiakiControllerState; CHIAKI_EXPORT void chiaki_controller_state_set_idle(ChiakiControllerState *state); @@ -83,12 +79,27 @@ CHIAKI_EXPORT void chiaki_controller_state_stop_touch(ChiakiControllerState *sta CHIAKI_EXPORT void chiaki_controller_state_set_touch_pos(ChiakiControllerState *state, uint8_t id, uint16_t x, uint16_t y); -CHIAKI_EXPORT bool chiaki_controller_state_equals(ChiakiControllerState *a, ChiakiControllerState *b); +static inline bool chiaki_controller_state_equals(ChiakiControllerState *a, ChiakiControllerState *b) +{ + if(!(a->buttons == b->buttons + && a->l2_state == b->l2_state + && a->r2_state == b->r2_state + && a->left_x == b->left_x + && a->left_y == b->left_y + && a->right_x == b->right_x + && a->right_y == b->right_y)) + return false; + + for(size_t i=0; itouches[i].id != b->touches[i].id) + return false; + if(a->touches[i].id >= 0 && (a->touches[i].x != b->touches[i].x || a->touches[i].y != b->touches[i].y)) + return false; + } + return true; +} -/** - * Union of two controller states. - * Ignores gyro, accel and orient because it makes no sense there. - */ CHIAKI_EXPORT void chiaki_controller_state_or(ChiakiControllerState *out, ChiakiControllerState *a, ChiakiControllerState *b); #ifdef __cplusplus diff --git a/lib/include/chiaki/discovery.h b/lib/include/chiaki/discovery.h index f26200b..c9881b5 100644 --- a/lib/include/chiaki/discovery.h +++ b/lib/include/chiaki/discovery.h @@ -25,8 +25,6 @@ extern "C" { #define CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS4 "00020020" #define CHIAKI_DISCOVERY_PORT_PS5 9302 #define CHIAKI_DISCOVERY_PROTOCOL_VERSION_PS5 "00030010" -#define CHIAKI_DISCOVERY_PORT_LOCAL_MIN 9303 -#define CHIAKI_DISCOVERY_PORT_LOCAL_MAX 9319 typedef enum chiaki_discovery_cmd_t { diff --git a/lib/include/chiaki/feedback.h b/lib/include/chiaki/feedback.h index be66384..264af5c 100644 --- a/lib/include/chiaki/feedback.h +++ b/lib/include/chiaki/feedback.h @@ -15,9 +15,6 @@ extern "C" { typedef struct chiaki_feedback_state_t { - float gyro_x, gyro_y, gyro_z; - float accel_x, accel_y, accel_z; - float orient_x, orient_y, orient_z, orient_w; int16_t left_x; int16_t left_y; int16_t right_x; diff --git a/lib/include/chiaki/orientation.h b/lib/include/chiaki/orientation.h deleted file mode 100644 index 6dde62b..0000000 --- a/lib/include/chiaki/orientation.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL - -#ifndef CHIAKI_ORIENTATION_H -#define CHIAKI_ORIENTATION_H - -#include "common.h" -#include "controller.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Quaternion orientation from accelerometer and gyroscope - * using Madgwick's algorithm. - * See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms - */ -typedef struct chiaki_orientation_t -{ - float x, y, z, w; -} ChiakiOrientation; - -CHIAKI_EXPORT void chiaki_orientation_init(ChiakiOrientation *orient); -CHIAKI_EXPORT void chiaki_orientation_update(ChiakiOrientation *orient, - float gx, float gy, float gz, float ax, float ay, float az, float beta, float time_step_sec); - -/** - * Extension of ChiakiOrientation, also tracking an absolute timestamp and the current gyro/accel state - */ -typedef struct chiaki_orientation_tracker_t -{ - float gyro_x, gyro_y, gyro_z; - float accel_x, accel_y, accel_z; - ChiakiOrientation orient; - uint32_t timestamp; - uint64_t sample_index; -} ChiakiOrientationTracker; - -CHIAKI_EXPORT void chiaki_orientation_tracker_init(ChiakiOrientationTracker *tracker); -CHIAKI_EXPORT void chiaki_orientation_tracker_update(ChiakiOrientationTracker *tracker, - float gx, float gy, float gz, float ax, float ay, float az, uint32_t timestamp_us); -CHIAKI_EXPORT void chiaki_orientation_tracker_apply_to_controller_state(ChiakiOrientationTracker *tracker, - ChiakiControllerState *state); - -#ifdef __cplusplus -} -#endif - -#endif // CHIAKI_ORIENTATION_H diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index 5c355ad..db7bf02 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -78,7 +78,6 @@ typedef struct chiaki_connect_info_t ChiakiConnectVideoProfile video_profile; bool video_profile_auto_downgrade; // Downgrade video_profile if server does not seem to support it. bool enable_keyboard; - bool enable_dualsense; } ChiakiConnectInfo; @@ -94,17 +93,11 @@ typedef enum { CHIAKI_QUIT_REASON_CTRL_CONNECT_FAILED, CHIAKI_QUIT_REASON_CTRL_CONNECTION_REFUSED, CHIAKI_QUIT_REASON_STREAM_CONNECTION_UNKNOWN, - CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED, - CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN, // like REMOTE_DISCONNECTED, but because the server shut down + CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED } ChiakiQuitReason; CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason); -static inline bool chiaki_quit_reason_is_error(ChiakiQuitReason reason) -{ - return reason != CHIAKI_QUIT_REASON_STOPPED && reason != CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN; -} - typedef struct chiaki_quit_event_t { ChiakiQuitReason reason; @@ -121,20 +114,6 @@ typedef struct chiaki_audio_stream_info_event_t ChiakiAudioHeader audio_header; } ChiakiAudioStreamInfoEvent; -typedef struct chiaki_rumble_event_t -{ - uint8_t unknown; - uint8_t left; // low-frequency - uint8_t right; // high-frequency -} ChiakiRumbleEvent; - -typedef struct chiaki_trigger_effects_event_t -{ - uint8_t type_left; - uint8_t type_right; - uint8_t left[10]; - uint8_t right[10]; -} ChiakiTriggerEffectsEvent; typedef enum { CHIAKI_EVENT_CONNECTED, @@ -142,9 +121,7 @@ typedef enum { CHIAKI_EVENT_KEYBOARD_OPEN, CHIAKI_EVENT_KEYBOARD_TEXT_CHANGE, CHIAKI_EVENT_KEYBOARD_REMOTE_CLOSE, - CHIAKI_EVENT_RUMBLE, CHIAKI_EVENT_QUIT, - CHIAKI_EVENT_TRIGGER_EFFECTS, } ChiakiEventType; typedef struct chiaki_event_t @@ -154,8 +131,6 @@ typedef struct chiaki_event_t { ChiakiQuitEvent quit; ChiakiKeyboardEvent keyboard; - ChiakiRumbleEvent rumble; - ChiakiTriggerEffectsEvent trigger_effects; struct { bool pin_incorrect; // false on first request, true if the pin entered before was incorrect @@ -180,14 +155,13 @@ typedef struct chiaki_session_t bool ps5; struct addrinfo *host_addrinfos; struct addrinfo *host_addrinfo_selected; - char hostname[256]; + char hostname[128]; char regist_key[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t morning[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t did[CHIAKI_RP_DID_SIZE]; ChiakiConnectVideoProfile video_profile; bool video_profile_auto_downgrade; bool enable_keyboard; - bool enable_dualsense; } connect_info; ChiakiTarget target; @@ -209,7 +183,6 @@ typedef struct chiaki_session_t ChiakiVideoSampleCallback video_sample_cb; void *video_sample_cb_user; ChiakiAudioSink audio_sink; - ChiakiAudioSink haptics_sink; ChiakiThread session_thread; @@ -265,14 +238,6 @@ static inline void chiaki_session_set_audio_sink(ChiakiSession *session, ChiakiA session->audio_sink = *sink; } -/** - * @param sink contents are copied - */ -static inline void chiaki_session_set_haptics_sink(ChiakiSession *session, ChiakiAudioSink *sink) -{ - session->haptics_sink = *sink; -} - #ifdef __cplusplus } #endif diff --git a/lib/include/chiaki/streamconnection.h b/lib/include/chiaki/streamconnection.h index 90578c6..ba1817a 100644 --- a/lib/include/chiaki/streamconnection.h +++ b/lib/include/chiaki/streamconnection.h @@ -32,7 +32,6 @@ typedef struct chiaki_stream_connection_t ChiakiPacketStats packet_stats; ChiakiAudioReceiver *audio_receiver; ChiakiVideoReceiver *video_receiver; - ChiakiAudioReceiver *haptics_receiver; ChiakiFeedbackSender feedback_sender; /** diff --git a/lib/include/chiaki/takion.h b/lib/include/chiaki/takion.h index 15d62e5..3f7e96f 100644 --- a/lib/include/chiaki/takion.h +++ b/lib/include/chiaki/takion.h @@ -26,9 +26,7 @@ extern "C" { typedef enum chiaki_takion_message_data_type_t { CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF = 0, - CHIAKI_TAKION_MESSAGE_DATA_TYPE_RUMBLE = 7, - CHIAKI_TAKION_MESSAGE_DATA_TYPE_9 = 9, - CHIAKI_TAKION_MESSAGE_DATA_TYPE_TRIGGER_EFFECTS = 11, + CHIAKI_TAKION_MESSAGE_DATA_TYPE_9 = 9 } ChiakiTakionMessageDataType; typedef struct chiaki_takion_av_packet_t @@ -37,7 +35,6 @@ typedef struct chiaki_takion_av_packet_t ChiakiSeqNum16 frame_index; bool uses_nalu_info_structs; bool is_video; - bool is_haptics; ChiakiSeqNum16 unit_index; uint16_t units_in_frame_total; // source + units_in_frame_fec uint16_t units_in_frame_fec; @@ -48,6 +45,8 @@ typedef struct chiaki_takion_av_packet_t uint64_t key_pos; + uint8_t byte_before_audio_data; + uint8_t *data; // not owned size_t data_size; } ChiakiTakionAVPacket; @@ -106,7 +105,6 @@ typedef struct chiaki_takion_connect_info_t ChiakiTakionCallback cb; void *cb_user; bool enable_crypt; - bool enable_dualsense; uint8_t protocol_version; } ChiakiTakionConnectInfo; @@ -163,8 +161,6 @@ typedef struct chiaki_takion_t ChiakiTakionAVPacketParse av_packet_parse; ChiakiKeyState key_state; - - bool enable_dualsense; } ChiakiTakion; diff --git a/lib/protobuf/CMakeLists.txt b/lib/protobuf/CMakeLists.txt index 43fde68..6efa342 100644 --- a/lib/protobuf/CMakeLists.txt +++ b/lib/protobuf/CMakeLists.txt @@ -11,16 +11,8 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/takion.pb" set(SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/takion.pb.c") set(HEADER_FILES "${CMAKE_CURRENT_BINARY_DIR}/takion.pb.h") -if(UNIX AND IS_ABSOLUTE "${PROTOC}") - # make sure protoc is in PATH when invoking the generator below, which needs it. - get_filename_component(PROTOC_PATH "${PROTOC}" DIRECTORY) - set(GEN_PREFIX "${CMAKE_COMMAND}" -E env "PATH=${PROTOC_PATH}:$ENV{PATH}") -else() - set(GEN_PREFIX "") -endif() - add_custom_command(OUTPUT ${SOURCE_FILES} ${HEADER_FILES} - COMMAND ${GEN_PREFIX} "${PYTHON_EXECUTABLE}" "${NANOPB_GENERATOR_PY}" "${CMAKE_CURRENT_BINARY_DIR}/takion.pb" + COMMAND "${PYTHON_EXECUTABLE}" "${NANOPB_GENERATOR_PY}" "${CMAKE_CURRENT_BINARY_DIR}/takion.pb" MAIN_DEPENDENCY "${CMAKE_CURRENT_BINARY_DIR}/takion.pb") set(CHIAKI_LIB_PROTO_SOURCE_FILES "${SOURCE_FILES}" PARENT_SCOPE) diff --git a/lib/protobuf/takion.proto b/lib/protobuf/takion.proto index ceef0f1..748d70a 100644 --- a/lib/protobuf/takion.proto +++ b/lib/protobuf/takion.proto @@ -312,8 +312,7 @@ message ControllerConnectionPayload { VITA = 3; XINPUT = 4; MOBILE = 5; - DUALSENSE = 6; - VR2SENSE = 7; + BOND = 6; } } diff --git a/lib/src/audioreceiver.c b/lib/src/audioreceiver.c index 744d807..5808e4c 100644 --- a/lib/src/audioreceiver.c +++ b/lib/src/audioreceiver.c @@ -5,7 +5,7 @@ #include -static void chiaki_audio_receiver_frame(ChiakiAudioReceiver *audio_receiver, ChiakiSeqNum16 frame_index, bool is_haptics, uint8_t *buf, size_t buf_size); +static void chiaki_audio_receiver_frame(ChiakiAudioReceiver *audio_receiver, ChiakiSeqNum16 frame_index, uint8_t *buf, size_t buf_size); CHIAKI_EXPORT ChiakiErrorCode chiaki_audio_receiver_init(ChiakiAudioReceiver *audio_receiver, ChiakiSession *session, ChiakiPacketStats *packet_stats) { @@ -23,6 +23,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_audio_receiver_init(ChiakiAudioReceiver *au return CHIAKI_ERR_SUCCESS; } + CHIAKI_EXPORT void chiaki_audio_receiver_fini(ChiakiAudioReceiver *audio_receiver) { #ifdef CHIAKI_LIB_ENABLE_OPUS @@ -31,6 +32,7 @@ CHIAKI_EXPORT void chiaki_audio_receiver_fini(ChiakiAudioReceiver *audio_receive chiaki_mutex_fini(&audio_receiver->mutex); } + CHIAKI_EXPORT void chiaki_audio_receiver_stream_info(ChiakiAudioReceiver *audio_receiver, ChiakiAudioHeader *audio_header) { chiaki_mutex_lock(&audio_receiver->mutex); @@ -77,15 +79,15 @@ CHIAKI_EXPORT void chiaki_audio_receiver_av_packet(ChiakiAudioReceiver *audio_re if(packet->data_size != (size_t)unit_size * (size_t)packet->units_in_frame_total) { CHIAKI_LOGE(audio_receiver->log, "Audio AV Packet size mismatch %#llx vs %#llx", - (unsigned long long)packet->data_size, - (unsigned long long)(unit_size * packet->units_in_frame_total)); + (unsigned long long)packet->data_size, + (unsigned long long)(unit_size * packet->units_in_frame_total)); return; } if(packet->frame_index > (1 << 15)) audio_receiver->frame_index_startup = false; - for(size_t i = 0; i < source_units_count + fec_units_count; i++) + for(size_t i=0; iframe_index - fec_units_count + fec_index; } - chiaki_audio_receiver_frame(audio_receiver, frame_index, packet->is_haptics, packet->data + unit_size * i, unit_size); + chiaki_audio_receiver_frame(audio_receiver, frame_index, packet->data + unit_size * i, unit_size); } if(audio_receiver->packet_stats) chiaki_packet_stats_push_seq(audio_receiver->packet_stats, packet->frame_index); } -static void chiaki_audio_receiver_frame(ChiakiAudioReceiver *audio_receiver, ChiakiSeqNum16 frame_index, bool is_haptics, uint8_t *buf, size_t buf_size) +static void chiaki_audio_receiver_frame(ChiakiAudioReceiver *audio_receiver, ChiakiSeqNum16 frame_index, uint8_t *buf, size_t buf_size) { chiaki_mutex_lock(&audio_receiver->mutex); @@ -117,9 +119,7 @@ static void chiaki_audio_receiver_frame(ChiakiAudioReceiver *audio_receiver, Chi goto beach; audio_receiver->frame_index_prev = frame_index; - if(is_haptics && audio_receiver->session->haptics_sink.frame_cb) - audio_receiver->session->haptics_sink.frame_cb(buf, buf_size, audio_receiver->session->haptics_sink.user); - else if(!is_haptics && audio_receiver->session->audio_sink.frame_cb) + if(audio_receiver->session->audio_sink.frame_cb) audio_receiver->session->audio_sink.frame_cb(buf, buf_size, audio_receiver->session->audio_sink.user); beach: diff --git a/lib/src/base64.c b/lib/src/base64.c index 9d0fecd..fbdf635 100644 --- a/lib/src/base64.c +++ b/lib/src/base64.c @@ -7,6 +7,7 @@ // Implementations taken from // https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 + CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_size, char *out, size_t out_size) { const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -22,11 +23,11 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_ // these three 8-bit (ASCII) characters become one 24-bit number n = ((uint32_t)in[x]) << 16; - if((x + 1) < in_size) - n += ((uint32_t)in[x + 1]) << 8; + if((x+1) < in_size) + n += ((uint32_t)in[x+1]) << 8; - if((x + 2) < in_size) - n += in[x + 2]; + if((x+2) < in_size) + n += in[x+2]; // this 24-bit number gets separated into four 6-bit numbers n0 = (uint8_t)(n >> 18) & 63; @@ -45,7 +46,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_ // if we have only two bytes available, then their encoding is // spread out over three chars - if((x + 1) < in_size) + if((x+1) < in_size) { if(result_index >= out_size) return CHIAKI_ERR_BUF_TOO_SMALL; @@ -54,7 +55,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_ // if we have all three bytes available, then their encoding is spread // out over four characters - if((x + 2) < in_size) + if((x+2) < in_size) { if(result_index >= out_size) return CHIAKI_ERR_BUF_TOO_SMALL; @@ -64,9 +65,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_ // create and add padding that is required if we did not have a multiple of 3 // number of characters available - if(pad_count > 0) + if (pad_count > 0) { - for(; pad_count < 3; pad_count++) + for (; pad_count < 3; pad_count++) { if(result_index >= out_size) return CHIAKI_ERR_BUF_TOO_SMALL; @@ -79,22 +80,25 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_encode(const uint8_t *in, size_t in_ return CHIAKI_ERR_SUCCESS; } + + + #define WHITESPACE 64 -#define EQUALS 65 -#define INVALID 66 +#define EQUALS 65 +#define INVALID 66 static const unsigned char d[] = { - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 64, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 62, 66, 66, 66, 63, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 66, 66, 66, 65, 66, 66, 66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 66, 66, 66, 66, 66, 66, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66 + 66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53, + 54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,66,66,66,66,66,66,26,27,28, + 29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66 }; CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_decode(const char *in, size_t in_size, uint8_t *out, size_t *out_size) @@ -104,17 +108,17 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_decode(const char *in, size_t in_siz uint32_t buf = 0; size_t len = 0; - while(in < end) + while (in < end) { unsigned char c = d[(size_t)(*in++)]; switch(c) { case WHITESPACE: - continue; // skip whitespace + continue; // skip whitespace case INVALID: - return CHIAKI_ERR_INVALID_DATA; // invalid input - case EQUALS: // pad character, end of data + return CHIAKI_ERR_INVALID_DATA; // invalid input + case EQUALS: // pad character, end of data in = end; continue; default: @@ -128,8 +132,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_base64_decode(const char *in, size_t in_siz *(out++) = (unsigned char)((buf >> 16) & 0xff); *(out++) = (unsigned char)((buf >> 8) & 0xff); *(out++) = (unsigned char)(buf & 0xff); - buf = 0; - iter = 0; + buf = 0; iter = 0; } } } diff --git a/lib/src/common.c b/lib/src/common.c index adb0fc6..0dd2006 100644 --- a/lib/src/common.c +++ b/lib/src/common.c @@ -1,14 +1,14 @@ // SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL #include -#include #include +#include #include -#include #include #include +#include #ifdef _WIN32 #include @@ -98,7 +98,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_lib_init() WORD wsa_version = MAKEWORD(2, 2); WSADATA wsa_data; int err = WSAStartup(wsa_version, &wsa_data); - if(err != 0) + if (err != 0) return CHIAKI_ERR_NETWORK; } #endif diff --git a/lib/src/congestioncontrol.c b/lib/src/congestioncontrol.c index 8fb912b..e478410 100644 --- a/lib/src/congestioncontrol.c +++ b/lib/src/congestioncontrol.c @@ -25,7 +25,7 @@ static void *congestion_control_thread_func(void *user) packet.received = (uint16_t)received; packet.lost = (uint16_t)lost; CHIAKI_LOGV(control->takion->log, "Sending Congestion Control Packet, received: %u, lost: %u", - (unsigned int)packet.received, (unsigned int)packet.lost); + (unsigned int)packet.received, (unsigned int)packet.lost); chiaki_takion_send_congestion(control->takion, &packet); } diff --git a/lib/src/controller.c b/lib/src/controller.c index 744a83f..b347bb7 100644 --- a/lib/src/controller.c +++ b/lib/src/controller.c @@ -14,25 +14,17 @@ CHIAKI_EXPORT void chiaki_controller_state_set_idle(ChiakiControllerState *state state->right_x = 0; state->right_y = 0; state->touch_id_next = 0; - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + for(size_t i=0; itouches[i].id = -1; state->touches[i].x = 0; state->touches[i].y = 0; } - state->gyro_x = state->gyro_y = state->gyro_z = 0.0f; - state->accel_x = 0.0f; - state->accel_y = 1.0f; - state->accel_z = 0.0f; - state->orient_x = 0.0f; - state->orient_y = 0.0f; - state->orient_z = 0.0f; - state->orient_w = 1.0f; } CHIAKI_EXPORT int8_t chiaki_controller_state_start_touch(ChiakiControllerState *state, uint16_t x, uint16_t y) { - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + for(size_t i=0; itouches[i].id < 0) { @@ -48,7 +40,7 @@ CHIAKI_EXPORT int8_t chiaki_controller_state_start_touch(ChiakiControllerState * CHIAKI_EXPORT void chiaki_controller_state_stop_touch(ChiakiControllerState *state, uint8_t id) { - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + for(size_t i=0; itouches[i].id == id) { @@ -61,7 +53,7 @@ CHIAKI_EXPORT void chiaki_controller_state_stop_touch(ChiakiControllerState *sta CHIAKI_EXPORT void chiaki_controller_state_set_touch_pos(ChiakiControllerState *state, uint8_t id, uint16_t x, uint16_t y) { id &= TOUCH_ID_MASK; - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + for(size_t i=0; itouches[i].id == id) { @@ -72,43 +64,8 @@ CHIAKI_EXPORT void chiaki_controller_state_set_touch_pos(ChiakiControllerState * } } -CHIAKI_EXPORT bool chiaki_controller_state_equals(ChiakiControllerState *a, ChiakiControllerState *b) -{ - if(!(a->buttons == b->buttons - && a->l2_state == b->l2_state - && a->r2_state == b->r2_state - && a->left_x == b->left_x - && a->left_y == b->left_y - && a->right_x == b->right_x - && a->right_y == b->right_y)) - return false; - - for(size_t i=0; itouches[i].id != b->touches[i].id) - return false; - if(a->touches[i].id >= 0 && (a->touches[i].x != b->touches[i].x || a->touches[i].y != b->touches[i].y)) - return false; - } - -#define CHECKF(n) if(a->n < b->n - 0.0000001f || a->n > b->n + 0.0000001f) return false - CHECKF(gyro_x); - CHECKF(gyro_y); - CHECKF(gyro_z); - CHECKF(accel_x); - CHECKF(accel_y); - CHECKF(accel_z); - CHECKF(orient_x); - CHECKF(orient_y); - CHECKF(orient_z); - CHECKF(orient_w); -#undef CHECKF - - return true; -} - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define ABS(a) ((a) > 0 ? (a) : -(a)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ABS(a) ((a) > 0 ? (a) : -(a)) #define MAX_ABS(a, b) (ABS(a) > ABS(b) ? (a) : (b)) CHIAKI_EXPORT void chiaki_controller_state_or(ChiakiControllerState *out, ChiakiControllerState *a, ChiakiControllerState *b) @@ -121,21 +78,8 @@ CHIAKI_EXPORT void chiaki_controller_state_or(ChiakiControllerState *out, Chiaki out->right_x = MAX_ABS(a->right_x, b->right_x); out->right_y = MAX_ABS(a->right_y, b->right_y); - #define ORF(n, idle_val) if(a->n == idle_val) out->n = b->n; else out->n = a->n - ORF(accel_x, 0.0f); - ORF(accel_y, 1.0f); - ORF(accel_z, 0.0f); - ORF(gyro_x, 0.0f); - ORF(gyro_y, 0.0f); - ORF(gyro_z, 0.0f); - ORF(orient_x, 0.0f); - ORF(orient_y, 0.0f); - ORF(orient_z, 0.0f); - ORF(orient_w, 1.0f); - #undef ORF - out->touch_id_next = 0; - for(size_t i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + for(size_t i=0; itouches[i].id >= 0 ? &a->touches[i] : (b->touches[i].id >= 0 ? &b->touches[i] : NULL); if(!touch) diff --git a/lib/src/ctrl.c b/lib/src/ctrl.c index 29a39b2..f92d12b 100644 --- a/lib/src/ctrl.c +++ b/lib/src/ctrl.c @@ -488,27 +488,20 @@ static void ctrl_message_received(ChiakiCtrl *ctrl, uint16_t msg_type, uint8_t * static void ctrl_enable_optional_features(ChiakiCtrl *ctrl) { - if(ctrl->session->connect_info.enable_dualsense) - { - CHIAKI_LOGI(ctrl->session->log, "Enabling DualSense features"); - const uint8_t enable[3] = { 0x00, 0x40, 0x00 }; - ctrl_message_send(ctrl, 0x13, enable, 3); - } - if(ctrl->session->connect_info.enable_keyboard) - { - CHIAKI_LOGI(ctrl->session->log, "Enabling Keyboard"); - // TODO: Last byte of pre_enable request is random (?) - // TODO: Signature ?! - uint8_t enable = 1; - uint8_t pre_enable[4] = { 0x00, 0x01, 0x01, 0x80 }; - uint8_t signature[0x10] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - ctrl_message_send(ctrl, 0xD, signature, 0x10); - ctrl_message_send(ctrl, 0x36, pre_enable, 4); - ctrl_message_send(ctrl, CTRL_MESSAGE_TYPE_KEYBOARD_ENABLE_TOGGLE, &enable, 1); - ctrl_message_send(ctrl, 0x36, pre_enable, 4); - } + if(!ctrl->session->connect_info.enable_keyboard) + return; + // TODO: Last byte of pre_enable request is random (?) + // TODO: Signature ?! + uint8_t enable = 1; + uint8_t pre_enable[4] = { 0x00, 0x01, 0x01, 0x80 }; + uint8_t signature[0x10] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + ctrl_message_send(ctrl, 0xD, signature, 0x10); + ctrl_message_send(ctrl, 0x36, pre_enable, 4); + ctrl_message_send(ctrl, CTRL_MESSAGE_TYPE_KEYBOARD_ENABLE_TOGGLE, &enable, 1); + ctrl_message_send(ctrl, 0x36, pre_enable, 4); } + static void ctrl_message_received_session_id(ChiakiCtrl *ctrl, uint8_t *payload, size_t payload_size) { if(ctrl->session->ctrl_session_id_received) @@ -659,7 +652,7 @@ static void ctrl_message_received_keyboard_close(ChiakiCtrl *ctrl, uint8_t *payl chiaki_session_send_event(ctrl->session, &keyboard_event); } -static void ctrl_message_received_keyboard_text_change(ChiakiCtrl *ctrl, uint8_t *payload, size_t payload_size) +static void ctrl_message_received_keyboard_text_change(ChiakiCtrl* ctrl, uint8_t* payload, size_t payload_size) { assert(payload_size >= sizeof(CtrlKeyboardTextResponseMessage)); @@ -683,8 +676,7 @@ static void ctrl_message_received_keyboard_text_change(ChiakiCtrl *ctrl, uint8_t free(buffer); } -typedef struct ctrl_response_t -{ +typedef struct ctrl_response_t { bool server_type_valid; uint8_t rp_server_type[0x10]; bool success; @@ -750,6 +742,7 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl) if(err != CHIAKI_ERR_SUCCESS) CHIAKI_LOGE(session->log, "Failed to set ctrl socket to non-blocking: %s", chiaki_error_string(err)); + chiaki_mutex_unlock(&ctrl->notif_mutex); err = chiaki_stop_pipe_connect(&ctrl->notif_pipe, sock, sa, addr->ai_addrlen); chiaki_mutex_lock(&ctrl->notif_mutex); diff --git a/lib/src/discovery.c b/lib/src/discovery.c index f207a54..0658c87 100644 --- a/lib/src/discovery.c +++ b/lib/src/discovery.c @@ -152,48 +152,27 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_discovery_init(ChiakiDiscovery *discovery, return CHIAKI_ERR_NETWORK; } - // First try CHIAKI_DISCOVERY_PORT_LOCAL_MIN..local_addr, 0, sizeof(discovery->local_addr)); + discovery->local_addr.sa_family = family; + if(family == AF_INET6) { - memset(&discovery->local_addr, 0, sizeof(discovery->local_addr)); - discovery->local_addr.sa_family = family; - if(family == AF_INET6) - { #ifndef __SWITCH__ - struct in6_addr anyaddr = IN6ADDR_ANY_INIT; + struct in6_addr anyaddr = IN6ADDR_ANY_INIT; #endif - struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&discovery->local_addr; + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&discovery->local_addr; #ifndef __SWITCH__ - addr->sin6_addr = anyaddr; + addr->sin6_addr = anyaddr; #endif - addr->sin6_port = htons(port); - } - else // AF_INET - { - struct sockaddr_in *addr = (struct sockaddr_in *)&discovery->local_addr; - addr->sin_addr.s_addr = htonl(INADDR_ANY); - addr->sin_port = htons(port); - } - - r = bind(discovery->socket, &discovery->local_addr, sizeof(discovery->local_addr)); - if(r >= 0 || !port) - break; - if(port == CHIAKI_DISCOVERY_PORT_LOCAL_MAX) - { - port = 0; - CHIAKI_LOGI(discovery->log, "Discovery failed to bind port %u, trying random", - (unsigned int)port); - } - else - { - port++; - CHIAKI_LOGI(discovery->log, "Discovery failed to bind port %u, trying one higher", - (unsigned int)port); - } + addr->sin6_port = htons(0); + } + else // AF_INET + { + struct sockaddr_in *addr = (struct sockaddr_in *)&discovery->local_addr; + addr->sin_addr.s_addr = htonl(INADDR_ANY); + addr->sin_port = htons(0); } + int r = bind(discovery->socket, &discovery->local_addr, sizeof(discovery->local_addr)); if(r < 0) { CHIAKI_LOGE(discovery->log, "Discovery failed to bind"); diff --git a/lib/src/discoveryservice.c b/lib/src/discoveryservice.c index f163092..09f31ef 100644 --- a/lib/src/discoveryservice.c +++ b/lib/src/discoveryservice.c @@ -238,7 +238,7 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use if(service->hosts_count == service->options.hosts_max) { CHIAKI_LOGE(service->log, "Discovery Service received new host, but no space available"); - goto rzcon; + goto r2con; } CHIAKI_LOGI(service->log, "Discovery Service detected new host with id %s", host->host_id); @@ -279,7 +279,7 @@ static void discovery_service_host_received(ChiakiDiscoveryHost *host, void *use if(change) discovery_service_report_state(service); -rzcon: +r2con: chiaki_mutex_unlock(&service->state_mutex); } diff --git a/lib/src/ecdh.c b/lib/src/ecdh.c index 3277b60..1a48b54 100644 --- a/lib/src/ecdh.c +++ b/lib/src/ecdh.c @@ -79,6 +79,7 @@ CHIAKI_EXPORT void chiaki_ecdh_fini(ChiakiECDH *ecdh) #endif } + CHIAKI_EXPORT ChiakiErrorCode chiaki_ecdh_set_local_key(ChiakiECDH *ecdh, const uint8_t *private_key, size_t private_key_size, const uint8_t *public_key, size_t public_key_size) { #ifdef CHIAKI_LIB_ENABLE_MBEDTLS @@ -88,19 +89,24 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_ecdh_set_local_key(ChiakiECDH *ecdh, const // public int r = 0; - r = mbedtls_ecp_point_read_binary(&ecdh->ctx.grp, &ecdh->ctx.Q, public_key, public_key_size); - if(r != 0) + r = mbedtls_ecp_point_read_binary(&ecdh->ctx.grp, &ecdh->ctx.Q, + public_key, public_key_size); + if(r != 0 ){ return CHIAKI_ERR_UNKNOWN; + } // secret r = mbedtls_mpi_read_binary(&ecdh->ctx.d, private_key, private_key_size); - if(r != 0) + if(r != 0 ){ return CHIAKI_ERR_UNKNOWN; + } // regen key - r = mbedtls_ecdh_gen_public(&ecdh->ctx.grp, &ecdh->ctx.d, &ecdh->ctx.Q, mbedtls_ctr_drbg_random, &ecdh->drbg); - if(r != 0) + r = mbedtls_ecdh_gen_public(&ecdh->ctx.grp, &ecdh->ctx.d, + &ecdh->ctx.Q, mbedtls_ctr_drbg_random, &ecdh->drbg); + if(r != 0 ){ return CHIAKI_ERR_UNKNOWN; + } return CHIAKI_ERR_SUCCESS; #else diff --git a/lib/src/feedback.c b/lib/src/feedback.c index 6db8364..d5a46bc 100644 --- a/lib/src/feedback.c +++ b/lib/src/feedback.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL -#define _USE_MATH_DEFINES - #include #include @@ -11,65 +9,26 @@ #include #endif #include -#include - -#define GYRO_MIN -30.0f -#define GYRO_MAX 30.0f -#define ACCEL_MIN -5.0f -#define ACCEL_MAX 5.0f - -static uint32_t compress_quat(float *q) -{ - // very similar idea as https://github.com/jpreiss/quatcompress - size_t largest_i = 0; - for(size_t i = 1; i < 4; i++) - { - if(fabs(q[i]) > fabs(q[largest_i])) - largest_i = i; - } - uint32_t r = (q[largest_i] < 0.0 ? 1 : 0) | (largest_i << 1); - for(size_t i = 0; i < 3; i++) - { - size_t qi = i < largest_i ? i : i + 1; - float v = q[qi]; - if(v < -M_SQRT1_2) - v = -M_SQRT1_2; - if(v > M_SQRT1_2) - v = M_SQRT1_2; - v += M_SQRT1_2; - v *= (float)0x1ff / (2.0f * M_SQRT1_2); - r |= (uint32_t)v << (3 + i * 9); - } - return r; -} CHIAKI_EXPORT void chiaki_feedback_state_format_v9(uint8_t *buf, ChiakiFeedbackState *state) { - buf[0x0] = 0xa0; - uint16_t v = (uint16_t)(0xffff * ((float)state->gyro_x - GYRO_MIN) / (GYRO_MAX - GYRO_MIN)); - buf[0x1] = v; - buf[0x2] = v >> 8; - v = (uint16_t)(0xffff * ((float)state->gyro_y - GYRO_MIN) / (GYRO_MAX - GYRO_MIN)); - buf[0x3] = v; - buf[0x4] = v >> 8; - v = (uint16_t)(0xffff * ((float)state->gyro_z - GYRO_MIN) / (GYRO_MAX - GYRO_MIN)); - buf[0x5] = v; - buf[0x6] = v >> 8; - v = (uint16_t)(0xffff * ((float)state->accel_x - ACCEL_MIN) / (ACCEL_MAX - ACCEL_MIN)); - buf[0x7] = v; - buf[0x8] = v >> 8; - v = (uint16_t)(0xffff * ((float)state->accel_y - ACCEL_MIN) / (ACCEL_MAX - ACCEL_MIN)); - buf[0x9] = v; - buf[0xa] = v >> 8; - v = (uint16_t)(0xffff * ((float)state->accel_z - ACCEL_MIN) / (ACCEL_MAX - ACCEL_MIN)); - buf[0xb] = v; - buf[0xc] = v >> 8; - float q[4] = { state->orient_x, state->orient_y, state->orient_z, state->orient_w }; - uint32_t qc = compress_quat(q); - buf[0xd] = qc; - buf[0xe] = qc >> 0x8; - buf[0xf] = qc >> 0x10; - buf[0x10] = qc >> 0x18; + buf[0x0] = 0xa0; // TODO + buf[0x1] = 0xff; // TODO + buf[0x2] = 0x7f; // TODO + buf[0x3] = 0xff; // TODO + buf[0x4] = 0x7f; // TODO + buf[0x5] = 0xff; // TODO + buf[0x6] = 0x7f; // TODO + buf[0x7] = 0xff; // TODO + buf[0x8] = 0x7f; // TODO + buf[0x9] = 0x99; // TODO + buf[0xa] = 0x99; // TODO + buf[0xb] = 0xff; // TODO + buf[0xc] = 0x7f; // TODO + buf[0xd] = 0xfe; // TODO + buf[0xe] = 0xf7; // TODO + buf[0xf] = 0xef; // TODO + buf[0x10] = 0x1f; // TODO *((chiaki_unaligned_uint16_t *)(buf + 0x11)) = htons((uint16_t)state->left_x); *((chiaki_unaligned_uint16_t *)(buf + 0x13)) = htons((uint16_t)state->left_y); *((chiaki_unaligned_uint16_t *)(buf + 0x15)) = htons((uint16_t)state->right_x); @@ -79,13 +38,9 @@ CHIAKI_EXPORT void chiaki_feedback_state_format_v9(uint8_t *buf, ChiakiFeedbackS CHIAKI_EXPORT void chiaki_feedback_state_format_v12(uint8_t *buf, ChiakiFeedbackState *state) { chiaki_feedback_state_format_v9(buf, state); - buf[0x19] = 0x0; + buf[0x10] = 0x0; buf[0x1a] = 0x0; - - // 1 is classic DualShock, 0 is DualSense, but using 0 requires setting [0x19] and [0x1a] to - // values taken from raw HID, which is generally not available. But setting 1 for both seems - // to always work fine. - buf[0x1b] = 0x1; + buf[0x1b] = 0x1; // 1 for Shock, 0 for Sense } CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_history_event_set_button(ChiakiFeedbackHistoryEvent *event, uint64_t button, uint8_t state) diff --git a/lib/src/feedbacksender.c b/lib/src/feedbacksender.c index cafffff..dc67bf6 100644 --- a/lib/src/feedbacksender.c +++ b/lib/src/feedbacksender.c @@ -83,24 +83,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_set_controller_state(Chiaki static bool controller_state_equals_for_feedback_state(ChiakiControllerState *a, ChiakiControllerState *b) { - if(!(a->left_x == b->left_x + return a->left_x == b->left_x && a->left_y == b->left_y && a->right_x == b->right_x - && a->right_y == b->right_y)) - return false; -#define CHECKF(n) if(a->n < b->n - 0.0000001f || a->n > b->n + 0.0000001f) return false - CHECKF(gyro_x); - CHECKF(gyro_y); - CHECKF(gyro_z); - CHECKF(accel_x); - CHECKF(accel_y); - CHECKF(accel_z); - CHECKF(orient_x); - CHECKF(orient_y); - CHECKF(orient_z); - CHECKF(orient_w); -#undef CHECKF - return true; + && a->right_y == b->right_y; } static void feedback_sender_send_state(ChiakiFeedbackSender *feedback_sender) @@ -110,18 +96,6 @@ static void feedback_sender_send_state(ChiakiFeedbackSender *feedback_sender) state.left_y = feedback_sender->controller_state.left_y; state.right_x = feedback_sender->controller_state.right_x; state.right_y = feedback_sender->controller_state.right_y; - state.gyro_x = feedback_sender->controller_state.gyro_x; - state.gyro_y = feedback_sender->controller_state.gyro_y; - state.gyro_z = feedback_sender->controller_state.gyro_z; - state.accel_x = feedback_sender->controller_state.accel_x; - state.accel_y = feedback_sender->controller_state.accel_y; - state.accel_z = feedback_sender->controller_state.accel_z; - - state.orient_x = feedback_sender->controller_state.orient_x; - state.orient_y = feedback_sender->controller_state.orient_y; - state.orient_z = feedback_sender->controller_state.orient_z; - state.orient_w = feedback_sender->controller_state.orient_w; - ChiakiErrorCode err = chiaki_takion_send_feedback_state(feedback_sender->takion, feedback_sender->state_seq_num++, &state); if(err != CHIAKI_ERR_SUCCESS) CHIAKI_LOGE(feedback_sender->log, "FeedbackSender failed to send Feedback State"); diff --git a/lib/src/frameprocessor.c b/lib/src/frameprocessor.c index bcee36b..058f6ac 100644 --- a/lib/src/frameprocessor.c +++ b/lib/src/frameprocessor.c @@ -48,8 +48,6 @@ CHIAKI_EXPORT void chiaki_frame_processor_init(ChiakiFrameProcessor *frame_proce frame_processor->buf_stride_per_unit = 0; frame_processor->units_source_expected = 0; frame_processor->units_fec_expected = 0; - frame_processor->units_source_received = 0; - frame_processor->units_fec_received = 0; frame_processor->unit_slots = NULL; frame_processor->unit_slots_size = 0; frame_processor->flushed = true; @@ -152,7 +150,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_put_unit(ChiakiFrameProcess CHIAKI_LOGE(frame_processor->log, "Packet's unit index is too high"); return CHIAKI_ERR_INVALID_DATA; } - + if(!packet->data_size) { CHIAKI_LOGW(frame_processor->log, "Unit is empty"); @@ -164,7 +162,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_put_unit(ChiakiFrameProcess CHIAKI_LOGW(frame_processor->log, "Unit is bigger than pre-calculated size!"); return CHIAKI_ERR_INVALID_DATA; } - + ChiakiFrameUnit *unit = frame_processor->unit_slots + packet->unit_index; if(unit->data_size) { diff --git a/lib/src/gkcrypt.c b/lib/src/gkcrypt.c index e8dcb12..c99c5c2 100644 --- a/lib/src/gkcrypt.c +++ b/lib/src/gkcrypt.c @@ -19,8 +19,10 @@ #include "utils.h" + #define KEY_BUF_CHUNK_SIZE 0x1000 + static ChiakiErrorCode gkcrypt_gen_key_iv(ChiakiGKCrypt *gkcrypt, uint8_t index, const uint8_t *handshake_key, const uint8_t *ecdh_secret); static void *gkcrypt_thread_func(void *user); @@ -108,6 +110,7 @@ CHIAKI_EXPORT void chiaki_gkcrypt_fini(ChiakiGKCrypt *gkcrypt) } } + static ChiakiErrorCode gkcrypt_gen_key_iv(ChiakiGKCrypt *gkcrypt, uint8_t index, const uint8_t *handshake_key, const uint8_t *ecdh_secret) { uint8_t data[3 + CHIAKI_HANDSHAKE_KEY_SIZE + 2]; @@ -120,41 +123,37 @@ static ChiakiErrorCode gkcrypt_gen_key_iv(ChiakiGKCrypt *gkcrypt, uint8_t index, uint8_t hmac[CHIAKI_GKCRYPT_BLOCK_SIZE*2]; size_t hmac_size = sizeof(hmac); -#ifdef CHIAKI_LIB_ENABLE_MBEDTLS + #ifdef CHIAKI_LIB_ENABLE_MBEDTLS mbedtls_md_context_t ctx; mbedtls_md_init(&ctx); - if(mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) != 0) - { + if(mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256) , 1) != 0){ mbedtls_md_free(&ctx); return CHIAKI_ERR_UNKNOWN; } - if(mbedtls_md_hmac_starts(&ctx, ecdh_secret, CHIAKI_ECDH_SECRET_SIZE) != 0) - { + if(mbedtls_md_hmac_starts(&ctx, ecdh_secret, CHIAKI_ECDH_SECRET_SIZE) != 0){ mbedtls_md_free(&ctx); return CHIAKI_ERR_UNKNOWN; } - if(mbedtls_md_hmac_update(&ctx, data, sizeof(data)) != 0) - { + if(mbedtls_md_hmac_update(&ctx, data, sizeof(data)) != 0){ mbedtls_md_free(&ctx); return CHIAKI_ERR_UNKNOWN; } - if(mbedtls_md_hmac_finish(&ctx, hmac) != 0) - { + if(mbedtls_md_hmac_finish(&ctx, hmac) != 0){ mbedtls_md_free(&ctx); return CHIAKI_ERR_UNKNOWN; } mbedtls_md_free(&ctx); -#else + #else if(!HMAC(EVP_sha256(), ecdh_secret, CHIAKI_ECDH_SECRET_SIZE, data, sizeof(data), hmac, (unsigned int *)&hmac_size)) return CHIAKI_ERR_UNKNOWN; -#endif + #endif assert(hmac_size == sizeof(hmac)); memcpy(gkcrypt->key_base, hmac, CHIAKI_GKCRYPT_BLOCK_SIZE); @@ -221,8 +220,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcry mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); - if(mbedtls_aes_setkey_enc(&ctx, gkcrypt->key_base, 128) != 0) - { + if(mbedtls_aes_setkey_enc(&ctx, gkcrypt->key_base, 128) != 0){ mbedtls_aes_free(&ctx); return CHIAKI_ERR_UNKNOWN; } @@ -250,11 +248,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcry counter_add(cur, gkcrypt->iv, counter_offset++); #ifdef CHIAKI_LIB_ENABLE_MBEDTLS - for(int i = 0; i < buf_size; i = i + 16) - { + for(int i=0; i #endif + CHIAKI_EXPORT void chiaki_http_header_free(ChiakiHttpHeader *header) { while(header) @@ -146,15 +147,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_recv_http_header(int sock, char *buf, size_ return err; } - int received; - do - { - received = (int)recv(sock, buf, (int)buf_size, 0); -#if _WIN32 - } while(false); -#else - } while(received < 0 && errno == EINTR); -#endif + int received = (int)recv(sock, buf, (int)buf_size, 0); if(received <= 0) return received == 0 ? CHIAKI_ERR_DISCONNECTED : CHIAKI_ERR_NETWORK; diff --git a/lib/src/orientation.c b/lib/src/orientation.c deleted file mode 100644 index 7f07b09..0000000 --- a/lib/src/orientation.c +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL - -#include -#include - -#define SIN_1_4_PI 0.7071067811865475 -#define SIN_NEG_1_4_PI -0.7071067811865475 -#define COS_1_4_PI 0.7071067811865476 -#define COS_NEG_1_4_PI 0.7071067811865476 - -#define WARMUP_SAMPLES_COUNT 30 -#define BETA_WARMUP 20.0f -#define BETA_DEFAULT 0.05f - -CHIAKI_EXPORT void chiaki_orientation_init(ChiakiOrientation *orient) -{ - // 90 deg rotation around x for Madgwick - orient->x = SIN_1_4_PI; - orient->y = 0.0f; - orient->z = 0.0f; - orient->w = COS_1_4_PI; -} - -static float inv_sqrt(float x); - -CHIAKI_EXPORT void chiaki_orientation_update(ChiakiOrientation *orient, - float gx, float gy, float gz, float ax, float ay, float az, float beta, float time_step_sec) -{ - float q0 = orient->w, q1 = orient->x, q2 = orient->y, q3 = orient->z; - // Madgwick's IMU algorithm. - // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms - float recip_norm; - float s0, s1, s2, s3; - float q_dot1, q_dot2, q_dot3, q_dot4; - float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; - - // Rate of change of quaternion from gyroscope - q_dot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); - q_dot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); - q_dot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); - q_dot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); - - // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) - if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) - { - // Normalise accelerometer measurement - recip_norm = inv_sqrt(ax * ax + ay * ay + az * az); - ax *= recip_norm; - ay *= recip_norm; - az *= recip_norm; - - // Auxiliary variables to avoid repeated arithmetic - _2q0 = 2.0f * q0; - _2q1 = 2.0f * q1; - _2q2 = 2.0f * q2; - _2q3 = 2.0f * q3; - _4q0 = 4.0f * q0; - _4q1 = 4.0f * q1; - _4q2 = 4.0f * q2; - _8q1 = 8.0f * q1; - _8q2 = 8.0f * q2; - q0q0 = q0 * q0; - q1q1 = q1 * q1; - q2q2 = q2 * q2; - q3q3 = q3 * q3; - - // Gradient decent algorithm corrective step - s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay; - s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; - s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; - s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay; - recip_norm = s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3; // normalise step magnitude - // avoid NaN when the orientation is already perfect or inverse to perfect - if(recip_norm > 0.000001f) - { - recip_norm = inv_sqrt(recip_norm); - s0 *= recip_norm; - s1 *= recip_norm; - s2 *= recip_norm; - s3 *= recip_norm; - - // Apply feedback step - q_dot1 -= beta * s0; - q_dot2 -= beta * s1; - q_dot3 -= beta * s2; - q_dot4 -= beta * s3; - } - } - - // Integrate rate of change of quaternion to yield quaternion - q0 += q_dot1 * time_step_sec; - q1 += q_dot2 * time_step_sec; - q2 += q_dot3 * time_step_sec; - q3 += q_dot4 * time_step_sec; - - // Normalise quaternion - recip_norm = inv_sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); - q0 *= recip_norm; - q1 *= recip_norm; - q2 *= recip_norm; - q3 *= recip_norm; - - orient->x = q1; - orient->y = q2; - orient->z = q3; - orient->w = q0; -} - -static float inv_sqrt(float x) -{ -#if 1 - return 1.0f / sqrt(x); -#else - // Fast inverse square-root - // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root - float halfx = 0.5f * x; - float y = x; - long i = *(long*)&y; - i = 0x5f3759df - (i>>1); - y = *(float*)&i; - y = y * (1.5f - (halfx * y * y)); - return y; -#endif -} - -CHIAKI_EXPORT void chiaki_orientation_tracker_init(ChiakiOrientationTracker *tracker) -{ - tracker->accel_x = 0.0f; - tracker->accel_y = 1.0f; - tracker->accel_z = 0.0f; - tracker->gyro_x = tracker->gyro_y = tracker->gyro_z = 0.0f; - chiaki_orientation_init(&tracker->orient); - tracker->timestamp = 0; - tracker->sample_index = 0; -} - -CHIAKI_EXPORT void chiaki_orientation_tracker_update(ChiakiOrientationTracker *tracker, - float gx, float gy, float gz, float ax, float ay, float az, uint32_t timestamp_us) -{ - tracker->gyro_x = gx; - tracker->gyro_y = gy; - tracker->gyro_z = gz; - tracker->accel_x = ax; - tracker->accel_y = ay; - tracker->accel_z = az; - tracker->sample_index++; - if(tracker->sample_index <= 1) - { - tracker->timestamp = timestamp_us; - return; - } - uint64_t delta_us = timestamp_us; - if(delta_us < tracker->timestamp) - delta_us += (1ULL << 32); - delta_us -= tracker->timestamp; - tracker->timestamp = timestamp_us; - chiaki_orientation_update(&tracker->orient, gx, gy, gz, ax, ay, az, - tracker->sample_index < WARMUP_SAMPLES_COUNT ? BETA_WARMUP : BETA_DEFAULT, - (float)delta_us / 1000000.0f); -} - -CHIAKI_EXPORT void chiaki_orientation_tracker_apply_to_controller_state(ChiakiOrientationTracker *tracker, - ChiakiControllerState *state) -{ - state->gyro_x = tracker->gyro_x; - state->gyro_y = tracker->gyro_y; - state->gyro_z = tracker->gyro_z; - state->accel_x = tracker->accel_x; - state->accel_y = tracker->accel_y; - state->accel_z = tracker->accel_z; - // -90 deg rotation around x from Madgwick - state->orient_w = COS_NEG_1_4_PI * tracker->orient.w - SIN_NEG_1_4_PI * tracker->orient.x; - state->orient_x = COS_NEG_1_4_PI * tracker->orient.x + SIN_NEG_1_4_PI * tracker->orient.w; - state->orient_y = COS_NEG_1_4_PI * tracker->orient.y - SIN_NEG_1_4_PI * tracker->orient.z; - state->orient_z = COS_NEG_1_4_PI * tracker->orient.z + SIN_NEG_1_4_PI * tracker->orient.y; -} diff --git a/lib/src/packetstats.c b/lib/src/packetstats.c index c7da9d6..c04adc8 100644 --- a/lib/src/packetstats.c +++ b/lib/src/packetstats.c @@ -74,3 +74,4 @@ CHIAKI_EXPORT void chiaki_packet_stats_get(ChiakiPacketStats *stats, bool reset, reset_stats(stats); chiaki_mutex_unlock(&stats->mutex); } + diff --git a/lib/src/pidecoder.c b/lib/src/pidecoder.c index ae99fbd..72a22f5 100644 --- a/lib/src/pidecoder.c +++ b/lib/src/pidecoder.c @@ -8,6 +8,7 @@ #include #include +#define MAX_DECODE_UNIT_SIZE 262144 CHIAKI_EXPORT ChiakiErrorCode chiaki_pi_decoder_init(ChiakiPiDecoder *decoder, ChiakiLog *log) { @@ -107,6 +108,29 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_pi_decoder_init(ChiakiPiDecoder *decoder, C return CHIAKI_ERR_UNKNOWN; } + OMX_PARAM_PORTDEFINITIONTYPE port; + + memset(&port, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + port.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); + port.nVersion.nVersion = OMX_VERSION; + port.nPortIndex = 130; + if(OMX_GetParameter(ILC_GET_HANDLE(decoder->video_decode), OMX_IndexParamPortDefinition, &port) != OMX_ErrorNone) + { + CHIAKI_LOGE(decoder->log, "Failed to get decoder port definition\n"); + chiaki_pi_decoder_fini(decoder); + return CHIAKI_ERR_UNKNOWN; + } + + // Increase the buffer size to fit the largest possible frame + port.nBufferSize = MAX_DECODE_UNIT_SIZE; + + if(OMX_SetParameter(ILC_GET_HANDLE(decoder->video_decode), OMX_IndexParamPortDefinition, &port) != OMX_ErrorNone) + { + CHIAKI_LOGE(decoder->log, "OMX_SetParameter failed for port"); + chiaki_pi_decoder_fini(decoder); + return CHIAKI_ERR_UNKNOWN; + } + if(ilclient_enable_port_buffers(decoder->video_decode, 130, NULL, NULL, NULL) != 0) { CHIAKI_LOGE(decoder->log, "ilclient_enable_port_buffers failed"); @@ -156,55 +180,50 @@ CHIAKI_EXPORT void chiaki_pi_decoder_fini(ChiakiPiDecoder *decoder) static bool push_buffer(ChiakiPiDecoder *decoder, uint8_t *buf, size_t buf_size) { - while(buf_size) + OMX_BUFFERHEADERTYPE *omx_buf = ilclient_get_input_buffer(decoder->video_decode, 130, 1); + if(!omx_buf) { - OMX_BUFFERHEADERTYPE *omx_buf = ilclient_get_input_buffer(decoder->video_decode, 130, 1); - if(!omx_buf) + CHIAKI_LOGE(decoder->log, "ilclient_get_input_buffer failed"); + return false; + } + + if(omx_buf->nAllocLen < buf_size) + { + CHIAKI_LOGE(decoder->log, "Buffer from omx is too small for frame"); + return false; + } + + omx_buf->nFilledLen = 0; + omx_buf->nOffset = 0; + omx_buf->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; + if(decoder->first_packet) + { + omx_buf->nFlags |= OMX_BUFFERFLAG_STARTTIME; + decoder->first_packet = false; + } + + memcpy(omx_buf->pBuffer + omx_buf->nFilledLen, buf, buf_size); + omx_buf->nFilledLen += buf_size; + + if(!decoder->port_settings_changed + && ((omx_buf->nFilledLen > 0 && ilclient_remove_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) + || (omx_buf->nFilledLen == 0 && ilclient_wait_for_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) + { + decoder->port_settings_changed = true; + + if(ilclient_setup_tunnel(decoder->tunnel, 0, 0) != 0) { - CHIAKI_LOGE(decoder->log, "ilclient_get_input_buffer failed"); + CHIAKI_LOGE(decoder->log, "ilclient_setup_tunnel failed"); return false; } - size_t push_size = buf_size; - if(push_size > omx_buf->nAllocLen) - { - CHIAKI_LOGW(decoder->log, "OMX Buffer too small, fragmenting to multiple buffers."); - push_size = omx_buf->nAllocLen; - } - memcpy(omx_buf->pBuffer, buf, push_size); - buf_size -= push_size; - buf += push_size; - omx_buf->nFilledLen = push_size; - omx_buf->nOffset = 0; - omx_buf->nFlags = 0; - if(!buf_size) - omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; - if(decoder->first_packet) - { - omx_buf->nFlags |= OMX_BUFFERFLAG_STARTTIME; - decoder->first_packet = false; - } + ilclient_change_component_state(decoder->video_render, OMX_StateExecuting); + } - if(!decoder->port_settings_changed - && ((omx_buf->nFilledLen > 0 && ilclient_remove_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) - || (omx_buf->nFilledLen == 0 && ilclient_wait_for_event(decoder->video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) - { - decoder->port_settings_changed = true; - - if(ilclient_setup_tunnel(decoder->tunnel, 0, 0) != 0) - { - CHIAKI_LOGE(decoder->log, "ilclient_setup_tunnel failed"); - return false; - } - - ilclient_change_component_state(decoder->video_render, OMX_StateExecuting); - } - - if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(decoder->video_decode), omx_buf) != OMX_ErrorNone) - { - CHIAKI_LOGE(decoder->log, "OMX_EmptyThisBuffer failed"); - return false; - } + if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(decoder->video_decode), omx_buf) != OMX_ErrorNone) + { + CHIAKI_LOGE(decoder->log, "OMX_EmptyThisBuffer failed"); + return false; } return true; } diff --git a/lib/src/random.c b/lib/src/random.c index 158ce4d..974db60 100644 --- a/lib/src/random.c +++ b/lib/src/random.c @@ -28,12 +28,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_random_bytes_crypt(uint8_t *buf, size_t buf mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF); - if(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"RANDOM_GEN", 10) != 0) - { + if(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) "RANDOM_GEN", 10 ) != 0 ){ return CHIAKI_ERR_UNKNOWN; } - if(mbedtls_ctr_drbg_random(&ctr_drbg, buf, buf_size) != 0) - { + if(mbedtls_ctr_drbg_random(&ctr_drbg, buf, buf_size) != 0){ return CHIAKI_ERR_UNKNOWN; } diff --git a/lib/src/regist.c b/lib/src/regist.c index af17942..47c6ab1 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -160,6 +160,7 @@ static int request_header_format(char *buf, size_t buf_size, size_t payload_size return cur; } + CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(ChiakiTarget target, const uint8_t *ambassador, uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id, uint32_t pin) { size_t buf_size_val = *buf_size; diff --git a/lib/src/rpcrypt.c b/lib/src/rpcrypt.c index 15b64d0..197580e 100644 --- a/lib/src/rpcrypt.c +++ b/lib/src/rpcrypt.c @@ -1488,7 +1488,7 @@ static ChiakiErrorCode bright_ambassador(ChiakiTarget target, uint8_t *bright, u 0x20, 0x98, 0xfd, 0x34, 0xca, 0x7a, 0x66, 0x20, 0x58, 0xd2, 0x36, 0x7f, 0x2b, 0xa7, 0xd1, 0xde, 0x6f, 0x36, 0xb4, 0xf2, 0x3b, 0x20, 0x5d, 0x02 - }; + }; if(target < CHIAKI_TARGET_PS4_10) return CHIAKI_ERR_INVALID_DATA; @@ -1698,7 +1698,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_aeropause(ChiakiTarget target, size CHIAKI_EXPORT void chiaki_rpcrypt_init_auth(ChiakiRPCrypt *rpcrypt, ChiakiTarget target, const uint8_t *nonce, const uint8_t *morning) { rpcrypt->target = target; - chiaki_rpcrypt_bright_ambassador(target, rpcrypt->bright, rpcrypt->ambassador, nonce, morning); + chiaki_rpcrypt_bright_ambassador(target, rpcrypt->bright, rpcrypt->ambassador, nonce, morning); } CHIAKI_EXPORT void chiaki_rpcrypt_init_regist_ps4_pre10(ChiakiRPCrypt *rpcrypt, const uint8_t *ambassador, uint32_t pin) @@ -1865,6 +1865,7 @@ static const uint8_t *rpcrypt_hmac_key(ChiakiRPCrypt *rpcrypt) } } + #ifdef CHIAKI_LIB_ENABLE_MBEDTLS CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, uint8_t *iv, uint64_t counter) { @@ -1967,6 +1968,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, buf[CHIAKI_RPCRYPT_KEY_SIZE + 6] = (uint8_t)((counter >> 0x08) & 0xff); buf[CHIAKI_RPCRYPT_KEY_SIZE + 7] = (uint8_t)((counter >> 0x00) & 0xff); + uint8_t hmac[32]; unsigned int hmac_len = 0; if(!HMAC(EVP_sha256(), hmac_key, CHIAKI_RPCRYPT_KEY_SIZE, buf, sizeof(buf), hmac, &hmac_len)) diff --git a/lib/src/senkusha.c b/lib/src/senkusha.c index fc4e600..1fa33d4 100644 --- a/lib/src/senkusha.c +++ b/lib/src/senkusha.c @@ -361,7 +361,7 @@ static ChiakiErrorCode senkusha_run_mtu_in_test(ChiakiSenkusha *senkusha, uint32 senkusha->state_failed = false; senkusha->mtu_id = ++request_id; - tkproto_SenkushaMtuCommand mtu_cmd = { 0 }; + tkproto_SenkushaMtuCommand mtu_cmd; mtu_cmd.id = request_id; mtu_cmd.mtu_req = cur; mtu_cmd.num = 1; @@ -645,6 +645,7 @@ static void senkusha_takion_data(ChiakiSenkusha *senkusha, ChiakiTakionMessageDa senkusha->state_finished = true; chiaki_cond_signal(&senkusha->state_cond); } + } chiaki_mutex_unlock(&senkusha->state_mutex); } @@ -877,3 +878,4 @@ static ChiakiErrorCode senkusha_send_data_wait_for_ack(ChiakiSenkusha *senkusha, return err; } + diff --git a/lib/src/session.c b/lib/src/session.c index aa56e19..de2f4e2 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -158,8 +158,6 @@ CHIAKI_EXPORT const char *chiaki_quit_reason_string(ChiakiQuitReason reason) return "Unknown Error in Stream Connection"; case CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED: return "Remote has disconnected from Stream Connection"; - case CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN: - return "Remote has disconnected from Stream Connection the because Server shut down"; case CHIAKI_QUIT_REASON_NONE: default: return "Unknown"; @@ -229,7 +227,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki session->connect_info.video_profile = connect_info->video_profile; session->connect_info.video_profile_auto_downgrade = connect_info->video_profile_auto_downgrade; session->connect_info.enable_keyboard = connect_info->enable_keyboard; - session->connect_info.enable_dualsense = connect_info->enable_dualsense; return CHIAKI_ERR_SUCCESS; error_stop_pipe: @@ -507,10 +504,7 @@ ctrl_failed: if(err == CHIAKI_ERR_DISCONNECTED) { CHIAKI_LOGE(session->log, "Remote disconnected from StreamConnection"); - if(!strcmp(session->stream_connection.remote_disconnect_reason, "Server shutting down")) - session->quit_reason = CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_SHUTDOWN; - else - session->quit_reason = CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED; + session->quit_reason = CHIAKI_QUIT_REASON_STREAM_CONNECTION_REMOTE_DISCONNECTED; session->quit_reason_str = strdup(session->stream_connection.remote_disconnect_reason); } else if(err != CHIAKI_ERR_SUCCESS && err != CHIAKI_ERR_CANCELED) @@ -546,8 +540,10 @@ quit: #undef QUIT } -typedef struct session_response_t -{ + + + +typedef struct session_response_t { uint32_t error_code; const char *nonce; const char *rp_version; @@ -600,11 +596,11 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session, Ch set_port(sa, htons(SESSION_PORT)); // TODO: this can block, make cancelable somehow - int r = getnameinfo(sa, (socklen_t)ai->ai_addrlen, session->connect_info.hostname, sizeof(session->connect_info.hostname), NULL, 0, NI_NUMERICHOST); + int r = getnameinfo(sa, (socklen_t)ai->ai_addrlen, session->connect_info.hostname, sizeof(session->connect_info.hostname), NULL, 0, 0); if(r != 0) { - CHIAKI_LOGE(session->log, "getnameinfo failed with %s, filling the hostname with fallback", gai_strerror(r)); - memcpy(session->connect_info.hostname, "unknown", 8); + free(sa); + continue; } CHIAKI_LOGI(session->log, "Trying to request session from %s:%d", session->connect_info.hostname, SESSION_PORT); @@ -615,7 +611,7 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session, Ch #ifdef _WIN32 CHIAKI_LOGE(session->log, "Failed to create socket to request session"); #else - CHIAKI_LOGE(session->log, "Failed to create socket to request session: %s", strerror(errno)); + CHIAKI_LOGE(session->log, "Failed to create socket to request session: %s", strerror(errno)); #endif free(sa); continue; @@ -656,6 +652,7 @@ static ChiakiErrorCode session_thread_request_session(ChiakiSession *session, Ch break; } + if(CHIAKI_SOCKET_IS_INVALID(session_sock)) { CHIAKI_LOGE(session->log, "Session request connect failed eventually."); diff --git a/lib/src/stoppipe.c b/lib/src/stoppipe.c index 003ad5d..dd069ef 100644 --- a/lib/src/stoppipe.c +++ b/lib/src/stoppipe.c @@ -27,8 +27,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_init(ChiakiStopPipe *stop_pipe) int addr_size = sizeof(stop_pipe->addr); stop_pipe->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if(stop_pipe->fd < 0) + if(stop_pipe->fd < 0){ return CHIAKI_ERR_UNKNOWN; + } stop_pipe->addr.sin_family = AF_INET; // bind to localhost stop_pipe->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -147,11 +148,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stop_pipe_select_single(ChiakiStopPipe *sto timeout = &timeout_s; } - int r; - do - { - r = select(nfds, &rfds, write ? &wfds : NULL, NULL, timeout); - } while(r < 0 && errno == EINTR); + int r = select(nfds, &rfds, write ? &wfds : NULL, NULL, timeout); if(r < 0) return CHIAKI_ERR_UNKNOWN; diff --git a/lib/src/streamconnection.c b/lib/src/streamconnection.c index 7187c1b..c8ed43c 100644 --- a/lib/src/streamconnection.c +++ b/lib/src/streamconnection.c @@ -45,11 +45,7 @@ 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); -static void stream_connection_takion_data_protobuf(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size); -static void stream_connection_takion_data_rumble(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size); -static void stream_connection_takion_data_trigger_effects(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size); static ChiakiErrorCode stream_connection_send_big(ChiakiStreamConnection *stream_connection); -static ChiakiErrorCode stream_connection_send_controller_connection(ChiakiStreamConnection *stream_connection); static ChiakiErrorCode stream_connection_send_disconnect(ChiakiStreamConnection *stream_connection); static void stream_connection_takion_data_idle(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size); static void stream_connection_takion_data_expect_bang(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size); @@ -58,6 +54,7 @@ static ChiakiErrorCode stream_connection_send_streaminfo_ack(ChiakiStreamConnect static void stream_connection_takion_av(ChiakiStreamConnection *stream_connection, ChiakiTakionAVPacket *packet); static ChiakiErrorCode stream_connection_send_heartbeat(ChiakiStreamConnection *stream_connection); + CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnection *stream_connection, ChiakiSession *session) { stream_connection->session = session; @@ -81,7 +78,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnecti stream_connection->video_receiver = NULL; stream_connection->audio_receiver = NULL; - stream_connection->haptics_receiver = NULL; err = chiaki_mutex_init(&stream_connection->feedback_sender_mutex, false); if(err != CHIAKI_ERR_SUCCESS) @@ -123,6 +119,7 @@ CHIAKI_EXPORT void chiaki_stream_connection_fini(ChiakiStreamConnection *stream_ chiaki_mutex_fini(&stream_connection->state_mutex); } + static bool state_finished_cond_check(void *user) { ChiakiStreamConnection *stream_connection = user; @@ -146,7 +143,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio takion_info.ip_dontfrag = false; takion_info.enable_crypt = true; - takion_info.enable_dualsense = session->connect_info.enable_dualsense; takion_info.protocol_version = chiaki_target_is_ps5(session->target) ? 12 : 9; takion_info.cb = stream_connection_takion_cb; @@ -168,20 +164,12 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio return CHIAKI_ERR_UNKNOWN; } - stream_connection->haptics_receiver = chiaki_audio_receiver_new(session, NULL); - if(!stream_connection->haptics_receiver) - { - CHIAKI_LOGE(session->log, "StreamConnection failed to initialize Haptics Receiver"); - err = CHIAKI_ERR_UNKNOWN; - goto err_audio_receiver; - } - stream_connection->video_receiver = chiaki_video_receiver_new(session, &stream_connection->packet_stats); if(!stream_connection->video_receiver) { CHIAKI_LOGE(session->log, "StreamConnection failed to initialize Video Receiver"); err = CHIAKI_ERR_UNKNOWN; - goto err_haptics_receiver; + goto err_audio_receiver; } stream_connection->state = STATE_TAKION_CONNECT; @@ -333,10 +321,6 @@ err_video_receiver: chiaki_video_receiver_free(stream_connection->video_receiver); stream_connection->video_receiver = NULL; -err_haptics_receiver: - chiaki_audio_receiver_free(stream_connection->haptics_receiver); - stream_connection->haptics_receiver = NULL; - err_audio_receiver: chiaki_audio_receiver_free(stream_connection->audio_receiver); stream_connection->audio_receiver = NULL; @@ -384,24 +368,9 @@ 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) { - switch(data_type) - { - case CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF: - stream_connection_takion_data_protobuf(stream_connection, buf, buf_size); - break; - case CHIAKI_TAKION_MESSAGE_DATA_TYPE_RUMBLE: - stream_connection_takion_data_rumble(stream_connection, buf, buf_size); - break; - case CHIAKI_TAKION_MESSAGE_DATA_TYPE_TRIGGER_EFFECTS: - stream_connection_takion_data_trigger_effects(stream_connection, buf, buf_size); - break; - default: - break; - } -} + if(data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF) + return; -static void stream_connection_takion_data_protobuf(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) -{ chiaki_mutex_lock(&stream_connection->state_mutex); switch(stream_connection->state) { @@ -418,40 +387,6 @@ static void stream_connection_takion_data_protobuf(ChiakiStreamConnection *strea chiaki_mutex_unlock(&stream_connection->state_mutex); } -static void stream_connection_takion_data_rumble(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) -{ - if(buf_size < 3) - { - CHIAKI_LOGE(stream_connection->log, "StreamConnection got rumble packet with size %#llx < 3", - (unsigned long long)buf_size); - return; - } - ChiakiEvent event = { 0 }; - event.type = CHIAKI_EVENT_RUMBLE; - event.rumble.unknown = buf[0]; - event.rumble.left = buf[1]; - event.rumble.right = buf[2]; - chiaki_session_send_event(stream_connection->session, &event); -} - - -static void stream_connection_takion_data_trigger_effects(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) -{ - if(buf_size < 25) - { - CHIAKI_LOGE(stream_connection->log, "StreamConnection got trigger effects packet with size %#llx < 25", - (unsigned long long)buf_size); - return; - } - ChiakiEvent event = { 0 }; - event.type = CHIAKI_EVENT_TRIGGER_EFFECTS; - event.trigger_effects.type_left = buf[1]; - event.trigger_effects.type_right = buf[2]; - memcpy(&event.trigger_effects.left, buf + 5, 10); - memcpy(&event.trigger_effects.right, buf + 15, 10); - chiaki_session_send_event(stream_connection->session, &event); -} - static void stream_connection_takion_data_handle_disconnect(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) { tkproto_TakionMessage msg; @@ -497,7 +432,7 @@ static void stream_connection_takion_data_idle(ChiakiStreamConnection *stream_co return; } - CHIAKI_LOGV(stream_connection->log, "StreamConnection received data with msg.type == %d", msg.type); + CHIAKI_LOGV(stream_connection->log, "StreamConnection received data"); chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_VERBOSE, buf, buf_size); if(msg.type == tkproto_TakionMessage_PayloadType_DISCONNECT) @@ -559,8 +494,7 @@ static void stream_connection_takion_data_expect_bang(ChiakiStreamConnection *st return; } - CHIAKI_LOGE(stream_connection->log, "StreamConnection expected bang payload but received something else: %d", msg.type); - chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_VERBOSE, buf, buf_size); + CHIAKI_LOGE(stream_connection->log, "StreamConnection expected bang payload but received something else"); return; } @@ -622,12 +556,6 @@ static void stream_connection_takion_data_expect_bang(ChiakiStreamConnection *st // stream_connection->state_mutex is expected to be locked by the caller of this function stream_connection->state_finished = true; chiaki_cond_signal(&stream_connection->state_cond); - err = stream_connection_send_controller_connection(stream_connection); - if(err != CHIAKI_ERR_SUCCESS) - { - CHIAKI_LOGE(stream_connection->log, "StreamConnection failed to send controller connection"); - goto error; - } return; error: stream_connection->state_failed = true; @@ -681,6 +609,7 @@ static bool pb_decode_resolution(pb_istream_t *stream, const pb_field_t *field, return true; } + static void stream_connection_takion_data_expect_streaminfo(ChiakiStreamConnection *stream_connection, uint8_t *buf, size_t buf_size) { tkproto_TakionMessage msg; @@ -749,9 +678,11 @@ error: chiaki_cond_signal(&stream_connection->state_cond); } + + static bool chiaki_pb_encode_zero_encrypted_key(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { - if(!pb_encode_tag_for_field(stream, field)) + if (!pb_encode_tag_for_field(stream, field)) return false; uint8_t data[] = { 0, 0, 0, 0 }; return pb_encode_string(stream, data, sizeof(data)); @@ -855,37 +786,6 @@ static ChiakiErrorCode stream_connection_send_big(ChiakiStreamConnection *stream return err; } -static ChiakiErrorCode stream_connection_send_controller_connection(ChiakiStreamConnection *stream_connection) -{ - ChiakiSession *session = stream_connection->session; - tkproto_TakionMessage msg; - memset(&msg, 0, sizeof(msg)); - - msg.type = tkproto_TakionMessage_PayloadType_CONTROLLERCONNECTION; - msg.has_controller_connection_payload = true; - msg.controller_connection_payload.has_connected = true; - msg.controller_connection_payload.connected = true; - msg.controller_connection_payload.has_controller_id = false; - msg.controller_connection_payload.has_controller_type = true; - msg.controller_connection_payload.controller_type = session->connect_info.enable_dualsense - ? tkproto_ControllerConnectionPayload_ControllerType_DUALSENSE - : tkproto_ControllerConnectionPayload_ControllerType_DUALSHOCK4; - - uint8_t buf[2048]; - size_t buf_size; - - pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf)); - bool pbr = pb_encode(&stream, tkproto_TakionMessage_fields, &msg); - if(!pbr) - { - CHIAKI_LOGE(stream_connection->log, "StreamConnection controller connection protobuf encoding failed"); - return CHIAKI_ERR_UNKNOWN; - } - - buf_size = stream.bytes_written; - return chiaki_takion_send_message_data(&stream_connection->takion, 1, 1, buf, buf_size, NULL); -} - static ChiakiErrorCode stream_connection_send_streaminfo_ack(ChiakiStreamConnection *stream_connection) { tkproto_TakionMessage msg; @@ -936,18 +836,18 @@ static ChiakiErrorCode stream_connection_send_disconnect(ChiakiStreamConnection return err; } + static void stream_connection_takion_av(ChiakiStreamConnection *stream_connection, ChiakiTakionAVPacket *packet) { chiaki_gkcrypt_decrypt(stream_connection->gkcrypt_remote, packet->key_pos + CHIAKI_GKCRYPT_BLOCK_SIZE, packet->data, packet->data_size); if(packet->is_video) chiaki_video_receiver_av_packet(stream_connection->video_receiver, packet); - else if(packet->is_haptics) - chiaki_audio_receiver_av_packet(stream_connection->haptics_receiver, packet); else chiaki_audio_receiver_av_packet(stream_connection->audio_receiver, packet); } + static ChiakiErrorCode stream_connection_send_heartbeat(ChiakiStreamConnection *stream_connection) { tkproto_TakionMessage msg = { 0 }; diff --git a/lib/src/takion.c b/lib/src/takion.c index baae28c..48a1537 100644 --- a/lib/src/takion.c +++ b/lib/src/takion.c @@ -56,9 +56,9 @@ typedef enum takion_packet_type_t { TAKION_PACKET_TYPE_HANDSHAKE = 4, TAKION_PACKET_TYPE_CONGESTION = 5, TAKION_PACKET_TYPE_FEEDBACK_STATE = 6, + TAKION_PACKET_TYPE_RUMBLE_EVENT = 7, TAKION_PACKET_TYPE_CLIENT_INFO = 8, - TAKION_PACKET_TYPE_PAD_INFO_EVENT = 9, - TAKION_PACKET_TYPE_PAD_ADAPTIVE_TRIGGERS = 11, + TAKION_PACKET_TYPE_PAD_INFO_EVENT = 9 } TakionPacketType; /** @@ -108,6 +108,7 @@ typedef enum takion_chunk_type_t { TAKION_CHUNK_TYPE_COOKIE_ACK = 0xb, } TakionChunkType; + typedef struct takion_message_t { uint32_t tag; @@ -120,6 +121,7 @@ typedef struct takion_message_t uint8_t *payload; } TakionMessage; + typedef struct takion_message_payload_init_t { uint32_t tag; @@ -151,12 +153,14 @@ typedef struct uint16_t channel; } TakionDataPacketEntry; + typedef struct chiaki_takion_postponed_packet_t { uint8_t *buf; size_t buf_size; } ChiakiTakionPostponedPacket; + static void *takion_thread_func(void *user); static void takion_handle_packet(ChiakiTakion *takion, uint8_t *buf, size_t buf_size); static ChiakiErrorCode takion_handle_packet_mac(ChiakiTakion *takion, uint8_t base_type, uint8_t *buf, size_t buf_size); @@ -216,7 +220,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_connect(ChiakiTakion *takion, Chiaki takion->postponed_packets = NULL; takion->postponed_packets_size = 0; takion->postponed_packets_count = 0; - takion->enable_dualsense = info->enable_dualsense; CHIAKI_LOGI(takion->log, "Takion connecting (version %u)", (unsigned int)info->protocol_version); @@ -505,7 +508,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_congestion(ChiakiTakion *takion return err; uint8_t buf[CHIAKI_TAKION_CONGESTION_PACKET_SIZE]; - chiaki_takion_format_congestion(buf, packet, key_pos); + chiaki_takion_format_congestion(buf, packet, key_pos); return chiaki_takion_send(takion, buf, sizeof(buf), key_pos); } @@ -601,6 +604,7 @@ static ChiakiErrorCode takion_handshake(ChiakiTakion *takion, uint32_t *seq_num_ CHIAKI_LOGI(takion->log, "Takion sent init"); + // INIT_ACK <- TakionMessagePayloadInitAck init_ack_payload; @@ -618,17 +622,20 @@ static ChiakiErrorCode takion_handshake(ChiakiTakion *takion, uint32_t *seq_num_ } CHIAKI_LOGI(takion->log, "Takion received init ack with remote tag %#x, outbound streams: %#x, inbound streams: %#x", - init_ack_payload.tag, init_ack_payload.outbound_streams, init_ack_payload.inbound_streams); + init_ack_payload.tag, init_ack_payload.outbound_streams, init_ack_payload.inbound_streams); takion->tag_remote = init_ack_payload.tag; *seq_num_remote_initial = takion->tag_remote; //init_ack_payload.initial_seq_num; - if(init_ack_payload.outbound_streams == 0 || init_ack_payload.inbound_streams == 0 || init_ack_payload.outbound_streams > TAKION_INBOUND_STREAMS || init_ack_payload.inbound_streams < TAKION_OUTBOUND_STREAMS) + if(init_ack_payload.outbound_streams == 0 || init_ack_payload.inbound_streams == 0 + || init_ack_payload.outbound_streams > TAKION_INBOUND_STREAMS + || init_ack_payload.inbound_streams < TAKION_OUTBOUND_STREAMS) { CHIAKI_LOGE(takion->log, "Takion min/max check failed"); return CHIAKI_ERR_INVALID_RESPONSE; } + // COOKIE -> err = takion_send_message_cookie(takion, init_ack_payload.cookie); @@ -774,6 +781,7 @@ beach: return NULL; } + static ChiakiErrorCode takion_recv(ChiakiTakion *takion, uint8_t *buf, size_t *buf_size, uint64_t timeout_ms) { ChiakiErrorCode err = chiaki_stop_pipe_select_single(&takion->stop_pipe, takion->sock, false, timeout_ms); @@ -798,6 +806,7 @@ static ChiakiErrorCode takion_recv(ChiakiTakion *takion, uint8_t *buf, size_t *b return CHIAKI_ERR_SUCCESS; } + static ChiakiErrorCode takion_handle_packet_mac(ChiakiTakion *takion, uint8_t base_type, uint8_t *buf, size_t buf_size) { if(!takion->gkcrypt_remote) @@ -858,6 +867,7 @@ static void takion_postpone_packet(ChiakiTakion *takion, uint8_t *buf, size_t bu packet->buf_size = buf_size; } + /** * @param buf ownership of this buf is taken. */ @@ -925,6 +935,7 @@ static void takion_handle_packet_message(ChiakiTakion *takion, uint8_t *buf, siz } } + static void takion_flush_data_queue(ChiakiTakion *takion) { uint64_t seq_num = 0; @@ -950,10 +961,7 @@ static void takion_flush_data_queue(ChiakiTakion *takion) if(zero_a != 0) CHIAKI_LOGW(takion->log, "Takion received data with unexpected nonzero %#x at buf+6", zero_a); - if(data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF - && data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_RUMBLE - && data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_TRIGGER_EFFECTS - && data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_9) + if(data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF && data_type != CHIAKI_TAKION_MESSAGE_DATA_TYPE_9) { CHIAKI_LOGW(takion->log, "Takion received data with unexpected data type %#x", data_type); chiaki_log_hexdump(takion->log, CHIAKI_LOG_WARNING, entry->packet_buf, entry->packet_size); @@ -1095,6 +1103,7 @@ static ChiakiErrorCode takion_parse_message(ChiakiTakion *takion, uint8_t *buf, return CHIAKI_ERR_SUCCESS; } + static ChiakiErrorCode takion_send_message_init(ChiakiTakion *takion, TakionMessagePayloadInit *payload) { uint8_t message[1 + TAKION_MESSAGE_HEADER_SIZE + 0x10]; @@ -1111,6 +1120,8 @@ static ChiakiErrorCode takion_send_message_init(ChiakiTakion *takion, TakionMess return chiaki_takion_send_raw(takion, message, sizeof(message)); } + + static ChiakiErrorCode takion_send_message_cookie(ChiakiTakion *takion, uint8_t *cookie) { uint8_t message[1 + TAKION_MESSAGE_HEADER_SIZE + TAKION_COOKIE_SIZE]; @@ -1120,6 +1131,8 @@ static ChiakiErrorCode takion_send_message_cookie(ChiakiTakion *takion, uint8_t return chiaki_takion_send_raw(takion, message, sizeof(message)); } + + static ChiakiErrorCode takion_recv_message_init_ack(ChiakiTakion *takion, TakionMessagePayloadInitAck *payload) { uint8_t message[1 + TAKION_MESSAGE_HEADER_SIZE + 0x10 + TAKION_COOKIE_SIZE]; @@ -1167,6 +1180,7 @@ static ChiakiErrorCode takion_recv_message_init_ack(ChiakiTakion *takion, Takion return CHIAKI_ERR_SUCCESS; } + static ChiakiErrorCode takion_recv_message_cookie_ack(ChiakiTakion *takion) { uint8_t message[1 + TAKION_MESSAGE_HEADER_SIZE]; @@ -1206,6 +1220,7 @@ static ChiakiErrorCode takion_recv_message_cookie_ack(ChiakiTakion *takion) return CHIAKI_ERR_SUCCESS; } + static void takion_handle_packet_av(ChiakiTakion *takion, uint8_t base_type, uint8_t *buf, size_t buf_size) { // HHIxIIx @@ -1311,7 +1326,7 @@ static ChiakiErrorCode av_packet_parse(bool v12, ChiakiTakionAVPacket *packet, C if(v12 && !packet->is_video) { - packet->is_haptics = *av == 0x02; + packet->byte_before_audio_data = *av; av += 1; av_size -= 1; } @@ -1437,4 +1452,5 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_parse(ChiakiTakionAVPac packet->data_size = buf_size; return CHIAKI_ERR_SUCCESS; + } diff --git a/lib/src/thread.c b/lib/src/thread.c index 0539e16..1948311 100644 --- a/lib/src/thread.c +++ b/lib/src/thread.c @@ -23,8 +23,7 @@ static DWORD WINAPI win32_thread_func(LPVOID param) #endif #ifdef __SWITCH__ -int64_t get_thread_limit() -{ +int64_t get_thread_limit(){ uint64_t resource_limit_handle_value = INVALID_HANDLE; svcGetInfo(&resource_limit_handle_value, InfoType_ResourceLimit, INVALID_HANDLE, 0); int64_t thread_cur_value = 0, thread_lim_value = 0; @@ -46,8 +45,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_create(ChiakiThread *thread, ChiakiT return CHIAKI_ERR_THREAD; #else #ifdef __SWITCH__ - if(get_thread_limit() <= 1) + if(get_thread_limit() <= 1){ return CHIAKI_ERR_THREAD; + } #endif int r = pthread_create(&thread->thread, NULL, func, arg); if(r != 0) @@ -90,13 +90,13 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_thread_set_name(ChiakiThread *thread, const if(r != 0) return CHIAKI_ERR_THREAD; #else - (void)thread; - (void)name; + (void)thread; (void)name; #endif #endif return CHIAKI_ERR_SUCCESS; } + CHIAKI_EXPORT ChiakiErrorCode chiaki_mutex_init(ChiakiMutex *mutex, bool rec) { #if _WIN32 @@ -172,6 +172,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_mutex_unlock(ChiakiMutex *mutex) return CHIAKI_ERR_SUCCESS; } + + + CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_init(ChiakiCond *cond) { #if _WIN32 @@ -211,6 +214,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_fini(ChiakiCond *cond) return CHIAKI_ERR_SUCCESS; } + + CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_wait(ChiakiCond *cond, ChiakiMutex *mutex) { #if _WIN32 @@ -318,6 +323,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_timedwait_pred(ChiakiCond *cond, Chiak #endif } return CHIAKI_ERR_SUCCESS; + } CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_signal(ChiakiCond *cond) @@ -344,6 +350,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_cond_broadcast(ChiakiCond *cond) return CHIAKI_ERR_SUCCESS; } + + + CHIAKI_EXPORT ChiakiErrorCode chiaki_bool_pred_cond_init(ChiakiBoolPredCond *cond) { cond->pred = false; @@ -375,6 +384,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_bool_pred_cond_fini(ChiakiBoolPredCond *con return CHIAKI_ERR_SUCCESS; } + CHIAKI_EXPORT ChiakiErrorCode chiaki_bool_pred_cond_lock(ChiakiBoolPredCond *cond) { return chiaki_mutex_lock(&cond->mutex); diff --git a/lib/src/videoreceiver.c b/lib/src/videoreceiver.c index 6468fcd..52beb02 100644 --- a/lib/src/videoreceiver.c +++ b/lib/src/videoreceiver.c @@ -17,7 +17,6 @@ CHIAKI_EXPORT void chiaki_video_receiver_init(ChiakiVideoReceiver *video_receive video_receiver->frame_index_cur = -1; video_receiver->frame_index_prev = -1; - video_receiver->frame_index_prev_complete = 0; chiaki_frame_processor_init(&video_receiver->frame_processor, video_receiver->log); video_receiver->packet_stats = packet_stats; diff --git a/scripts/Dockerfile.noble b/scripts/Dockerfile.noble deleted file mode 100644 index abc33c3..0000000 --- a/scripts/Dockerfile.noble +++ /dev/null @@ -1,13 +0,0 @@ - -FROM ubuntu:noble - -RUN apt-get update -# Hint: python3-setuptools should not be needed with nanopb >= 0.4.9 -RUN apt-get -y install git g++ cmake ninja-build curl pkg-config unzip \ - python3-protobuf protobuf-compiler \ - python3-setuptools \ - libssl-dev libopus-dev qtbase5-dev qtmultimedia5-dev libqt5multimedia5-plugins libqt5svg5-dev \ - libgl1-mesa-dev nasm libudev-dev libva-dev fuse libevdev-dev libudev-dev file - -CMD [] - diff --git a/scripts/Dockerfile.xenial b/scripts/Dockerfile.xenial new file mode 100644 index 0000000..b741028 --- /dev/null +++ b/scripts/Dockerfile.xenial @@ -0,0 +1,13 @@ + +FROM ubuntu:xenial + +RUN apt-get update +RUN apt-get install -y software-properties-common +RUN add-apt-repository ppa:beineri/opt-qt-5.12.3-xenial +RUN apt-get update +RUN apt-get -y install git g++ cmake ninja-build curl unzip python3-pip \ + libssl-dev libopus-dev qt512base qt512multimedia qt512svg \ + libgl1-mesa-dev nasm libudev-dev libva-dev fuse + +CMD [] + diff --git a/scripts/appveyor-win.sh b/scripts/appveyor-win.sh index 7bbc0f3..f751200 100755 --- a/scripts/appveyor-win.sh +++ b/scripts/appveyor-win.sh @@ -1,92 +1,77 @@ #!/bin/bash -set -xe +echo "APPVEYOR_BUILD_FOLDER=$APPVEYOR_BUILD_FOLDER" -BUILD_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" -BUILD_ROOT="$(echo $BUILD_ROOT | sed 's|^/\([a-z]\)|\1:|g')" # replace /c/... by c:/... for cmake to understand it -echo "BUILD_ROOT=$BUILD_ROOT" +mkdir ninja && cd ninja || exit 1 +wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-win.zip && 7z x ninja-win.zip || exit 1 +cd .. || exit 1 -mkdir ninja && cd ninja -wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-win.zip && 7z x ninja-win.zip -cd .. - -mkdir yasm && cd yasm -wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe && mv yasm-1.3.0-win64.exe yasm.exe -cd .. +mkdir yasm && cd yasm || exit 1 +wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe && mv yasm-1.3.0-win64.exe yasm.exe || exit 1 +cd .. || exit 1 export PATH="$PWD/ninja:$PWD/yasm:/c/Qt/5.12/msvc2017_64/bin:$PATH" -scripts/build-ffmpeg.sh . --target-os=win64 --arch=x86_64 --toolchain=msvc +scripts/build-ffmpeg.sh . --target-os=win64 --arch=x86_64 --toolchain=msvc || exit 1 -git clone https://github.com/xiph/opus.git && cd opus && git checkout ad8fe90db79b7d2a135e3dfd2ed6631b0c5662ab -mkdir build && cd build +git clone https://github.com/xiph/opus.git && cd opus && git checkout ad8fe90db79b7d2a135e3dfd2ed6631b0c5662ab || exit 1 +mkdir build && cd build || exit 1 cmake \ -G Ninja \ -DCMAKE_C_COMPILER=cl \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="$BUILD_ROOT/opus-prefix" \ - .. -ninja -ninja install -cd ../.. + -DCMAKE_INSTALL_PREFIX="$APPVEYOR_BUILD_FOLDER/opus-prefix" \ + .. || exit 1 +ninja || exit 1 +ninja install || exit 1 +cd ../.. || exit 1 -wget https://download.firedaemon.com/FireDaemon-OpenSSL/openssl-1.1.1s.zip && 7z x openssl-1.1.*.zip +wget https://mirror.firedaemon.com/OpenSSL/openssl-1.1.1d-dev.zip && 7z x openssl-1.1.1d-dev.zip || exit 1 -wget https://www.libsdl.org/release/SDL2-devel-2.26.2-VC.zip && 7z x SDL2-devel-2.26.2-VC.zip -export SDL_ROOT="$BUILD_ROOT/SDL2-2.26.2" -export SDL_ROOT=${SDL_ROOT//[\\]//} +wget https://www.libsdl.org/release/SDL2-devel-2.0.10-VC.zip && 7z x SDL2-devel-2.0.10-VC.zip || exit 1 +export SDL_ROOT="$APPVEYOR_BUILD_FOLDER/SDL2-2.0.10" || exit 1 +export SDL_ROOT=${SDL_ROOT//[\\]//} || exit 1 echo "set(SDL2_INCLUDE_DIRS \"$SDL_ROOT/include\") set(SDL2_LIBRARIES \"$SDL_ROOT/lib/x64/SDL2.lib\") -set(SDL2_LIBDIR \"$SDL_ROOT/lib/x64\") -include($SDL_ROOT/cmake/sdl2-config-version.cmake)" > "$SDL_ROOT/SDL2Config.cmake" +set(SDL2_LIBDIR \"$SDL_ROOT/lib/x64\")" > "$SDL_ROOT/SDL2Config.cmake" || exit 1 -mkdir protoc && cd protoc -wget https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protoc-3.9.1-win64.zip && 7z x protoc-3.9.1-win64.zip -cd .. -export PATH="$PWD/protoc/bin:$PATH" +mkdir protoc && cd protoc || exit 1 +wget https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protoc-3.9.1-win64.zip && 7z x protoc-3.9.1-win64.zip || exit 1 +cd .. || exit 1 +export PATH="$PWD/protoc/bin:$PATH" || exit 1 PYTHON="C:/Python37/python.exe" -"$PYTHON" -m pip install protobuf==3.19.5 +"$PYTHON" -m pip install protobuf || exit 1 -QT_PATH="C:/Qt/5.15/msvc2019_64" +QT_PATH="C:/Qt/5.12/msvc2017_64" COPY_DLLS="$PWD/openssl-1.1/x64/bin/libcrypto-1_1-x64.dll $PWD/openssl-1.1/x64/bin/libssl-1_1-x64.dll $SDL_ROOT/lib/x64/SDL2.dll" -echo "-- Configure" - -mkdir build && cd build - +mkdir build && cd build || exit 1 cmake \ -G Ninja \ -DCMAKE_C_COMPILER=cl \ -DCMAKE_C_FLAGS="-we4013" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_PREFIX_PATH="$BUILD_ROOT/ffmpeg-prefix;$BUILD_ROOT/opus-prefix;$BUILD_ROOT/openssl-1.1/x64;$QT_PATH;$SDL_ROOT" \ + -DCMAKE_PREFIX_PATH="$APPVEYOR_BUILD_FOLDER/ffmpeg-prefix;$APPVEYOR_BUILD_FOLDER/opus-prefix;$APPVEYOR_BUILD_FOLDER/openssl-1.1/x64;$QT_PATH;$SDL_ROOT" \ -DPYTHON_EXECUTABLE="$PYTHON" \ -DCHIAKI_ENABLE_TESTS=ON \ -DCHIAKI_ENABLE_CLI=OFF \ -DCHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER=ON \ - .. + .. || exit 1 -echo "-- Build" +ninja || exit 1 -ninja +test/chiaki-unit.exe || exit 1 -echo "-- Test" - -cp $COPY_DLLS test/ -test/chiaki-unit.exe - -cd .. +cd .. || exit 1 # Deploy -echo "-- Deploy" +mkdir Chiaki && cp build/gui/chiaki.exe Chiaki || exit 1 +mkdir Chiaki-PDB && cp build/gui/chiaki.pdb Chiaki-PDB || exit 1 -mkdir Chiaki && cp build/gui/chiaki.exe Chiaki -mkdir Chiaki-PDB && cp build/gui/chiaki.pdb Chiaki-PDB - -"$QT_PATH/bin/windeployqt.exe" Chiaki/chiaki.exe +"$QT_PATH/bin/windeployqt.exe" Chiaki/chiaki.exe || exit 1 cp -v $COPY_DLLS Chiaki diff --git a/scripts/build-appimage.sh b/scripts/build-appimage.sh index 05c0428..7ba4acf 100755 --- a/scripts/build-appimage.sh +++ b/scripts/build-appimage.sh @@ -2,11 +2,10 @@ set -xe -# sometimes there are errors in linuxdeploy in docker/podman when the appdir is on a mount -appdir=${1:-`pwd`/appimage/appdir} - mkdir appimage +pip3 install --user protobuf +scripts/fetch-protoc.sh appimage export PATH="`pwd`/appimage/protoc/bin:$PATH" scripts/build-ffmpeg.sh appimage scripts/build-sdl2.sh appimage @@ -16,31 +15,29 @@ cd build_appimage cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=Release \ - "-DCMAKE_PREFIX_PATH=`pwd`/../appimage/ffmpeg-prefix;`pwd`/../appimage/sdl2-prefix" \ + "-DCMAKE_PREFIX_PATH=`pwd`/../appimage/ffmpeg-prefix;`pwd`/../appimage/sdl2-prefix;/opt/qt512" \ -DCHIAKI_ENABLE_TESTS=ON \ -DCHIAKI_ENABLE_CLI=OFF \ - -DCHIAKI_ENABLE_GUI=ON \ -DCHIAKI_GUI_ENABLE_SDL_GAMECONTROLLER=ON \ -DCMAKE_INSTALL_PREFIX=/usr \ .. cd .. - -# purge leftover proto/nanopb_pb2.py which may have been created with another protobuf version -rm -fv third-party/nanopb/generator/proto/nanopb_pb2.py - ninja -C build_appimage build_appimage/test/chiaki-unit -DESTDIR="${appdir}" ninja -C build_appimage install +DESTDIR=`pwd`/appimage/appdir ninja -C build_appimage install cd appimage curl -L -O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage chmod +x linuxdeploy-x86_64.AppImage curl -L -O https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage chmod +x linuxdeploy-plugin-qt-x86_64.AppImage +set +e +source /opt/qt512/bin/qt512-env.sh +set -e export LD_LIBRARY_PATH="`pwd`/sdl2-prefix/lib:$LD_LIBRARY_PATH" export EXTRA_QT_PLUGINS=opengl -./linuxdeploy-x86_64.AppImage --appdir="${appdir}" -e "${appdir}/usr/bin/chiaki" -d "${appdir}/usr/share/applications/chiaki.desktop" --plugin qt --output appimage -mv Chiaki*-x86_64.AppImage Chiaki.AppImage +./linuxdeploy-x86_64.AppImage --appdir=appdir -e appdir/usr/bin/chiaki -d appdir/usr/share/applications/chiaki.desktop --plugin qt --output appimage +mv Chiaki-*-x86_64.AppImage Chiaki.AppImage diff --git a/scripts/build-common.sh b/scripts/build-common.sh index dd4be2c..0eb87b9 100755 --- a/scripts/build-common.sh +++ b/scripts/build-common.sh @@ -1,8 +1,5 @@ #!/bin/bash -# purge leftover proto/nanopb_pb2.py which may have been created with another protobuf version -rm -fv third-party/nanopb/generator/proto/nanopb_pb2.py - mkdir build && cd build || exit 1 cmake \ -DCMAKE_BUILD_TYPE=Release \ diff --git a/scripts/build-ffmpeg.sh b/scripts/build-ffmpeg.sh index 9b6348f..4761520 100755 --- a/scripts/build-ffmpeg.sh +++ b/scripts/build-ffmpeg.sh @@ -5,10 +5,10 @@ cd "./$1" shift ROOT="`pwd`" -TAG=n4.3.9 +TAG=n4.3.1 git clone https://git.ffmpeg.org/ffmpeg.git --depth 1 -b $TAG && cd ffmpeg || exit 1 -./configure --disable-all --enable-avcodec --enable-decoder=h264 --enable-decoder=hevc --enable-hwaccel=h264_vaapi --enable-hwaccel=hevc_vaapi --prefix="$ROOT/ffmpeg-prefix" "$@" || exit 1 +./configure --disable-all --enable-avcodec --enable-decoder=h264 --enable-decoder=hevc --enable-hwaccel=h264_vaapi --prefix="$ROOT/ffmpeg-prefix" "$@" || exit 1 make -j4 || exit 1 make install || exit 1 diff --git a/scripts/build-sdl2.sh b/scripts/build-sdl2.sh index 716b486..f06b9cc 100755 --- a/scripts/build-sdl2.sh +++ b/scripts/build-sdl2.sh @@ -6,10 +6,9 @@ cd $(dirname "${BASH_SOURCE[0]}")/.. cd "./$1" ROOT="`pwd`" -SDL_VER=2.26.1 -URL=https://www.libsdl.org/release/SDL2-${SDL_VER}.tar.gz -FILE=SDL2-${SDL_VER}.tar.gz -DIR=SDL2-${SDL_VER} +URL=https://www.libsdl.org/release/SDL2-2.0.10.tar.gz +FILE=SDL2-2.0.10.tar.gz +DIR=SDL2-2.0.10 if [ ! -d "$DIR" ]; then curl -L "$URL" -O @@ -22,14 +21,14 @@ mkdir -p build && cd build || exit 1 cmake \ -DCMAKE_INSTALL_PREFIX="$ROOT/sdl2-prefix" \ -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=ON \ + -DSDL_AUDIO=OFF \ -DSDL_CPUINFO=OFF \ -DSDL_EVENTS=ON \ -DSDL_FILE=OFF \ -DSDL_FILESYSTEM=OFF \ -DSDL_HAPTIC=ON \ -DSDL_JOYSTICK=ON \ - -DSDL_LOADSO=ON \ + -DSDL_LOADSO=OFF \ -DSDL_RENDER=OFF \ -DSDL_SHARED=ON \ -DSDL_STATIC=OFF \ diff --git a/scripts/fetch-protoc.sh b/scripts/fetch-protoc.sh new file mode 100755 index 0000000..e1d2d2f --- /dev/null +++ b/scripts/fetch-protoc.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -xe + +cd $(dirname "${BASH_SOURCE[0]}")/.. +cd "./$1" +ROOT="`pwd`" + +URL=https://github.com/protocolbuffers/protobuf/releases/download/v3.9.1/protoc-3.9.1-linux-x86_64.zip + +curl -L "$URL" -o protoc.zip +unzip protoc.zip -d protoc + diff --git a/scripts/flatpak/com.github.thestr4ng3r.Chiaki.json b/scripts/flatpak/com.github.thestr4ng3r.Chiaki.json index daab8a0..7cc6c43 100644 --- a/scripts/flatpak/com.github.thestr4ng3r.Chiaki.json +++ b/scripts/flatpak/com.github.thestr4ng3r.Chiaki.json @@ -89,8 +89,8 @@ { "type": "git", "url": "https://git.sr.ht/~thestr4ng3r/chiaki", - "tag": "v2.1.1", - "commit": "2257030adeb5c5a84380c78d34be4d783971663c" + "tag": "v1.3.0", + "commit": "702d31eb01d37518e77f5c1be3ea493df9f18323" } ] } diff --git a/scripts/macos-dist-local.sh b/scripts/macos-dist-local.sh deleted file mode 100755 index d2ac740..0000000 --- a/scripts/macos-dist-local.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# Build Chiaki for macOS distribution using dependencies from MacPorts and custom ffmpeg - -set -xe -cd $(dirname "${BASH_SOURCE[0]}")/.. -scripts/build-ffmpeg.sh -export CMAKE_PREFIX_PATH="`pwd`/ffmpeg-prefix" -scripts/build-common.sh -cp -a build/gui/chiaki.app Chiaki.app -/opt/local/libexec/qt5/bin/macdeployqt Chiaki.app - -# Remove all LC_RPATH load commands that have absolute paths of the build machine -RPATHS=$(otool -l Chiaki.app/Contents/MacOS/chiaki | grep -A 2 LC_RPATH | grep 'path /' | awk '{print $2}') -for p in ${RPATHS}; do install_name_tool -delete_rpath "$p" Chiaki.app/Contents/MacOS/chiaki; done - -# This may warn because we already ran macdeployqt above -/opt/local/libexec/qt5/bin/macdeployqt Chiaki.app -dmg diff --git a/scripts/run-docker-build-appimage.sh b/scripts/run-docker-build-appimage.sh new file mode 100755 index 0000000..931499c --- /dev/null +++ b/scripts/run-docker-build-appimage.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -xe +cd "`dirname $(readlink -f ${0})`" + +docker build -t chiaki-xenial . -f Dockerfile.xenial +cd .. +docker run --rm \ + -v "`pwd`:/build/chiaki" \ + -w "/build/chiaki" \ + --device /dev/fuse \ + --cap-add SYS_ADMIN \ + -t chiaki-xenial \ + /bin/bash -c "scripts/build-appimage.sh" + diff --git a/scripts/run-docker-build-bullseye.sh b/scripts/run-docker-build-bullseye.sh new file mode 100755 index 0000000..fd19bb1 --- /dev/null +++ b/scripts/run-docker-build-bullseye.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -xe +cd "`dirname $(readlink -f ${0})`" + +docker build -t chiaki-bullseye . -f Dockerfile.bullseye +cd .. +docker run --rm -v "`pwd`:/build" chiaki-bullseye /bin/bash -c " + cd /build && + mkdir build_bullseye && + cmake -Bbuild_bullseye -GNinja -DCHIAKI_ENABLE_SETSU=ON -DCHIAKI_USE_SYSTEM_JERASURE=ON -DCHIAKI_USE_SYSTEM_NANOPB=ON && + ninja -C build_bullseye && + ninja -C build_bullseye test" + diff --git a/scripts/run-podman-build-appimage.sh b/scripts/run-podman-build-appimage.sh deleted file mode 100755 index 5024952..0000000 --- a/scripts/run-podman-build-appimage.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -xe -cd "`dirname $(readlink -f ${0})`" - -podman build --arch amd64 -t localhost/chiaki-noble . -f Dockerfile.noble -cd .. -podman run --rm \ - --arch amd64 \ - -v "`pwd`:/build/chiaki" \ - -w "/build/chiaki" \ - --device /dev/fuse \ - --cap-add SYS_ADMIN \ - -t localhost/chiaki-noble \ - /bin/bash -c "scripts/build-appimage.sh /build/appdir" - diff --git a/scripts/run-podman-build-bullseye.sh b/scripts/run-podman-build-bullseye.sh deleted file mode 100755 index 344a76e..0000000 --- a/scripts/run-podman-build-bullseye.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -xe -cd "`dirname $(readlink -f ${0})`" - -podman build -t chiaki-bullseye . -f Dockerfile.bullseye -cd .. -podman run --rm -v "`pwd`:/build" chiaki-bullseye /bin/bash -c " - cd /build && - rm -fv third-party/nanopb/generator/proto/nanopb_pb2.py && - mkdir build_bullseye && - cmake -Bbuild_bullseye -GNinja -DCHIAKI_USE_SYSTEM_JERASURE=ON -DCHIAKI_USE_SYSTEM_NANOPB=ON && - ninja -C build_bullseye && - ninja -C build_bullseye test" - diff --git a/scripts/switch/build.sh b/scripts/switch/build.sh index 37b825d..1e03a2a 100755 --- a/scripts/switch/build.sh +++ b/scripts/switch/build.sh @@ -5,7 +5,10 @@ set -xveo pipefail arg1=$1 build="./build" if [ "$arg1" != "linux" ]; then + # source /opt/devkitpro/switchvars.sh + # toolchain="${DEVKITPRO}/switch.cmake" toolchain="cmake/switch.cmake" + export PORTLIBS_PREFIX="$(${DEVKITPRO}/portlibs_prefix.sh switch)" build="./build_switch" fi @@ -16,9 +19,6 @@ build_chiaki (){ pushd "${BASEDIR}" #rm -rf ./build - # purge leftover proto/nanopb_pb2.py which may have been created with another protobuf version - rm -fv third-party/nanopb/generator/proto/nanopb_pb2.py - cmake -B "${build}" \ -GNinja \ -DCMAKE_TOOLCHAIN_FILE=${toolchain} \ diff --git a/scripts/switch/push-docker-build-chiaki.sh b/scripts/switch/push-docker-build-chiaki.sh new file mode 100755 index 0000000..ff66e40 --- /dev/null +++ b/scripts/switch/push-docker-build-chiaki.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +cd "`dirname $(readlink -f ${0})`/../.." + +docker run \ + -v "`pwd`:/build/chiaki" \ + -p 28771:28771 -ti \ + chiaki-switch \ + -c "/opt/devkitpro/tools/bin/nxlink -a $@ -s /build/chiaki/build_switch/switch/chiaki.nro" + diff --git a/scripts/switch/push-podman-build-chiaki.sh b/scripts/switch/push-podman-build-chiaki.sh deleted file mode 100755 index ac82029..0000000 --- a/scripts/switch/push-podman-build-chiaki.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -cd "`dirname $(readlink -f ${0})`/../.." - -docker run \ - -v "`pwd`:/build/chiaki" \ - -w "/build/chiaki" \ - -ti -p 28771:28771 \ - --entrypoint /opt/devkitpro/tools/bin/nxlink \ - thestr4ng3r/chiaki-build-switch \ - "$@" -s /build/chiaki/build_switch/switch/chiaki.nro - diff --git a/scripts/switch/dev-container.sh b/scripts/switch/run-docker-build-chiaki.sh similarity index 55% rename from scripts/switch/dev-container.sh rename to scripts/switch/run-docker-build-chiaki.sh index 4cfedb3..c81c788 100755 --- a/scripts/switch/dev-container.sh +++ b/scripts/switch/run-docker-build-chiaki.sh @@ -2,9 +2,10 @@ cd "`dirname $(readlink -f ${0})`/../.." -podman run --rm \ +docker run \ -v "`pwd`:/build/chiaki" \ -w "/build/chiaki" \ - -it \ - quay.io/thestr4ng3r/chiaki-build-switch:v3 \ - /bin/bash + -t \ + thestr4ng3r/chiaki-build-switch \ + -c "scripts/switch/build.sh" + diff --git a/scripts/switch/run-podman-build-chiaki.sh b/scripts/switch/run-podman-build-chiaki.sh deleted file mode 100755 index 513cdc8..0000000 --- a/scripts/switch/run-podman-build-chiaki.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -cd "`dirname $(readlink -f ${0})`/../.." - -podman run --rm \ - -v "`pwd`:/build/chiaki" \ - -w "/build/chiaki" \ - -it \ - quay.io/thestr4ng3r/chiaki-build-switch:v3 \ - ${1:-/bin/bash -c "scripts/switch/build.sh"} diff --git a/setsu/CMakeLists.txt b/setsu/CMakeLists.txt index 2dedb0c..90c1465 100644 --- a/setsu/CMakeLists.txt +++ b/setsu/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2) project(libsetsu) -option(SETSU_BUILD_DEMOS "Build testing executables for libsetsu" OFF) +option(SETSU_BUILD_DEMO "Build testing executable for libsetsu" OFF) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -17,10 +17,9 @@ find_package(Udev REQUIRED) find_package(Evdev REQUIRED) target_link_libraries(setsu Udev::libudev Evdev::libevdev) -if(SETSU_BUILD_DEMOS) - add_executable(setsu-demo-touchpad demo/touchpad.c) - target_link_libraries(setsu-demo-touchpad setsu) - add_executable(setsu-demo-motion demo/motion.c) - target_link_libraries(setsu-demo-motion setsu) +if(SETSU_BUILD_DEMO) + add_executable(setsu-demo + demo/main.c) + target_link_libraries(setsu-demo setsu) endif() diff --git a/setsu/cmake/FindEvdev.cmake b/setsu/cmake/FindEvdev.cmake index 23f2515..5ea7dea 100644 --- a/setsu/cmake/FindEvdev.cmake +++ b/setsu/cmake/FindEvdev.cmake @@ -5,11 +5,7 @@ set(_target "${_prefix}::libevdev") find_package(PkgConfig) if(PkgConfig_FOUND AND NOT TARGET ${_target}) - if(CMAKE_VERSION VERSION_LESS "3.6") - pkg_check_modules("${_prefix}" libevdev) - else() - pkg_check_modules("${_prefix}" libevdev IMPORTED_TARGET) - endif() + pkg_check_modules("${_prefix}" libevdev IMPORTED_TARGET) if((TARGET PkgConfig::${_prefix}) AND (NOT CMAKE_VERSION VERSION_LESS "3.11.0")) set_target_properties(PkgConfig::${_prefix} PROPERTIES IMPORTED_GLOBAL ON) add_library(${_target} ALIAS PkgConfig::${_prefix}) diff --git a/setsu/cmake/FindUdev.cmake b/setsu/cmake/FindUdev.cmake index c9c8450..fc1c81f 100644 --- a/setsu/cmake/FindUdev.cmake +++ b/setsu/cmake/FindUdev.cmake @@ -5,11 +5,7 @@ set(_target "${_prefix}::libudev") find_package(PkgConfig) if(PkgConfig_FOUND AND NOT TARGET ${_target}) - if(CMAKE_VERSION VERSION_LESS "3.6") - pkg_check_modules("${_prefix}" libudev) - else() - pkg_check_modules("${_prefix}" libudev IMPORTED_TARGET) - endif() + pkg_check_modules("${_prefix}" libudev IMPORTED_TARGET) if((TARGET PkgConfig::${_prefix}) AND (NOT CMAKE_VERSION VERSION_LESS "3.11.0")) set_target_properties(PkgConfig::${_prefix} PROPERTIES IMPORTED_GLOBAL ON) add_library(${_target} ALIAS PkgConfig::${_prefix}) diff --git a/setsu/demo/touchpad.c b/setsu/demo/main.c similarity index 83% rename from setsu/demo/touchpad.c rename to setsu/demo/main.c index b51d628..4219638 100644 --- a/setsu/demo/touchpad.c +++ b/setsu/demo/main.c @@ -68,25 +68,21 @@ void event(SetsuEvent *event, void *user) switch(event->type) { case SETSU_EVENT_DEVICE_ADDED: { - if(event->dev_type != SETSU_DEVICE_TYPE_TOUCHPAD) - break; - SetsuDevice *dev = setsu_connect(setsu, event->path, SETSU_DEVICE_TYPE_TOUCHPAD); + SetsuDevice *dev = setsu_connect(setsu, event->path); LOG("Device added: %s, connect %s\n", event->path, dev ? "succeeded" : "FAILED!"); break; } case SETSU_EVENT_DEVICE_REMOVED: - if(event->dev_type != SETSU_DEVICE_TYPE_TOUCHPAD) - break; LOG("Device removed: %s\n", event->path); break; case SETSU_EVENT_TOUCH_DOWN: - LOG("Down for %s, tracking id %d\n", setsu_device_get_path(event->dev), event->touch.tracking_id); + LOG("Down for %s, tracking id %d\n", setsu_device_get_path(event->dev), event->tracking_id); for(size_t i=0; itouch.tracking_id; + touches[i].tracking_id = event->tracking_id; break; } } @@ -94,19 +90,19 @@ void event(SetsuEvent *event, void *user) case SETSU_EVENT_TOUCH_POSITION: case SETSU_EVENT_TOUCH_UP: if(event->type == SETSU_EVENT_TOUCH_UP) - LOG("Up for %s, tracking id %d\n", setsu_device_get_path(event->dev), event->touch.tracking_id); + LOG("Up for %s, tracking id %d\n", setsu_device_get_path(event->dev), event->tracking_id); else LOG("Position for %s, tracking id %d: %u, %u\n", setsu_device_get_path(event->dev), - event->touch.tracking_id, (unsigned int)event->touch.x, (unsigned int)event->touch.y); + event->tracking_id, (unsigned int)event->x, (unsigned int)event->y); for(size_t i=0; itouch.tracking_id) + if(touches[i].down && touches[i].tracking_id == event->tracking_id) { switch(event->type) { case SETSU_EVENT_TOUCH_POSITION: - touches[i].x = event->touch.x; - touches[i].y = event->touch.y; + touches[i].x = event->x; + touches[i].y = event->y; break; case SETSU_EVENT_TOUCH_UP: touches[i].down = false; @@ -122,8 +118,6 @@ void event(SetsuEvent *event, void *user) LOG("Button for %s: %llu %s\n", setsu_device_get_path(event->dev), (unsigned long long)event->button, event->type == SETSU_EVENT_BUTTON_DOWN ? "down" : "up"); break; - default: - break; } } diff --git a/setsu/demo/motion.c b/setsu/demo/motion.c deleted file mode 100644 index ebb5fdd..0000000 --- a/setsu/demo/motion.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL - -#include - -#include -#include -#include -#include -#include -#include -#include - -Setsu *setsu; - -#define NAME_LEN 8 -const char * const names[] = { - "accel x ", - "accel y ", - "accel z ", - " gyro x ", - " gyro y ", - " gyro z " -}; -union -{ - struct - { - float accel_x, accel_y, accel_z; - float gyro_x, gyro_y, gyro_z; - }; - float v[6]; -} vals; -uint32_t timestamp; -bool dirty = false; -bool log_mode; -volatile bool should_quit; - -#define LOG(...) do { if(log_mode) fprintf(stderr, __VA_ARGS__); } while(0) - -void sigint(int s) -{ - should_quit = true; -} - -#define BAR_LENGTH 100 -#define BAR_MAX 2.0f -#define BAR_MAX_GYRO M_PI - -void print_state() -{ - char buf[6 * (1 + NAME_LEN + BAR_LENGTH) + 1]; - size_t i = 0; - for(size_t b=0; b<6; b++) - { - buf[i++] = '\n'; - memcpy(buf + i, names[b], NAME_LEN); - i += NAME_LEN; - buf[i++] = '['; - size_t max = BAR_LENGTH-2; - for(size_t bi=0; bi 2 ? BAR_MAX_GYRO : BAR_MAX) * (2.0f * (float)(x) / (float)max - 1.0f)) - float cur = BAR_VAL(bi); - float prev = BAR_VAL((int)bi - 1); - if(prev < 0.0f && cur >= 0.0f) - { - buf[i++] = '|'; - continue; - } - bool cov = ((vals.v[b] < 0.0f) == (cur < 0.0f)) && fabsf(vals.v[b]) > fabsf(cur); - float next = BAR_VAL(bi + 1); -#define MARK_VAL (b > 2 ? 0.5f * M_PI : 1.0f) - bool mark = cur < -MARK_VAL && next >= -MARK_VAL || prev < MARK_VAL && cur >= MARK_VAL; - buf[i++] = cov ? (mark ? '#' : '=') : (mark ? '.' : ' '); -#undef BAR_VAL - } - buf[i++] = ']'; - } - buf[i++] = '\0'; - assert(i == sizeof(buf)); - printf("\033[2J%s", buf); - fflush(stdout); -} - -void event(SetsuEvent *event, void *user) -{ - dirty = true; - switch(event->type) - { - case SETSU_EVENT_DEVICE_ADDED: { - if(event->dev_type != SETSU_DEVICE_TYPE_MOTION) - break; - SetsuDevice *dev = setsu_connect(setsu, event->path, SETSU_DEVICE_TYPE_MOTION); - LOG("Device added: %s, connect %s\n", event->path, dev ? "succeeded" : "FAILED!"); - break; - } - case SETSU_EVENT_DEVICE_REMOVED: - if(event->dev_type != SETSU_DEVICE_TYPE_MOTION) - break; - LOG("Device removed: %s\n", event->path); - break; - case SETSU_EVENT_MOTION: - LOG("Motion: %f, %f, %f / %f, %f, %f / %u\n", - event->motion.accel_x, event->motion.accel_y, event->motion.accel_z, - event->motion.gyro_x, event->motion.gyro_y, event->motion.gyro_z, - (unsigned int)event->motion.timestamp); - vals.accel_x = event->motion.accel_x; - vals.accel_y = event->motion.accel_y; - vals.accel_z = event->motion.accel_z; - vals.gyro_x = event->motion.gyro_x; - vals.gyro_y = event->motion.gyro_y; - vals.gyro_z = event->motion.gyro_z; - timestamp = event->motion.timestamp; - dirty = true; - default: - break; - } -} - -void usage(const char *prog) -{ - printf("usage: %s [-l]\n -l log mode\n", prog); - exit(1); -} - -int main(int argc, const char *argv[]) -{ - log_mode = false; - if(argc == 2) - { - if(!strcmp(argv[1], "-l")) - log_mode = true; - else - usage(argv[0]); - } - else if(argc != 1) - usage(argv[0]); - - setsu = setsu_new(); - if(!setsu) - { - printf("Failed to init setsu\n"); - return 1; - } - - struct sigaction sa = {0}; - sa.sa_handler = sigint; - sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, NULL); - - dirty = true; - while(!should_quit) - { - if(dirty && !log_mode) - print_state(); - dirty = false; - setsu_poll(setsu, event, NULL); - } - setsu_free(setsu); - printf("\nさよなら!\n"); - return 0; -} - diff --git a/setsu/include/setsu.h b/setsu/include/setsu.h index a3ed0e3..5e546bc 100644 --- a/setsu/include/setsu.h +++ b/setsu/include/setsu.h @@ -13,18 +13,13 @@ typedef struct setsu_t Setsu; typedef struct setsu_device_t SetsuDevice; typedef int SetsuTrackingId; -typedef enum { - SETSU_DEVICE_TYPE_TOUCHPAD, - SETSU_DEVICE_TYPE_MOTION -} SetsuDeviceType; - typedef enum { /* New device available to connect. - * Event will have path and type set to the new device. */ + * Event will have path set to the new device. */ SETSU_EVENT_DEVICE_ADDED, /* Previously available device removed. - * Event will have path and type set to the removed device. + * Event will have path set to the new device. * Any SetsuDevice connected to this path will automatically * be disconnected and their pointers will be invalid immediately * after the callback for this event returns. */ @@ -46,10 +41,7 @@ typedef enum { SETSU_EVENT_BUTTON_DOWN, /* Event will have dev and button set. */ - SETSU_EVENT_BUTTON_UP, - - /* Event will have motion set. */ - SETSU_EVENT_MOTION + SETSU_EVENT_BUTTON_UP } SetsuEventType; #define SETSU_BUTTON_0 (1u << 0) @@ -61,11 +53,7 @@ typedef struct setsu_event_t SetsuEventType type; union { - struct - { - const char *path; - SetsuDeviceType dev_type; - }; + const char *path; struct { SetsuDevice *dev; @@ -75,14 +63,8 @@ typedef struct setsu_event_t { SetsuTrackingId tracking_id; uint32_t x, y; - } touch; + }; SetsuButton button; - struct - { - float accel_x, accel_y, accel_z; // unit is 1G - float gyro_x, gyro_y, gyro_z; // unit is rad/sec - uint32_t timestamp; // microseconds - } motion; }; }; }; @@ -93,12 +75,11 @@ typedef void (*SetsuEventCb)(SetsuEvent *event, void *user); Setsu *setsu_new(); void setsu_free(Setsu *setsu); void setsu_poll(Setsu *setsu, SetsuEventCb cb, void *user); -SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type); +SetsuDevice *setsu_connect(Setsu *setsu, const char *path); void setsu_disconnect(Setsu *setsu, SetsuDevice *dev); const char *setsu_device_get_path(SetsuDevice *dev); -uint32_t setsu_device_touchpad_get_width(SetsuDevice *dev); -uint32_t setsu_device_touchpad_get_height(SetsuDevice *dev); - +uint32_t setsu_device_get_width(SetsuDevice *dev); +uint32_t setsu_device_get_height(SetsuDevice *dev); #ifdef __cplusplus } diff --git a/setsu/src/setsu.c b/setsu/src/setsu.c index c31fe83..f899d07 100644 --- a/setsu/src/setsu.c +++ b/setsu/src/setsu.c @@ -11,7 +11,6 @@ #include #include #include -#include #include @@ -23,12 +22,9 @@ #define SETSU_LOG(...) do {} while(0) #endif -#define DEG2RAD (2.0f * M_PI / 360.0f) - typedef struct setsu_avail_device_t { struct setsu_avail_device_t *next; - SetsuDeviceType type; char *path; bool connect_dirty; // whether the connect has not been sent as an event yet bool disconnect_dirty; // whether the disconnect has not been sent as an event yet @@ -40,44 +36,27 @@ typedef struct setsu_device_t { struct setsu_device_t *next; char *path; - SetsuDeviceType type; int fd; struct libevdev *evdev; + int min_x, min_y, max_x, max_y; - union - { - struct - { - int min_x, min_y, max_x, max_y; + struct { + /* Saves the old tracking id that was just up-ed. + * also for handling "atomic" up->down + * i.e. when there is an up, then down with a different tracking id + * in a single frame (before SYN_REPORT), this saves the old + * tracking id that must be reported as up. */ + int tracking_id_prev; - struct - { - /* Saves the old tracking id that was just up-ed. - * also for handling "atomic" up->down - * i.e. when there is an up, then down with a different tracking id - * in a single frame (before SYN_REPORT), this saves the old - * tracking id that must be reported as up. */ - int tracking_id_prev; + int tracking_id; + int x, y; + bool downed; + bool pos_dirty; + } slots[SLOTS_COUNT]; + unsigned int slot_cur; - int tracking_id; - int x, y; - bool downed; - bool pos_dirty; - } slots[SLOTS_COUNT]; - unsigned int slot_cur; - uint64_t buttons_prev; - uint64_t buttons_cur; - } touchpad; - struct - { - int accel_res_x, accel_res_y, accel_res_z; - int gyro_res_x, gyro_res_y, gyro_res_z; - int accel_x, accel_y, accel_z; - int gyro_x, gyro_y, gyro_z; - uint32_t timestamp; - bool dirty; - } motion; - }; + uint64_t buttons_prev; + uint64_t buttons_cur; } SetsuDevice; struct setsu_t @@ -152,8 +131,8 @@ static void scan_udev(Setsu *setsu) if(udev_enumerate_add_match_subsystem(udev_enum, "input") < 0) goto beach; - //if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0) - // goto beach; + if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0) + goto beach; if(udev_enumerate_scan_devices(udev_enum) < 0) goto beach; @@ -174,32 +153,16 @@ beach: udev_enumerate_unref(udev_enum); } -static bool is_device_interesting(struct udev_device *dev, SetsuDeviceType *type) +static bool is_device_interesting(struct udev_device *dev) { static const uint32_t device_ids[] = { // vendor id, model id - 0x054c, 0x05c4, // DualShock 4 Gen 1 - 0x054c, 0x09cc, // DualShock 4 Gen 2 - 0x54c, 0x0ce6 // DualSense + 0x054c, 0x05c4, // DualShock 4 Gen 1 USB + 0x054c, 0x09cc // DualShock 4 Gen 2 USB }; - const char *touchpad_str = udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD"); - const char *accel_str = udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER"); - if(touchpad_str && !strcmp(touchpad_str, "1")) - { - // Filter mouse-device (/dev/input/mouse*) away and only keep the evdev (/dev/input/event*) one: - if(!udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD_INTEGRATION")) - return false; - *type = SETSU_DEVICE_TYPE_TOUCHPAD; - } - else if(accel_str && !strcmp(accel_str, "1")) - { - // Filter /dev/input/js* away and keep /dev/input/event* - if(!udev_device_get_property_value(dev, "ID_INPUT_WIDTH_MM")) - return false; - *type = SETSU_DEVICE_TYPE_MOTION; - } - else + // Filter mouse-device (/dev/input/mouse*) away and only keep the evdev (/dev/input/event*) one: + if(!udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD_INTEGRATION")) return false; uint32_t vendor; @@ -257,14 +220,12 @@ static void update_udev_device(Setsu *setsu, struct udev_device *dev) } // not yet added - SetsuDeviceType type; - if(!is_device_interesting(dev, &type)) + if(!is_device_interesting(dev)) return; SetsuAvailDevice *adev = calloc(1, sizeof(SetsuAvailDevice)); if(!adev) return; - adev->type = type; adev->path = strdup(path); if(!adev->path) { @@ -310,7 +271,7 @@ bool get_dev_ids(const char *path, uint32_t *vendor_id, uint32_t *model_id) return true; } -SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type) +SetsuDevice *setsu_connect(Setsu *setsu, const char *path) { SetsuDevice *dev = calloc(1, sizeof(SetsuDevice)); if(!dev) @@ -319,15 +280,10 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type) dev->path = strdup(path); if(!dev->path) goto error; - dev->type = type; dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK); if(dev->fd == -1) - { - SETSU_LOG("Failed to open %s\n", dev->path); - perror("setsu_connect"); goto error; - } if(libevdev_new_from_fd(dev->fd, &dev->evdev) < 0) { @@ -335,29 +291,15 @@ SetsuDevice *setsu_connect(Setsu *setsu, const char *path, SetsuDeviceType type) goto error; } - switch(type) - { - case SETSU_DEVICE_TYPE_TOUCHPAD: - dev->touchpad.min_x = libevdev_get_abs_minimum(dev->evdev, ABS_X); - dev->touchpad.min_y = libevdev_get_abs_minimum(dev->evdev, ABS_Y); - dev->touchpad.max_x = libevdev_get_abs_maximum(dev->evdev, ABS_X); - dev->touchpad.max_y = libevdev_get_abs_maximum(dev->evdev, ABS_Y); + dev->min_x = libevdev_get_abs_minimum(dev->evdev, ABS_X); + dev->min_y = libevdev_get_abs_minimum(dev->evdev, ABS_Y); + dev->max_x = libevdev_get_abs_maximum(dev->evdev, ABS_X); + dev->max_y = libevdev_get_abs_maximum(dev->evdev, ABS_Y); - for(size_t i=0; itouchpad.slots[i].tracking_id_prev = -1; - dev->touchpad.slots[i].tracking_id = -1; - } - break; - case SETSU_DEVICE_TYPE_MOTION: - dev->motion.accel_res_x = libevdev_get_abs_resolution(dev->evdev, ABS_X); - dev->motion.accel_res_y = libevdev_get_abs_resolution(dev->evdev, ABS_Y); - dev->motion.accel_res_z = libevdev_get_abs_resolution(dev->evdev, ABS_Z); - dev->motion.gyro_res_x = libevdev_get_abs_resolution(dev->evdev, ABS_RX); - dev->motion.gyro_res_y = libevdev_get_abs_resolution(dev->evdev, ABS_RY); - dev->motion.gyro_res_z = libevdev_get_abs_resolution(dev->evdev, ABS_RZ); - dev->motion.accel_y = dev->motion.accel_res_y; // 1G down - break; + for(size_t i=0; islots[i].tracking_id_prev = -1; + dev->slots[i].tracking_id = -1; } dev->next = setsu->dev; @@ -399,18 +341,14 @@ const char *setsu_device_get_path(SetsuDevice *dev) return dev->path; } -uint32_t setsu_device_touchpad_get_width(SetsuDevice *dev) +uint32_t setsu_device_get_width(SetsuDevice *dev) { - if(dev->type != SETSU_DEVICE_TYPE_TOUCHPAD) - return 0; - return dev->touchpad.max_x - dev->touchpad.min_x; + return dev->max_x - dev->min_x; } -uint32_t setsu_device_touchpad_get_height(SetsuDevice *dev) +uint32_t setsu_device_get_height(SetsuDevice *dev) { - if(dev->type != SETSU_DEVICE_TYPE_TOUCHPAD) - return 0; - return dev->touchpad.max_y - dev->touchpad.min_y; + return dev->max_y - dev->min_y; } void kill_avail_device(Setsu *setsu, SetsuAvailDevice *adev) @@ -455,7 +393,6 @@ void setsu_poll(Setsu *setsu, SetsuEventCb cb, void *user) SetsuEvent event = { 0 }; event.type = SETSU_EVENT_DEVICE_ADDED; event.path = adev->path; - event.dev_type = adev->type; cb(&event, user); adev->connect_dirty = false; } @@ -464,7 +401,6 @@ void setsu_poll(Setsu *setsu, SetsuEventCb cb, void *user) SetsuEvent event = { 0 }; event.type = SETSU_EVENT_DEVICE_REMOVED; event.path = adev->path; - event.dev_type = adev->type; cb(&event, user); // kill the device only after sending the event SetsuAvailDevice *next = adev->next; @@ -529,106 +465,59 @@ static void device_event(Setsu *setsu, SetsuDevice *dev, struct input_event *ev, libevdev_event_code_get_name(ev->type, ev->code), ev->value); #endif - if(ev->type == EV_SYN && ev->code == SYN_REPORT) +#define S dev->slots[dev->slot_cur] + switch(ev->type) { - device_drain(setsu, dev, cb, user); - return; - } - switch(dev->type) - { - case SETSU_DEVICE_TYPE_TOUCHPAD: - switch(ev->type) + case EV_ABS: + switch(ev->code) { - case EV_ABS: -#define S dev->touchpad.slots[dev->touchpad.slot_cur] - switch(ev->code) + case ABS_MT_SLOT: + if((unsigned int)ev->value >= SLOTS_COUNT) { - case ABS_MT_SLOT: - if((unsigned int)ev->value >= SLOTS_COUNT) - { - SETSU_LOG("slot too high\n"); - break; - } - dev->touchpad.slot_cur = ev->value; - break; - case ABS_MT_TRACKING_ID: - if(S.tracking_id != -1 && S.tracking_id_prev == -1) - { - // up the tracking id - S.tracking_id_prev = S.tracking_id; - // reset the rest - S.x = S.y = 0; - S.pos_dirty = false; - } - S.tracking_id = ev->value; - if(ev->value != -1) - S.downed = true; - break; - case ABS_MT_POSITION_X: - S.x = ev->value; - S.pos_dirty = true; - break; - case ABS_MT_POSITION_Y: - S.y = ev->value; - S.pos_dirty = true; - break; - } - break; -#undef S - case EV_KEY: { - uint64_t button = button_from_evdev(ev->code); - if(!button) + SETSU_LOG("slot too high\n"); break; - if(ev->value) - dev->touchpad.buttons_cur |= button; - else - dev->touchpad.buttons_cur &= ~button; + } + dev->slot_cur = ev->value; + break; + case ABS_MT_TRACKING_ID: + if(S.tracking_id != -1 && S.tracking_id_prev == -1) + { + // up the tracking id + S.tracking_id_prev = S.tracking_id; + // reset the rest + S.x = S.y = 0; + S.pos_dirty = false; + } + S.tracking_id = ev->value; + if(ev->value != -1) + S.downed = true; + break; + case ABS_MT_POSITION_X: + S.x = ev->value; + S.pos_dirty = true; + break; + case ABS_MT_POSITION_Y: + S.y = ev->value; + S.pos_dirty = true; break; - } } break; - case SETSU_DEVICE_TYPE_MOTION: - switch(ev->type) - { - case EV_ABS: - switch(ev->code) - { - case ABS_X: - dev->motion.accel_x = ev->value; - dev->motion.dirty = true; - break; - case ABS_Y: - dev->motion.accel_y = ev->value; - dev->motion.dirty = true; - break; - case ABS_Z: - dev->motion.accel_z = ev->value; - dev->motion.dirty = true; - break; - case ABS_RX: - dev->motion.gyro_x = ev->value; - dev->motion.dirty = true; - break; - case ABS_RY: - dev->motion.gyro_y = ev->value; - dev->motion.dirty = true; - break; - case ABS_RZ: - dev->motion.gyro_z = ev->value; - dev->motion.dirty = true; - break; - } - break; - case EV_MSC: - if(ev->code == MSC_TIMESTAMP) - { - dev->motion.timestamp = ev->value; - dev->motion.dirty = true; - } - break; - } + case EV_KEY: { + uint64_t button = button_from_evdev(ev->code); + if(!button) + break; + if(ev->value) + dev->buttons_cur |= button; + else + dev->buttons_cur &= ~button; + break; + } + case EV_SYN: + if(ev->code == SYN_REPORT) + device_drain(setsu, dev, cb, user); break; } +#undef S } static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void *user) @@ -636,68 +525,48 @@ static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void * SetsuEvent event; #define BEGIN_EVENT(tp) do { memset(&event, 0, sizeof(event)); event.dev = dev; event.type = tp; } while(0) #define SEND_EVENT() do { cb(&event, user); } while (0) - switch(dev->type) + for(size_t i=0; itouchpad.slots[i].tracking_id_prev != -1) - { - BEGIN_EVENT(SETSU_EVENT_TOUCH_UP); - event.touch.tracking_id = dev->touchpad.slots[i].tracking_id_prev; - SEND_EVENT(); - dev->touchpad.slots[i].tracking_id_prev = -1; - } - if(dev->touchpad.slots[i].downed) - { - BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN); - event.touch.tracking_id = dev->touchpad.slots[i].tracking_id; - SEND_EVENT(); - dev->touchpad.slots[i].downed = false; - } - if(dev->touchpad.slots[i].pos_dirty) - { - BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION); - event.touch.tracking_id = dev->touchpad.slots[i].tracking_id; - event.touch.x = (uint32_t)(dev->touchpad.slots[i].x - dev->touchpad.min_x); - event.touch.y = (uint32_t)(dev->touchpad.slots[i].y - dev->touchpad.min_y); - SEND_EVENT(); - dev->touchpad.slots[i].pos_dirty = false; - } - } + if(dev->slots[i].tracking_id_prev != -1) + { + BEGIN_EVENT(SETSU_EVENT_TOUCH_UP); + event.tracking_id = dev->slots[i].tracking_id_prev; + SEND_EVENT(); + dev->slots[i].tracking_id_prev = -1; + } + if(dev->slots[i].downed) + { + BEGIN_EVENT(SETSU_EVENT_TOUCH_DOWN); + event.tracking_id = dev->slots[i].tracking_id; + SEND_EVENT(); + dev->slots[i].downed = false; + } + if(dev->slots[i].pos_dirty) + { + BEGIN_EVENT(SETSU_EVENT_TOUCH_POSITION); + event.tracking_id = dev->slots[i].tracking_id; + event.x = (uint32_t)(dev->slots[i].x - dev->min_x); + event.y = (uint32_t)(dev->slots[i].y - dev->min_y); + SEND_EVENT(); + dev->slots[i].pos_dirty = false; + } + } - uint64_t buttons_diff = dev->touchpad.buttons_prev ^ dev->touchpad.buttons_cur; - for(uint64_t i=0; i<64; i++) - { - if(buttons_diff & 1) - { - uint64_t button = 1 << i; - BEGIN_EVENT((dev->touchpad.buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP); - event.button = button; - SEND_EVENT(); - } - buttons_diff >>= 1; - if(!buttons_diff) - break; - } - dev->touchpad.buttons_prev = dev->touchpad.buttons_cur; - break; - case SETSU_DEVICE_TYPE_MOTION: - if(dev->motion.dirty) - { - BEGIN_EVENT(SETSU_EVENT_MOTION); - event.motion.accel_x = (float)dev->motion.accel_x / (float)dev->motion.accel_res_x; - event.motion.accel_y = (float)dev->motion.accel_y / (float)dev->motion.accel_res_y; - event.motion.accel_z = (float)dev->motion.accel_z / (float)dev->motion.accel_res_z; - event.motion.gyro_x = DEG2RAD * (float)dev->motion.gyro_x / (float)dev->motion.gyro_res_x; - event.motion.gyro_y = DEG2RAD * (float)dev->motion.gyro_y / (float)dev->motion.gyro_res_y; - event.motion.gyro_z = DEG2RAD * (float)dev->motion.gyro_z / (float)dev->motion.gyro_res_z; - event.motion.timestamp = dev->motion.timestamp; - SEND_EVENT(); - dev->motion.dirty = false; - } + uint64_t buttons_diff = dev->buttons_prev ^ dev->buttons_cur; + for(uint64_t i=0; i<64; i++) + { + if(buttons_diff & 1) + { + uint64_t button = 1 << i; + BEGIN_EVENT((dev->buttons_cur & button) ? SETSU_EVENT_BUTTON_DOWN : SETSU_EVENT_BUTTON_UP); + event.button = button; + SEND_EVENT(); + } + buttons_diff >>= 1; + if(!buttons_diff) break; } + dev->buttons_prev = dev->buttons_cur; #undef BEGIN_EVENT #undef SEND_EVENT } diff --git a/switch/CMakeLists.txt b/switch/CMakeLists.txt index 3d5639a..89bd789 100644 --- a/switch/CMakeLists.txt +++ b/switch/CMakeLists.txt @@ -61,16 +61,17 @@ target_include_directories(borealis PUBLIC find_package(glfw3 REQUIRED) find_library(EGL EGL) -target_link_libraries(borealis PUBLIC +find_library(GLAPI glapi) +find_library(DRM_NOUVEAU drm_nouveau) +target_link_libraries(borealis glfw - ${EGL}) + ${EGL} + ${GLAPI} + ${DRM_NOUVEAU}) if(CHIAKI_IS_SWITCH) target_compile_definitions(borealis PUBLIC BOREALIS_RESOURCES="romfs:/") - find_library(GLAPI glapi) - find_library(DRM_NOUVEAU drm_nouveau) - target_link_libraries(borealis PUBLIC ${GLAPI} ${DRM_NOUVEAU}) else() target_compile_definitions(borealis PUBLIC BOREALIS_RESOURCES="./switch/res/") @@ -113,7 +114,9 @@ target_link_libraries(chiaki-borealis if(CHIAKI_IS_SWITCH) # libnx is forced by the switch toolchain find_library(Z z) - target_link_libraries(chiaki-borealis ${Z} ${GLAPI}) + find_library(GLAPI glapi) # TODO: make it transitive from borealis + find_library(DRM_NOUVEAU drm_nouveau) # TODO: make it transitive from borealis + target_link_libraries(chiaki-borealis ${Z} ${GLAPI} ${DRM_NOUVEAU}) endif() install(TARGETS chiaki-borealis @@ -123,9 +126,9 @@ install(TARGETS chiaki-borealis if(CHIAKI_IS_SWITCH) add_nro_target(chiaki chiaki-borealis - "Chiaki" - "H0neyBadger and thestr4ng3r" + "chiaki" + "Chiaki team" "${CHIAKI_VERSION}" - "${CMAKE_CURRENT_SOURCE_DIR}/nro_icon.jpg" - "${CMAKE_CURRENT_SOURCE_DIR}/res") + "${CMAKE_SOURCE_DIR}/switch/res/icon.jpg" + "${CMAKE_SOURCE_DIR}/switch/res") endif() diff --git a/switch/README.md b/switch/README.md index 2307fa4..709f900 100644 --- a/switch/README.md +++ b/switch/README.md @@ -4,10 +4,26 @@ this project requires the devkitpro toolchain. you can use your personal computer to install devkitpro but the easiest way is to use the following container. +Build container image +--------------------- +``` +bash scripts/switch/build-docker-image.sh +``` + +Run container +------------- +from the project's [root folder](../) +``` +docker run -it --rm \ + -v "$(pwd):/build" \ + -p 28771:28771 \ + chiaki-switch +``` + Build Project ------------- ``` -bash scripts/switch/run-podman-build-chiaki.sh +bash scripts/switch/run-docker-build-chiaki.sh ``` tools @@ -15,7 +31,7 @@ tools Push to homebrew Netloader ``` # where X.X.X.X is the IP of your switch -bash scripts/switch/push-podman-build-chiaki.sh -a 192.168.0.200 +scripts/switch/push-docker-build-chiaki.sh 192.168.0.200 ``` Troubleshoot @@ -36,7 +52,7 @@ this file contains sensitive data. (do not share this file) [PS*-***] # required: lan PlayStation IP address # IP from Settings > System > system information -host_addr = *.*.*.* +host_ip = *.*.*.* # required: sony oline id (login) psn_online_id = ps_online_id # required (PS4>7.0 Only): https://git.sr.ht/~thestr4ng3r/chiaki/tree/master/item/README.md#obtaining-your-psn-accountid diff --git a/switch/borealis b/switch/borealis index eae1371..205e97a 160000 --- a/switch/borealis +++ b/switch/borealis @@ -1 +1 @@ -Subproject commit eae1371831d6cebf11b8ebd4c611069bccc6fb9b +Subproject commit 205e97ab45922fa7f5c9fa6a85d5d686cd50b669 diff --git a/switch/include/discoverymanager.h b/switch/include/discoverymanager.h index 49c8dcc..76c504d 100644 --- a/switch/include/discoverymanager.h +++ b/switch/include/discoverymanager.h @@ -24,7 +24,7 @@ class DiscoveryManager struct sockaddr * host_addr = nullptr; size_t host_addr_len = 0; uint32_t GetIPv4BroadcastAddr(); - bool service_enable = false; + bool service_enable; public: typedef enum hoststate diff --git a/switch/include/gui.h b/switch/include/gui.h index 033cf67..afd2bab 100644 --- a/switch/include/gui.h +++ b/switch/include/gui.h @@ -50,6 +50,10 @@ class MainApplication IO *io; brls::TabFrame *rootFrame; std::map host_menuitems; + // add_host local settings + std::string remote_display_name = ""; + std::string remote_addr = ""; + ChiakiTarget remote_ps_version = CHIAKI_TARGET_PS5_1; bool BuildConfigurationMenu(brls::List *, Host *host = nullptr); void BuildAddHostConfigurationMenu(brls::List *); @@ -69,6 +73,12 @@ class PSRemotePlay : public brls::View // to send gamepad inputs Host *host; brls::Label *label; + ChiakiControllerState state = {0}; + // FPS calculation + // double base_time; + // int frame_counter = 0; + // int fps = 0; + public: PSRemotePlay(Host *host); ~PSRemotePlay(); diff --git a/switch/include/host.h b/switch/include/host.h index e28183e..ae6f05e 100644 --- a/switch/include/host.h +++ b/switch/include/host.h @@ -54,9 +54,7 @@ class Host std::function chiaki_regist_event_type_finished_success = nullptr; std::function chiaki_event_connected_cb = nullptr; std::function chiaki_even_login_pin_request_cb = nullptr; - std::function chiaki_event_rumble_cb = nullptr; std::function chiaki_event_quit_cb = nullptr; - std::function *)> io_read_controller_cb = nullptr; // internal state bool discovered = false; @@ -75,8 +73,6 @@ class Host std::string server_nickname; ChiakiTarget target = CHIAKI_TARGET_PS4_UNKNOWN; ChiakiDiscoveryHostState state = CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN; - ChiakiControllerState controller_state = {0}; - std::map finger_id_touch_id; // mac address = 48 bits uint8_t server_mac[6] = {0}; @@ -94,13 +90,13 @@ class Host public: Host(std::string host_name); ~Host(); - int Register(int pin); + int Register(std::string pin); int Wakeup(); int InitSession(IO *); int FiniSession(); void StopSession(); void StartSession(); - void SendFeedbackState(); + void SendFeedbackState(ChiakiControllerState *); void RegistCB(ChiakiRegistEvent *); void ConnectionEventCB(ChiakiEvent *); bool GetVideoResolution(int *ret_width, int *ret_height); @@ -114,9 +110,7 @@ class Host void SetRegistEventTypeFinishedSuccess(std::function chiaki_regist_event_type_finished_success); void SetEventConnectedCallback(std::function chiaki_event_connected_cb); void SetEventLoginPinRequestCallback(std::function chiaki_even_login_pin_request_cb); - void SetEventRumbleCallback(std::function chiaki_event_rumble_cb); void SetEventQuitCallback(std::function chiaki_event_quit_cb); - void SetReadControllerCallback(std::function *)> io_read_controller_cb); bool IsRegistered(); bool IsDiscovered(); bool IsReady(); diff --git a/switch/include/io.h b/switch/include/io.h index 3bb6fd1..8427684 100644 --- a/switch/include/io.h +++ b/switch/include/io.h @@ -28,15 +28,7 @@ Omit khrplatform: False Reproducible: False */ -#ifdef __SWITCH__ -#include -#else -#include -#endif - #include -#include - extern "C" { #include @@ -67,17 +59,12 @@ class IO // default nintendo switch res int screen_width = 1280; int screen_height = 720; - const AVCodec *codec; + AVCodec *codec; AVCodecContext *codec_context; AVFrame *frame; SDL_AudioDeviceID sdl_audio_device_id = 0; SDL_Event sdl_event; SDL_Joystick *sdl_joystick_ptr[SDL_JOYSTICK_COUNT] = {0}; -#ifdef __SWITCH__ - PadState pad; - HidSixAxisSensorHandle sixaxis_handles[4]; - HidVibrationDeviceHandle vibration_handles[2][2]; -#endif GLuint vao; GLuint vbo; GLuint tex[PLANES_COUNT]; @@ -98,8 +85,8 @@ class IO GLuint CreateAndCompileShader(GLenum type, const char *source); void SetOpenGlYUVPixels(AVFrame *frame); bool ReadGameKeys(SDL_Event *event, ChiakiControllerState *state); - bool ReadGameTouchScreen(ChiakiControllerState *state, std::map *finger_id_touch_id); - bool ReadGameSixAxis(ChiakiControllerState *state); + bool ReadGameTouchScreen(ChiakiControllerState *state); + public: // singleton configuration IO(const IO&) = delete; @@ -113,11 +100,10 @@ class IO void AudioCB(int16_t *buf, size_t samples_count); bool InitVideo(int video_width, int video_height, int screen_width, int screen_height); bool FreeVideo(); - bool InitController(); - bool FreeController(); - bool MainLoop(); - void UpdateControllerState(ChiakiControllerState *state, std::map *finger_id_touch_id); - void SetRumble(uint8_t left, uint8_t right); + bool InitJoystick(); + bool FreeJoystick(); + bool ReadUserKeyboard(char *buffer, size_t buffer_size); + bool MainLoop(ChiakiControllerState *state); }; #endif //CHIAKI_IO_H diff --git a/switch/include/settings.h b/switch/include/settings.h index 6bcb445..08ecbb2 100644 --- a/switch/include/settings.h +++ b/switch/include/settings.h @@ -49,8 +49,8 @@ class Settings // the goal is to read/write inernal flat configuration file const std::map re_map = { {HOST_NAME, std::regex("^\\[\\s*(.+)\\s*\\]")}, - {HOST_ADDR, std::regex("^\\s*host_(?:ip|addr)\\s*=\\s*\"?([^\"]*)\"?")}, - {PSN_ONLINE_ID, std::regex("^\\s*psn_online_id\\s*=\\s*\"?([\\w_-]+)\"?")}, + {HOST_ADDR, std::regex("^\\s*host_(?:ip|addr)\\s*=\\s*\"?((\\d+\\.\\d+\\.\\d+\\.\\d+)|([A-Za-z0-9-]{1,255}))\"?")}, + {PSN_ONLINE_ID, std::regex("^\\s*psn_online_id\\s*=\\s*\"?(\\w+)\"?")}, {PSN_ACCOUNT_ID, std::regex("^\\s*psn_account_id\\s*=\\s*\"?([\\w/=+]+)\"?")}, {RP_KEY, std::regex("^\\s*rp_key\\s*=\\s*\"?([\\w/=+]+)\"?")}, {RP_KEY_TYPE, std::regex("^\\s*rp_key_type\\s*=\\s*\"?(\\d)\"?")}, @@ -61,6 +61,7 @@ class Settings }; ConfigurationItem ParseLine(std::string * line, std::string * value); + size_t GetB64encodeSize(size_t); public: // singleton configuration diff --git a/switch/nro_icon.jpg b/switch/nro_icon.jpg deleted file mode 100644 index 0ed61ec..0000000 Binary files a/switch/nro_icon.jpg and /dev/null differ diff --git a/switch/nro_icon.png b/switch/nro_icon.png deleted file mode 100644 index 65d745e..0000000 Binary files a/switch/nro_icon.png and /dev/null differ diff --git a/switch/res/icon.jpg b/switch/res/icon.jpg new file mode 100644 index 0000000..cb515da Binary files /dev/null and b/switch/res/icon.jpg differ diff --git a/switch/res/icon.png b/switch/res/icon.png deleted file mode 100644 index 5b2ad9c..0000000 Binary files a/switch/res/icon.png and /dev/null differ diff --git a/switch/src/discoverymanager.cpp b/switch/src/discoverymanager.cpp index 7fa7122..7f71578 100644 --- a/switch/src/discoverymanager.cpp +++ b/switch/src/discoverymanager.cpp @@ -16,9 +16,9 @@ #define HOSTS_MAX 16 #define DROP_PINGS 3 -static void Discovery(ChiakiDiscoveryHost *discovered_hosts, size_t hosts_count, void *user) +static void Discovery(ChiakiDiscoveryHost * discovered_hosts, size_t hosts_count, void * user) { - DiscoveryManager *dm = (DiscoveryManager *)user; + DiscoveryManager * dm = (DiscoveryManager *)user; for(size_t i = 0; i < hosts_count; i++) { dm->DiscoveryCB(discovered_hosts + i); @@ -35,13 +35,19 @@ DiscoveryManager::~DiscoveryManager() { // join discovery thread if(this->service_enable) + { SetService(false); + } + + chiaki_discovery_fini(&this->discovery); } void DiscoveryManager::SetService(bool enable) { if(this->service_enable == enable) + { return; + } this->service_enable = enable; @@ -99,7 +105,7 @@ uint32_t DiscoveryManager::GetIPv4BroadcastAddr() #endif } -int DiscoveryManager::Send(struct sockaddr *host_addr, size_t host_addr_len) +int DiscoveryManager::Send(struct sockaddr * host_addr, size_t host_addr_len) { if(!host_addr) { @@ -114,9 +120,9 @@ int DiscoveryManager::Send(struct sockaddr *host_addr, size_t host_addr_len) return 0; } -int DiscoveryManager::Send(const char *discover_ip_dest) +int DiscoveryManager::Send(const char * discover_ip_dest) { - struct addrinfo *host_addrinfos; + struct addrinfo * host_addrinfos; int r = getaddrinfo(discover_ip_dest, NULL, NULL, &host_addrinfos); if(r != 0) { @@ -124,10 +130,10 @@ int DiscoveryManager::Send(const char *discover_ip_dest) return 1; } - struct sockaddr *host_addr = nullptr; + struct sockaddr * host_addr = nullptr; socklen_t host_addr_len = 0; - for(struct addrinfo *ai = host_addrinfos; ai; ai = ai->ai_next) + for(struct addrinfo * ai = host_addrinfos; ai; ai = ai->ai_next) { if(ai->ai_protocol != IPPROTO_UDP) continue; @@ -164,13 +170,13 @@ int DiscoveryManager::Send() return DiscoveryManager::Send(this->host_addr, this->host_addr_len); } -void DiscoveryManager::DiscoveryCB(ChiakiDiscoveryHost *discovered_host) +void DiscoveryManager::DiscoveryCB(ChiakiDiscoveryHost * discovered_host) { // the user ptr is passed as // chiaki_discovery_thread_start arg std::string key = discovered_host->host_name; - Host *host = this->settings->GetOrCreateHost(&key); + Host * host = this->settings->GetOrCreateHost(&key); CHIAKI_LOGI(this->log, "--"); CHIAKI_LOGI(this->log, "Discovered Host:"); diff --git a/switch/src/gui.cpp b/switch/src/gui.cpp index c23f470..e49852b 100644 --- a/switch/src/gui.cpp +++ b/switch/src/gui.cpp @@ -42,9 +42,6 @@ HostInterface::HostInterface(Host *host) // when the host is connected this->host->SetEventConnectedCallback(std::bind(&HostInterface::Stream, this)); this->host->SetEventQuitCallback(std::bind(&HostInterface::CloseStream, this, std::placeholders::_1)); - // allow host to update controller state - this->host->SetEventRumbleCallback(std::bind(&IO::SetRumble, this->io, std::placeholders::_1, std::placeholders::_2)); - this->host->SetReadControllerCallback(std::bind(&IO::UpdateControllerState, this->io, std::placeholders::_1, std::placeholders::_2)); } HostInterface::~HostInterface() @@ -100,31 +97,42 @@ void HostInterface::Register(Host *host, std::function success_cb) host->SetRegistEventTypeFinishedFailed(event_type_finished_failed_cb); // the host is not registered yet - // use callback to ensure that the message is showed on screen - // before the Swkbd - auto pin_input_cb = [host](int pin) { - // prevent users form messing with the gui - brls::Application::blockInputs(); - int ret = host->Register(pin); - if(ret != HOST_REGISTER_OK) + brls::Dialog *peprpc = new brls::Dialog("Please enter your PlayStation registration PIN code"); + brls::GenericEvent::Callback cb_peprpc = [host, io, peprpc](brls::View *view) { + bool pin_provided = false; + char pin_input[9] = {0}; + std::string error_message; + + // use callback to ensure that the message is showed on screen + // before the the ReadUserKeyboard + peprpc->close(); + + pin_provided = io->ReadUserKeyboard(pin_input, sizeof(pin_input)); + if(pin_provided) { - switch(ret) + // prevent users form messing with the gui + brls::Application::blockInputs(); + int ret = host->Register(pin_input); + if(ret != HOST_REGISTER_OK) { - // account not configured - case HOST_REGISTER_ERROR_SETTING_PSNACCOUNTID: - brls::Application::notify("No PSN Account ID provided"); - brls::Application::unblockInputs(); - break; - case HOST_REGISTER_ERROR_SETTING_PSNONLINEID: - brls::Application::notify("No PSN Online ID provided"); - brls::Application::unblockInputs(); - break; + switch(ret) + { + // account not configured + case HOST_REGISTER_ERROR_SETTING_PSNACCOUNTID: + brls::Application::notify("No PSN Account ID provided"); + brls::Application::unblockInputs(); + break; + case HOST_REGISTER_ERROR_SETTING_PSNONLINEID: + brls::Application::notify("No PSN Online ID provided"); + brls::Application::unblockInputs(); + break; + } } } }; - // the pin is 8 digit - bool success = brls::Swkbd::openForNumber(pin_input_cb, - "Please enter your PlayStation registration PIN code", "8 digits without spaces", 8, "", "", ""); + peprpc->addButton("Ok", cb_peprpc); + peprpc->setCancelable(false); + peprpc->open(); } void HostInterface::Register() @@ -248,7 +256,7 @@ MainApplication::MainApplication(DiscoveryManager *discoverymanager) MainApplication::~MainApplication() { this->discoverymanager->SetService(false); - this->io->FreeController(); + //this->io->FreeJoystick(); this->io->FreeVideo(); } @@ -267,21 +275,22 @@ bool MainApplication::Load() // init chiaki gl after borealis // let borealis manage the main screen/window + if(!io->InitVideo(0, 0, SCREEN_W, SCREEN_H)) { brls::Logger::error("Failed to initiate Video"); } - brls::Logger::info("Load sdl/hid controller"); - if(!io->InitController()) + brls::Logger::info("Load sdl joysticks"); + if(!io->InitJoystick()) { - brls::Logger::error("Faled to initiate Controller"); + brls::Logger::error("Faled to initiate Joysticks"); } // Create a view this->rootFrame = new brls::TabFrame(); this->rootFrame->setTitle("Chiaki: Open Source PlayStation Remote Play Client"); - this->rootFrame->setIcon(BOREALIS_ASSET("icon.png")); + this->rootFrame->setIcon(BOREALIS_ASSET("icon.jpg")); brls::List *config = new brls::List(); brls::List *add_host = new brls::List(); @@ -318,36 +327,39 @@ bool MainApplication::Load() bool MainApplication::BuildConfigurationMenu(brls::List *ls, Host *host) { std::string psn_account_id_string = this->settings->GetPSNAccountID(host); - brls::InputListItem *psn_account_id = new brls::InputListItem("PSN Account ID", psn_account_id_string, - "Account ID in base64 format", "PS5 or PS4 v7.0 and greater", CHIAKI_PSN_ACCOUNT_ID_SIZE * 2, - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_SPACE | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_AT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_PERCENT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_BACKSLASH); - + brls::ListItem *psn_account_id = new brls::ListItem("PSN Account ID", "PS5 or PS4 v7.0 and greater (base64 account_id)"); + psn_account_id->setValue(psn_account_id_string.c_str()); auto psn_account_id_cb = [this, host, psn_account_id](brls::View *view) { - // retrieve, push and save setting - this->settings->SetPSNAccountID(host, psn_account_id->getValue()); - // write on disk - this->settings->WriteFile(); + char account_id[CHIAKI_PSN_ACCOUNT_ID_SIZE * 2] = {0}; + bool input = this->io->ReadUserKeyboard(account_id, sizeof(account_id)); + if(input) + { + // update gui + psn_account_id->setValue(account_id); + // push in setting + this->settings->SetPSNAccountID(host, account_id); + // write on disk + this->settings->WriteFile(); + } }; psn_account_id->getClickEvent()->subscribe(psn_account_id_cb); ls->addView(psn_account_id); std::string psn_online_id_string = this->settings->GetPSNOnlineID(host); - brls::InputListItem *psn_online_id = new brls::InputListItem("PSN Online ID", - psn_online_id_string, "", "", 16, - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_SPACE | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_AT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_PERCENT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_FORWSLASH | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_BACKSLASH); - + brls::ListItem *psn_online_id = new brls::ListItem("PSN Online ID"); + psn_online_id->setValue(psn_online_id_string.c_str()); auto psn_online_id_cb = [this, host, psn_online_id](brls::View *view) { - // retrieve, push and save setting - this->settings->SetPSNOnlineID(host, psn_online_id->getValue()); - // write on disk - this->settings->WriteFile(); + char online_id[256] = {0}; + bool input = this->io->ReadUserKeyboard(online_id, sizeof(online_id)); + if(input) + { + // update gui + psn_online_id->setValue(online_id); + // push in setting + this->settings->SetPSNOnlineID(host, online_id); + // write on disk + this->settings->WriteFile(); + } }; psn_online_id->getClickEvent()->subscribe(psn_online_id_cb); ls->addView(psn_online_id); @@ -368,7 +380,7 @@ bool MainApplication::BuildConfigurationMenu(brls::List *ls, Host *host) } brls::SelectListItem *resolution = new brls::SelectListItem( - "Resolution", { "720p", "540p", "360p" }, value); + "Resolution", {"720p", "540p", "360p"}, value); auto resolution_cb = [this, host](int result) { ChiakiVideoResolutionPreset value = CHIAKI_VIDEO_RESOLUTION_PRESET_720p; @@ -402,7 +414,7 @@ bool MainApplication::BuildConfigurationMenu(brls::List *ls, Host *host) } brls::SelectListItem *fps = new brls::SelectListItem( - "FPS", { "60", "30" }, value); + "FPS", {"60", "30"}, value); auto fps_cb = [this, host](int result) { ChiakiVideoFPSPreset value = CHIAKI_VIDEO_FPS_PRESET_60; @@ -453,24 +465,34 @@ void MainApplication::BuildAddHostConfigurationMenu(brls::List *add_host) // brls::Label* add_host_label = new brls::Label(brls::LabelStyle::REGULAR, // "Add Host configuration", true); - brls::InputListItem *display_name = new brls::InputListItem("Display name", - "default", "configuration name", "", 16, - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_SPACE | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_AT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_PERCENT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_FORWSLASH | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_BACKSLASH); - + brls::ListItem *display_name = new brls::ListItem("Display name"); + auto display_name_cb = [this, display_name](brls::View *view) { + char name[16] = {0}; + bool input = this->io->ReadUserKeyboard(name, sizeof(name)); + if(input) + { + // update gui + display_name->setValue(name); + // set internal value + this->remote_display_name = name; + } + }; + display_name->getClickEvent()->subscribe(display_name_cb); add_host->addView(display_name); - brls::InputListItem *address = new brls::InputListItem("Remote IP/name", - "", "IP address or fqdn", "", 255, - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_SPACE | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_AT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_PERCENT | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_FORWSLASH | - brls::KeyboardKeyDisableBitmask::KEYBOARD_DISABLE_BACKSLASH); - + brls::ListItem *address = new brls::ListItem("Remote IP/name"); + auto address_cb = [this, address](brls::View *view) { + char addr[256] = {0}; + bool input = this->io->ReadUserKeyboard(addr, sizeof(addr)); + if(input) + { + // update gui + address->setValue(addr); + // set internal value + this->remote_addr = addr; + } + }; + address->getClickEvent()->subscribe(address_cb); add_host->addView(address); // TODO @@ -478,49 +500,47 @@ void MainApplication::BuildAddHostConfigurationMenu(brls::List *add_host) // brls::ListItem* port = new brls::ListItem("Remote stream port", "udp 9296"); // brls::ListItem* port = new brls::ListItem("Remote Senkusha port", "udp 9297"); brls::SelectListItem *ps_version = new brls::SelectListItem("PlayStation Version", - { "PS5", "PS4 > 8", "7 < PS4 < 8", "PS4 < 7" }); - add_host->addView(ps_version); - - brls::ListItem *register_host = new brls::ListItem("Register"); - auto register_host_cb = [this, display_name, address, ps_version](brls::View *view) { - bool err = false; - std::string dn = display_name->getValue(); - std::string addr = address->getValue(); - ChiakiTarget version = CHIAKI_TARGET_PS4_UNKNOWN; - - switch(ps_version->getSelectedValue()) + {"PS5", "PS4 > 8", "7 < PS4 < 8", "PS4 < 7"}); + auto ps_version_cb = [this, ps_version](int result) { + switch(result) { case 0: // ps5 v1 - version = CHIAKI_TARGET_PS5_1; + this->remote_ps_version = CHIAKI_TARGET_PS5_1; break; case 1: // ps4 v8 - version = CHIAKI_TARGET_PS4_10; + this->remote_ps_version = CHIAKI_TARGET_PS4_10; break; case 2: // ps4 v7 - version = CHIAKI_TARGET_PS4_9; + this->remote_ps_version = CHIAKI_TARGET_PS4_9; break; case 3: // ps4 v6 - version = CHIAKI_TARGET_PS4_8; + this->remote_ps_version = CHIAKI_TARGET_PS4_8; break; } + }; + ps_version->getValueSelectedEvent()->subscribe(ps_version_cb); + add_host->addView(ps_version); - if(dn.length() <= 0) + brls::ListItem *register_host = new brls::ListItem("Register"); + auto register_host_cb = [this](brls::View *view) { + bool err = false; + if(this->remote_display_name.length() <= 0) { brls::Application::notify("No Display name defined"); err = true; } - if(addr.length() <= 0) + if(this->remote_addr.length() <= 0) { brls::Application::notify("No Remote address provided"); err = true; } - if(version <= CHIAKI_TARGET_PS4_UNKNOWN) + if(this->remote_ps_version < 0) { brls::Application::notify("No PlayStation Version provided"); err = true; @@ -529,9 +549,10 @@ void MainApplication::BuildAddHostConfigurationMenu(brls::List *add_host) if(err) return; - Host *host = this->settings->GetOrCreateHost(&dn); - host->SetHostAddr(addr); - host->SetChiakiTarget(version); + Host *host = this->settings->GetOrCreateHost(&this->remote_display_name); + host->SetHostAddr(this->remote_addr); + host->SetChiakiTarget(this->remote_ps_version); + HostInterface::Register(host); }; register_host->getClickEvent()->subscribe(register_host_cb); @@ -543,12 +564,38 @@ PSRemotePlay::PSRemotePlay(Host *host) : host(host) { this->io = IO::GetInstance(); + + // store joycon/touchpad keys + for(int x = 0; x < CHIAKI_CONTROLLER_TOUCHES_MAX; x++) + // start touchpad as "untouched" + this->state.touches[x].id = -1; + + // this->base_time=glfwGetTime(); } void PSRemotePlay::draw(NVGcontext *vg, int x, int y, unsigned width, unsigned height, brls::Style *style, brls::FrameContext *ctx) { - this->io->MainLoop(); - this->host->SendFeedbackState(); + this->io->MainLoop(&this->state); + this->host->SendFeedbackState(&this->state); + + // FPS calculation + // this->frame_counter += 1; + // double frame_time = glfwGetTime(); + // if((frame_time - base_time) >= 1.0) + // { + // base_time += 1; + // //printf("FPS: %d\n", this->frame_counter); + // this->fps = this->frame_counter; + // this->frame_counter = 0; + // } + // nvgBeginPath(vg); + // nvgFillColor(vg, nvgRGBA(255,192,0,255)); + // nvgFontFaceId(vg, ctx->fontStash->regular); + // nvgFontSize(vg, style->Label.smallFontSize); + // nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + // char fps_str[9] = {0}; + // sprintf(fps_str, "FPS: %000d", this->fps); + // nvgText(vg, 5,10, fps_str, NULL); } PSRemotePlay::~PSRemotePlay() diff --git a/switch/src/host.cpp b/switch/src/host.cpp index 39ac1b3..6db9c50 100644 --- a/switch/src/host.cpp +++ b/switch/src/host.cpp @@ -72,7 +72,7 @@ int Host::Wakeup() return ret; } -int Host::Register(int pin) +int Host::Register(std::string pin) { // use pin and accont_id to negociate secrets for session // @@ -103,7 +103,7 @@ int Host::Register(int pin) if(online_id.length() > 0) { regist_info.psn_online_id = this->psn_online_id.c_str(); - // regist_info.psn_account_id = '\0'; + // regist_info.psn_account_id = {0}; } else { @@ -117,16 +117,16 @@ int Host::Register(int pin) throw Exception("Undefined PS4 system version (please run discover first)"); } - this->regist_info.pin = pin; + this->regist_info.pin = atoi(pin.c_str()); this->regist_info.host = this->host_addr.c_str(); this->regist_info.broadcast = false; if(this->target >= CHIAKI_TARGET_PS4_9) - CHIAKI_LOGI(this->log, "Registering to host `%s` `%s` with PSN AccountID `%s` pin `%d`", - this->host_name.c_str(), this->host_addr.c_str(), account_id.c_str(), pin); + CHIAKI_LOGI(this->log, "Registering to host `%s` `%s` with PSN AccountID `%s` pin `%s`", + this->host_name.c_str(), this->host_addr.c_str(), account_id.c_str(), pin.c_str()); else - CHIAKI_LOGI(this->log, "Registering to host `%s` `%s` with PSN OnlineID `%s` pin `%d`", - this->host_name.c_str(), this->host_addr.c_str(), online_id.c_str(), pin); + CHIAKI_LOGI(this->log, "Registering to host `%s` `%s` with PSN OnlineID `%s` pin `%s`", + this->host_name.c_str(), this->host_addr.c_str(), online_id.c_str(), pin.c_str()); chiaki_regist_start(&this->regist, this->log, &this->regist_info, RegistEventCB, this); return HOST_REGISTER_OK; @@ -157,13 +157,9 @@ int Host::InitSession(IO *user) // audio setting_cb and frame_cb chiaki_opus_decoder_set_cb(&this->opus_decoder, InitAudioCB, AudioCB, user); chiaki_opus_decoder_get_sink(&this->opus_decoder, &audio_sink); - chiaki_session_set_audio_sink(&this->session, &audio_sink); - chiaki_session_set_video_sample_cb(&this->session, VideoCB, user); - chiaki_session_set_event_cb(&this->session, EventCB, this); - - // init controller states - chiaki_controller_state_set_idle(&this->controller_state); - + chiaki_session_set_audio_sink(&(this->session), &audio_sink); + chiaki_session_set_video_sample_cb(&(this->session), VideoCB, user); + chiaki_session_set_event_cb(&(this->session), EventCB, this); return 0; } @@ -194,13 +190,10 @@ void Host::StartSession() } } -void Host::SendFeedbackState() +void Host::SendFeedbackState(ChiakiControllerState *state) { // send controller/joystick key - if(this->io_read_controller_cb != nullptr) - this->io_read_controller_cb(&this->controller_state, &finger_id_touch_id); - - chiaki_session_set_controller_state(&this->session, &this->controller_state); + chiaki_session_set_controller_state(&this->session, state); } void Host::ConnectionEventCB(ChiakiEvent *event) @@ -217,11 +210,6 @@ void Host::ConnectionEventCB(ChiakiEvent *event) if(this->chiaki_even_login_pin_request_cb != nullptr) this->chiaki_even_login_pin_request_cb(event->login_pin_request.pin_incorrect); break; - case CHIAKI_EVENT_RUMBLE: - CHIAKI_LOGD(this->log, "EventCB CHIAKI_EVENT_RUMBLE"); - if(this->chiaki_event_rumble_cb != nullptr) - this->chiaki_event_rumble_cb(event->rumble.left, event->rumble.right); - break; case CHIAKI_EVENT_QUIT: CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_QUIT"); if(this->chiaki_event_quit_cb != nullptr) @@ -365,16 +353,6 @@ void Host::SetEventQuitCallback(std::function chiaki_ev this->chiaki_event_quit_cb = chiaki_event_quit_cb; } -void Host::SetEventRumbleCallback(std::function chiaki_event_rumble_cb) -{ - this->chiaki_event_rumble_cb = chiaki_event_rumble_cb; -} - -void Host::SetReadControllerCallback(std::function *)> io_read_controller_cb) -{ - this->io_read_controller_cb = io_read_controller_cb; -} - bool Host::IsRegistered() { return this->registered; diff --git a/switch/src/io.cpp b/switch/src/io.cpp index 409bba0..d7c28f7 100644 --- a/switch/src/io.cpp +++ b/switch/src/io.cpp @@ -1,5 +1,11 @@ // SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL +#ifdef __SWITCH__ +#include +#else +#include +#endif + #include "io.h" #include "settings.h" @@ -285,16 +291,6 @@ void IO::AudioCB(int16_t *buf, size_t samples_count) else buf[x] = (int16_t)sample; } - - int audio_queued_size = SDL_GetQueuedAudioSize(this->sdl_audio_device_id); - if(audio_queued_size > 16000) - { - // clear audio queue to avoid big audio delay - // average values are close to 13000 bytes - CHIAKI_LOGW(this->log, "Triggering SDL_ClearQueuedAudio with queue size = %d", audio_queued_size); - SDL_ClearQueuedAudio(this->sdl_audio_device_id); - } - int success = SDL_QueueAudio(this->sdl_audio_device_id, buf, sizeof(int16_t) * samples_count * 2); if(success != 0) CHIAKI_LOGE(this->log, "SDL_QueueAudio failed: %s\n", SDL_GetError()); @@ -339,187 +335,94 @@ bool IO::FreeVideo() return ret; } -bool IO::ReadGameTouchScreen(ChiakiControllerState *chiaki_state, std::map *finger_id_touch_id) +bool IO::ReadUserKeyboard(char *buffer, size_t buffer_size) { -#ifdef __SWITCH__ - HidTouchScreenState sw_state = {0}; - - bool ret = false; - hidGetTouchScreenStates(&sw_state, 1); - // scale switch screen to the PS trackpad - chiaki_state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release - - // un-touch all old touches - for(auto it = finger_id_touch_id->begin(); it != finger_id_touch_id->end();) - { - auto cur = it; - it++; - for(int i = 0; i < sw_state.count; i++) - { - if(sw_state.touches[i].finger_id == cur->first) - goto cont; - } - if(cur->second >= 0) - chiaki_controller_state_stop_touch(chiaki_state, (uint8_t)cur->second); - finger_id_touch_id->erase(cur); -cont: - continue; - } - - - // touch or update all current touches - for(int i = 0; i < sw_state.count; i++) - { - uint16_t x = sw_state.touches[i].x * ((float)DS4_TRACKPAD_MAX_X / (float)SWITCH_TOUCHSCREEN_MAX_X); - uint16_t y = sw_state.touches[i].y * ((float)DS4_TRACKPAD_MAX_Y / (float)SWITCH_TOUCHSCREEN_MAX_Y); - // use nintendo switch border's 5% to trigger the touchpad button - if(x <= (DS4_TRACKPAD_MAX_X * 0.05) || x >= (DS4_TRACKPAD_MAX_X * 0.95) || y <= (DS4_TRACKPAD_MAX_Y * 0.05) || y >= (DS4_TRACKPAD_MAX_Y * 0.95)) - chiaki_state->buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen - - auto it = finger_id_touch_id->find(sw_state.touches[i].finger_id); - if(it == finger_id_touch_id->end()) - { - // new touch - (*finger_id_touch_id)[sw_state.touches[i].finger_id] = - chiaki_controller_state_start_touch(chiaki_state, x, y); - } - else if(it->second >= 0) - chiaki_controller_state_set_touch_pos(chiaki_state, (uint8_t)it->second, x, y); - // it->second < 0 ==> touch ignored because there were already too many multi-touches - ret = true; - } - return ret; +#ifndef __SWITCH__ + // use cin to get user input from linux + std::cin.getline(buffer, buffer_size); + CHIAKI_LOGI(this->log, "Got user input: %s\n", buffer); #else - return false; -#endif -} + // https://kvadevack.se/post/nintendo-switch-virtual-keyboard/ + SwkbdConfig kbd; + Result rc = swkbdCreate(&kbd, 0); -void IO::SetRumble(uint8_t left, uint8_t right) -{ -#ifdef __SWITCH__ - Result rc = 0; - HidVibrationValue vibration_values[] = { + if(R_SUCCEEDED(rc)) + { + swkbdConfigMakePresetDefault(&kbd); + rc = swkbdShow(&kbd, buffer, buffer_size); + + if(R_SUCCEEDED(rc)) { - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, - }, - { - .amp_low = 0.0f, - .freq_low = 160.0f, - .amp_high = 0.0f, - .freq_high = 320.0f, - }}; - - int target_device = padIsHandheld(&pad) ? 0 : 1; - if(left > 0) - { - // SDL_HapticRumblePlay(this->sdl_haptic_ptr[0], left / 100, 5000); - vibration_values[0].amp_low = (float)left / (float)100; - vibration_values[0].amp_high = (float)left / (float)100; - vibration_values[0].freq_low *= (float)left / (float)100; - vibration_values[0].freq_high *= (float)left / (float)100; - } - - if(right > 0) - { - // SDL_HapticRumblePlay(this->sdl_haptic_ptr[1], right / 100, 5000); - vibration_values[1].amp_low = (float)right / (float)100; - vibration_values[1].amp_high = (float)right / (float)100; - vibration_values[1].freq_low *= (float)left / (float)100; - vibration_values[1].freq_high *= (float)left / (float)100; - } - - // printf("left ptr %p amp_low %f amp_high %f freq_low %f freq_high %f\n", - // &vibration_values[0], - // vibration_values[0].amp_low, - // vibration_values[0].amp_high, - // vibration_values[0].freq_low, - // vibration_values[0].freq_high); - - // printf("right ptr %p amp_low %f amp_high %f freq_low %f freq_high %f\n", - // &vibration_values[1], - // vibration_values[1].amp_low, - // vibration_values[1].amp_high, - // vibration_values[1].freq_low, - // vibration_values[1].freq_high); - - rc = hidSendVibrationValues(this->vibration_handles[target_device], vibration_values, 2); - if(R_FAILED(rc)) - CHIAKI_LOGE(this->log, "hidSendVibrationValues() returned: 0x%x", rc); - -#endif -} - -bool IO::ReadGameSixAxis(ChiakiControllerState *state) -{ -#ifdef __SWITCH__ - // Read from the correct sixaxis handle depending on the current input style - HidSixAxisSensorState sixaxis = {0}; - uint64_t style_set = padGetStyleSet(&pad); - if(style_set & HidNpadStyleTag_NpadHandheld) - hidGetSixAxisSensorStates(this->sixaxis_handles[0], &sixaxis, 1); - else if(style_set & HidNpadStyleTag_NpadFullKey) - hidGetSixAxisSensorStates(this->sixaxis_handles[1], &sixaxis, 1); - else if(style_set & HidNpadStyleTag_NpadJoyDual) - { - // For JoyDual, read from either the Left or Right Joy-Con depending on which is/are connected - u64 attrib = padGetAttributes(&pad); - if(attrib & HidNpadAttribute_IsLeftConnected) - hidGetSixAxisSensorStates(this->sixaxis_handles[2], &sixaxis, 1); - else if(attrib & HidNpadAttribute_IsRightConnected) - hidGetSixAxisSensorStates(this->sixaxis_handles[3], &sixaxis, 1); - } - - state->gyro_x = sixaxis.angular_velocity.x * 2.0f * M_PI; - state->gyro_y = sixaxis.angular_velocity.z * 2.0f * M_PI; - state->gyro_z = -sixaxis.angular_velocity.y * 2.0f * M_PI; - state->accel_x = -sixaxis.acceleration.x; - state->accel_y = -sixaxis.acceleration.z; - state->accel_z = sixaxis.acceleration.y; - - // https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf - float (*dm)[3] = sixaxis.direction.direction; - float m[3][3] = { - { dm[0][0], dm[2][0], dm[1][0] }, - { dm[0][2], dm[2][2], dm[1][2] }, - { dm[0][1], dm[2][1], dm[1][1] } - }; - std::array q; - float t; - if(m[2][2] < 0) - { - if (m[0][0] > m[1][1]) - { - t = 1 + m[0][0] - m[1][1] - m[2][2]; - q = { t, m[0][1] + m[1][0], m[2][0] + m[0][2], m[1][2] - m[2][1] }; + CHIAKI_LOGI(this->log, "Got user input: %s\n", buffer); } else { - t = 1 - m[0][0] + m[1][1] -m[2][2]; - q = { m[0][1] + m[1][0], t, m[1][2] + m[2][1], m[2][0] - m[0][2] }; + CHIAKI_LOGE(this->log, "swkbdShow() error: %u\n", rc); + return false; } + swkbdClose(&kbd); } else { - if(m[0][0] < -m[1][1]) + CHIAKI_LOGE(this->log, "swkbdCreate() error: %u\n", rc); + return false; + } +#endif + return true; +} + +bool IO::ReadGameTouchScreen(ChiakiControllerState *state) +{ +#ifdef __SWITCH__ + hidScanInput(); + int touch_count = hidTouchCount(); + bool ret = false; + if(!touch_count) + { + for(int i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) { - t = 1 - m[0][0] - m[1][1] + m[2][2]; - q = { m[2][0] + m[0][2], m[1][2] + m[2][1], t, m[0][1] - m[1][0] }; + if(state->touches[i].id != -1) + { + state->touches[i].x = 0; + state->touches[i].y = 0; + state->touches[i].id = -1; + state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release + // the state changed + ret = true; + } + } + return ret; + } + + touchPosition touch; + for(int i = 0; i < touch_count && i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) + { + hidTouchRead(&touch, i); + + // 1280×720 px (16:9) + // ps4 controller aspect ratio looks closer to 29:10 + uint16_t x = touch.px * (DS4_TRACKPAD_MAX_X / SWITCH_TOUCHSCREEN_MAX_X); + uint16_t y = touch.py * (DS4_TRACKPAD_MAX_Y / SWITCH_TOUCHSCREEN_MAX_Y); + + // use nintendo switch border's 5% to + if(x <= (SWITCH_TOUCHSCREEN_MAX_X * 0.05) || x >= (SWITCH_TOUCHSCREEN_MAX_X * 0.95) || y <= (SWITCH_TOUCHSCREEN_MAX_Y * 0.05) || y >= (SWITCH_TOUCHSCREEN_MAX_Y * 0.95)) + { + state->buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen + // printf("CHIAKI_CONTROLLER_BUTTON_TOUCHPAD\n"); } else { - t = 1 + m[0][0] + m[1][1] + m[2][2]; - q = { m[1][2] - m[2][1], m[2][0] - m[0][2], m[0][1] - m[1][0], t }; + state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release } + + state->touches[i].x = x; + state->touches[i].y = y; + state->touches[i].id = i; + // printf("[point_id=%d] px=%03d, py=%03d, dx=%03d, dy=%03d, angle=%03d\n", + // i, touch.px, touch.py, touch.dx, touch.dy, touch.angle); + ret = true; } - float fac = 0.5f / sqrt(t); - state->orient_x = q[0] * fac; - state->orient_y = q[1] * fac; - state->orient_z = -q[2] * fac; - state->orient_w = q[3] * fac; - return true; + return ret; #else return false; #endif @@ -531,6 +434,8 @@ bool IO::ReadGameKeys(SDL_Event *event, ChiakiControllerState *state) // TODO // share vs PS button + // Gyro ? + // rumble ? bool ret = true; switch(event->type) { @@ -907,7 +812,7 @@ inline void IO::OpenGlDraw() D(glFinish()); } -bool IO::InitController() +bool IO::InitJoystick() { // https://github.com/switchbrew/switch-examples/blob/master/graphics/sdl2/sdl2-simple/source/main.cpp#L57 // open CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 @@ -921,64 +826,24 @@ bool IO::InitController() CHIAKI_LOGE(this->log, "SDL_JoystickOpen: %s\n", SDL_GetError()); return false; } - // this->sdl_haptic_ptr[i] = SDL_HapticOpenFromJoystick(sdl_joystick_ptr[i]); - // SDL_HapticRumbleInit(this->sdl_haptic_ptr[i]); - // if(sdl_haptic_ptr[i] == nullptr) - // { - // CHIAKI_LOGE(this->log, "SDL_HapticRumbleInit: %s\n", SDL_GetError()); - // } } -#ifdef __SWITCH__ -Result rc = 0; - // Configure our supported input layout: a single player with standard controller styles - padConfigureInput(1, HidNpadStyleSet_NpadStandard); - - // Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller) - padInitializeDefault(&this->pad); - // touchpad - hidInitializeTouchScreen(); - // It's necessary to initialize these separately as they all have different handle values - hidGetSixAxisSensorHandles(&this->sixaxis_handles[0], 1, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld); - hidGetSixAxisSensorHandles(&this->sixaxis_handles[1], 1, HidNpadIdType_No1, HidNpadStyleTag_NpadFullKey); - hidGetSixAxisSensorHandles(&this->sixaxis_handles[2], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual); - hidStartSixAxisSensor(this->sixaxis_handles[0]); - hidStartSixAxisSensor(this->sixaxis_handles[1]); - hidStartSixAxisSensor(this->sixaxis_handles[2]); - hidStartSixAxisSensor(this->sixaxis_handles[3]); - - rc = hidInitializeVibrationDevices(this->vibration_handles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld); - if(R_FAILED(rc)) - CHIAKI_LOGE(this->log, "hidInitializeVibrationDevices() HidNpadIdType_Handheld returned: 0x%x", rc); - - rc = hidInitializeVibrationDevices(this->vibration_handles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual); - if(R_FAILED(rc)) - CHIAKI_LOGE(this->log, "hidInitializeVibrationDevices() HidNpadIdType_No1 returned: 0x%x", rc); - -#endif return true; } -bool IO::FreeController() +bool IO::FreeJoystick() { for(int i = 0; i < SDL_JOYSTICK_COUNT; i++) { - SDL_JoystickClose(this->sdl_joystick_ptr[i]); - // SDL_HapticClose(this->sdl_haptic_ptr[i]); + if(SDL_JoystickGetAttached(sdl_joystick_ptr[i])) + SDL_JoystickClose(sdl_joystick_ptr[i]); } -#ifdef __SWITCH__ - hidStopSixAxisSensor(this->sixaxis_handles[0]); - hidStopSixAxisSensor(this->sixaxis_handles[1]); - hidStopSixAxisSensor(this->sixaxis_handles[2]); - hidStopSixAxisSensor(this->sixaxis_handles[3]); -#endif return true; } -void IO::UpdateControllerState(ChiakiControllerState *state, std::map *finger_id_touch_id) +bool IO::MainLoop(ChiakiControllerState *state) { -#ifdef __SWITCH__ - padUpdate(&this->pad); -#endif + D(glUseProgram(this->prog)); + // handle SDL events while(SDL_PollEvent(&this->sdl_event)) { @@ -986,17 +851,11 @@ void IO::UpdateControllerState(ChiakiControllerState *state, std::mapsdl_event.type) { case SDL_QUIT: - this->quit = true; + return false; } } - ReadGameTouchScreen(state, finger_id_touch_id); - ReadGameSixAxis(state); -} - -bool IO::MainLoop() -{ - D(glUseProgram(this->prog)); + ReadGameTouchScreen(state); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/switch/src/main.cpp b/switch/src/main.cpp index 1dd33de..c12d413 100644 --- a/switch/src/main.cpp +++ b/switch/src/main.cpp @@ -28,6 +28,8 @@ bool appletMainLoop() // use a custom nintendo switch socket config // chiaki requiers many threads with udp/tcp sockets static const SocketInitConfig g_chiakiSocketInitConfig = { + .bsdsockets_version = 1, + .tcp_tx_buf_size = 0x8000, .tcp_rx_buf_size = 0x10000, .tcp_tx_buf_max_size = 0x40000, @@ -81,6 +83,12 @@ extern "C" void userAppInit() // load socket custom config socketInitialize(&g_chiakiSocketInitConfig); setsysInitialize(); + + // padConfigureInput(1, HidNpadStyleSet_NpadStandard); + // PadState pad; + // padInitializeDefault(&pad); + + //hidInitializeTouchScreen(); } extern "C" void userAppExit() @@ -103,11 +111,11 @@ extern "C" void userAppExit() } #endif // __SWITCH__ -int main(int argc, char *argv[]) +int main(int argc, char * argv[]) { // load chiaki lib - Settings *settings = Settings::GetInstance(); - ChiakiLog *log = settings->GetLogger(); + Settings * settings = Settings::GetInstance(); + ChiakiLog * log = settings->GetLogger(); CHIAKI_LOGI(log, "Loading chaki lib"); @@ -118,7 +126,7 @@ int main(int argc, char *argv[]) return 1; } - CHIAKI_LOGI(log, "Loading SDL audio / joystick / haptic"); + CHIAKI_LOGI(log, "Loading SDL audio / joystick"); if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)) { CHIAKI_LOGE(log, "SDL initialization failed: %s", SDL_GetError()); @@ -127,11 +135,8 @@ int main(int argc, char *argv[]) // build sdl OpenGl and AV decoders graphical interface DiscoveryManager discoverymanager = DiscoveryManager(); - { - // scope to delete MainApplication before SDL_Quit() - MainApplication app(&discoverymanager); - app.Load(); - } + MainApplication app = MainApplication(&discoverymanager); + app.Load(); CHIAKI_LOGI(log, "Quit applet"); SDL_Quit(); diff --git a/switch/src/settings.cpp b/switch/src/settings.cpp index 7d3300a..f0eb3e3 100644 --- a/switch/src/settings.cpp +++ b/switch/src/settings.cpp @@ -7,13 +7,13 @@ Settings::Settings() { #if defined(__SWITCH__) - chiaki_log_init(&this->log, CHIAKI_LOG_ALL & ~(CHIAKI_LOG_VERBOSE | CHIAKI_LOG_DEBUG), chiaki_log_cb_print, NULL); + chiaki_log_init(&this->log, CHIAKI_LOG_ALL ^ CHIAKI_LOG_VERBOSE ^ CHIAKI_LOG_DEBUG, chiaki_log_cb_print, NULL); #else - chiaki_log_init(&this->log, CHIAKI_LOG_ALL & ~CHIAKI_LOG_VERBOSE, chiaki_log_cb_print, NULL); + chiaki_log_init(&this->log, CHIAKI_LOG_ALL, chiaki_log_cb_print, NULL); #endif } -Settings::ConfigurationItem Settings::ParseLine(std::string *line, std::string *value) +Settings::ConfigurationItem Settings::ParseLine(std::string * line, std::string * value) { Settings::ConfigurationItem ci; std::smatch m; @@ -29,11 +29,15 @@ Settings::ConfigurationItem Settings::ParseLine(std::string *line, std::string * return UNKNOWN; } -#define B64_ENCODED_SIZE(in) (((4 * in / 3) + 3) & ~3) +size_t Settings::GetB64encodeSize(size_t in) +{ + // calculate base64 buffer size after encode + return ((4 * in / 3) + 3) & ~3; +} -Settings *Settings::instance = nullptr; +Settings * Settings::instance = nullptr; -Settings *Settings::GetInstance() +Settings * Settings::GetInstance() { if(instance == nullptr) { @@ -43,17 +47,17 @@ Settings *Settings::GetInstance() return instance; } -ChiakiLog *Settings::GetLogger() +ChiakiLog * Settings::GetLogger() { return &this->log; } -std::map *Settings::GetHostsMap() +std::map * Settings::GetHostsMap() { return &this->hosts; } -Host *Settings::GetOrCreateHost(std::string *host_name) +Host * Settings::GetOrCreateHost(std::string * host_name) { bool created = false; // update of create Host instance @@ -65,7 +69,7 @@ Host *Settings::GetOrCreateHost(std::string *host_name) created = true; } - Host *host = &(this->hosts.at(*host_name)); + Host * host = &(this->hosts.at(*host_name)); if(created) { // copy default settings @@ -86,7 +90,7 @@ void Settings::ParseFile() std::string line; std::string value; bool rp_key_b = false, rp_regist_key_b = false, rp_key_type_b = false; - Host *current_host = nullptr; + Host * current_host = nullptr; if(config_file.is_open()) { CHIAKI_LOGV(&this->log, "Config file opened"); @@ -98,63 +102,63 @@ void Settings::ParseFile() ci = this->ParseLine(&line, &value); switch(ci) { - // got to next line - case UNKNOWN: - CHIAKI_LOGV(&this->log, "UNKNOWN config"); - break; - case HOST_NAME: - CHIAKI_LOGV(&this->log, "HOST_NAME %s", value.c_str()); - // current host is in context - current_host = this->GetOrCreateHost(&value); - // all following case will edit the current_host config + // got to next line + case UNKNOWN: + CHIAKI_LOGV(&this->log, "UNKNOWN config"); + break; + case HOST_NAME: + CHIAKI_LOGV(&this->log, "HOST_NAME %s", value.c_str()); + // current host is in context + current_host = this->GetOrCreateHost(&value); + // all following case will edit the current_host config - rp_key_b = false; - rp_regist_key_b = false; - rp_key_type_b = false; - break; - case HOST_ADDR: - CHIAKI_LOGV(&this->log, "HOST_ADDR %s", value.c_str()); - if(current_host != nullptr) - current_host->host_addr = value; - break; - case PSN_ONLINE_ID: - CHIAKI_LOGV(&this->log, "PSN_ONLINE_ID %s", value.c_str()); - // current_host == nullptr - // means we are in global ini section - // update default setting - this->SetPSNOnlineID(current_host, value); - break; - case PSN_ACCOUNT_ID: - CHIAKI_LOGV(&this->log, "PSN_ACCOUNT_ID %s", value.c_str()); - this->SetPSNAccountID(current_host, value); - break; - case RP_KEY: - CHIAKI_LOGV(&this->log, "RP_KEY %s", value.c_str()); - if(current_host != nullptr) - rp_key_b = this->SetHostRPKey(current_host, value); - break; - case RP_KEY_TYPE: - CHIAKI_LOGV(&this->log, "RP_KEY_TYPE %s", value.c_str()); - if(current_host != nullptr) - // TODO Check possible rp_type values - rp_key_type_b = this->SetHostRPKeyType(current_host, value); - break; - case RP_REGIST_KEY: - CHIAKI_LOGV(&this->log, "RP_REGIST_KEY %s", value.c_str()); - if(current_host != nullptr) - rp_regist_key_b = this->SetHostRPRegistKey(current_host, value); - break; - case VIDEO_RESOLUTION: - this->SetVideoResolution(current_host, value); - break; - case VIDEO_FPS: - this->SetVideoFPS(current_host, value); - break; - case TARGET: - CHIAKI_LOGV(&this->log, "TARGET %s", value.c_str()); - if(current_host != nullptr) - this->SetChiakiTarget(current_host, value); - break; + rp_key_b = false; + rp_regist_key_b = false; + rp_key_type_b = false; + break; + case HOST_ADDR: + CHIAKI_LOGV(&this->log, "HOST_ADDR %s", value.c_str()); + if(current_host != nullptr) + current_host->host_addr = value; + break; + case PSN_ONLINE_ID: + CHIAKI_LOGV(&this->log, "PSN_ONLINE_ID %s", value.c_str()); + // current_host == nullptr + // means we are in global ini section + // update default setting + this->SetPSNOnlineID(current_host, value); + break; + case PSN_ACCOUNT_ID: + CHIAKI_LOGV(&this->log, "PSN_ACCOUNT_ID %s", value.c_str()); + this->SetPSNAccountID(current_host, value); + break; + case RP_KEY: + CHIAKI_LOGV(&this->log, "RP_KEY %s", value.c_str()); + if(current_host != nullptr) + rp_key_b = this->SetHostRPKey(current_host, value); + break; + case RP_KEY_TYPE: + CHIAKI_LOGV(&this->log, "RP_KEY_TYPE %s", value.c_str()); + if(current_host != nullptr) + // TODO Check possible rp_type values + rp_key_type_b = this->SetHostRPKeyType(current_host, value); + break; + case RP_REGIST_KEY: + CHIAKI_LOGV(&this->log, "RP_REGIST_KEY %s", value.c_str()); + if(current_host != nullptr) + rp_regist_key_b = this->SetHostRPRegistKey(current_host, value); + break; + case VIDEO_RESOLUTION: + this->SetVideoResolution(current_host, value); + break; + case VIDEO_FPS: + this->SetVideoFPS(current_host, value); + break; + case TARGET: + CHIAKI_LOGV(&this->log, "TARGET %s", value.c_str()); + if(current_host != nullptr) + this->SetChiakiTarget(current_host, value); + break; } // ci switch if(rp_key_b && rp_regist_key_b && rp_key_type_b) // the current host contains rp key data @@ -206,8 +210,9 @@ int Settings::WriteFile() config_file << "[" << it->first << "]\n" << "host_addr = \"" << it->second.GetHostAddr() << "\"\n" - << "target = \"" << it->second.GetChiakiTarget() << "\"\n"; + << "target = " << it->second.GetChiakiTarget() << "\"\n"; + config_file << "target = \"" << it->second.psn_account_id << "\"\n"; if(it->second.video_resolution) config_file << "video_resolution = \"" << this->ResolutionPresetToString(this->GetVideoResolution(&it->second)) @@ -226,7 +231,7 @@ int Settings::WriteFile() if(it->second.rp_key_data || it->second.registered) { - char rp_key_type[33] = { 0 }; + char rp_key_type[33] = {0}; snprintf(rp_key_type, sizeof(rp_key_type), "%d", it->second.rp_key_type); // save registered rp key for auto login config_file << "rp_key = \"" << this->GetHostRPKey(&it->second) << "\"\n" @@ -245,14 +250,14 @@ std::string Settings::ResolutionPresetToString(ChiakiVideoResolutionPreset resol { switch(resolution) { - case CHIAKI_VIDEO_RESOLUTION_PRESET_360p: - return "360p"; - case CHIAKI_VIDEO_RESOLUTION_PRESET_540p: - return "540p"; - case CHIAKI_VIDEO_RESOLUTION_PRESET_720p: - return "720p"; - case CHIAKI_VIDEO_RESOLUTION_PRESET_1080p: - return "1080p"; + case CHIAKI_VIDEO_RESOLUTION_PRESET_360p: + return "360p"; + case CHIAKI_VIDEO_RESOLUTION_PRESET_540p: + return "540p"; + case CHIAKI_VIDEO_RESOLUTION_PRESET_720p: + return "720p"; + case CHIAKI_VIDEO_RESOLUTION_PRESET_1080p: + return "1080p"; } return "UNKNOWN"; } @@ -261,14 +266,14 @@ int Settings::ResolutionPresetToInt(ChiakiVideoResolutionPreset resolution) { switch(resolution) { - case CHIAKI_VIDEO_RESOLUTION_PRESET_360p: - return 360; - case CHIAKI_VIDEO_RESOLUTION_PRESET_540p: - return 540; - case CHIAKI_VIDEO_RESOLUTION_PRESET_720p: - return 720; - case CHIAKI_VIDEO_RESOLUTION_PRESET_1080p: - return 1080; + case CHIAKI_VIDEO_RESOLUTION_PRESET_360p: + return 360; + case CHIAKI_VIDEO_RESOLUTION_PRESET_540p: + return 540; + case CHIAKI_VIDEO_RESOLUTION_PRESET_720p: + return 720; + case CHIAKI_VIDEO_RESOLUTION_PRESET_1080p: + return 1080; } return 0; } @@ -295,10 +300,10 @@ std::string Settings::FPSPresetToString(ChiakiVideoFPSPreset fps) { switch(fps) { - case CHIAKI_VIDEO_FPS_PRESET_30: - return "30"; - case CHIAKI_VIDEO_FPS_PRESET_60: - return "60"; + case CHIAKI_VIDEO_FPS_PRESET_30: + return "30"; + case CHIAKI_VIDEO_FPS_PRESET_60: + return "60"; } return "UNKNOWN"; } @@ -307,10 +312,10 @@ int Settings::FPSPresetToInt(ChiakiVideoFPSPreset fps) { switch(fps) { - case CHIAKI_VIDEO_FPS_PRESET_30: - return 30; - case CHIAKI_VIDEO_FPS_PRESET_60: - return 60; + case CHIAKI_VIDEO_FPS_PRESET_30: + return 30; + case CHIAKI_VIDEO_FPS_PRESET_60: + return 60; } return 0; } @@ -329,7 +334,7 @@ ChiakiVideoFPSPreset Settings::StringToFPSPreset(std::string value) return CHIAKI_VIDEO_FPS_PRESET_30; } -std::string Settings::GetHostName(Host *host) +std::string Settings::GetHostName(Host * host) { if(host != nullptr) return host->GetHostName(); @@ -338,7 +343,7 @@ std::string Settings::GetHostName(Host *host) return ""; } -std::string Settings::GetHostAddr(Host *host) +std::string Settings::GetHostAddr(Host * host) { if(host != nullptr) return host->GetHostAddr(); @@ -347,7 +352,7 @@ std::string Settings::GetHostAddr(Host *host) return ""; } -std::string Settings::GetPSNOnlineID(Host *host) +std::string Settings::GetPSNOnlineID(Host * host) { if(host == nullptr || host->psn_online_id.length() == 0) return this->global_psn_online_id; @@ -355,7 +360,7 @@ std::string Settings::GetPSNOnlineID(Host *host) return host->psn_online_id; } -void Settings::SetPSNOnlineID(Host *host, std::string psn_online_id) +void Settings::SetPSNOnlineID(Host * host, std::string psn_online_id) { if(host == nullptr) this->global_psn_online_id = psn_online_id; @@ -363,7 +368,7 @@ void Settings::SetPSNOnlineID(Host *host, std::string psn_online_id) host->psn_online_id = psn_online_id; } -std::string Settings::GetPSNAccountID(Host *host) +std::string Settings::GetPSNAccountID(Host * host) { if(host == nullptr || host->psn_account_id.length() == 0) return this->global_psn_account_id; @@ -371,7 +376,7 @@ std::string Settings::GetPSNAccountID(Host *host) return host->psn_account_id; } -void Settings::SetPSNAccountID(Host *host, std::string psn_account_id) +void Settings::SetPSNAccountID(Host * host, std::string psn_account_id) { if(host == nullptr) this->global_psn_account_id = psn_account_id; @@ -379,7 +384,7 @@ void Settings::SetPSNAccountID(Host *host, std::string psn_account_id) host->psn_account_id = psn_account_id; } -ChiakiVideoResolutionPreset Settings::GetVideoResolution(Host *host) +ChiakiVideoResolutionPreset Settings::GetVideoResolution(Host * host) { if(host == nullptr) return this->global_video_resolution; @@ -387,7 +392,7 @@ ChiakiVideoResolutionPreset Settings::GetVideoResolution(Host *host) return host->video_resolution; } -void Settings::SetVideoResolution(Host *host, ChiakiVideoResolutionPreset value) +void Settings::SetVideoResolution(Host * host, ChiakiVideoResolutionPreset value) { if(host == nullptr) this->global_video_resolution = value; @@ -395,13 +400,13 @@ void Settings::SetVideoResolution(Host *host, ChiakiVideoResolutionPreset value) host->video_resolution = value; } -void Settings::SetVideoResolution(Host *host, std::string value) +void Settings::SetVideoResolution(Host * host, std::string value) { ChiakiVideoResolutionPreset p = StringToResolutionPreset(value); this->SetVideoResolution(host, p); } -ChiakiVideoFPSPreset Settings::GetVideoFPS(Host *host) +ChiakiVideoFPSPreset Settings::GetVideoFPS(Host * host) { if(host == nullptr) return this->global_video_fps; @@ -409,7 +414,7 @@ ChiakiVideoFPSPreset Settings::GetVideoFPS(Host *host) return host->video_fps; } -void Settings::SetVideoFPS(Host *host, ChiakiVideoFPSPreset value) +void Settings::SetVideoFPS(Host * host, ChiakiVideoFPSPreset value) { if(host == nullptr) this->global_video_fps = value; @@ -417,18 +422,18 @@ void Settings::SetVideoFPS(Host *host, ChiakiVideoFPSPreset value) host->video_fps = value; } -void Settings::SetVideoFPS(Host *host, std::string value) +void Settings::SetVideoFPS(Host * host, std::string value) { ChiakiVideoFPSPreset p = StringToFPSPreset(value); this->SetVideoFPS(host, p); } -ChiakiTarget Settings::GetChiakiTarget(Host *host) +ChiakiTarget Settings::GetChiakiTarget(Host * host) { return host->GetChiakiTarget(); } -bool Settings::SetChiakiTarget(Host *host, ChiakiTarget target) +bool Settings::SetChiakiTarget(Host * host, ChiakiTarget target) { if(host != nullptr) { @@ -442,19 +447,20 @@ bool Settings::SetChiakiTarget(Host *host, ChiakiTarget target) } } -bool Settings::SetChiakiTarget(Host *host, std::string value) +bool Settings::SetChiakiTarget(Host * host, std::string value) { // TODO Check possible target values return this->SetChiakiTarget(host, static_cast(std::atoi(value.c_str()))); } -std::string Settings::GetHostRPKey(Host *host) +std::string Settings::GetHostRPKey(Host * host) { if(host != nullptr) { if(host->rp_key_data || host->registered) { - char rp_key_b64[B64_ENCODED_SIZE(0x10) + 1] = { 0 }; + size_t rp_key_b64_sz = this->GetB64encodeSize(0x10); + char rp_key_b64[rp_key_b64_sz + 1] = {0}; ChiakiErrorCode err; err = chiaki_base64_encode( host->rp_key, 0x10, @@ -472,7 +478,7 @@ std::string Settings::GetHostRPKey(Host *host) return ""; } -bool Settings::SetHostRPKey(Host *host, std::string rp_key_b64) +bool Settings::SetHostRPKey(Host * host, std::string rp_key_b64) { if(host != nullptr) { @@ -491,13 +497,14 @@ bool Settings::SetHostRPKey(Host *host, std::string rp_key_b64) return false; } -std::string Settings::GetHostRPRegistKey(Host *host) +std::string Settings::GetHostRPRegistKey(Host * host) { if(host != nullptr) { if(host->rp_key_data || host->registered) { - char rp_regist_key_b64[B64_ENCODED_SIZE(CHIAKI_SESSION_AUTH_SIZE) + 1] = { 0 }; + size_t rp_regist_key_b64_sz = this->GetB64encodeSize(CHIAKI_SESSION_AUTH_SIZE); + char rp_regist_key_b64[rp_regist_key_b64_sz + 1] = {0}; ChiakiErrorCode err; err = chiaki_base64_encode( (uint8_t *)host->rp_regist_key, CHIAKI_SESSION_AUTH_SIZE, @@ -515,7 +522,7 @@ std::string Settings::GetHostRPRegistKey(Host *host) return ""; } -bool Settings::SetHostRPRegistKey(Host *host, std::string rp_regist_key_b64) +bool Settings::SetHostRPRegistKey(Host * host, std::string rp_regist_key_b64) { if(host != nullptr) { @@ -534,7 +541,7 @@ bool Settings::SetHostRPRegistKey(Host *host, std::string rp_regist_key_b64) return false; } -int Settings::GetHostRPKeyType(Host *host) +int Settings::GetHostRPKeyType(Host * host) { if(host != nullptr) return host->rp_key_type; @@ -543,7 +550,7 @@ int Settings::GetHostRPKeyType(Host *host) return 0; } -bool Settings::SetHostRPKeyType(Host *host, std::string value) +bool Settings::SetHostRPKeyType(Host * host, std::string value) { if(host != nullptr) { @@ -555,7 +562,7 @@ bool Settings::SetHostRPKeyType(Host *host, std::string value) } #ifdef CHIAKI_ENABLE_SWITCH_OVERCLOCK -int Settings::GetCPUOverclock(Host *host) +int Settings::GetCPUOverclock(Host * host) { if(host == nullptr) return this->global_cpu_overclock; @@ -563,7 +570,7 @@ int Settings::GetCPUOverclock(Host *host) return host->cpu_overclock; } -void Settings::SetCPUOverclock(Host *host, int value) +void Settings::SetCPUOverclock(Host * host, int value) { int oc = OC_1326; if(value > OC_1580) @@ -585,9 +592,11 @@ void Settings::SetCPUOverclock(Host *host, int value) host->cpu_overclock = oc; } -void Settings::SetCPUOverclock(Host *host, std::string value) +void Settings::SetCPUOverclock(Host * host, std::string value) { int v = atoi(value.c_str()); this->SetCPUOverclock(host, v); } #endif + + diff --git a/test/reorderqueue.c b/test/reorderqueue.c index f0fd5fe..e5a90c9 100644 --- a/test/reorderqueue.c +++ b/test/reorderqueue.c @@ -16,7 +16,7 @@ typedef struct drop_record_t static void drop(uint64_t seq_num, void *elem_user, void *cb_user) { DropRecord *record = cb_user; - uint64_t v = (uint64_t)(size_t)elem_user; + uint64_t v = (uint64_t)elem_user; if(v > DROP_RECORD_MAX) { record->failed = true; @@ -58,7 +58,7 @@ static MunitResult test_reorder_queue_16(const MunitParameter params[], void *te munit_assert_uint64(chiaki_reorder_queue_count(&queue), ==, 0); munit_assert(!drop_record.failed); munit_assert_uint64(drop_record.count[0], ==, 0); - munit_assert_uint64((uint64_t)(size_t)user, ==, 0); + munit_assert_uint64((uint64_t)user, ==, 0); munit_assert_uint64(seq_num, ==, 42); // push outdated @@ -105,22 +105,22 @@ static MunitResult test_reorder_queue_16(const MunitParameter params[], void *te pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 44); - munit_assert_uint64((uint64_t)(size_t)user, ==, 3); + munit_assert_uint64((uint64_t)user, ==, 3); pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 45); - munit_assert_uint64((uint64_t)(size_t)user, ==, 2); + munit_assert_uint64((uint64_t)user, ==, 2); pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 46); - munit_assert_uint64((uint64_t)(size_t)user, ==, 1); + munit_assert_uint64((uint64_t)user, ==, 1); pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 47); - munit_assert_uint64((uint64_t)(size_t)user, ==, 5); + munit_assert_uint64((uint64_t)user, ==, 5); // should be empty now again pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); @@ -142,7 +142,7 @@ static MunitResult test_reorder_queue_16(const MunitParameter params[], void *te pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 1337); - munit_assert_uint64((uint64_t)(size_t)user, ==, 6); + munit_assert_uint64((uint64_t)user, ==, 6); munit_assert_uint64(chiaki_reorder_queue_count(&queue), ==, 0); // same as before, but with an element in the queue that will be dropped @@ -163,7 +163,7 @@ static MunitResult test_reorder_queue_16(const MunitParameter params[], void *te pulled = chiaki_reorder_queue_pull(&queue, &seq_num, &user); munit_assert(pulled); munit_assert_uint64(seq_num, ==, 2000); - munit_assert_uint64((uint64_t)(size_t)user, ==, 8); + munit_assert_uint64((uint64_t)user, ==, 8); munit_assert_uint64(chiaki_reorder_queue_count(&queue), ==, 0); chiaki_reorder_queue_fini(&queue); @@ -182,4 +182,4 @@ MunitTest tests_reorder_queue[] = { NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } -}; +}; \ No newline at end of file diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index f6ebc40..b1f0b46 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -4,13 +4,11 @@ if(NOT CHIAKI_USE_SYSTEM_NANOPB) # nanopb ################## - add_definitions(-DPB_C99_STATIC_ASSERT) # Fix PB_STATIC_ASSERT on msvc without using C11 for now add_subdirectory(nanopb EXCLUDE_FROM_ALL) set(NANOPB_GENERATOR_PY "${CMAKE_CURRENT_SOURCE_DIR}/nanopb/generator/nanopb_generator.py" PARENT_SCOPE) add_library(nanopb INTERFACE) target_link_libraries(nanopb INTERFACE protobuf-nanopb-static) target_include_directories(nanopb INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/nanopb") - target_compile_definitions(nanopb INTERFACE -DPB_C99_STATIC_ASSERT) # see above add_library(Nanopb::nanopb ALIAS nanopb) endif() diff --git a/third-party/nanopb b/third-party/nanopb index afc499f..ae9901f 160000 --- a/third-party/nanopb +++ b/third-party/nanopb @@ -1 +1 @@ -Subproject commit afc499f9a410fc9bbf6c9c48cdd8d8b199d49eb4 +Subproject commit ae9901f2a31500e8fdc93fa9804d24851c58bb1e