mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-07-30 11:40:26 -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
|
||||
on: [push]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -13,4 +17,8 @@ jobs:
|
|||
git submodule update
|
||||
- name: Build Chiaki
|
||||
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"]
|
||||
path = android/app/src/main/cpp/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")
|
||||
|
||||
# configure nintendo switch toolchain
|
||||
if(CHIAKI_ENABLE_SWITCH AND CHIAKI_ENABLE_SWITCH_LINUX)
|
||||
# CHIAKI_ENABLE_SWITCH_LINUX is a special testing version
|
||||
# the aim is to troubleshoot nitendo switch chiaki verison
|
||||
# from a x86 linux os
|
||||
add_definitions(-DCHIAKI_ENABLE_SWITCH_LINUX)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
elseif(CHIAKI_ENABLE_SWITCH)
|
||||
add_definitions(-D__SWITCH__)
|
||||
if(CHIAKI_ENABLE_SWITCH)
|
||||
# load switch.cmake toolchain form ./cmake folder
|
||||
# include(switch)
|
||||
# to compile borealis third party
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
# TODO check if android ... or other versions are enabled
|
||||
# force mbedtls as crypto lib
|
||||
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()
|
||||
|
||||
if(CHIAKI_USE_SYSTEM_JERASURE)
|
||||
|
@ -120,6 +131,5 @@ if(CHIAKI_ENABLE_ANDROID)
|
|||
endif()
|
||||
|
||||
if(CHIAKI_ENABLE_SWITCH)
|
||||
#TODO
|
||||
#add_subdirectory(switch)
|
||||
add_subdirectory(switch)
|
||||
endif()
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[](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
|
||||
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.
|
||||
* **macOS**: Drag the application from the `.dmg` into your Applications folder.
|
||||
* **Windows**: Extract the `.zip` file and execute `chiaki.exe`.
|
||||
* **Switch**: Follow README specific [instructions](./switch/README.md)
|
||||
|
||||
### Building from Source
|
||||
|
||||
|
|
|
@ -1,116 +1,79 @@
|
|||
# https://github.com/nxengine/nxengine-evo
|
||||
|
||||
# Find DEVKITPRO
|
||||
if(NOT DEFINED ENV{DEVKITPRO})
|
||||
message(FATAL_ERROR "You must have defined DEVKITPRO before calling cmake.")
|
||||
if(NOT DEFINED ENV{DEVKITPRO} OR NOT DEFINED ENV{PORTLIBS_PREFIX})
|
||||
message(FATAL_ERROR "Please set DEVKITPRO & PORTLIBS_PREFIX env before calling cmake. https://devkitpro.org/wiki/Getting_Started")
|
||||
endif()
|
||||
|
||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
||||
set(DEVKITPRO "$ENV{DEVKITPRO}")
|
||||
set(PORTLIBS_PREFIX "$ENV{PORTLIBS_PREFIX}")
|
||||
|
||||
function(switchvar cmakevar var default)
|
||||
# read or set env var
|
||||
if(NOT DEFINED "ENV{$var}")
|
||||
set("ENV{$var}" default)
|
||||
endif()
|
||||
set("$cmakevar" "ENV{$var}")
|
||||
endfunction()
|
||||
# include devkitpro toolchain
|
||||
include("${DEVKITPRO}/switch.cmake")
|
||||
|
||||
# allow gcc -g to use
|
||||
# aarch64-none-elf-addr2line -e build_switch/switch/chiaki -f -p -C -a 0xCCB5C
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
# Enable gcc -g, to use
|
||||
# /opt/devkitpro/devkitA64/bin/aarch64-none-elf-addr2line -e build_switch/switch/chiaki -f -p -C -a 0xCCB5C
|
||||
# set(CMAKE_BUILD_TYPE Debug)
|
||||
# set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
# set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available" )
|
||||
|
||||
set( TOOL_OS_SUFFIX "" )
|
||||
if( CMAKE_HOST_WIN32 )
|
||||
set( TOOL_OS_SUFFIX ".exe" )
|
||||
endif()
|
||||
# FIXME rework this file to use the toolchain only
|
||||
# https://github.com/diasurgical/devilutionX/pull/764
|
||||
set(ARCH "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -ftls-model=local-exec")
|
||||
# set(CMAKE_C_FLAGS "-O2 -ffunction-sections ${ARCH}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")
|
||||
# workaroud force -fPIE to avoid
|
||||
# aarch64-none-elf/bin/ld: read-only segment has dynamic relocations
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-specs=${DEVKITPRO}/libnx/switch.specs ${ARCH} -fPIE -Wl,-Map,Output.map")
|
||||
|
||||
set(CMAKE_SYSTEM_PROCESSOR "armv8-a")
|
||||
set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler")
|
||||
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")
|
||||
# add portlibs to the list of include dir
|
||||
include_directories("${PORTLIBS_PREFIX}/include")
|
||||
|
||||
# custom /opt/devkitpro/switchvars.sh
|
||||
switchvar(PORTLIBS_PREFIX PORTLIBS_PREFIX "${DEVKITPRO}/portlibs/switch")
|
||||
switchvar(ARCH ARCH "-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec")
|
||||
switchvar(CMAKE_C_FLAGS CFLAGS "${ARCH} -O2 -ffunction-sections -fdata-sections")
|
||||
switchvar(CMAKE_CXX_FLAGS CXXFLAGS "${CMAKE_C_FLAGS}")
|
||||
switchvar(CMAKE_CPP_FLAGS CPPFLAGS "-D__SWITCH__ -I${PORTLIBS_PREFIX}/include -isystem${DEVKITPRO}/libnx/include")
|
||||
switchvar(CMAKE_LD_FLAGS LDFLAGS "${ARCH} -L${PORTLIBS_PREFIX}/lib -L${DEVKITPRO}/libnx/lib")
|
||||
switchvar(LIBS LIBS "-lnx")
|
||||
|
||||
|
||||
|
||||
# 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 )
|
||||
# troubleshoot
|
||||
message(STATUS "CMAKE_FIND_ROOT_PATH = ${CMAKE_FIND_ROOT_PATH}")
|
||||
message(STATUS "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}")
|
||||
message(STATUS "CMAKE_EXE_LINKER_FLAGS = ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
get_property(include_directories DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
|
||||
message(STATUS "INCLUDE_DIRECTORIES = ${include_directories}")
|
||||
message(STATUS "CMAKE_C_COMPILER = ${CMAKE_C_COMPILER}")
|
||||
message(STATUS "CMAKE_CXX_COMPILER = ${CMAKE_CXX_COMPILER}")
|
||||
|
||||
find_program(ELF2NRO elf2nro ${DEVKITPRO}/tools/bin)
|
||||
if (ELF2NRO)
|
||||
message(STATUS "elf2nro: ${ELF2NRO} - found")
|
||||
else ()
|
||||
message(WARNING "elf2nro - not found")
|
||||
endif ()
|
||||
else()
|
||||
message(WARNING "elf2nro - not found")
|
||||
endif()
|
||||
|
||||
find_program(NACPTOOL nacptool ${DEVKITPRO}/tools/bin)
|
||||
if (NACPTOOL)
|
||||
message(STATUS "nacptool: ${NACPTOOL} - found")
|
||||
else ()
|
||||
message(WARNING "nacptool - not found")
|
||||
endif ()
|
||||
message(STATUS "nacptool: ${NACPTOOL} - found")
|
||||
else()
|
||||
message(WARNING "nacptool - not found")
|
||||
endif()
|
||||
|
||||
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}
|
||||
COMMAND ${__NACP_COMMAND}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}
|
||||
COMMAND ${__NACP_COMMAND}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(add_nro_target target title author version icon romfs)
|
||||
get_filename_component(target_we ${target} NAME_WE)
|
||||
if (NOT ${target_we}.nacp)
|
||||
__add_nacp(${target_we}.nacp ${title} ${author} ${version})
|
||||
endif ()
|
||||
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
|
||||
# --romfsdir=${romfs}
|
||||
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)
|
||||
get_filename_component(target_we ${target} NAME_WE)
|
||||
if(NOT ${target_we}.nacp)
|
||||
__add_nacp(${target_we}.nacp ${title} ${author} ${version})
|
||||
endif()
|
||||
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
|
||||
--romfsdir=${romfs}
|
||||
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()
|
||||
|
||||
|
||||
|
|
|
@ -101,8 +101,10 @@ target_link_libraries(chiaki-lib Threads::Threads)
|
|||
|
||||
if(CHIAKI_LIB_ENABLE_MBEDTLS)
|
||||
# provided by mbedtls-static (mbedtls-devel)
|
||||
# find_package(mbedcrypto REQUIRED)
|
||||
target_link_libraries(chiaki-lib mbedtls mbedx509 mbedcrypto)
|
||||
find_library(MBEDTLS mbedtls)
|
||||
find_library(MBEDX509 mbedx509)
|
||||
find_library(MBEDCRYPTO mbedcrypto)
|
||||
target_link_libraries(chiaki-lib ${MBEDTLS} ${MBEDX509} ${MBEDCRYPTO})
|
||||
elseif(CHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT)
|
||||
target_link_libraries(chiaki-lib OpenSSL_Crypto)
|
||||
else()
|
||||
|
@ -111,11 +113,6 @@ else()
|
|||
target_link_libraries(chiaki-lib OpenSSL::Crypto)
|
||||
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 Jerasure::Jerasure)
|
||||
|
||||
|
|
|
@ -3,15 +3,14 @@
|
|||
set -xveo pipefail
|
||||
|
||||
arg1=$1
|
||||
CHIAKI_ENABLE_SWITCH_LINUX="ON"
|
||||
CHIAKI_SWITCH_ENABLE_LINUX="ON"
|
||||
build="./build"
|
||||
if [ "$arg1" != "linux" ]; then
|
||||
CHIAKI_ENABLE_SWITCH_LINUX="OFF"
|
||||
source /opt/devkitpro/switchvars.sh
|
||||
toolchain=../cmake/switch.cmake # TODO: devkitpro ships a toolchain in /opt/devkitpro/switch.cmake, but it's broken.
|
||||
|
||||
export CC=${TOOL_PREFIX}gcc
|
||||
export CXX=${TOOL_PREFIX}g++
|
||||
CHIAKI_SWITCH_ENABLE_LINUX="OFF"
|
||||
# source /opt/devkitpro/switchvars.sh
|
||||
# toolchain="${DEVKITPRO}/switch.cmake"
|
||||
toolchain="cmake/switch.cmake"
|
||||
export PORTLIBS_PREFIX="$(${DEVKITPRO}/portlibs_prefix.sh switch)"
|
||||
build="./build_switch"
|
||||
fi
|
||||
|
||||
|
@ -22,14 +21,17 @@ build_chiaki (){
|
|||
pushd "${BASEDIR}"
|
||||
#rm -rf ./build
|
||||
|
||||
cmake -B "${build}" -DCMAKE_TOOLCHAIN_FILE=${toolchain} \
|
||||
cmake -B "${build}" \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${toolchain} \
|
||||
-DCHIAKI_ENABLE_TESTS=OFF \
|
||||
-DCHIAKI_ENABLE_CLI=OFF \
|
||||
-DCHIAKI_ENABLE_GUI=OFF \
|
||||
-DCHIAKI_ENABLE_ANDROID=OFF \
|
||||
-DCHIAKI_ENABLE_SWITCH=ON \
|
||||
-DCHIAKI_ENABLE_SWITCH_LINUX="${CHIAKI_ENABLE_SWITCH_LINUX}" \
|
||||
-DCHIAKI_LIB_ENABLE_MBEDTLS=ON
|
||||
-DCHIAKI_SWITCH_ENABLE_LINUX="${CHIAKI_SWITCH_ENABLE_LINUX}" \
|
||||
-DCHIAKI_LIB_ENABLE_MBEDTLS=ON \
|
||||
# -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
|
||||
# -DCMAKE_FIND_DEBUG_MODE=ON
|
||||
|
||||
pushd "${BASEDIR}/${build}"
|
||||
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 \
|
||||
-v "`pwd`:/build/chiaki" \
|
||||
-w "/build/chiaki" \
|
||||
-t \
|
||||
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)
|
||||
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