mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-19 13:09:39 -07:00
Add Nintendo Switch Borealis GUI (#349)
This commit is contained in:
parent
e83cb04049
commit
f7c83e8416
34 changed files with 3470 additions and 124 deletions
12
.github/workflows/switch.yml
vendored
12
.github/workflows/switch.yml
vendored
|
@ -1,5 +1,9 @@
|
||||||
name: Switch
|
name: Switch
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -13,4 +17,8 @@ jobs:
|
||||||
git submodule update
|
git submodule update
|
||||||
- name: Build Chiaki
|
- name: Build Chiaki
|
||||||
run: scripts/switch/run-docker-build-chiaki.sh
|
run: scripts/switch/run-docker-build-chiaki.sh
|
||||||
|
- name: Upload chiaki.nro
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: chiaki.nro
|
||||||
|
path: ./build_switch/switch/chiaki.nro
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -13,3 +13,6 @@
|
||||||
[submodule "android/app/src/main/cpp/oboe"]
|
[submodule "android/app/src/main/cpp/oboe"]
|
||||||
path = android/app/src/main/cpp/oboe
|
path = android/app/src/main/cpp/oboe
|
||||||
url = https://github.com/google/oboe
|
url = https://github.com/google/oboe
|
||||||
|
[submodule "third-party/borealis"]
|
||||||
|
path = third-party/borealis
|
||||||
|
url = https://github.com/natinusala/borealis.git
|
||||||
|
|
|
@ -40,17 +40,28 @@ include(CPack)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_CURRENT_SOURCE_DIR}/setsu/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_CURRENT_SOURCE_DIR}/setsu/cmake")
|
||||||
|
|
||||||
# configure nintendo switch toolchain
|
# configure nintendo switch toolchain
|
||||||
if(CHIAKI_ENABLE_SWITCH AND CHIAKI_ENABLE_SWITCH_LINUX)
|
if(CHIAKI_ENABLE_SWITCH)
|
||||||
# CHIAKI_ENABLE_SWITCH_LINUX is a special testing version
|
# load switch.cmake toolchain form ./cmake folder
|
||||||
# the aim is to troubleshoot nitendo switch chiaki verison
|
# include(switch)
|
||||||
# from a x86 linux os
|
# to compile borealis third party
|
||||||
add_definitions(-DCHIAKI_ENABLE_SWITCH_LINUX)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
|
||||||
elseif(CHIAKI_ENABLE_SWITCH)
|
|
||||||
add_definitions(-D__SWITCH__)
|
|
||||||
# TODO check if android ... or other versions are enabled
|
# TODO check if android ... or other versions are enabled
|
||||||
# force mbedtls as crypto lib
|
# force mbedtls as crypto lib
|
||||||
set(CHIAKI_LIB_ENABLE_MBEDTLS ON)
|
set(CHIAKI_LIB_ENABLE_MBEDTLS ON)
|
||||||
|
|
||||||
|
if(CHIAKI_SWITCH_ENABLE_LINUX)
|
||||||
|
# CHIAKI_SWITCH_ENABLE_LINUX is a special testing version
|
||||||
|
# the aim is to troubleshoot nitendo switch chiaki verison
|
||||||
|
# from a x86 linux os
|
||||||
|
add_definitions(-DCHIAKI_SWITCH_ENABLE_LINUX)
|
||||||
|
add_definitions(-DBOREALIS_RESOURCES="./switch/res/")
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
add_definitions(-DDEBUG_OPENGL)
|
||||||
|
else()
|
||||||
|
add_definitions(-D__SWITCH__)
|
||||||
|
# use symbolic links to load font ..
|
||||||
|
add_definitions(-DBOREALIS_RESOURCES="romfs:/")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CHIAKI_USE_SYSTEM_JERASURE)
|
if(CHIAKI_USE_SYSTEM_JERASURE)
|
||||||
|
@ -120,6 +131,5 @@ if(CHIAKI_ENABLE_ANDROID)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CHIAKI_ENABLE_SWITCH)
|
if(CHIAKI_ENABLE_SWITCH)
|
||||||
#TODO
|
add_subdirectory(switch)
|
||||||
#add_subdirectory(switch)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
[](https://travis-ci.com/thestr4ng3r/chiaki) [](https://ci.appveyor.com/project/thestr4ng3r/chiaki) [](https://builds.sr.ht/~thestr4ng3r/chiaki?)
|
[](https://travis-ci.com/thestr4ng3r/chiaki) [](https://ci.appveyor.com/project/thestr4ng3r/chiaki) [](https://builds.sr.ht/~thestr4ng3r/chiaki?)
|
||||||
|
|
||||||
Chiaki is a Free and Open Source Software Client for PlayStation 4 Remote Play
|
Chiaki is a Free and Open Source Software Client for PlayStation 4 Remote Play
|
||||||
for Linux, FreeBSD, OpenBSD, Android, macOS, Windows and potentially even more platforms.
|
for Linux, FreeBSD, OpenBSD, Android, macOS, Windows, Nintendo Switch and potentially even more platforms.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ You can download them [here](https://github.com/thestr4ng3r/chiaki/releases).
|
||||||
* **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 GitHub.
|
* **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 GitHub.
|
||||||
* **macOS**: Drag the application from the `.dmg` into your Applications folder.
|
* **macOS**: Drag the application from the `.dmg` into your Applications folder.
|
||||||
* **Windows**: Extract the `.zip` file and execute `chiaki.exe`.
|
* **Windows**: Extract the `.zip` file and execute `chiaki.exe`.
|
||||||
|
* **Switch**: Follow README specific [instructions](./switch/README.md)
|
||||||
|
|
||||||
### Building from Source
|
### Building from Source
|
||||||
|
|
||||||
|
|
|
@ -1,116 +1,79 @@
|
||||||
# https://github.com/nxengine/nxengine-evo
|
|
||||||
|
|
||||||
# Find DEVKITPRO
|
# Find DEVKITPRO
|
||||||
if(NOT DEFINED ENV{DEVKITPRO})
|
if(NOT DEFINED ENV{DEVKITPRO} OR NOT DEFINED ENV{PORTLIBS_PREFIX})
|
||||||
message(FATAL_ERROR "You must have defined DEVKITPRO before calling cmake.")
|
message(FATAL_ERROR "Please set DEVKITPRO & PORTLIBS_PREFIX env before calling cmake. https://devkitpro.org/wiki/Getting_Started")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
set(DEVKITPRO "$ENV{DEVKITPRO}")
|
||||||
|
set(PORTLIBS_PREFIX "$ENV{PORTLIBS_PREFIX}")
|
||||||
|
|
||||||
function(switchvar cmakevar var default)
|
# include devkitpro toolchain
|
||||||
# read or set env var
|
include("${DEVKITPRO}/switch.cmake")
|
||||||
if(NOT DEFINED "ENV{$var}")
|
|
||||||
set("ENV{$var}" default)
|
|
||||||
endif()
|
|
||||||
set("$cmakevar" "ENV{$var}")
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# allow gcc -g to use
|
# Enable gcc -g, to use
|
||||||
# aarch64-none-elf-addr2line -e build_switch/switch/chiaki -f -p -C -a 0xCCB5C
|
# /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_BUILD_TYPE Debug)
|
||||||
|
# set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
# set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available" )
|
||||||
|
|
||||||
set( TOOL_OS_SUFFIX "" )
|
# FIXME rework this file to use the toolchain only
|
||||||
if( CMAKE_HOST_WIN32 )
|
# https://github.com/diasurgical/devilutionX/pull/764
|
||||||
set( TOOL_OS_SUFFIX ".exe" )
|
set(ARCH "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -ftls-model=local-exec")
|
||||||
endif()
|
# 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")
|
||||||
|
|
||||||
set(CMAKE_SYSTEM_PROCESSOR "armv8-a")
|
# add portlibs to the list of include dir
|
||||||
set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
|
include_directories("${PORTLIBS_PREFIX}/include")
|
||||||
set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
|
|
||||||
set(CMAKE_ASM_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-as${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler")
|
|
||||||
set(CMAKE_STRIP "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip")
|
|
||||||
set(CMAKE_AR "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive")
|
|
||||||
set(CMAKE_LINKER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker")
|
|
||||||
set(CMAKE_NM "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm")
|
|
||||||
set(CMAKE_OBJCOPY "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy")
|
|
||||||
set(CMAKE_OBJDUMP "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump")
|
|
||||||
set(CMAKE_RANLIB "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib")
|
|
||||||
|
|
||||||
# custom /opt/devkitpro/switchvars.sh
|
# troubleshoot
|
||||||
switchvar(PORTLIBS_PREFIX PORTLIBS_PREFIX "${DEVKITPRO}/portlibs/switch")
|
message(STATUS "CMAKE_FIND_ROOT_PATH = ${CMAKE_FIND_ROOT_PATH}")
|
||||||
switchvar(ARCH ARCH "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec")
|
message(STATUS "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}")
|
||||||
switchvar(CMAKE_C_FLAGS CFLAGS "${ARCH} -O2 -ffunction-sections -fdata-sections")
|
message(STATUS "CMAKE_EXE_LINKER_FLAGS = ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
switchvar(CMAKE_CXX_FLAGS CXXFLAGS "${CMAKE_C_FLAGS}")
|
get_property(include_directories DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
|
||||||
switchvar(CMAKE_CPP_FLAGS CPPFLAGS "-D__SWITCH__ -I${PORTLIBS_PREFIX}/include -isystem${DEVKITPRO}/libnx/include")
|
message(STATUS "INCLUDE_DIRECTORIES = ${include_directories}")
|
||||||
switchvar(CMAKE_LD_FLAGS LDFLAGS "${ARCH} -L${PORTLIBS_PREFIX}/lib -L${DEVKITPRO}/libnx/lib")
|
message(STATUS "CMAKE_C_COMPILER = ${CMAKE_C_COMPILER}")
|
||||||
switchvar(LIBS LIBS "-lnx")
|
message(STATUS "CMAKE_CXX_COMPILER = ${CMAKE_CXX_COMPILER}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# cache flags
|
|
||||||
set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" )
|
|
||||||
set( CMAKE_C_FLAGS "" CACHE STRING "c flags" )
|
|
||||||
set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" )
|
|
||||||
set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" )
|
|
||||||
set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" )
|
|
||||||
set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" )
|
|
||||||
set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" )
|
|
||||||
set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" )
|
|
||||||
set( CMAKE_EXE_LINKER_FLAGS "-mtp=soft -fPIE -L${DEVKITPRO}/portlibs/switch/lib -L${DEVKITPRO}/libnx/lib -specs=${DEVKITPRO}/libnx/switch.specs -g" CACHE STRING "executable linker flags" )
|
|
||||||
|
|
||||||
# we require the relocation table
|
|
||||||
set(CMAKE_C_FLAGS "-I/opt/devkitpro/libnx/include -D__SWITCH__ -march=armv8-a -mtune=cortex-a57 -mtp=soft -ffunction-sections -fdata-sections -fPIE")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
|
|
||||||
|
|
||||||
# switchvar(CMAKE_CXX_FLAGS CXXFLAGS "${CMAKE_C_FLAGS} -fno-rtti")
|
|
||||||
include_directories(${DEVKITPRO}/libnx/include ${PORTLIBS_PREFIX}/include)
|
|
||||||
|
|
||||||
# where is the target environment
|
|
||||||
set(CMAKE_FIND_ROOT_PATH
|
|
||||||
${DEVKITPRO}/devkitA64
|
|
||||||
${DEVKITPRO}/libnx
|
|
||||||
${DEVKITPRO}/portlibs/switch)
|
|
||||||
|
|
||||||
# only search for libraries and includes in toolchain
|
|
||||||
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
|
|
||||||
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
|
|
||||||
|
|
||||||
find_program(ELF2NRO elf2nro ${DEVKITPRO}/tools/bin)
|
find_program(ELF2NRO elf2nro ${DEVKITPRO}/tools/bin)
|
||||||
if (ELF2NRO)
|
if (ELF2NRO)
|
||||||
message(STATUS "elf2nro: ${ELF2NRO} - found")
|
message(STATUS "elf2nro: ${ELF2NRO} - found")
|
||||||
else ()
|
else()
|
||||||
message(WARNING "elf2nro - not found")
|
message(WARNING "elf2nro - not found")
|
||||||
endif ()
|
endif()
|
||||||
|
|
||||||
find_program(NACPTOOL nacptool ${DEVKITPRO}/tools/bin)
|
find_program(NACPTOOL nacptool ${DEVKITPRO}/tools/bin)
|
||||||
if (NACPTOOL)
|
if (NACPTOOL)
|
||||||
message(STATUS "nacptool: ${NACPTOOL} - found")
|
message(STATUS "nacptool: ${NACPTOOL} - found")
|
||||||
else ()
|
else()
|
||||||
message(WARNING "nacptool - not found")
|
message(WARNING "nacptool - not found")
|
||||||
endif ()
|
endif()
|
||||||
|
|
||||||
function(__add_nacp target APP_TITLE APP_AUTHOR APP_VERSION)
|
function(__add_nacp target APP_TITLE APP_AUTHOR APP_VERSION)
|
||||||
set(__NACP_COMMAND ${NACPTOOL} --create ${APP_TITLE} ${APP_AUTHOR} ${APP_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/${target})
|
set(__NACP_COMMAND ${NACPTOOL} --create ${APP_TITLE} ${APP_AUTHOR} ${APP_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/${target})
|
||||||
|
|
||||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}
|
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}
|
||||||
COMMAND ${__NACP_COMMAND}
|
COMMAND ${__NACP_COMMAND}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(add_nro_target target title author version icon romfs)
|
function(add_nro_target target title author version icon romfs)
|
||||||
get_filename_component(target_we ${target} NAME_WE)
|
get_filename_component(target_we ${target} NAME_WE)
|
||||||
if (NOT ${target_we}.nacp)
|
if(NOT ${target_we}.nacp)
|
||||||
__add_nacp(${target_we}.nacp ${title} ${author} ${version})
|
__add_nacp(${target_we}.nacp ${title} ${author} ${version})
|
||||||
endif ()
|
endif()
|
||||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro
|
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro
|
||||||
COMMAND ${ELF2NRO} $<TARGET_FILE:${target}> ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro --icon=${icon} --nacp=${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp
|
COMMAND ${ELF2NRO} $<TARGET_FILE:${target}>
|
||||||
# --romfsdir=${romfs}
|
${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro
|
||||||
DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp
|
--icon=${icon}
|
||||||
VERBATIM
|
--nacp=${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp
|
||||||
)
|
--romfsdir=${romfs}
|
||||||
add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro)
|
DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,8 +101,10 @@ target_link_libraries(chiaki-lib Threads::Threads)
|
||||||
|
|
||||||
if(CHIAKI_LIB_ENABLE_MBEDTLS)
|
if(CHIAKI_LIB_ENABLE_MBEDTLS)
|
||||||
# provided by mbedtls-static (mbedtls-devel)
|
# provided by mbedtls-static (mbedtls-devel)
|
||||||
# find_package(mbedcrypto REQUIRED)
|
find_library(MBEDTLS mbedtls)
|
||||||
target_link_libraries(chiaki-lib mbedtls mbedx509 mbedcrypto)
|
find_library(MBEDX509 mbedx509)
|
||||||
|
find_library(MBEDCRYPTO mbedcrypto)
|
||||||
|
target_link_libraries(chiaki-lib ${MBEDTLS} ${MBEDX509} ${MBEDCRYPTO})
|
||||||
elseif(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT)
|
elseif(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT)
|
||||||
target_link_libraries(chiaki-lib OpenSSL_Crypto)
|
target_link_libraries(chiaki-lib OpenSSL_Crypto)
|
||||||
else()
|
else()
|
||||||
|
@ -111,11 +113,6 @@ else()
|
||||||
target_link_libraries(chiaki-lib OpenSSL::Crypto)
|
target_link_libraries(chiaki-lib OpenSSL::Crypto)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CHIAKI_ENABLE_SWITCH AND NOT CHIAKI_ENABLE_SWITCH_LINUX)
|
|
||||||
# to provides csrngGetRandomBytes
|
|
||||||
target_link_libraries(chiaki-lib nx)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(chiaki-lib protobuf-nanopb-static)
|
target_link_libraries(chiaki-lib protobuf-nanopb-static)
|
||||||
target_link_libraries(chiaki-lib Jerasure::Jerasure)
|
target_link_libraries(chiaki-lib Jerasure::Jerasure)
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,14 @@
|
||||||
set -xveo pipefail
|
set -xveo pipefail
|
||||||
|
|
||||||
arg1=$1
|
arg1=$1
|
||||||
CHIAKI_ENABLE_SWITCH_LINUX="ON"
|
CHIAKI_SWITCH_ENABLE_LINUX="ON"
|
||||||
build="./build"
|
build="./build"
|
||||||
if [ "$arg1" != "linux" ]; then
|
if [ "$arg1" != "linux" ]; then
|
||||||
CHIAKI_ENABLE_SWITCH_LINUX="OFF"
|
CHIAKI_SWITCH_ENABLE_LINUX="OFF"
|
||||||
source /opt/devkitpro/switchvars.sh
|
# source /opt/devkitpro/switchvars.sh
|
||||||
toolchain=../cmake/switch.cmake # TODO: devkitpro ships a toolchain in /opt/devkitpro/switch.cmake, but it's broken.
|
# toolchain="${DEVKITPRO}/switch.cmake"
|
||||||
|
toolchain="cmake/switch.cmake"
|
||||||
export CC=${TOOL_PREFIX}gcc
|
export PORTLIBS_PREFIX="$(${DEVKITPRO}/portlibs_prefix.sh switch)"
|
||||||
export CXX=${TOOL_PREFIX}g++
|
|
||||||
build="./build_switch"
|
build="./build_switch"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -22,14 +21,17 @@ build_chiaki (){
|
||||||
pushd "${BASEDIR}"
|
pushd "${BASEDIR}"
|
||||||
#rm -rf ./build
|
#rm -rf ./build
|
||||||
|
|
||||||
cmake -B "${build}" -DCMAKE_TOOLCHAIN_FILE=${toolchain} \
|
cmake -B "${build}" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${toolchain} \
|
||||||
-DCHIAKI_ENABLE_TESTS=OFF \
|
-DCHIAKI_ENABLE_TESTS=OFF \
|
||||||
-DCHIAKI_ENABLE_CLI=OFF \
|
-DCHIAKI_ENABLE_CLI=OFF \
|
||||||
-DCHIAKI_ENABLE_GUI=OFF \
|
-DCHIAKI_ENABLE_GUI=OFF \
|
||||||
-DCHIAKI_ENABLE_ANDROID=OFF \
|
-DCHIAKI_ENABLE_ANDROID=OFF \
|
||||||
-DCHIAKI_ENABLE_SWITCH=ON \
|
-DCHIAKI_ENABLE_SWITCH=ON \
|
||||||
-DCHIAKI_ENABLE_SWITCH_LINUX="${CHIAKI_ENABLE_SWITCH_LINUX}" \
|
-DCHIAKI_SWITCH_ENABLE_LINUX="${CHIAKI_SWITCH_ENABLE_LINUX}" \
|
||||||
-DCHIAKI_LIB_ENABLE_MBEDTLS=ON
|
-DCHIAKI_LIB_ENABLE_MBEDTLS=ON \
|
||||||
|
# -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
|
||||||
|
# -DCMAKE_FIND_DEBUG_MODE=ON
|
||||||
|
|
||||||
pushd "${BASEDIR}/${build}"
|
pushd "${BASEDIR}/${build}"
|
||||||
make -j8
|
make -j8
|
||||||
|
|
10
scripts/switch/push-docker-build-chiaki.sh
Executable file
10
scripts/switch/push-docker-build-chiaki.sh
Executable file
|
@ -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"
|
||||||
|
|
|
@ -4,7 +4,8 @@ cd "`dirname $(readlink -f ${0})`/../.."
|
||||||
|
|
||||||
docker run \
|
docker run \
|
||||||
-v "`pwd`:/build/chiaki" \
|
-v "`pwd`:/build/chiaki" \
|
||||||
|
-w "/build/chiaki" \
|
||||||
-t \
|
-t \
|
||||||
thestr4ng3r/chiaki-build-switch \
|
thestr4ng3r/chiaki-build-switch \
|
||||||
-c "cd /build/chiaki && scripts/switch/build.sh"
|
-c "scripts/switch/build.sh"
|
||||||
|
|
||||||
|
|
46
switch/CMakeLists.txt
Normal file
46
switch/CMakeLists.txt
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
find_package(FFMPEG REQUIRED COMPONENTS avcodec avutil swscale)
|
||||||
|
find_library(SDL2 SDL2)
|
||||||
|
find_library(SWRESAMPLE swresample)
|
||||||
|
|
||||||
|
# find -type f | grep -P '\.(h|cpp)$' | sed 's#\./#\t\t#g'
|
||||||
|
add_executable(chiaki WIN32
|
||||||
|
src/discoverymanager.cpp
|
||||||
|
src/settings.cpp
|
||||||
|
src/io.cpp
|
||||||
|
src/host.cpp
|
||||||
|
src/main.cpp
|
||||||
|
src/gui.cpp)
|
||||||
|
|
||||||
|
target_include_directories(chiaki PRIVATE include)
|
||||||
|
|
||||||
|
target_link_libraries(chiaki
|
||||||
|
chiaki-lib
|
||||||
|
borealis
|
||||||
|
${SDL2}
|
||||||
|
FFMPEG::avcodec
|
||||||
|
FFMPEG::avutil
|
||||||
|
FFMPEG::swscale
|
||||||
|
${SWRESAMPLE}
|
||||||
|
${SWSCALE})
|
||||||
|
|
||||||
|
# OS links
|
||||||
|
if(CHIAKI_SWITCH_ENABLE_LINUX)
|
||||||
|
target_link_libraries(chiaki dl)
|
||||||
|
else()
|
||||||
|
# libnx is forced by the switch toolchain
|
||||||
|
find_library(Z z)
|
||||||
|
find_library(GLAPI glapi)
|
||||||
|
find_library(DRM_NOUVEAU drm_nouveau)
|
||||||
|
target_link_libraries(chiaki ${Z} ${GLAPI} ${DRM_NOUVEAU})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS chiaki
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
BUNDLE DESTINATION bin)
|
||||||
|
|
||||||
|
if(CHIAKI_ENABLE_SWITCH AND NOT CHIAKI_SWITCH_ENABLE_LINUX)
|
||||||
|
add_nro_target(chiaki "chiaki" "Chiaki team" "${CHIAKI_VERSION}" "${CMAKE_SOURCE_DIR}/switch/res/icon.jpg" "${CMAKE_SOURCE_DIR}/switch/res")
|
||||||
|
endif()
|
64
switch/README.md
Normal file
64
switch/README.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
Nintendo Switch build instructions
|
||||||
|
==================================
|
||||||
|
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-docker-build-chiaki.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
tools
|
||||||
|
-----
|
||||||
|
Push to homebrew Netloader
|
||||||
|
```
|
||||||
|
# where X.X.X.X is the IP of your switch
|
||||||
|
scripts/switch/push-docker-build-chiaki.sh 192.168.0.200
|
||||||
|
```
|
||||||
|
|
||||||
|
Troubleshoot
|
||||||
|
```
|
||||||
|
# replace 0xCCB5C with the backtrace adress (PC - Backtrace Start Address)
|
||||||
|
aarch64-none-elf-addr2line \
|
||||||
|
-e ./build_switch/switch/chiaki \
|
||||||
|
-f -p -C -a 0xCCB5C
|
||||||
|
```
|
||||||
|
|
||||||
|
Chiaki config file
|
||||||
|
------------------
|
||||||
|
The **chiaki.conf** is generated by the application.
|
||||||
|
this file contains sensitive data. (do not share this file)
|
||||||
|
```ini
|
||||||
|
# required: PS4-XXX (PS4 local name)
|
||||||
|
# name from PS4 Settings > System > system information
|
||||||
|
[PS4-XXX]
|
||||||
|
# required: lan PS4 IP address
|
||||||
|
# IP from PS4 Settings > System > system information
|
||||||
|
host_ip = X.X.X.X
|
||||||
|
# required: sony oline id (login)
|
||||||
|
psn_online_id = ps4_online_id
|
||||||
|
# required (PS4>7.0 Only): https://github.com/thestr4ng3r/chiaki#obtaining-your-psn-accountid
|
||||||
|
psn_account_id = ps4_base64_account_id
|
||||||
|
# optional(default 60): remote play fps (must be 30 or 60)
|
||||||
|
video_fps = 60
|
||||||
|
# optional(default 720p): remote play resolution (must be 720p, 540p or 360p)
|
||||||
|
video_resolution = 720p
|
||||||
|
```
|
61
switch/include/discoverymanager.h
Normal file
61
switch/include/discoverymanager.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_DISCOVERYMANAGER_H
|
||||||
|
#define CHIAKI_DISCOVERYMANAGER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
#include <chiaki/discoveryservice.h>
|
||||||
|
|
||||||
|
#include "host.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
static void Discovery(ChiakiDiscoveryHost*, void*);
|
||||||
|
|
||||||
|
class DiscoveryManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Settings * settings;
|
||||||
|
ChiakiLog * log;
|
||||||
|
ChiakiDiscoveryService service;
|
||||||
|
ChiakiDiscovery discovery;
|
||||||
|
struct sockaddr * host_addr;
|
||||||
|
size_t host_addr_len;
|
||||||
|
uint32_t GetIPv4BroadcastAddr();
|
||||||
|
bool service_enable;
|
||||||
|
public:
|
||||||
|
typedef enum hoststate
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
READY,
|
||||||
|
STANDBY,
|
||||||
|
SHUTDOWN,
|
||||||
|
} HostState;
|
||||||
|
|
||||||
|
DiscoveryManager(Settings *settings);
|
||||||
|
~DiscoveryManager();
|
||||||
|
void SetService(bool);
|
||||||
|
int Send();
|
||||||
|
int Send(struct sockaddr *host_addr, size_t host_addr_len);
|
||||||
|
int Send(const char *);
|
||||||
|
void DiscoveryCB(ChiakiDiscoveryHost*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //CHIAKI_DISCOVERYMANAGER_H
|
35
switch/include/exception.h
Normal file
35
switch/include/exception.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_EXCEPTION_H
|
||||||
|
#define CHIAKI_EXCEPTION_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Exception : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const char *msg;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Exception(const char *msg) : msg(msg) {}
|
||||||
|
const char *what() const noexcept override { return msg; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHIAKI_EXCEPTION_H
|
102
switch/include/gui.h
Normal file
102
switch/include/gui.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_GUI_H
|
||||||
|
#define CHIAKI_GUI_H
|
||||||
|
|
||||||
|
#include <glad.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include "nanovg.h"
|
||||||
|
#include "nanovg_gl.h"
|
||||||
|
#include "nanovg_gl_utils.h"
|
||||||
|
|
||||||
|
#include <borealis.hpp>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "host.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "discoverymanager.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
class HostInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
brls::TabFrame * root;
|
||||||
|
IO * io;
|
||||||
|
Host * host;
|
||||||
|
Settings * settings;
|
||||||
|
brls::List * hostList;
|
||||||
|
bool connected = false;
|
||||||
|
public:
|
||||||
|
HostInterface(brls::List * hostList, IO * io, Host * host, Settings * settings);
|
||||||
|
~HostInterface();
|
||||||
|
|
||||||
|
void Register(bool pin_incorrect);
|
||||||
|
void Wakeup(brls::View * view);
|
||||||
|
void Connect(brls::View * view);
|
||||||
|
void ConnectSession();
|
||||||
|
void Disconnect();
|
||||||
|
bool Stream();
|
||||||
|
bool CloseStream(ChiakiQuitEvent * quit);
|
||||||
|
};
|
||||||
|
|
||||||
|
class MainApplication
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ChiakiLog * log;
|
||||||
|
std::map<std::string, Host> * hosts;
|
||||||
|
Settings * settings;
|
||||||
|
DiscoveryManager * discoverymanager;
|
||||||
|
IO * io;
|
||||||
|
brls::TabFrame * rootFrame;
|
||||||
|
std::map<Host *, brls::List *> host_menuitems;
|
||||||
|
bool BuildConfigurationMenu(brls::List *, Host * host = nullptr);
|
||||||
|
public:
|
||||||
|
MainApplication(std::map<std::string, Host> * hosts,
|
||||||
|
Settings * settings, DiscoveryManager * discoverymanager,
|
||||||
|
IO * io, ChiakiLog * log);
|
||||||
|
|
||||||
|
~MainApplication();
|
||||||
|
bool Load();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PS4RemotePlay : public brls::View
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
brls::AppletFrame * frame;
|
||||||
|
// to display stream on screen
|
||||||
|
IO * io;
|
||||||
|
// 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:
|
||||||
|
PS4RemotePlay(IO * io, Host * host);
|
||||||
|
~PS4RemotePlay();
|
||||||
|
|
||||||
|
void draw(NVGcontext * vg, int x, int y, unsigned width, unsigned height, brls::Style * style, brls::FrameContext * ctx) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHIAKI_GUI_H
|
||||||
|
|
129
switch/include/host.h
Normal file
129
switch/include/host.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_HOST_H
|
||||||
|
#define CHIAKI_HOST_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
#include <chiaki/regist.h>
|
||||||
|
#include <chiaki/discovery.h>
|
||||||
|
#include <chiaki/opusdecoder.h>
|
||||||
|
#include <chiaki/controller.h>
|
||||||
|
|
||||||
|
#include "exception.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
class DiscoveryManager;
|
||||||
|
static void Discovery(ChiakiDiscoveryHost*, void *);
|
||||||
|
static void InitAudioCB(unsigned int channels, unsigned int rate, void * user);
|
||||||
|
static bool VideoCB(uint8_t * buf, size_t buf_size, void * user);
|
||||||
|
static void AudioCB(int16_t * buf, size_t samples_count, void * user);
|
||||||
|
static void RegistEventCB(ChiakiRegistEvent * event, void * user);
|
||||||
|
static void EventCB(ChiakiEvent * event, void * user);
|
||||||
|
|
||||||
|
enum RegistError
|
||||||
|
{
|
||||||
|
HOST_REGISTER_OK,
|
||||||
|
HOST_REGISTER_ERROR_SETTING_PSNACCOUNTID,
|
||||||
|
HOST_REGISTER_ERROR_SETTING_PSNONLINEID
|
||||||
|
};
|
||||||
|
|
||||||
|
class Settings;
|
||||||
|
|
||||||
|
class Host
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ChiakiLog * log = nullptr;
|
||||||
|
Settings * settings = nullptr;
|
||||||
|
//video config
|
||||||
|
ChiakiVideoResolutionPreset video_resolution = CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
ChiakiVideoFPSPreset video_fps = CHIAKI_VIDEO_FPS_PRESET_60;
|
||||||
|
// info from discovery manager
|
||||||
|
int device_discovery_protocol_version = 0;
|
||||||
|
std::string host_type;
|
||||||
|
// user info
|
||||||
|
std::string psn_online_id = "";
|
||||||
|
std::string psn_account_id = "";
|
||||||
|
// info from regist/settings
|
||||||
|
ChiakiRegist regist = {};
|
||||||
|
ChiakiRegistInfo regist_info = {};
|
||||||
|
std::function<void()> chiaki_regist_event_type_finished_canceled = nullptr;
|
||||||
|
std::function<void()> chiaki_regist_event_type_finished_failed = nullptr;
|
||||||
|
std::function<void()> chiaki_regist_event_type_finished_success = nullptr;
|
||||||
|
|
||||||
|
std::string ap_ssid;
|
||||||
|
std::string ap_bssid;
|
||||||
|
std::string ap_key;
|
||||||
|
std::string ap_name;
|
||||||
|
std::string ps4_nickname;
|
||||||
|
// mac address = 48 bits
|
||||||
|
uint8_t ps4_mac[6] = {0};
|
||||||
|
char rp_regist_key[CHIAKI_SESSION_AUTH_SIZE] = {0};
|
||||||
|
uint32_t rp_key_type = 0;
|
||||||
|
uint8_t rp_key[0x10] = {0};
|
||||||
|
// manage stream session
|
||||||
|
bool session_init = false;
|
||||||
|
ChiakiSession session;
|
||||||
|
ChiakiOpusDecoder opus_decoder;
|
||||||
|
ChiakiConnectVideoProfile video_profile;
|
||||||
|
ChiakiControllerState keyboard_state;
|
||||||
|
friend class DiscoveryManager;
|
||||||
|
friend class Settings;
|
||||||
|
public:
|
||||||
|
// internal state
|
||||||
|
ChiakiDiscoveryHostState state = CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN;
|
||||||
|
bool discovered = false;
|
||||||
|
bool registered = false;
|
||||||
|
// rp_key_data is true when rp_key, rp_regist_key, rp_key_type
|
||||||
|
bool rp_key_data = false;
|
||||||
|
std::string host_name;
|
||||||
|
int system_version = 0;
|
||||||
|
// sony's host_id == mac addr without colon
|
||||||
|
std::string host_id;
|
||||||
|
std::string host_addr;
|
||||||
|
Host(ChiakiLog * log, Settings * settings, std::string host_name);
|
||||||
|
~Host();
|
||||||
|
bool GetVideoResolution(int * ret_width, int * ret_height);
|
||||||
|
int Register(std::string pin);
|
||||||
|
int Wakeup();
|
||||||
|
int InitSession(IO *);
|
||||||
|
int FiniSession();
|
||||||
|
void StopSession();
|
||||||
|
void StartSession();
|
||||||
|
void SendFeedbackState(ChiakiControllerState*);
|
||||||
|
void RegistCB(ChiakiRegistEvent *);
|
||||||
|
|
||||||
|
void SetRegistEventTypeFinishedCanceled(std::function<void()> chiaki_regist_event_type_finished_canceled)
|
||||||
|
{
|
||||||
|
this->chiaki_regist_event_type_finished_canceled = chiaki_regist_event_type_finished_canceled;
|
||||||
|
};
|
||||||
|
void SetRegistEventTypeFinishedFailed(std::function<void()> chiaki_regist_event_type_finished_failed)
|
||||||
|
{
|
||||||
|
this->chiaki_regist_event_type_finished_failed = chiaki_regist_event_type_finished_failed;
|
||||||
|
};
|
||||||
|
void SetRegistEventTypeFinishedSuccess(std::function<void()> chiaki_regist_event_type_finished_success)
|
||||||
|
{
|
||||||
|
this->chiaki_regist_event_type_finished_success = chiaki_regist_event_type_finished_success;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
136
switch/include/io.h
Normal file
136
switch/include/io.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_IO_H
|
||||||
|
#define CHIAKI_IO_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include <glad.h> // glad library (OpenGL loader)
|
||||||
|
|
||||||
|
#include <chiaki/session.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://github.com/devkitPro/switch-glad/blob/master/include/glad/glad.h
|
||||||
|
https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.3&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_filter_anisotropic
|
||||||
|
|
||||||
|
Language/Generator: C/C++
|
||||||
|
Specification: gl
|
||||||
|
APIs: gl=4.3
|
||||||
|
Profile: core
|
||||||
|
Extensions:
|
||||||
|
GL_EXT_texture_compression_s3tc,
|
||||||
|
GL_EXT_texture_filter_anisotropic
|
||||||
|
Loader: False
|
||||||
|
Local files: False
|
||||||
|
Omit khrplatform: False
|
||||||
|
Reproducible: False
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
#include <chiaki/controller.h>
|
||||||
|
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
#define PLANES_COUNT 3
|
||||||
|
#define SDL_JOYSTICK_COUNT 2
|
||||||
|
|
||||||
|
class IO
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ChiakiLog * log;
|
||||||
|
int video_width;
|
||||||
|
int video_height;
|
||||||
|
bool quit = false;
|
||||||
|
// opengl reader writer
|
||||||
|
std::mutex mtx;
|
||||||
|
// default nintendo switch res
|
||||||
|
int screen_width = 1280;
|
||||||
|
int screen_height = 720;
|
||||||
|
std::function<bool()> chiaki_event_connected_cb = nullptr;
|
||||||
|
std::function<bool(bool)> chiaki_even_login_pin_request_cb = nullptr;
|
||||||
|
std::function<bool(ChiakiQuitEvent *)> chiaki_event_quit_cb = nullptr;
|
||||||
|
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};
|
||||||
|
GLuint vao;
|
||||||
|
GLuint vbo;
|
||||||
|
GLuint tex[PLANES_COUNT];
|
||||||
|
GLuint pbo[PLANES_COUNT];
|
||||||
|
GLuint vert;
|
||||||
|
GLuint frag;
|
||||||
|
GLuint prog;
|
||||||
|
private:
|
||||||
|
bool InitAVCodec();
|
||||||
|
bool InitOpenGl();
|
||||||
|
bool InitOpenGlTextures();
|
||||||
|
bool InitOpenGlShader();
|
||||||
|
void OpenGlDraw();
|
||||||
|
#ifdef DEBUG_OPENGL
|
||||||
|
void CheckGLError(const char * func, const char * file, int line);
|
||||||
|
void DumpShaderError(GLuint prog, const char * func, const char * file, int line);
|
||||||
|
void DumpProgramError(GLuint prog, const char * func, const char * file, int line);
|
||||||
|
#endif
|
||||||
|
GLuint CreateAndCompileShader(GLenum type, const char * source);
|
||||||
|
void SetOpenGlYUVPixels(AVFrame * frame);
|
||||||
|
bool ReadGameKeys(SDL_Event * event, ChiakiControllerState * state);
|
||||||
|
bool ReadGameTouchScreen(ChiakiControllerState * state);
|
||||||
|
public:
|
||||||
|
IO(ChiakiLog * log);
|
||||||
|
~IO();
|
||||||
|
void SetMesaConfig();
|
||||||
|
bool VideoCB(uint8_t * buf, size_t buf_size);
|
||||||
|
void SetEventConnectedCallback(std::function<bool()> chiaki_event_connected_cb)
|
||||||
|
{
|
||||||
|
this->chiaki_event_connected_cb = chiaki_event_connected_cb;
|
||||||
|
};
|
||||||
|
void SetEventLoginPinRequestCallback(std::function<bool(bool)> chiaki_even_login_pin_request_cb)
|
||||||
|
{
|
||||||
|
this->chiaki_even_login_pin_request_cb = chiaki_even_login_pin_request_cb;
|
||||||
|
};
|
||||||
|
void SetEventQuitCallback(std::function<bool(ChiakiQuitEvent *)> chiaki_event_quit_cb)
|
||||||
|
{
|
||||||
|
this->chiaki_event_quit_cb = chiaki_event_quit_cb;
|
||||||
|
};
|
||||||
|
void InitAudioCB(unsigned int channels, unsigned int rate);
|
||||||
|
void AudioCB(int16_t * buf, size_t samples_count);
|
||||||
|
void EventCB(ChiakiEvent *event);
|
||||||
|
bool InitVideo(int video_width, int video_height, int screen_width, int screen_height);
|
||||||
|
bool FreeVideo();
|
||||||
|
bool InitJoystick();
|
||||||
|
bool FreeJoystick();
|
||||||
|
bool ReadUserKeyboard(char * buffer, size_t buffer_size);
|
||||||
|
bool MainLoop(ChiakiControllerState * state);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //CHIAKI_IO_H
|
||||||
|
|
||||||
|
|
105
switch/include/settings.h
Normal file
105
switch/include/settings.h
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHIAKI_SETTINGS_H
|
||||||
|
#define CHIAKI_SETTINGS_H
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "host.h"
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
|
||||||
|
// mutual host and settings
|
||||||
|
class Host;
|
||||||
|
|
||||||
|
class Settings
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ChiakiLog * log;
|
||||||
|
const char * filename = "chiaki.conf";
|
||||||
|
|
||||||
|
std::map<std::string, Host> *hosts;
|
||||||
|
// global_settings from psedo INI file
|
||||||
|
ChiakiVideoResolutionPreset global_video_resolution = CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
ChiakiVideoFPSPreset global_video_fps = CHIAKI_VIDEO_FPS_PRESET_60;
|
||||||
|
std::string global_psn_online_id = "";
|
||||||
|
std::string global_psn_account_id = "";
|
||||||
|
|
||||||
|
typedef enum configurationitem
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
HOST_NAME,
|
||||||
|
HOST_IP,
|
||||||
|
PSN_ONLINE_ID,
|
||||||
|
PSN_ACCOUNT_ID,
|
||||||
|
RP_KEY,
|
||||||
|
RP_KEY_TYPE,
|
||||||
|
RP_REGIST_KEY,
|
||||||
|
VIDEO_RESOLUTION,
|
||||||
|
VIDEO_FPS,
|
||||||
|
} ConfigurationItem;
|
||||||
|
|
||||||
|
// dummy parser implementation
|
||||||
|
// the aim is not to have bulletproof parser
|
||||||
|
// the goal is to read/write inernal flat configuration file
|
||||||
|
const std::map<Settings::ConfigurationItem, std::regex> re_map = {
|
||||||
|
{ HOST_NAME, std::regex("^\\[\\s*(.+)\\s*\\]") },
|
||||||
|
{ HOST_IP, std::regex("^\\s*host_ip\\s*=\\s*\"?(\\d+\\.\\d+\\.\\d+\\.\\d+)\"?") },
|
||||||
|
{ 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)\"?") },
|
||||||
|
{ RP_REGIST_KEY, std::regex("^\\s*rp_regist_key\\s*=\\s*\"?([\\w/=+]+)\"?") },
|
||||||
|
{ VIDEO_RESOLUTION, std::regex("^\\s*video_resolution\\s*=\\s*\"?(1080p|720p|540p|360p)\"?") },
|
||||||
|
{ VIDEO_FPS, std::regex("^\\s*video_fps\\s*=\\s*\"?(60|30)\"?") },
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigurationItem ParseLine(std::string * line, std::string * value);
|
||||||
|
size_t GetB64encodeSize(size_t);
|
||||||
|
public:
|
||||||
|
Settings(ChiakiLog * log, std::map<std::string, Host> * hosts): log(log), hosts(hosts){};
|
||||||
|
Host * GetOrCreateHost(std::string * host_name);
|
||||||
|
ChiakiLog* GetLogger();
|
||||||
|
std::string GetPSNOnlineID(Host * host);
|
||||||
|
std::string GetPSNAccountID(Host * host);
|
||||||
|
void SetPSNOnlineID(Host * host, std::string psn_online_id);
|
||||||
|
void SetPSNAccountID(Host * host, std::string psn_account_id);
|
||||||
|
ChiakiVideoResolutionPreset GetVideoResolution(Host * host);
|
||||||
|
ChiakiVideoFPSPreset GetVideoFPS(Host * host);
|
||||||
|
std::string ResolutionPresetToString(ChiakiVideoResolutionPreset resolution);
|
||||||
|
std::string FPSPresetToString(ChiakiVideoFPSPreset fps);
|
||||||
|
ChiakiVideoResolutionPreset StringToResolutionPreset(std::string value);
|
||||||
|
ChiakiVideoFPSPreset StringToFPSPreset(std::string value);
|
||||||
|
int ResolutionPresetToInt(ChiakiVideoResolutionPreset resolution);
|
||||||
|
int FPSPresetToInt(ChiakiVideoFPSPreset fps);
|
||||||
|
void SetVideoResolution(Host * host, ChiakiVideoResolutionPreset value);
|
||||||
|
void SetVideoFPS(Host * host, ChiakiVideoFPSPreset value);
|
||||||
|
void SetVideoResolution(Host * host, std::string value);
|
||||||
|
void SetVideoFPS(Host * host, std::string value);
|
||||||
|
std::string GetHostIPAddr(Host * host);
|
||||||
|
std::string GetHostName(Host * host);
|
||||||
|
bool SetHostRPKeyType(Host * host, std::string value);
|
||||||
|
int GetHostRPKeyType(Host * host);
|
||||||
|
std::string GetHostRPKey(Host * host);
|
||||||
|
std::string GetHostRPRegistKey(Host * host);
|
||||||
|
bool SetHostRPKey(Host * host, std::string rp_key_b64);
|
||||||
|
bool SetHostRPRegistKey(Host * host, std::string rp_regist_key_b64);
|
||||||
|
void ParseFile();
|
||||||
|
int WriteFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHIAKI_SETTINGS_H
|
1
switch/res/add-24px.svg
Symbolic link
1
switch/res/add-24px.svg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../gui/res/add-24px.svg
|
1
switch/res/console.svg
Symbolic link
1
switch/res/console.svg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../assets/console.svg
|
1
switch/res/discover-24px.svg
Symbolic link
1
switch/res/discover-24px.svg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../gui/res/discover-24px.svg
|
1
switch/res/discover-off-24px.svg
Symbolic link
1
switch/res/discover-off-24px.svg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../gui/res/discover-off-24px.svg
|
1
switch/res/i18n/en-US
Symbolic link
1
switch/res/i18n/en-US
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../../third-party/borealis/resources/i18n/en-US
|
BIN
switch/res/icon.jpg
Normal file
BIN
switch/res/icon.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
1
switch/res/inter
Symbolic link
1
switch/res/inter
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../third-party/borealis/resources/inter
|
1
switch/res/material
Symbolic link
1
switch/res/material
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../third-party/borealis/resources/material
|
1
switch/res/settings-20px.svg
Symbolic link
1
switch/res/settings-20px.svg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../gui/res/settings-20px.svg
|
259
switch/src/discoverymanager.cpp
Normal file
259
switch/src/discoverymanager.cpp
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
#include <switch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <discoverymanager.h>
|
||||||
|
|
||||||
|
#define PING_MS 500
|
||||||
|
#define HOSTS_MAX 16
|
||||||
|
#define DROP_PINGS 3
|
||||||
|
|
||||||
|
static void Discovery(ChiakiDiscoveryHost * discovered_hosts, size_t hosts_count, void * user)
|
||||||
|
{
|
||||||
|
DiscoveryManager * dm = (DiscoveryManager *) user;
|
||||||
|
for(size_t i=0; i < hosts_count; i++)
|
||||||
|
{
|
||||||
|
dm->DiscoveryCB(discovered_hosts+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DiscoveryManager::DiscoveryManager(Settings *settings)
|
||||||
|
: settings(settings), host_addr(nullptr), host_addr_len(0)
|
||||||
|
{
|
||||||
|
this->log = this->settings->GetLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if(enable)
|
||||||
|
{
|
||||||
|
ChiakiDiscoveryServiceOptions options;
|
||||||
|
options.ping_ms = PING_MS;
|
||||||
|
options.hosts_max = HOSTS_MAX;
|
||||||
|
options.host_drop_pings = DROP_PINGS;
|
||||||
|
options.cb = Discovery;
|
||||||
|
options.cb_user = this;
|
||||||
|
|
||||||
|
sockaddr_in addr = {};
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(CHIAKI_DISCOVERY_PORT);
|
||||||
|
addr.sin_addr.s_addr = GetIPv4BroadcastAddr();
|
||||||
|
options.send_addr = reinterpret_cast<sockaddr *>(&addr);
|
||||||
|
options.send_addr_size = sizeof(addr);
|
||||||
|
|
||||||
|
ChiakiErrorCode err = chiaki_discovery_service_init(&this->service, &options, log);
|
||||||
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
this->service_enable = false;
|
||||||
|
CHIAKI_LOGE(this->log, "DiscoveryManager failed to init Discovery Service");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chiaki_discovery_service_fini(&this->service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DiscoveryManager::GetIPv4BroadcastAddr()
|
||||||
|
{
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
uint32_t current_addr, subnet_mask;
|
||||||
|
// init nintendo net interface service
|
||||||
|
Result rc = nifmInitialize(NifmServiceType_User);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
// read current IP and netmask
|
||||||
|
rc = nifmGetCurrentIpConfigInfo(
|
||||||
|
¤t_addr, &subnet_mask,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
nifmExit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to get nintendo nifmGetCurrentIpConfigInfo");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return current_addr | (~subnet_mask);
|
||||||
|
#else
|
||||||
|
return 0xffffffff;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int DiscoveryManager::Send(struct sockaddr *host_addr, size_t host_addr_len)
|
||||||
|
{
|
||||||
|
if(!host_addr)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(log, "Null sockaddr");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
((struct sockaddr_in *)host_addr)->sin_port = htons(CHIAKI_DISCOVERY_PORT);
|
||||||
|
|
||||||
|
ChiakiDiscoveryPacket packet;
|
||||||
|
memset(&packet, 0, sizeof(packet));
|
||||||
|
packet.cmd = CHIAKI_DISCOVERY_CMD_SRCH;
|
||||||
|
|
||||||
|
chiaki_discovery_send(&this->discovery, &packet, this->host_addr, this->host_addr_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DiscoveryManager::Send(const char * discover_ip_dest)
|
||||||
|
{
|
||||||
|
struct addrinfo * host_addrinfos;
|
||||||
|
int r = getaddrinfo(discover_ip_dest, NULL, NULL, &host_addrinfos);
|
||||||
|
if(r != 0)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(log, "getaddrinfo failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr * host_addr = nullptr;
|
||||||
|
socklen_t host_addr_len = 0;
|
||||||
|
|
||||||
|
for(struct addrinfo *ai=host_addrinfos; ai; ai=ai->ai_next)
|
||||||
|
{
|
||||||
|
if(ai->ai_protocol != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
if(ai->ai_family != AF_INET) // TODO: IPv6
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this->host_addr_len = ai->ai_addrlen;
|
||||||
|
this->host_addr = (struct sockaddr *)malloc(host_addr_len);
|
||||||
|
if(!this->host_addr)
|
||||||
|
break;
|
||||||
|
memcpy(this->host_addr, ai->ai_addr, this->host_addr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(host_addrinfos);
|
||||||
|
|
||||||
|
if(!this->host_addr)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(log, "Failed to get addr for hostname");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return DiscoveryManager::Send(this->host_addr, this->host_addr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DiscoveryManager::Send()
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = GetIPv4BroadcastAddr();
|
||||||
|
addr.sin_port = htons(CHIAKI_DISCOVERY_PORT);
|
||||||
|
|
||||||
|
this->host_addr_len = sizeof(sockaddr_in);
|
||||||
|
this->host_addr = (struct sockaddr *)malloc(host_addr_len);
|
||||||
|
memcpy(this->host_addr, &addr, this->host_addr_len);
|
||||||
|
|
||||||
|
return DiscoveryManager::Send(this->host_addr, this->host_addr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
CHIAKI_LOGI(this->log, "--");
|
||||||
|
CHIAKI_LOGI(this->log, "Discovered Host:");
|
||||||
|
CHIAKI_LOGI(this->log, "State: %s", chiaki_discovery_host_state_string(discovered_host->state));
|
||||||
|
/*
|
||||||
|
host attr
|
||||||
|
uint32_t host_addr;
|
||||||
|
int system_version;
|
||||||
|
int device_discovery_protocol_version;
|
||||||
|
std::string host_name;
|
||||||
|
std::string host_type;
|
||||||
|
std::string host_id;
|
||||||
|
*/
|
||||||
|
host->state = discovered_host->state;
|
||||||
|
|
||||||
|
// add host ptr to list
|
||||||
|
if(discovered_host->system_version)
|
||||||
|
{
|
||||||
|
// example: 07020001
|
||||||
|
host->system_version = atoi(discovered_host->system_version);
|
||||||
|
CHIAKI_LOGI(this->log, "System Version: %s", discovered_host->system_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(discovered_host->device_discovery_protocol_version)
|
||||||
|
{
|
||||||
|
host->device_discovery_protocol_version = atoi(discovered_host->device_discovery_protocol_version);
|
||||||
|
CHIAKI_LOGI(this->log, "Device Discovery Protocol Version: %s", discovered_host->device_discovery_protocol_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(discovered_host->host_request_port)
|
||||||
|
CHIAKI_LOGI(this->log, "Request Port: %hu", (unsigned short)discovered_host->host_request_port);
|
||||||
|
|
||||||
|
if(discovered_host->host_addr)
|
||||||
|
{
|
||||||
|
host->host_addr = discovered_host->host_addr;
|
||||||
|
CHIAKI_LOGI(this->log, "Host Addr: %s", discovered_host->host_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(discovered_host->host_name)
|
||||||
|
{
|
||||||
|
host->host_name = discovered_host->host_name;
|
||||||
|
CHIAKI_LOGI(this->log, "Host Name: %s", discovered_host->host_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(discovered_host->host_type)
|
||||||
|
CHIAKI_LOGI(this->log, "Host Type: %s", discovered_host->host_type);
|
||||||
|
|
||||||
|
if(discovered_host->host_id)
|
||||||
|
CHIAKI_LOGI(this->log, "Host ID: %s", discovered_host->host_id);
|
||||||
|
|
||||||
|
if(discovered_host->running_app_titleid)
|
||||||
|
CHIAKI_LOGI(this->log, "Running App Title ID: %s", discovered_host->running_app_titleid);
|
||||||
|
|
||||||
|
if(discovered_host->running_app_name)
|
||||||
|
CHIAKI_LOGI(this->log, "Running App Name: %s", discovered_host->running_app_name);
|
||||||
|
|
||||||
|
CHIAKI_LOGI(this->log, "--");
|
||||||
|
}
|
||||||
|
|
514
switch/src/gui.cpp
Normal file
514
switch/src/gui.cpp
Normal file
|
@ -0,0 +1,514 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
#define SCREEN_W 1280
|
||||||
|
#define SCREEN_H 720
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
using namespace brls::i18n::literals; // for _i18n
|
||||||
|
|
||||||
|
#define DIALOG(dialog, r) \
|
||||||
|
brls::Dialog* d_##dialog = new brls::Dialog(r); \
|
||||||
|
brls::GenericEvent::Callback cb_##dialog = [d_##dialog](brls::View* view) \
|
||||||
|
{ \
|
||||||
|
d_##dialog->close(); \
|
||||||
|
}; \
|
||||||
|
d_##dialog->addButton("Ok", cb_##dialog); \
|
||||||
|
d_##dialog->setCancelable(false); \
|
||||||
|
d_##dialog->open(); \
|
||||||
|
brls::Logger::info("Dialog: {0}", r);
|
||||||
|
|
||||||
|
|
||||||
|
HostInterface::HostInterface(brls::List * hostList, IO * io, Host * host, Settings * settings)
|
||||||
|
: hostList(hostList), io(io), host(host), settings(settings)
|
||||||
|
{
|
||||||
|
brls::ListItem* connect = new brls::ListItem("Connect");
|
||||||
|
connect->getClickEvent()->subscribe(std::bind(&HostInterface::Connect, this, std::placeholders::_1));
|
||||||
|
this->hostList->addView(connect);
|
||||||
|
|
||||||
|
brls::ListItem* wakeup = new brls::ListItem("Wakeup");
|
||||||
|
wakeup->getClickEvent()->subscribe(std::bind(&HostInterface::Wakeup, this, std::placeholders::_1));
|
||||||
|
this->hostList->addView(wakeup);
|
||||||
|
|
||||||
|
// message delimiter
|
||||||
|
brls::Label* info = new brls::Label(brls::LabelStyle::REGULAR,
|
||||||
|
"Host configuration", true);
|
||||||
|
this->hostList->addView(info);
|
||||||
|
|
||||||
|
// push opengl chiaki stream
|
||||||
|
// when the host is connected
|
||||||
|
this->io->SetEventConnectedCallback(std::bind(&HostInterface::Stream, this));
|
||||||
|
this->io->SetEventQuitCallback(std::bind(&HostInterface::CloseStream, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
HostInterface::~HostInterface()
|
||||||
|
{
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostInterface::Register(bool pin_incorrect)
|
||||||
|
{
|
||||||
|
if(pin_incorrect)
|
||||||
|
{
|
||||||
|
DIALOG(srfpvyps, "Session Registration Failed, Please verify your PS4 settings");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the host is not registered yet
|
||||||
|
brls::Dialog* peprpc = new brls::Dialog("Please enter your PS4 registration PIN code");
|
||||||
|
brls::GenericEvent::Callback cb_peprpc = [this, 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 = this->io->ReadUserKeyboard(pin_input, sizeof(pin_input));
|
||||||
|
if(pin_provided)
|
||||||
|
{
|
||||||
|
// prevent users form messing with the gui
|
||||||
|
brls::Application::blockInputs();
|
||||||
|
int ret = this->host->Register(pin_input);
|
||||||
|
if(ret != HOST_REGISTER_OK)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
peprpc->addButton("Ok", cb_peprpc);
|
||||||
|
peprpc->setCancelable(false);
|
||||||
|
peprpc->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostInterface::Wakeup(brls::View * view)
|
||||||
|
{
|
||||||
|
if(!this->host->rp_key_data)
|
||||||
|
{
|
||||||
|
// the host is not registered yet
|
||||||
|
DIALOG(prypf, "Please register your PS4 first");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int r = host->Wakeup();
|
||||||
|
if(r == 0)
|
||||||
|
{
|
||||||
|
brls::Application::notify("PS4 Wakeup packet sent");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
brls::Application::notify("PS4 Wakeup packet failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostInterface::Connect(brls::View * view)
|
||||||
|
{
|
||||||
|
// check that all requirements are met
|
||||||
|
if(this->host->state != CHIAKI_DISCOVERY_HOST_STATE_READY)
|
||||||
|
{
|
||||||
|
// host in standby mode
|
||||||
|
DIALOG(ptoyp, "Please turn on your PS4");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this->host->rp_key_data)
|
||||||
|
{
|
||||||
|
// user must provide psn id for registration
|
||||||
|
std::string account_id = this->settings->GetPSNAccountID(this->host);
|
||||||
|
std::string online_id = this->settings->GetPSNOnlineID(this->host);
|
||||||
|
if(this->host->system_version >= 7000000 && account_id.length() <= 0)
|
||||||
|
{
|
||||||
|
// PS4 firmware > 7.0
|
||||||
|
DIALOG(upaid, "Undefined PSN Account ID (Please configure a valid psn_account_id)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if( this->host->system_version < 7000000 && this->host->system_version > 0 && online_id.length() <= 0)
|
||||||
|
{
|
||||||
|
// use oline ID for ps4 < 7.0
|
||||||
|
DIALOG(upoid, "Undefined PSN Online ID (Please configure a valid psn_online_id)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add HostConnected function to regist_event_type_finished_success
|
||||||
|
auto event_type_finished_success_cb = [this]()
|
||||||
|
{
|
||||||
|
// save RP keys
|
||||||
|
this->settings->WriteFile();
|
||||||
|
// FIXME: may raise a connection refused
|
||||||
|
// when the connection is triggered
|
||||||
|
// just after the register success
|
||||||
|
sleep(2);
|
||||||
|
ConnectSession();
|
||||||
|
// decrement block input token number
|
||||||
|
brls::Application::unblockInputs();
|
||||||
|
};
|
||||||
|
this->host->SetRegistEventTypeFinishedSuccess(event_type_finished_success_cb);
|
||||||
|
|
||||||
|
auto event_type_finished_failed_cb = [this]()
|
||||||
|
{
|
||||||
|
// unlock user inputs
|
||||||
|
brls::Application::unblockInputs();
|
||||||
|
brls::Application::notify("Registration failed");
|
||||||
|
};
|
||||||
|
this->host->SetRegistEventTypeFinishedFailed(event_type_finished_failed_cb);
|
||||||
|
|
||||||
|
this->Register(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the host is already registered
|
||||||
|
// start session directly
|
||||||
|
ConnectSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostInterface::ConnectSession()
|
||||||
|
{
|
||||||
|
// ignore all user inputs (avoid double connect)
|
||||||
|
// user inputs are restored with the CloseStream
|
||||||
|
brls::Application::blockInputs();
|
||||||
|
|
||||||
|
// connect host sesssion
|
||||||
|
this->host->InitSession(this->io);
|
||||||
|
this->host->StartSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostInterface::Disconnect()
|
||||||
|
{
|
||||||
|
if(this->connected)
|
||||||
|
{
|
||||||
|
brls::Application::popView();
|
||||||
|
this->host->StopSession();
|
||||||
|
this->connected = false;
|
||||||
|
}
|
||||||
|
this->host->FiniSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostInterface::Stream()
|
||||||
|
{
|
||||||
|
this->connected = true;
|
||||||
|
// https://github.com/natinusala/borealis/issues/59
|
||||||
|
// disable 60 fps limit
|
||||||
|
brls::Application::setMaximumFPS(0);
|
||||||
|
|
||||||
|
// show FPS counter
|
||||||
|
// brls::Application::setDisplayFramerate(true);
|
||||||
|
|
||||||
|
// push raw opengl stream over borealis
|
||||||
|
brls::Application::pushView(new PS4RemotePlay(this->io, this->host));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HostInterface::CloseStream(ChiakiQuitEvent * quit)
|
||||||
|
{
|
||||||
|
// session QUIT call back
|
||||||
|
brls::Application::unblockInputs();
|
||||||
|
|
||||||
|
// restore 60 fps limit
|
||||||
|
brls::Application::setMaximumFPS(60);
|
||||||
|
|
||||||
|
// brls::Application::setDisplayFramerate(false);
|
||||||
|
/*
|
||||||
|
DIALOG(sqrs, chiaki_quit_reason_string(quit->reason));
|
||||||
|
*/
|
||||||
|
brls::Application::notify(chiaki_quit_reason_string(quit->reason));
|
||||||
|
Disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainApplication::MainApplication(std::map<std::string, Host> * hosts,
|
||||||
|
Settings * settings, DiscoveryManager * discoverymanager,
|
||||||
|
IO * io, ChiakiLog * log)
|
||||||
|
: hosts(hosts), settings(settings), discoverymanager(discoverymanager),
|
||||||
|
io(io), log(log)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MainApplication::~MainApplication()
|
||||||
|
{
|
||||||
|
this->discoverymanager->SetService(false);
|
||||||
|
//this->io->FreeJoystick();
|
||||||
|
this->io->FreeVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainApplication::Load()
|
||||||
|
{
|
||||||
|
this->discoverymanager->SetService(true);
|
||||||
|
// Init the app
|
||||||
|
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
|
||||||
|
|
||||||
|
brls::i18n::loadTranslations();
|
||||||
|
if (!brls::Application::init("Chiaki Remote play"))
|
||||||
|
{
|
||||||
|
brls::Logger::error("Unable to init Borealis application");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 joysticks");
|
||||||
|
if(!io->InitJoystick())
|
||||||
|
{
|
||||||
|
brls::Logger::error("Faled to initiate Joysticks");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a view
|
||||||
|
this->rootFrame = new brls::TabFrame();
|
||||||
|
this->rootFrame->setTitle("Chiaki: Open Source PS4 Remote Play Client");
|
||||||
|
this->rootFrame->setIcon(BOREALIS_ASSET("icon.jpg"));
|
||||||
|
|
||||||
|
brls::List* config = new brls::List();
|
||||||
|
BuildConfigurationMenu(config);
|
||||||
|
|
||||||
|
this->rootFrame->addTab("Configuration", config);
|
||||||
|
// ----------------
|
||||||
|
this->rootFrame->addSeparator();
|
||||||
|
|
||||||
|
// Add the root view to the stack
|
||||||
|
brls::Application::pushView(this->rootFrame);
|
||||||
|
while(brls::Application::mainLoop())
|
||||||
|
{
|
||||||
|
for(auto it = this->hosts->begin(); it != this->hosts->end(); it++)
|
||||||
|
{
|
||||||
|
if(this->host_menuitems.find(&it->second) == this->host_menuitems.end())
|
||||||
|
{
|
||||||
|
brls::List* new_host = new brls::List();
|
||||||
|
this->host_menuitems[&it->second] = new_host;
|
||||||
|
// create host if udefined
|
||||||
|
HostInterface host_menu = HostInterface(new_host, this->io, &it->second, this->settings);
|
||||||
|
BuildConfigurationMenu(new_host, &it->second);
|
||||||
|
this->rootFrame->addTab(it->second.host_name.c_str(), new_host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainApplication::BuildConfigurationMenu(brls::List * ls, Host * host)
|
||||||
|
{
|
||||||
|
std::string psn_online_id_string = this->settings->GetPSNOnlineID(host);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
std::string psn_account_id_string = this->settings->GetPSNAccountID(host);
|
||||||
|
brls::ListItem* psn_account_id = new brls::ListItem("PSN Account ID", "v7.0 and greater");
|
||||||
|
psn_account_id->setValue(psn_account_id_string.c_str());
|
||||||
|
auto psn_account_id_cb = [this, host, psn_account_id](brls::View * view)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
int value;
|
||||||
|
ChiakiVideoResolutionPreset resolution_preset = this->settings->GetVideoResolution(host);
|
||||||
|
switch(resolution_preset)
|
||||||
|
{
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_720p:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_540p:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_360p:
|
||||||
|
value = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
brls::SelectListItem* resolution = new brls::SelectListItem(
|
||||||
|
"Resolution", { "720p", "540p", "360p" }, value);
|
||||||
|
|
||||||
|
auto resolution_cb = [this, host](int result)
|
||||||
|
{
|
||||||
|
ChiakiVideoResolutionPreset value = CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
switch(result)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
value = CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value = CHIAKI_VIDEO_RESOLUTION_PRESET_540p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value = CHIAKI_VIDEO_RESOLUTION_PRESET_360p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->settings->SetVideoResolution(host, value);
|
||||||
|
this->settings->WriteFile();
|
||||||
|
};
|
||||||
|
resolution->getValueSelectedEvent()->subscribe(resolution_cb);
|
||||||
|
ls->addView(resolution);
|
||||||
|
|
||||||
|
ChiakiVideoFPSPreset fps_preset = this->settings->GetVideoFPS(host);
|
||||||
|
switch(fps_preset)
|
||||||
|
{
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_60:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_30:
|
||||||
|
value = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
brls::SelectListItem* fps = new brls::SelectListItem(
|
||||||
|
"FPS", { "60", "30"}, value);
|
||||||
|
|
||||||
|
auto fps_cb = [this, host](int result)
|
||||||
|
{
|
||||||
|
ChiakiVideoFPSPreset value = CHIAKI_VIDEO_FPS_PRESET_60;
|
||||||
|
switch(result)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
value = CHIAKI_VIDEO_FPS_PRESET_60;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value = CHIAKI_VIDEO_FPS_PRESET_30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->settings->SetVideoFPS(host, value);
|
||||||
|
this->settings->WriteFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
fps->getValueSelectedEvent()->subscribe(fps_cb);
|
||||||
|
ls->addView(fps);
|
||||||
|
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
// message delimiter
|
||||||
|
brls::Label* info = new brls::Label(brls::LabelStyle::REGULAR,
|
||||||
|
"Host information", true);
|
||||||
|
ls->addView(info);
|
||||||
|
|
||||||
|
std::string host_name_string = this->settings->GetHostName(host);
|
||||||
|
brls::ListItem* host_name = new brls::ListItem("PS4 Hostname");
|
||||||
|
host_name->setValue(host_name_string.c_str());
|
||||||
|
ls->addView(host_name);
|
||||||
|
|
||||||
|
std::string host_ipaddr_string = settings->GetHostIPAddr(host);
|
||||||
|
brls::ListItem* host_ipaddr = new brls::ListItem("PS4 IP Address");
|
||||||
|
host_ipaddr->setValue(host_ipaddr_string.c_str());
|
||||||
|
ls->addView(host_ipaddr);
|
||||||
|
|
||||||
|
std::string host_rp_regist_key_string = settings->GetHostRPRegistKey(host);
|
||||||
|
brls::ListItem* host_rp_regist_key = new brls::ListItem("RP Register Key");
|
||||||
|
host_rp_regist_key->setValue(host_rp_regist_key_string.c_str());
|
||||||
|
ls->addView(host_rp_regist_key);
|
||||||
|
|
||||||
|
std::string host_rp_key_string = settings->GetHostRPKey(host);
|
||||||
|
brls::ListItem* host_rp_key = new brls::ListItem("RP Key");
|
||||||
|
host_rp_key->setValue(host_rp_key_string.c_str());
|
||||||
|
ls->addView(host_rp_key);
|
||||||
|
|
||||||
|
std::string host_rp_key_type_string = std::to_string(settings->GetHostRPKeyType(host));
|
||||||
|
brls::ListItem* host_rp_key_type = new brls::ListItem("RP Key type");
|
||||||
|
host_rp_key_type->setValue(host_rp_key_type_string.c_str());
|
||||||
|
ls->addView(host_rp_key_type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PS4RemotePlay::PS4RemotePlay(IO * io, Host * host)
|
||||||
|
: io(io), host(host)
|
||||||
|
{
|
||||||
|
// 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 PS4RemotePlay::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
||||||
|
{
|
||||||
|
this->io->MainLoop(&this->state);
|
||||||
|
this->host->SendFeedbackState(&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);
|
||||||
|
}
|
||||||
|
|
||||||
|
PS4RemotePlay::~PS4RemotePlay()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
287
switch/src/host.cpp
Normal file
287
switch/src/host.cpp
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <chiaki/base64.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void InitAudioCB(unsigned int channels, unsigned int rate, void * user)
|
||||||
|
{
|
||||||
|
IO * io = (IO *) user;
|
||||||
|
io->InitAudioCB(channels, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool VideoCB(uint8_t * buf, size_t buf_size, void * user)
|
||||||
|
{
|
||||||
|
IO * io = (IO *) user;
|
||||||
|
return io->VideoCB(buf, buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AudioCB(int16_t * buf, size_t samples_count, void * user)
|
||||||
|
{
|
||||||
|
IO * io = (IO *) user;
|
||||||
|
io->AudioCB(buf, samples_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EventCB(ChiakiEvent * event, void * user)
|
||||||
|
{
|
||||||
|
IO * io = (IO *) user;
|
||||||
|
io->EventCB(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RegistEventCB(ChiakiRegistEvent * event, void * user)
|
||||||
|
{
|
||||||
|
Host * host = (Host *) user;
|
||||||
|
host->RegistCB(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::Host(ChiakiLog * log, Settings * settings, std::string host_name)
|
||||||
|
: log(log), settings(settings), host_name(host_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Host::~Host()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int Host::Wakeup()
|
||||||
|
{
|
||||||
|
if(strlen(this->rp_regist_key) > 8)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Given registkey is too long");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (strlen(this->rp_regist_key) <=0)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Given registkey is not defined");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t credential = (uint64_t)strtoull(this->rp_regist_key, NULL, 16);
|
||||||
|
ChiakiErrorCode ret = chiaki_discovery_wakeup(this->log, NULL, host_addr.c_str(), credential);
|
||||||
|
if(ret == CHIAKI_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
//FIXME
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Host::Register(std::string pin)
|
||||||
|
{
|
||||||
|
// use pin and accont_id to negociate secrets for session
|
||||||
|
//
|
||||||
|
// convert psn_account_id into uint8_t[CHIAKI_PSN_ACCOUNT_ID_SIZE]
|
||||||
|
// CHIAKI_PSN_ACCOUNT_ID_SIZE == 8
|
||||||
|
std::string account_id = this->settings->GetPSNAccountID(this);
|
||||||
|
std::string online_id = this->settings->GetPSNOnlineID(this);
|
||||||
|
size_t account_id_size = sizeof(uint8_t[CHIAKI_PSN_ACCOUNT_ID_SIZE]);
|
||||||
|
|
||||||
|
// PS4 firmware > 7.0
|
||||||
|
if(this->system_version >= 7000000)
|
||||||
|
{
|
||||||
|
// use AccountID for ps4 > 7.0
|
||||||
|
if(account_id.length() > 0)
|
||||||
|
{
|
||||||
|
chiaki_base64_decode(account_id.c_str(), account_id.length(),
|
||||||
|
regist_info.psn_account_id, &(account_id_size));
|
||||||
|
regist_info.psn_online_id = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Undefined PSN Account ID (Please configure a valid psn_account_id)");
|
||||||
|
return HOST_REGISTER_ERROR_SETTING_PSNACCOUNTID;
|
||||||
|
}
|
||||||
|
if(this->system_version >= 8000000)
|
||||||
|
regist_info.target = CHIAKI_TARGET_PS4_10;
|
||||||
|
else
|
||||||
|
regist_info.target = CHIAKI_TARGET_PS4_9;
|
||||||
|
}
|
||||||
|
else if( this->system_version < 7000000 && this->system_version > 0)
|
||||||
|
{
|
||||||
|
// use oline ID for ps4 < 7.0
|
||||||
|
if(online_id.length() > 0)
|
||||||
|
{
|
||||||
|
regist_info.psn_online_id = this->psn_online_id.c_str();
|
||||||
|
// regist_info.psn_account_id = {0};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Undefined PSN Online ID (Please configure a valid psn_online_id)");
|
||||||
|
return HOST_REGISTER_ERROR_SETTING_PSNONLINEID;
|
||||||
|
}
|
||||||
|
regist_info.target = CHIAKI_TARGET_PS4_8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Undefined PS4 system version (please run discover first)");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->regist_info.pin = atoi(pin.c_str());
|
||||||
|
this->regist_info.host = this->host_addr.c_str();
|
||||||
|
this->regist_info.broadcast = false;
|
||||||
|
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(), psn_account_id.c_str(), pin.c_str());
|
||||||
|
chiaki_regist_start(&this->regist, this->log, &this->regist_info, RegistEventCB, this);
|
||||||
|
return HOST_REGISTER_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Host::InitSession(IO * user)
|
||||||
|
{
|
||||||
|
chiaki_connect_video_profile_preset(&(this->video_profile),
|
||||||
|
this->video_resolution, this->video_fps);
|
||||||
|
// Build chiaki ps4 stream session
|
||||||
|
chiaki_opus_decoder_init(&(this->opus_decoder), this->log);
|
||||||
|
ChiakiAudioSink audio_sink;
|
||||||
|
ChiakiConnectInfo chiaki_connect_info;
|
||||||
|
|
||||||
|
chiaki_connect_info.host = this->host_addr.c_str();
|
||||||
|
chiaki_connect_info.video_profile = this->video_profile;
|
||||||
|
memcpy(chiaki_connect_info.regist_key, this->rp_regist_key, sizeof(chiaki_connect_info.regist_key));
|
||||||
|
memcpy(chiaki_connect_info.morning, this->rp_key, sizeof(chiaki_connect_info.morning));
|
||||||
|
// set keybord state to 0
|
||||||
|
memset(&(this->keyboard_state), 0, sizeof(keyboard_state));
|
||||||
|
|
||||||
|
ChiakiErrorCode err = chiaki_session_init(&(this->session), &chiaki_connect_info, this->log);
|
||||||
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
|
throw Exception(chiaki_error_string(err));
|
||||||
|
this->session_init = true;
|
||||||
|
// 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, user);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Host::FiniSession()
|
||||||
|
{
|
||||||
|
if(this->session_init)
|
||||||
|
{
|
||||||
|
chiaki_session_join(&this->session);
|
||||||
|
chiaki_session_fini(&this->session);
|
||||||
|
chiaki_opus_decoder_fini(&this->opus_decoder);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Host::StopSession()
|
||||||
|
{
|
||||||
|
chiaki_session_stop(&this->session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Host::StartSession()
|
||||||
|
{
|
||||||
|
ChiakiErrorCode err = chiaki_session_start(&this->session);
|
||||||
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
chiaki_session_fini(&this->session);
|
||||||
|
throw Exception("Chiaki Session Start failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Host::SendFeedbackState(ChiakiControllerState * state)
|
||||||
|
{
|
||||||
|
// send controller/joystick key
|
||||||
|
chiaki_session_set_controller_state(&this->session, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Host::RegistCB(ChiakiRegistEvent * event)
|
||||||
|
{
|
||||||
|
// Chiaki callback fuction
|
||||||
|
// fuction called by lib chiaki regist
|
||||||
|
// durring client pin code registration
|
||||||
|
//
|
||||||
|
// read data from lib and record secrets into Host object
|
||||||
|
|
||||||
|
this->registered = false;
|
||||||
|
switch(event->type)
|
||||||
|
{
|
||||||
|
case CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED:
|
||||||
|
CHIAKI_LOGI(this->log, "Register event CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED");
|
||||||
|
if(this->chiaki_regist_event_type_finished_canceled != nullptr)
|
||||||
|
{
|
||||||
|
this->chiaki_regist_event_type_finished_canceled();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED:
|
||||||
|
CHIAKI_LOGI(this->log, "Register event CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED");
|
||||||
|
if(this->chiaki_regist_event_type_finished_failed != nullptr)
|
||||||
|
{
|
||||||
|
this->chiaki_regist_event_type_finished_failed();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS:
|
||||||
|
{
|
||||||
|
ChiakiRegisteredHost *r_host = event->registered_host;
|
||||||
|
CHIAKI_LOGI(this->log, "Register event CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS");
|
||||||
|
// copy values form ChiakiRegisteredHost object
|
||||||
|
this->ap_ssid = r_host->ap_ssid;
|
||||||
|
this->ap_key = r_host->ap_key;
|
||||||
|
this->ap_name = r_host->ap_name;
|
||||||
|
memcpy( &(this->ps4_mac), &(r_host->ps4_mac), sizeof(this->ps4_mac) );
|
||||||
|
this->ps4_nickname = r_host->ps4_nickname;
|
||||||
|
memcpy( &(this->rp_regist_key), &(r_host->rp_regist_key), sizeof(this->rp_regist_key) );
|
||||||
|
this->rp_key_type = r_host->rp_key_type;
|
||||||
|
memcpy( &(this->rp_key), &(r_host->rp_key), sizeof(this->rp_key) );
|
||||||
|
// mark host as registered
|
||||||
|
this->registered = true;
|
||||||
|
this->rp_key_data = true;
|
||||||
|
CHIAKI_LOGI(this->log, "Register Success %s", this->host_name.c_str());
|
||||||
|
|
||||||
|
if(this->chiaki_regist_event_type_finished_success != nullptr)
|
||||||
|
this->chiaki_regist_event_type_finished_success();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close registration socket
|
||||||
|
chiaki_regist_stop(&this->regist);
|
||||||
|
chiaki_regist_fini(&this->regist);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Host::GetVideoResolution(int * ret_width, int * ret_height)
|
||||||
|
{
|
||||||
|
switch(this->video_resolution)
|
||||||
|
{
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_360p:
|
||||||
|
*ret_width = 640;
|
||||||
|
*ret_height = 360;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_540p:
|
||||||
|
*ret_width = 950;
|
||||||
|
*ret_height = 540;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_720p:
|
||||||
|
*ret_width = 1280;
|
||||||
|
*ret_height = 720;
|
||||||
|
break;
|
||||||
|
case CHIAKI_VIDEO_RESOLUTION_PRESET_1080p:
|
||||||
|
*ret_width = 1920;
|
||||||
|
*ret_height = 1080;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
797
switch/src/io.cpp
Normal file
797
switch/src/io.cpp
Normal file
|
@ -0,0 +1,797 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// https://github.com/matlo/GIMX/blob/3af491c3b6a89c6a76c9831f1f022a1b73a00752/shared/gimxcontroller/include/ds4.h#L112
|
||||||
|
#define DS4_TRACKPAD_MAX_X 1919
|
||||||
|
#define DS4_TRACKPAD_MAX_Y 919
|
||||||
|
#define SWITCH_TOUCHSCREEN_MAX_X 1280
|
||||||
|
#define SWITCH_TOUCHSCREEN_MAX_Y 720
|
||||||
|
|
||||||
|
// source:
|
||||||
|
// https://github.com/thestr4ng3r/chiaki/blob/master/gui/src/avopenglwidget.cpp
|
||||||
|
//
|
||||||
|
// examples :
|
||||||
|
// https://www.roxlu.com/2014/039/decoding-h264-and-yuv420p-playback
|
||||||
|
// https://gist.github.com/roxlu/9329339
|
||||||
|
|
||||||
|
// use OpenGl to decode YUV
|
||||||
|
// the aim is to spare CPU load on nintendo switch
|
||||||
|
|
||||||
|
static const char* shader_vert_glsl = R"glsl(
|
||||||
|
#version 150 core
|
||||||
|
in vec2 pos_attr;
|
||||||
|
out vec2 uv_var;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uv_var = pos_attr;
|
||||||
|
gl_Position = vec4(pos_attr * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static const char *yuv420p_shader_frag_glsl = R"glsl(
|
||||||
|
#version 150 core
|
||||||
|
uniform sampler2D plane1; // Y
|
||||||
|
uniform sampler2D plane2; // U
|
||||||
|
uniform sampler2D plane3; // V
|
||||||
|
in vec2 uv_var;
|
||||||
|
out vec4 out_color;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec3 yuv = vec3(
|
||||||
|
(texture(plane1, uv_var).r - (16.0 / 255.0)) / ((235.0 - 16.0) / 255.0),
|
||||||
|
(texture(plane2, uv_var).r - (16.0 / 255.0)) / ((240.0 - 16.0) / 255.0) - 0.5,
|
||||||
|
(texture(plane3, uv_var).r - (16.0 / 255.0)) / ((240.0 - 16.0) / 255.0) - 0.5);
|
||||||
|
vec3 rgb = mat3(
|
||||||
|
1.0, 1.0, 1.0,
|
||||||
|
0.0, -0.21482, 2.12798,
|
||||||
|
1.28033, -0.38059, 0.0) * yuv;
|
||||||
|
out_color = vec4(rgb, 1.0);
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
static const float vert_pos[] = {
|
||||||
|
0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f,
|
||||||
|
1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
IO::IO(ChiakiLog * log)
|
||||||
|
: log(log)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IO::~IO()
|
||||||
|
{
|
||||||
|
//FreeJoystick();
|
||||||
|
if(this->sdl_audio_device_id <= 0)
|
||||||
|
{
|
||||||
|
SDL_CloseAudioDevice(this->sdl_audio_device_id);
|
||||||
|
}
|
||||||
|
FreeVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IO::SetMesaConfig()
|
||||||
|
{
|
||||||
|
//TRACE("%s", "Mesaconfig");
|
||||||
|
//setenv("MESA_GL_VERSION_OVERRIDE", "3.3", 1);
|
||||||
|
//setenv("MESA_GLSL_VERSION_OVERRIDE", "330", 1);
|
||||||
|
// Uncomment below to disable error checking and save CPU time (useful for production):
|
||||||
|
//setenv("MESA_NO_ERROR", "1", 1);
|
||||||
|
#ifdef DEBUG_OPENGL
|
||||||
|
// Uncomment below to enable Mesa logging:
|
||||||
|
setenv("EGL_LOG_LEVEL", "debug", 1);
|
||||||
|
setenv("MESA_VERBOSE", "all", 1);
|
||||||
|
setenv("NOUVEAU_MESA_DEBUG", "1", 1);
|
||||||
|
|
||||||
|
// Uncomment below to enable shader debugging in Nouveau:
|
||||||
|
//setenv("NV50_PROG_OPTIMIZE", "0", 1);
|
||||||
|
setenv("NV50_PROG_DEBUG", "1", 1);
|
||||||
|
//setenv("NV50_PROG_CHIPSET", "0x120", 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_OPENGL
|
||||||
|
#define D(x){ (x); CheckGLError(__func__, __FILE__, __LINE__); }
|
||||||
|
void IO::CheckGLError(const char* func, const char* file, int line)
|
||||||
|
{
|
||||||
|
GLenum err;
|
||||||
|
while( (err = glGetError()) != GL_NO_ERROR )
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "glGetError: %x function: %s from %s line %d", err, func, file, line);
|
||||||
|
//GL_INVALID_VALUE, 0x0501
|
||||||
|
// Given when a value parameter is not a legal value for that function. T
|
||||||
|
// his is only given for local problems;
|
||||||
|
// if the spec allows the value in certain circumstances,
|
||||||
|
// where other parameters or state dictate those circumstances,
|
||||||
|
// then GL_INVALID_OPERATION is the result instead.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DS(x){ DumpShaderError(x, __func__, __FILE__, __LINE__); }
|
||||||
|
void IO::DumpShaderError(GLuint shader, const char* func, const char* file, int line)
|
||||||
|
{
|
||||||
|
GLchar str[512+1];
|
||||||
|
GLsizei len = 0;
|
||||||
|
glGetShaderInfoLog(shader, 512, &len, str);
|
||||||
|
if (len > 512) len = 512;
|
||||||
|
str[len] = '\0';
|
||||||
|
CHIAKI_LOGE(this->log, "glGetShaderInfoLog: %s function: %s from %s line %d", str, func, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DP(x){ DumpProgramError(x, __func__, __FILE__, __LINE__); }
|
||||||
|
void IO::DumpProgramError(GLuint prog, const char* func, const char* file, int line)
|
||||||
|
{
|
||||||
|
GLchar str[512+1];
|
||||||
|
GLsizei len = 0;
|
||||||
|
glGetProgramInfoLog(prog, 512, &len, str);
|
||||||
|
if (len > 512) len = 512;
|
||||||
|
str[len] = '\0';
|
||||||
|
CHIAKI_LOGE(this->log, "glGetProgramInfoLog: %s function: %s from %s line %d", str, func, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// do nothing
|
||||||
|
#define D(x){ (x); }
|
||||||
|
#define DS(x){ }
|
||||||
|
#define DP(x){ }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
bool IO::VideoCB(uint8_t * buf, size_t buf_size)
|
||||||
|
{
|
||||||
|
// callback function to decode video buffer
|
||||||
|
|
||||||
|
AVPacket packet;
|
||||||
|
av_init_packet(&packet);
|
||||||
|
packet.data = buf;
|
||||||
|
packet.size = buf_size;
|
||||||
|
AVFrame * frame = av_frame_alloc();
|
||||||
|
if(!frame)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "UpdateFrame Failed to alloc AVFrame");
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_packet:
|
||||||
|
// Push
|
||||||
|
int r = avcodec_send_packet(this->codec_context, &packet);
|
||||||
|
if(r != 0)
|
||||||
|
{
|
||||||
|
if(r == AVERROR(EAGAIN))
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "AVCodec internal buffer is full removing frames before pushing");
|
||||||
|
r = avcodec_receive_frame(this->codec_context, frame);
|
||||||
|
// send decoded frame for sdl texture update
|
||||||
|
if(r != 0)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to pull frame");
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
goto send_packet;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char errbuf[128];
|
||||||
|
av_make_error_string(errbuf, sizeof(errbuf), r);
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to push frame: %s", errbuf);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mtx.lock();
|
||||||
|
// Pull
|
||||||
|
r = avcodec_receive_frame(this->codec_context, this->frame);
|
||||||
|
this->mtx.unlock();
|
||||||
|
|
||||||
|
if(r != 0)
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to pull frame");
|
||||||
|
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_packet_unref(&packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IO::InitAudioCB(unsigned int channels, unsigned int rate)
|
||||||
|
{
|
||||||
|
SDL_AudioSpec want, have, test;
|
||||||
|
SDL_memset(&want, 0, sizeof(want));
|
||||||
|
|
||||||
|
//source
|
||||||
|
//[I] Audio Header:
|
||||||
|
//[I] channels = 2
|
||||||
|
//[I] bits = 16
|
||||||
|
//[I] rate = 48000
|
||||||
|
//[I] frame size = 480
|
||||||
|
//[I] unknown = 1
|
||||||
|
want.freq = rate;
|
||||||
|
want.format = AUDIO_S16SYS;
|
||||||
|
// 2 == stereo
|
||||||
|
want.channels = channels;
|
||||||
|
want.samples = 1024;
|
||||||
|
want.callback = NULL;
|
||||||
|
|
||||||
|
if(this->sdl_audio_device_id <= 0)
|
||||||
|
{
|
||||||
|
// the chiaki session might be called many times
|
||||||
|
// open the audio device only once
|
||||||
|
this->sdl_audio_device_id = SDL_OpenAudioDevice(NULL, 0, &want, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this->sdl_audio_device_id <= 0)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SDL_PauseAudioDevice(this->sdl_audio_device_id, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IO::AudioCB(int16_t * buf, size_t samples_count)
|
||||||
|
{
|
||||||
|
//int az = SDL_GetQueuedAudioSize(host->audio_device_id);
|
||||||
|
// len the number of bytes (not samples!) to which (data) points
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::InitVideo(int video_width, int video_height, int screen_width, int screen_height)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "load InitVideo");
|
||||||
|
this->video_width = video_width;
|
||||||
|
this->video_height = video_height;
|
||||||
|
|
||||||
|
this->screen_width = screen_width;
|
||||||
|
this->screen_height = screen_height;
|
||||||
|
this->frame = av_frame_alloc();
|
||||||
|
|
||||||
|
if(!InitAVCodec())
|
||||||
|
{
|
||||||
|
throw Exception("Failed to initiate libav codec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!InitOpenGl())
|
||||||
|
{
|
||||||
|
throw Exception("Failed to initiate OpenGl");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IO::EventCB(ChiakiEvent *event)
|
||||||
|
{
|
||||||
|
switch(event->type)
|
||||||
|
{
|
||||||
|
case CHIAKI_EVENT_CONNECTED:
|
||||||
|
CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_CONNECTED");
|
||||||
|
if(this->chiaki_event_connected_cb != nullptr)
|
||||||
|
this->quit = !this->chiaki_event_connected_cb();
|
||||||
|
else
|
||||||
|
this->quit = false;
|
||||||
|
break;
|
||||||
|
case CHIAKI_EVENT_LOGIN_PIN_REQUEST:
|
||||||
|
CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_LOGIN_PIN_REQUEST");
|
||||||
|
if(this->chiaki_even_login_pin_request_cb != nullptr)
|
||||||
|
this->quit = !this->chiaki_even_login_pin_request_cb(event->login_pin_request.pin_incorrect);
|
||||||
|
break;
|
||||||
|
case CHIAKI_EVENT_QUIT:
|
||||||
|
CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_QUIT");
|
||||||
|
if(this->chiaki_event_quit_cb != nullptr)
|
||||||
|
this->quit = !this->chiaki_event_quit_cb(&event->quit);
|
||||||
|
else
|
||||||
|
this->quit = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool IO::FreeVideo()
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if(this->frame)
|
||||||
|
av_frame_free(&this->frame);
|
||||||
|
|
||||||
|
// avcodec_alloc_context3(codec);
|
||||||
|
if(this->codec_context)
|
||||||
|
{
|
||||||
|
avcodec_close(this->codec_context);
|
||||||
|
avcodec_free_context(&this->codec_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::ReadUserKeyboard(char *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
#ifdef CHIAKI_SWITCH_ENABLE_LINUX
|
||||||
|
// 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
|
||||||
|
// https://kvadevack.se/post/nintendo-switch-virtual-keyboard/
|
||||||
|
SwkbdConfig kbd;
|
||||||
|
Result rc = swkbdCreate(&kbd, 0);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
swkbdConfigMakePresetDefault(&kbd);
|
||||||
|
rc = swkbdShow(&kbd, buffer, buffer_size);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
CHIAKI_LOGI(this->log, "Got user input: %s\n", buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "swkbdShow() error: %u\n", rc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
swkbdClose(&kbd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::ReadGameKeys(SDL_Event *event, ChiakiControllerState *state)
|
||||||
|
{
|
||||||
|
// return true if an event changed (gamepad input)
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// share vs PS button
|
||||||
|
// Gyro ?
|
||||||
|
// rumble ?
|
||||||
|
bool ret = true;
|
||||||
|
switch(event->type)
|
||||||
|
{
|
||||||
|
case SDL_JOYAXISMOTION:
|
||||||
|
if(event->jaxis.which == 0)
|
||||||
|
{
|
||||||
|
// left joystick
|
||||||
|
if(event->jaxis.axis == 0)
|
||||||
|
// Left-right movement
|
||||||
|
state->left_x = event->jaxis.value;
|
||||||
|
else if(event->jaxis.axis == 1)
|
||||||
|
// Up-Down movement
|
||||||
|
state->left_y = event->jaxis.value;
|
||||||
|
else if(event->jaxis.axis == 2)
|
||||||
|
// Left-right movement
|
||||||
|
state->right_x = event->jaxis.value;
|
||||||
|
else if(event->jaxis.axis == 3)
|
||||||
|
// Up-Down movement
|
||||||
|
state->right_y = event->jaxis.value;
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
else if (event->jaxis.which == 1)
|
||||||
|
{
|
||||||
|
// right joystick
|
||||||
|
if(event->jaxis.axis == 0)
|
||||||
|
// Left-right movement
|
||||||
|
state->right_x = event->jaxis.value;
|
||||||
|
else if(event->jaxis.axis == 1)
|
||||||
|
// Up-Down movement
|
||||||
|
state->right_y = event->jaxis.value;
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
case SDL_JOYBUTTONDOWN:
|
||||||
|
// printf("Joystick %d button %d DOWN\n",
|
||||||
|
// event->jbutton.which, event->jbutton.button);
|
||||||
|
switch(event->jbutton.button)
|
||||||
|
{
|
||||||
|
case 0: state->buttons |= CHIAKI_CONTROLLER_BUTTON_MOON; break; // KEY_A
|
||||||
|
case 1: state->buttons |= CHIAKI_CONTROLLER_BUTTON_CROSS; break; // KEY_B
|
||||||
|
case 2: state->buttons |= CHIAKI_CONTROLLER_BUTTON_PYRAMID; break; // KEY_X
|
||||||
|
case 3: state->buttons |= CHIAKI_CONTROLLER_BUTTON_BOX; break; // KEY_Y
|
||||||
|
case 12: state->buttons |= CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT; break; // KEY_DLEFT
|
||||||
|
case 14: state->buttons |= CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT; break; // KEY_DRIGHT
|
||||||
|
case 13: state->buttons |= CHIAKI_CONTROLLER_BUTTON_DPAD_UP; break; // KEY_DUP
|
||||||
|
case 15: state->buttons |= CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN; break; // KEY_DDOWN
|
||||||
|
case 6: state->buttons |= CHIAKI_CONTROLLER_BUTTON_L1; break; // KEY_L
|
||||||
|
case 7: state->buttons |= CHIAKI_CONTROLLER_BUTTON_R1; break; // KEY_R
|
||||||
|
case 8: state->l2_state = 0xff; break; // KEY_ZL
|
||||||
|
case 9: state->r2_state = 0xff; break; // KEY_ZR
|
||||||
|
case 4: state->buttons |= CHIAKI_CONTROLLER_BUTTON_L3; break; // KEY_LSTICK
|
||||||
|
case 5: state->buttons |= CHIAKI_CONTROLLER_BUTTON_R3; break; // KEY_RSTICK
|
||||||
|
case 10: state->buttons |= CHIAKI_CONTROLLER_BUTTON_OPTIONS; break; // KEY_PLUS
|
||||||
|
// FIXME
|
||||||
|
// case 11: state->buttons |= CHIAKI_CONTROLLER_BUTTON_SHARE; break; // KEY_MINUS
|
||||||
|
case 11: state->buttons |= CHIAKI_CONTROLLER_BUTTON_PS; break; // KEY_MINUS
|
||||||
|
default:
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_JOYBUTTONUP:
|
||||||
|
// printf("Joystick %d button %d UP\n",
|
||||||
|
// event->jbutton.which, event->jbutton.button);
|
||||||
|
switch(event->jbutton.button)
|
||||||
|
{
|
||||||
|
case 0: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_MOON; break; // KEY_A
|
||||||
|
case 1: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_CROSS; break; // KEY_B
|
||||||
|
case 2: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_PYRAMID; break; // KEY_X
|
||||||
|
case 3: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_BOX; break; // KEY_Y
|
||||||
|
case 12: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_DPAD_LEFT; break; // KEY_DLEFT
|
||||||
|
case 14: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_DPAD_RIGHT; break; // KEY_DRIGHT
|
||||||
|
case 13: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_DPAD_UP; break; // KEY_DUP
|
||||||
|
case 15: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_DPAD_DOWN; break; // KEY_DDOWN
|
||||||
|
case 6: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_L1; break; // KEY_L
|
||||||
|
case 7: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_R1; break; // KEY_R
|
||||||
|
case 8: state->l2_state = 0x00; break; // KEY_ZL
|
||||||
|
case 9: state->r2_state = 0x00; break; // KEY_ZR
|
||||||
|
case 4: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_L3; break; // KEY_LSTICK
|
||||||
|
case 5: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_R3; break; // KEY_RSTICK
|
||||||
|
case 10: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_OPTIONS; break; // KEY_PLUS
|
||||||
|
//case 11: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_SHARE; break; // KEY_MINUS
|
||||||
|
case 11: state->buttons ^= CHIAKI_CONTROLLER_BUTTON_PS; break; // KEY_MINUS
|
||||||
|
default:
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::InitAVCodec()
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "loading AVCodec");
|
||||||
|
// set libav video context
|
||||||
|
this->codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||||
|
if(!this->codec)
|
||||||
|
throw Exception("H264 Codec not available");
|
||||||
|
|
||||||
|
this->codec_context = avcodec_alloc_context3(codec);
|
||||||
|
if(!this->codec_context)
|
||||||
|
throw Exception("Failed to alloc codec context");
|
||||||
|
|
||||||
|
// use rock88's mooxlight-nx optimization
|
||||||
|
// https://github.com/rock88/moonlight-nx/blob/698d138b9fdd4e483c998254484ccfb4ec829e95/src/streaming/ffmpeg/FFmpegVideoDecoder.cpp#L63
|
||||||
|
// this->codec_context->skip_loop_filter = AVDISCARD_ALL;
|
||||||
|
this->codec_context->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
||||||
|
this->codec_context->flags2 |= AV_CODEC_FLAG2_FAST;
|
||||||
|
// this->codec_context->flags2 |= AV_CODEC_FLAG2_CHUNKS;
|
||||||
|
this->codec_context->thread_type = FF_THREAD_SLICE;
|
||||||
|
this->codec_context->thread_count = 4;
|
||||||
|
|
||||||
|
if(avcodec_open2(this->codec_context, this->codec, nullptr) < 0)
|
||||||
|
{
|
||||||
|
avcodec_free_context(&this->codec_context);
|
||||||
|
throw Exception("Failed to open codec context");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::InitOpenGl()
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "loading OpenGL");
|
||||||
|
|
||||||
|
if(!InitOpenGlShader())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!InitOpenGlTextures())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::InitOpenGlTextures()
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "loading OpenGL textrures");
|
||||||
|
|
||||||
|
D(glGenTextures(PLANES_COUNT, this->tex));
|
||||||
|
D(glGenBuffers(PLANES_COUNT, this->pbo));
|
||||||
|
uint8_t uv_default[] = {0x7f, 0x7f};
|
||||||
|
for(int i=0; i < PLANES_COUNT; i++)
|
||||||
|
{
|
||||||
|
D(glBindTexture(GL_TEXTURE_2D, this->tex[i]));
|
||||||
|
D(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||||
|
D(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||||
|
D(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||||
|
D(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||||
|
D(glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, i > 0 ? uv_default : nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
D(glUseProgram(this->prog));
|
||||||
|
// bind only as many planes as we need
|
||||||
|
const char *plane_names[] = {"plane1", "plane2", "plane3"};
|
||||||
|
for(int i=0; i < PLANES_COUNT; i++)
|
||||||
|
D(glUniform1i(glGetUniformLocation(this->prog, plane_names[i]), i));
|
||||||
|
|
||||||
|
D(glGenVertexArrays(1, &this->vao));
|
||||||
|
D(glBindVertexArray(this->vao));
|
||||||
|
|
||||||
|
D(glGenBuffers(1, &this->vbo));
|
||||||
|
D(glBindBuffer(GL_ARRAY_BUFFER, this->vbo));
|
||||||
|
D(glBufferData(GL_ARRAY_BUFFER, sizeof(vert_pos), vert_pos, GL_STATIC_DRAW));
|
||||||
|
|
||||||
|
D(glBindBuffer(GL_ARRAY_BUFFER, this->vbo));
|
||||||
|
D(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
|
||||||
|
D(glEnableVertexAttribArray(0));
|
||||||
|
|
||||||
|
D(glCullFace(GL_BACK));
|
||||||
|
D(glEnable(GL_CULL_FACE));
|
||||||
|
D(glClearColor(0.5, 0.5, 0.5, 1.0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint IO::CreateAndCompileShader(GLenum type, const char* source)
|
||||||
|
{
|
||||||
|
GLint success;
|
||||||
|
GLchar msg[512];
|
||||||
|
|
||||||
|
GLuint handle;
|
||||||
|
D(handle = glCreateShader(type));
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "%u: cannot create shader", type);
|
||||||
|
DP(this->prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
D(glShaderSource(handle, 1, &source, nullptr));
|
||||||
|
D(glCompileShader(handle));
|
||||||
|
D(glGetShaderiv(handle, GL_COMPILE_STATUS, &success));
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
D(glGetShaderInfoLog(handle, sizeof(msg), nullptr, msg));
|
||||||
|
CHIAKI_LOGE(this->log, "%u: %s\n", type, msg);
|
||||||
|
D(glDeleteShader(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::InitOpenGlShader()
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "loading OpenGl Shaders");
|
||||||
|
|
||||||
|
D(this->vert = CreateAndCompileShader(GL_VERTEX_SHADER, shader_vert_glsl));
|
||||||
|
D(this->frag = CreateAndCompileShader(GL_FRAGMENT_SHADER, yuv420p_shader_frag_glsl));
|
||||||
|
|
||||||
|
D(this->prog = glCreateProgram());
|
||||||
|
|
||||||
|
D(glAttachShader(this->prog, this->vert));
|
||||||
|
D(glAttachShader(this->prog, this->frag));
|
||||||
|
D(glBindAttribLocation(this->prog, 0, "pos_attr"));
|
||||||
|
D(glLinkProgram(this->prog));
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
D(glGetProgramiv(this->prog, GL_LINK_STATUS, &success));
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
glGetProgramInfoLog(this->prog, sizeof(buf), nullptr, buf);
|
||||||
|
CHIAKI_LOGE(this->log, "OpenGL link error: %s", buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D(glDeleteShader(this->vert));
|
||||||
|
D(glDeleteShader(this->frag));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IO::SetOpenGlYUVPixels(AVFrame * frame)
|
||||||
|
{
|
||||||
|
D(glUseProgram(this->prog));
|
||||||
|
|
||||||
|
int planes[][3] = {
|
||||||
|
// { width_divide, height_divider, data_per_pixel }
|
||||||
|
{ 1, 1, 1 }, // Y
|
||||||
|
{ 2, 2, 1 }, // U
|
||||||
|
{ 2, 2, 1 } // V
|
||||||
|
};
|
||||||
|
|
||||||
|
this->mtx.lock();
|
||||||
|
for(int i = 0; i < PLANES_COUNT; i++)
|
||||||
|
{
|
||||||
|
int width = frame->width / planes[i][0];
|
||||||
|
int height = frame->height / planes[i][1];
|
||||||
|
int size = width * height * planes[i][2];
|
||||||
|
uint8_t * buf;
|
||||||
|
|
||||||
|
D(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->pbo[i]));
|
||||||
|
D(glBufferData(GL_PIXEL_UNPACK_BUFFER, size, nullptr, GL_STREAM_DRAW));
|
||||||
|
D(buf = reinterpret_cast<uint8_t *>(glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)));
|
||||||
|
if(!buf)
|
||||||
|
{
|
||||||
|
GLint data;
|
||||||
|
D(glGetBufferParameteriv(GL_PIXEL_UNPACK_BUFFER, GL_BUFFER_SIZE, &data));
|
||||||
|
CHIAKI_LOGE(this->log, "AVOpenGLFrame failed to map PBO");
|
||||||
|
CHIAKI_LOGE(this->log, "Info buf == %p. size %d frame %d * %d, divs %d, %d, pbo %d GL_BUFFER_SIZE %x",
|
||||||
|
buf, size, frame->width, frame->height, planes[i][0], planes[i][1], pbo[i], data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frame->linesize[i] == width)
|
||||||
|
{
|
||||||
|
// Y
|
||||||
|
memcpy(buf, frame->data[i], size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// UV
|
||||||
|
for(int l=0; l<height; l++)
|
||||||
|
memcpy(buf + width * l * planes[i][2],
|
||||||
|
frame->data[i] + frame->linesize[i] * l,
|
||||||
|
width * planes[i][2]);
|
||||||
|
}
|
||||||
|
D(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));
|
||||||
|
D(glBindTexture(GL_TEXTURE_2D, tex[i]));
|
||||||
|
D(glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr));
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
}
|
||||||
|
this->mtx.unlock();
|
||||||
|
glFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IO::OpenGlDraw()
|
||||||
|
{
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// send to OpenGl
|
||||||
|
SetOpenGlYUVPixels(this->frame);
|
||||||
|
|
||||||
|
//avcodec_flush_buffers(this->codec_context);
|
||||||
|
D(glBindVertexArray(this->vao));
|
||||||
|
|
||||||
|
for(int i=0; i< PLANES_COUNT; i++)
|
||||||
|
{
|
||||||
|
D(glActiveTexture(GL_TEXTURE0 + i));
|
||||||
|
D(glBindTexture(GL_TEXTURE_2D, this->tex[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
D(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||||
|
D(glBindVertexArray(0));
|
||||||
|
D(glFinish());
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// when railed, both joycons are mapped to joystick #0,
|
||||||
|
// else joycons are individually mapped to joystick #0, joystick #1, ...
|
||||||
|
for (int i = 0; i < SDL_JOYSTICK_COUNT; i++)
|
||||||
|
{
|
||||||
|
this->sdl_joystick_ptr[i] = SDL_JoystickOpen(i);
|
||||||
|
if (sdl_joystick_ptr[i] == nullptr)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(this->log, "SDL_JoystickOpen: %s\n", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::FreeJoystick()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SDL_JOYSTICK_COUNT; i++)
|
||||||
|
{
|
||||||
|
if(SDL_JoystickGetAttached(sdl_joystick_ptr[i]))
|
||||||
|
SDL_JoystickClose(sdl_joystick_ptr[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IO::MainLoop(ChiakiControllerState * state)
|
||||||
|
{
|
||||||
|
D(glUseProgram(this->prog));
|
||||||
|
|
||||||
|
// handle SDL events
|
||||||
|
while(SDL_PollEvent(&this->sdl_event))
|
||||||
|
{
|
||||||
|
this->ReadGameKeys(&this->sdl_event, state);
|
||||||
|
switch(this->sdl_event.type)
|
||||||
|
{
|
||||||
|
case SDL_QUIT:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadGameTouchScreen(state);
|
||||||
|
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
OpenGlDraw();
|
||||||
|
|
||||||
|
return !this->quit;
|
||||||
|
}
|
||||||
|
|
175
switch/src/main.cpp
Normal file
175
switch/src/main.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// chiaki modules
|
||||||
|
#include <chiaki/log.h>
|
||||||
|
#include <chiaki/discovery.h>
|
||||||
|
|
||||||
|
// discover and wakeup ps4 host
|
||||||
|
// from local network
|
||||||
|
#include "discoverymanager.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
bool appletMainLoop()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CHIAKI_SWITCH_ENABLE_LINUX
|
||||||
|
#define CHIAKI_ENABLE_SWITCH_NXLINK 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
// 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,
|
||||||
|
.tcp_rx_buf_max_size = 0x40000,
|
||||||
|
|
||||||
|
.udp_tx_buf_size = 0x40000,
|
||||||
|
.udp_rx_buf_size = 0x40000,
|
||||||
|
|
||||||
|
.sb_efficiency = 8,
|
||||||
|
|
||||||
|
.num_bsd_sessions = 16,
|
||||||
|
.bsd_service_type = BsdServiceType_User,
|
||||||
|
};
|
||||||
|
#endif // __SWITCH__
|
||||||
|
|
||||||
|
#ifdef CHIAKI_ENABLE_SWITCH_NXLINK
|
||||||
|
static int s_nxlinkSock = -1;
|
||||||
|
|
||||||
|
static void initNxLink()
|
||||||
|
{
|
||||||
|
// use chiaki socket config initialization
|
||||||
|
if (R_FAILED(socketInitialize(&g_chiakiSocketInitConfig)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_nxlinkSock = nxlinkStdio();
|
||||||
|
if (s_nxlinkSock >= 0)
|
||||||
|
printf("initNxLink");
|
||||||
|
else
|
||||||
|
socketExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deinitNxLink()
|
||||||
|
{
|
||||||
|
if (s_nxlinkSock >= 0)
|
||||||
|
{
|
||||||
|
close(s_nxlinkSock);
|
||||||
|
s_nxlinkSock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CHIAKI_ENABLE_SWITCH_NXLINK
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
extern "C" void userAppInit()
|
||||||
|
{
|
||||||
|
#ifdef CHIAKI_ENABLE_SWITCH_NXLINK
|
||||||
|
initNxLink();
|
||||||
|
#endif
|
||||||
|
// to load gui resources
|
||||||
|
romfsInit();
|
||||||
|
plInitialize(PlServiceType_User);
|
||||||
|
// load socket custom config
|
||||||
|
socketInitialize(&g_chiakiSocketInitConfig);
|
||||||
|
setsysInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void userAppExit()
|
||||||
|
{
|
||||||
|
#ifdef CHIAKI_ENABLE_SWITCH_NXLINK
|
||||||
|
deinitNxLink();
|
||||||
|
#endif // CHIAKI_ENABLE_SWITCH_NXLINK
|
||||||
|
socketExit();
|
||||||
|
/* Cleanup tesla required services. */
|
||||||
|
hidsysExit();
|
||||||
|
pmdmntExit();
|
||||||
|
plExit();
|
||||||
|
|
||||||
|
/* Cleanup default services. */
|
||||||
|
fsExit();
|
||||||
|
hidExit();
|
||||||
|
appletExit();
|
||||||
|
setsysExit();
|
||||||
|
smExit();
|
||||||
|
}
|
||||||
|
#endif // __SWITCH__
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// init chiaki lib
|
||||||
|
ChiakiLog log;
|
||||||
|
#if defined(CHIAKI_ENABLE_SWITCH_NXLINK) || defined(CHIAKI_SWITCH_ENABLE_LINUX)
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
chiaki_log_init(&log, CHIAKI_LOG_ALL ^ CHIAKI_LOG_VERBOSE, chiaki_log_cb_print, NULL);
|
||||||
|
#else
|
||||||
|
chiaki_log_init(&log, CHIAKI_LOG_ALL, chiaki_log_cb_print, NULL);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// null log for switch version
|
||||||
|
chiaki_log_init(&log, 0, chiaki_log_cb_print, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// load chiaki lib
|
||||||
|
CHIAKI_LOGI(&log, "Loading chaki lib");
|
||||||
|
|
||||||
|
ChiakiErrorCode err = chiaki_lib_init();
|
||||||
|
if(err != CHIAKI_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
CHIAKI_LOGE(&log, "Chiaki lib init failed: %s\n", chiaki_error_string(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build sdl OpenGl and AV decoders graphical interface
|
||||||
|
IO io = IO(&log); // open Input Output class
|
||||||
|
|
||||||
|
// manage ps4 setting discovery wakeup and registration
|
||||||
|
std::map<std::string, Host> hosts;
|
||||||
|
// create host objects form config file
|
||||||
|
Settings settings = Settings(&log, &hosts);
|
||||||
|
CHIAKI_LOGI(&log, "Read chiaki settings file");
|
||||||
|
// FIXME use GUI for config
|
||||||
|
settings.ParseFile();
|
||||||
|
Host * host = nullptr;
|
||||||
|
|
||||||
|
DiscoveryManager discoverymanager = DiscoveryManager(&settings);
|
||||||
|
MainApplication app = MainApplication(&hosts, &settings, &discoverymanager, &io, &log);
|
||||||
|
app.Load();
|
||||||
|
|
||||||
|
CHIAKI_LOGI(&log, "Quit applet");
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
561
switch/src/settings.cpp
Normal file
561
switch/src/settings.cpp
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Chiaki.
|
||||||
|
*
|
||||||
|
* Chiaki is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chiaki is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <chiaki/base64.h>
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
Host * Settings::GetOrCreateHost(std::string *host_name)
|
||||||
|
{
|
||||||
|
bool created = false;
|
||||||
|
// update of create Host instance
|
||||||
|
if(this->hosts->find(*host_name) == hosts->end())
|
||||||
|
{
|
||||||
|
// create host if udefined
|
||||||
|
Host h = Host(this->log, this, *host_name);
|
||||||
|
this->hosts->emplace( *host_name, h);
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Host *host = &(this->hosts->at(*host_name));
|
||||||
|
if(created)
|
||||||
|
{
|
||||||
|
// copy default settings
|
||||||
|
// to the newly created host
|
||||||
|
this->SetPSNOnlineID(host, this->global_psn_online_id);
|
||||||
|
this->SetPSNAccountID(host, this->global_psn_account_id);
|
||||||
|
this->SetVideoResolution(host, this->global_video_resolution);
|
||||||
|
this->SetVideoFPS(host, this->global_video_fps);
|
||||||
|
}
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Settings::ConfigurationItem Settings::ParseLine(std::string *line, std::string *value)
|
||||||
|
{
|
||||||
|
Settings::ConfigurationItem ci;
|
||||||
|
std::smatch m;
|
||||||
|
for(auto it = re_map.begin(); it != re_map.end(); it++)
|
||||||
|
{
|
||||||
|
if(regex_search(*line, m, it->second))
|
||||||
|
{
|
||||||
|
ci = it->first;
|
||||||
|
*value = m[1];
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiLog* Settings::GetLogger()
|
||||||
|
{
|
||||||
|
return this->log;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Settings::GetB64encodeSize(size_t in)
|
||||||
|
{
|
||||||
|
// calculate base64 buffer size after encode
|
||||||
|
return ((4 * in / 3) + 3) & ~3;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::GetPSNOnlineID(Host * host)
|
||||||
|
{
|
||||||
|
if(host == nullptr || host->psn_online_id.length() == 0 )
|
||||||
|
return this->global_psn_online_id;
|
||||||
|
else
|
||||||
|
return host->psn_online_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::GetPSNAccountID(Host * host)
|
||||||
|
{
|
||||||
|
if(host == nullptr || host->psn_account_id.length() == 0 )
|
||||||
|
return this->global_psn_account_id;
|
||||||
|
else
|
||||||
|
return host->psn_account_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetPSNOnlineID(Host * host, std::string psn_online_id)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
this->global_psn_online_id = psn_online_id;
|
||||||
|
else
|
||||||
|
host->psn_online_id = psn_online_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetPSNAccountID(Host * host, std::string psn_account_id)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
this->global_psn_account_id = psn_account_id;
|
||||||
|
else
|
||||||
|
host->psn_account_id = psn_account_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::ResolutionPresetToString(ChiakiVideoResolutionPreset resolution)
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::FPSPresetToString(ChiakiVideoFPSPreset fps)
|
||||||
|
{
|
||||||
|
switch(fps)
|
||||||
|
{
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_30:
|
||||||
|
return "30";
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_60:
|
||||||
|
return "60";
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiVideoResolutionPreset Settings::StringToResolutionPreset(std::string value)
|
||||||
|
{
|
||||||
|
if (value.compare("1080p") == 0)
|
||||||
|
return CHIAKI_VIDEO_RESOLUTION_PRESET_1080p;
|
||||||
|
else if (value.compare("720p") == 0)
|
||||||
|
return CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
else if (value.compare("540p") == 0)
|
||||||
|
return CHIAKI_VIDEO_RESOLUTION_PRESET_540p;
|
||||||
|
else if (value.compare("360p") == 0)
|
||||||
|
return CHIAKI_VIDEO_RESOLUTION_PRESET_360p;
|
||||||
|
|
||||||
|
// default
|
||||||
|
CHIAKI_LOGE(this->log, "Unable to parse String resolution: %s",
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
return CHIAKI_VIDEO_RESOLUTION_PRESET_720p;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiVideoFPSPreset Settings::StringToFPSPreset(std::string value)
|
||||||
|
{
|
||||||
|
if (value.compare("60") == 0)
|
||||||
|
return CHIAKI_VIDEO_FPS_PRESET_60;
|
||||||
|
else if (value.compare("30") == 0)
|
||||||
|
return CHIAKI_VIDEO_FPS_PRESET_30;
|
||||||
|
|
||||||
|
// default
|
||||||
|
CHIAKI_LOGE(this->log, "Unable to parse String fps: %s",
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
return CHIAKI_VIDEO_FPS_PRESET_30;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Settings::FPSPresetToInt(ChiakiVideoFPSPreset fps)
|
||||||
|
{
|
||||||
|
switch(fps)
|
||||||
|
{
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_30:
|
||||||
|
return 30;
|
||||||
|
case CHIAKI_VIDEO_FPS_PRESET_60:
|
||||||
|
return 60;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiVideoResolutionPreset Settings::GetVideoResolution(Host * host)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
return this->global_video_resolution;
|
||||||
|
else
|
||||||
|
return host->video_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChiakiVideoFPSPreset Settings::GetVideoFPS(Host * host)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
return this->global_video_fps;
|
||||||
|
else
|
||||||
|
return host->video_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetVideoResolution(Host * host, ChiakiVideoResolutionPreset value)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
this->global_video_resolution = value;
|
||||||
|
else
|
||||||
|
host->video_resolution = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetVideoResolution(Host * host, std::string value)
|
||||||
|
{
|
||||||
|
ChiakiVideoResolutionPreset p = StringToResolutionPreset(value);
|
||||||
|
this->SetVideoResolution(host, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetVideoFPS(Host * host, ChiakiVideoFPSPreset value)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
this->global_video_fps = value;
|
||||||
|
else
|
||||||
|
host->video_fps = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetVideoFPS(Host * host, std::string value)
|
||||||
|
{
|
||||||
|
ChiakiVideoFPSPreset p = StringToFPSPreset(value);
|
||||||
|
this->SetVideoFPS(host, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CHIAKI_ENABLE_SWITCH_OVERCLOCK
|
||||||
|
int Settings::GetCPUOverclock(Host * host)
|
||||||
|
{
|
||||||
|
if(host == nullptr)
|
||||||
|
return this->global_cpu_overclock;
|
||||||
|
else
|
||||||
|
return host->cpu_overclock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetCPUOverclock(Host * host, int value)
|
||||||
|
{
|
||||||
|
int oc = OC_1326;
|
||||||
|
if(value > OC_1580)
|
||||||
|
// max OC
|
||||||
|
oc = OC_1785;
|
||||||
|
else if(OC_1580 >= value && value > OC_1326)
|
||||||
|
oc = OC_1580;
|
||||||
|
else if(OC_1326 >= value && value > OC_1220)
|
||||||
|
oc = OC_1326;
|
||||||
|
else if(OC_1220 >= value && value > OC_1020)
|
||||||
|
oc = OC_1220;
|
||||||
|
else if(OC_1020 >= value)
|
||||||
|
// no overclock
|
||||||
|
// default nintendo switch value
|
||||||
|
oc = OC_1020;
|
||||||
|
if(host == nullptr)
|
||||||
|
this->global_cpu_overclock = oc;
|
||||||
|
else
|
||||||
|
host->cpu_overclock = oc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::SetCPUOverclock(Host * host, std::string value)
|
||||||
|
{
|
||||||
|
int v = atoi(value.c_str());
|
||||||
|
this->SetCPUOverclock(host, v);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string Settings::GetHostIPAddr(Host * host)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
return host->host_addr;
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot GetHostIPAddr from nullptr host");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::GetHostName(Host * host)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
return host->host_name;
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot GetHostName from nullptr host");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int Settings::GetHostRPKeyType(Host * host)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
return host->rp_key_type;
|
||||||
|
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot GetHostRPKeyType from nullptr host");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Settings::SetHostRPKeyType(Host * host, std::string value)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
// TODO Check possible rp_type values
|
||||||
|
host->rp_key_type = std::atoi(value.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::GetHostRPKey(Host * host)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
if(host->rp_key_data || host->registered)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
rp_key_b64, sizeof(rp_key_b64));
|
||||||
|
|
||||||
|
if(CHIAKI_ERR_SUCCESS == err)
|
||||||
|
return rp_key_b64;
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to encode rp_key to base64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot GetHostRPKey from nullptr host");
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Settings::GetHostRPRegistKey(Host * host)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
if(host->rp_key_data || host->registered)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
rp_regist_key_b64, sizeof(rp_regist_key_b64));
|
||||||
|
|
||||||
|
if(CHIAKI_ERR_SUCCESS == err)
|
||||||
|
return rp_regist_key_b64;
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to encode rp_regist_key to base64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot GetHostRPRegistKey from nullptr host");
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::SetHostRPKey(Host * host, std::string rp_key_b64)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
size_t rp_key_sz = sizeof(host->rp_key);
|
||||||
|
ChiakiErrorCode err = chiaki_base64_decode(
|
||||||
|
rp_key_b64.c_str(), rp_key_b64.length(),
|
||||||
|
host->rp_key, &rp_key_sz);
|
||||||
|
if(CHIAKI_ERR_SUCCESS != err)
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to parse RP_KEY %s (it must be a base64 encoded)", rp_key_b64.c_str());
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot SetHostRPKey from nullptr host");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::SetHostRPRegistKey(Host * host, std::string rp_regist_key_b64)
|
||||||
|
{
|
||||||
|
if(host != nullptr)
|
||||||
|
{
|
||||||
|
size_t rp_regist_key_sz = sizeof(host->rp_regist_key);
|
||||||
|
ChiakiErrorCode err = chiaki_base64_decode(
|
||||||
|
rp_regist_key_b64.c_str(), rp_regist_key_b64.length(),
|
||||||
|
(uint8_t*) host->rp_regist_key, &rp_regist_key_sz);
|
||||||
|
if(CHIAKI_ERR_SUCCESS != err)
|
||||||
|
CHIAKI_LOGE(this->log, "Failed to parse RP_REGIST_KEY %s (it must be a base64 encoded)", rp_regist_key_b64.c_str());
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CHIAKI_LOGE(this->log, "Cannot SetHostRPKey from nullptr host");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::ParseFile()
|
||||||
|
{
|
||||||
|
CHIAKI_LOGI(this->log, "Parse config file %s", this->filename);
|
||||||
|
std::fstream config_file;
|
||||||
|
config_file.open(this->filename, std::fstream::in);
|
||||||
|
std::string line;
|
||||||
|
std::string value;
|
||||||
|
bool rp_key_b, rp_regist_key_b, rp_key_type_b;
|
||||||
|
Host *current_host = nullptr;
|
||||||
|
if(config_file.is_open())
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "Config file opened");
|
||||||
|
Settings::ConfigurationItem ci;
|
||||||
|
while(getline(config_file, line))
|
||||||
|
{
|
||||||
|
CHIAKI_LOGV(this->log, "Parse config line `%s`", line.c_str());
|
||||||
|
// for each line loop over config regex
|
||||||
|
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
|
||||||
|
break;
|
||||||
|
case HOST_IP:
|
||||||
|
CHIAKI_LOGV(this->log, "HOST_IP %s", value.c_str());
|
||||||
|
if(current_host != nullptr)
|
||||||
|
current_host->host_addr = value;
|
||||||
|
|
||||||
|
// reset bool flags
|
||||||
|
rp_key_b=false;
|
||||||
|
rp_regist_key_b=false;
|
||||||
|
rp_key_type_b=false;
|
||||||
|
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;
|
||||||
|
} // ci switch
|
||||||
|
if(rp_key_b && rp_regist_key_b && rp_key_type_b)
|
||||||
|
// the current host contains rp key data
|
||||||
|
current_host->rp_key_data = true;
|
||||||
|
} // is_open
|
||||||
|
config_file.close();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Settings::WriteFile()
|
||||||
|
{
|
||||||
|
std::fstream config_file;
|
||||||
|
CHIAKI_LOGI(this->log, "Write config file %s", this->filename);
|
||||||
|
// flush file (trunc)
|
||||||
|
// the config file is completely overwritten
|
||||||
|
config_file.open(this->filename, std::fstream::out | std::ofstream::trunc);
|
||||||
|
std::string line;
|
||||||
|
std::string value;
|
||||||
|
|
||||||
|
if(this->hosts == nullptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(config_file.is_open())
|
||||||
|
{
|
||||||
|
// save global settings
|
||||||
|
CHIAKI_LOGD(this->log, "Write Global config file %s", this->filename);
|
||||||
|
|
||||||
|
if(this->global_video_resolution)
|
||||||
|
config_file << "video_resolution = \""
|
||||||
|
<< this->ResolutionPresetToString(this->GetVideoResolution(nullptr))
|
||||||
|
<< "\"\n";
|
||||||
|
|
||||||
|
if(this->global_video_fps)
|
||||||
|
config_file << "video_fps = "
|
||||||
|
<< this->FPSPresetToString(this->GetVideoFPS(nullptr))
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
if(this->global_psn_online_id.length())
|
||||||
|
config_file << "psn_online_id = \"" << this->global_psn_online_id << "\"\n";
|
||||||
|
|
||||||
|
if(this->global_psn_account_id.length())
|
||||||
|
config_file << "psn_account_id = \"" << this->global_psn_account_id << "\"\n";
|
||||||
|
|
||||||
|
// write host config in file
|
||||||
|
// loop over all configured
|
||||||
|
for(auto it = this->hosts->begin(); it != this->hosts->end(); it++ )
|
||||||
|
{
|
||||||
|
// first is std::string
|
||||||
|
// second is Host
|
||||||
|
CHIAKI_LOGD(this->log, "Write Host config file %s", it->first.c_str());
|
||||||
|
|
||||||
|
config_file << "[" << it->first << "]\n"
|
||||||
|
<< "host_ip = \"" << it->second.host_addr << "\"\n";
|
||||||
|
|
||||||
|
if(it->second.video_resolution)
|
||||||
|
config_file << "video_resolution = \""
|
||||||
|
<< this->ResolutionPresetToString(this->GetVideoResolution(&it->second))
|
||||||
|
<< "\"\n";
|
||||||
|
|
||||||
|
if(it->second.video_fps)
|
||||||
|
config_file << "video_fps = "
|
||||||
|
<< this->FPSPresetToString(this->GetVideoFPS(&it->second))
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
if(it->second.psn_online_id.length())
|
||||||
|
config_file << "psn_online_id = \"" << it->second.psn_online_id << "\"\n";
|
||||||
|
|
||||||
|
if(it->second.psn_account_id.length())
|
||||||
|
config_file << "psn_account_id = \"" << it->second.psn_account_id << "\"\n";
|
||||||
|
|
||||||
|
if(it->second.rp_key_data || it->second.registered)
|
||||||
|
{
|
||||||
|
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"
|
||||||
|
<< "rp_regist_key = \"" << this->GetHostRPRegistKey(&it->second) << "\"\n"
|
||||||
|
<< "rp_key_type = " << rp_key_type << "\n";
|
||||||
|
} //
|
||||||
|
config_file << "\n";
|
||||||
|
} // for host
|
||||||
|
} // is_open
|
||||||
|
config_file.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
71
third-party/CMakeLists.txt
vendored
71
third-party/CMakeLists.txt
vendored
|
@ -50,3 +50,74 @@ if(NOT CHIAKI_USE_SYSTEM_JERASURE)
|
||||||
|
|
||||||
add_library(Jerasure::Jerasure ALIAS jerasure)
|
add_library(Jerasure::Jerasure ALIAS jerasure)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
##################
|
||||||
|
# borealis
|
||||||
|
##################
|
||||||
|
|
||||||
|
if(CHIAKI_ENABLE_SWITCH)
|
||||||
|
# do not include
|
||||||
|
# borealis/library/lib/switch_wrapper.c
|
||||||
|
# switch functions are in switch/src/main.cpp
|
||||||
|
set(BOREALIS_SOURCE
|
||||||
|
borealis/library/lib/extern/libretro-common/features/features_cpu.c
|
||||||
|
borealis/library/lib/extern/libretro-common/encodings/encoding_utf.c
|
||||||
|
borealis/library/lib/extern/libretro-common/compat/compat_strl.c
|
||||||
|
borealis/library/lib/extern/nxfmtwrapper/format.cpp
|
||||||
|
borealis/library/lib/extern/nanovg/nanovg.c
|
||||||
|
borealis/library/lib/extern/glad/glad.c
|
||||||
|
borealis/library/lib/scroll_view.cpp
|
||||||
|
borealis/library/lib/style.cpp
|
||||||
|
borealis/library/lib/table.cpp
|
||||||
|
borealis/library/lib/task_manager.cpp
|
||||||
|
borealis/library/lib/progress_display.cpp
|
||||||
|
borealis/library/lib/staged_applet_frame.cpp
|
||||||
|
borealis/library/lib/applet_frame.cpp
|
||||||
|
borealis/library/lib/hint.cpp
|
||||||
|
borealis/library/lib/image.cpp
|
||||||
|
borealis/library/lib/logger.cpp
|
||||||
|
borealis/library/lib/swkbd.cpp
|
||||||
|
borealis/library/lib/crash_frame.cpp
|
||||||
|
borealis/library/lib/header.cpp
|
||||||
|
borealis/library/lib/progress_spinner.cpp
|
||||||
|
borealis/library/lib/layer_view.cpp
|
||||||
|
borealis/library/lib/notification_manager.cpp
|
||||||
|
borealis/library/lib/rectangle.cpp
|
||||||
|
borealis/library/lib/application.cpp
|
||||||
|
borealis/library/lib/box_layout.cpp
|
||||||
|
borealis/library/lib/sidebar.cpp
|
||||||
|
borealis/library/lib/dropdown.cpp
|
||||||
|
borealis/library/lib/popup_frame.cpp
|
||||||
|
borealis/library/lib/repeating_task.cpp
|
||||||
|
borealis/library/lib/absolute_layout.cpp
|
||||||
|
borealis/library/lib/i18n.cpp
|
||||||
|
borealis/library/lib/tab_frame.cpp
|
||||||
|
borealis/library/lib/thumbnail_frame.cpp
|
||||||
|
borealis/library/lib/animations.cpp
|
||||||
|
borealis/library/lib/dialog.cpp
|
||||||
|
borealis/library/lib/view.cpp
|
||||||
|
borealis/library/lib/list.cpp
|
||||||
|
borealis/library/lib/button.cpp
|
||||||
|
borealis/library/lib/label.cpp
|
||||||
|
borealis/library/lib/theme.cpp
|
||||||
|
borealis/library/lib/material_icon.cpp)
|
||||||
|
|
||||||
|
add_library(borealis STATIC ${BOREALIS_SOURCE})
|
||||||
|
target_include_directories(borealis PUBLIC
|
||||||
|
borealis/library/include
|
||||||
|
borealis/library/include/borealis/extern
|
||||||
|
borealis/library/include/borealis/extern/glad
|
||||||
|
borealis/library/include/borealis/extern/nanovg
|
||||||
|
borealis/library/include/borealis/extern/libretro-common
|
||||||
|
borealis/library/lib/extern/fmt/include)
|
||||||
|
|
||||||
|
find_package(glfw3 REQUIRED)
|
||||||
|
find_library(EGL EGL)
|
||||||
|
find_library(GLAPI glapi)
|
||||||
|
find_library(DRM_NOUVEAU drm_nouveau)
|
||||||
|
target_link_libraries(borealis
|
||||||
|
glfw
|
||||||
|
${EGL}
|
||||||
|
${GLAPI}
|
||||||
|
${DRM_NOUVEAU})
|
||||||
|
endif()
|
||||||
|
|
1
third-party/borealis
vendored
Submodule
1
third-party/borealis
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 205e97ab45922fa7f5c9fa6a85d5d686cd50b669
|
Loading…
Add table
Add a link
Reference in a new issue