mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-04 00:36:01 +00:00
Merge branch 'master' into pc
This commit is contained in:
commit
e1ae9f4874
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "common"]
|
[submodule "common"]
|
||||||
path = common
|
path = third_party/moonlight-common-c
|
||||||
url = https://github.com/irtimmer/moonlight-common-c.git
|
url = https://github.com/irtimmer/moonlight-common-c.git
|
||||||
|
@ -6,10 +6,10 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
|||||||
aux_source_directory(./src SRC_LIST)
|
aux_source_directory(./src SRC_LIST)
|
||||||
list(APPEND SRC_LIST ./src/video/fake.c)
|
list(APPEND SRC_LIST ./src/video/fake.c)
|
||||||
|
|
||||||
aux_source_directory(./common/limelight-common SRC_LIST)
|
aux_source_directory(./third_party/moonlight-common-c/limelight-common SRC_LIST)
|
||||||
aux_source_directory(./common/limelight-common/OpenAES SRC_LIST)
|
aux_source_directory(./third_party/moonlight-common-c/limelight-common/OpenAES SRC_LIST)
|
||||||
|
|
||||||
include_directories(./common)
|
include_directories(./third_party/moonlight-common-c)
|
||||||
|
|
||||||
set(MOONLIGHT_DEFINITIONS)
|
set(MOONLIGHT_DEFINITIONS)
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ find_package(ALSA REQUIRED)
|
|||||||
find_package(Opus REQUIRED)
|
find_package(Opus REQUIRED)
|
||||||
find_package(Broadcom)
|
find_package(Broadcom)
|
||||||
find_package(Freescale)
|
find_package(Freescale)
|
||||||
|
find_package(CEC)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(EVDEV REQUIRED libevdev)
|
pkg_check_modules(EVDEV REQUIRED libevdev)
|
||||||
@ -31,9 +32,14 @@ pkg_check_modules(AVCODEC libavcodec)
|
|||||||
pkg_check_modules(AVUTIL libavutil)
|
pkg_check_modules(AVUTIL libavutil)
|
||||||
pkg_check_modules(SWSCALE libswscale)
|
pkg_check_modules(SWSCALE libswscale)
|
||||||
|
|
||||||
|
if(CEC_FOUND)
|
||||||
|
include_directories(./third_party/libcec)
|
||||||
|
list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(BROADCOM_FOUND)
|
if(BROADCOM_FOUND)
|
||||||
aux_source_directory(./ilclient SRC_LIST)
|
aux_source_directory(./third_party/ilclient SRC_LIST)
|
||||||
aux_source_directory(./h264bitstream SRC_LIST)
|
aux_source_directory(./third_party/h264bitstream SRC_LIST)
|
||||||
list(APPEND SRC_LIST ./src/video/omx.c)
|
list(APPEND SRC_LIST ./src/video/omx.c)
|
||||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_OMX)
|
list(APPEND MOONLIGHT_DEFINITIONS HAVE_OMX)
|
||||||
endif()
|
endif()
|
||||||
@ -52,7 +58,7 @@ add_executable(moonlight ${SRC_LIST})
|
|||||||
set_property(TARGET moonlight PROPERTY C_STANDARD 11)
|
set_property(TARGET moonlight PROPERTY C_STANDARD 11)
|
||||||
|
|
||||||
if(BROADCOM_FOUND)
|
if(BROADCOM_FOUND)
|
||||||
include_directories(./ilclient ./h264bitstream ${BROADCOM_INCLUDE_DIRS})
|
include_directories(./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS})
|
||||||
target_link_libraries (moonlight PUBLIC ${BROADCOM_LIBRARIES})
|
target_link_libraries (moonlight PUBLIC ${BROADCOM_LIBRARIES})
|
||||||
list(APPEND MOONLIGHT_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
list(APPEND MOONLIGHT_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
||||||
endif()
|
endif()
|
||||||
@ -68,8 +74,8 @@ if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND AND SDL_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${MOONLIGHT_DEFINITIONS})
|
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${MOONLIGHT_DEFINITIONS})
|
||||||
include_directories(./moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${AVAHI_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS})
|
include_directories(./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${AVAHI_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ${CEC_INCLUDE_DIRS})
|
||||||
target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS})
|
target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS} ${CEC_LIBRARIES})
|
||||||
|
|
||||||
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
|
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
|
||||||
install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
129
README.md
129
README.md
@ -8,31 +8,12 @@ your powerful Windows desktop to your embedded system, like Raspberry Pi, CuBox-
|
|||||||
|
|
||||||
For a demo see this [video](https://www.youtube.com/watch?v=XRW6O0bSHNw).
|
For a demo see this [video](https://www.youtube.com/watch?v=XRW6O0bSHNw).
|
||||||
|
|
||||||
[Moonlight-common-c](https://github.com/moonlight-stream/moonlight-common-c) is the shared codebase between
|
|
||||||
different C implementations of Moonlight
|
|
||||||
|
|
||||||
[Moonlight](https://github.com/moonlight-stream/moonlight-android) also has an Android
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
[Moonlight-pc](https://github.com/moonlight-stream/moonlight-pc) also has an Linux/OSX/Windows
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
[Moonlight iOS](https://github.com/moonlight-stream/moonlight-ios) also has an iOS
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
[Moonlight Windows](https://github.com/moonlight-stream/moonlight-windows) also has an Windows and Windows Phone
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
|
|
||||||
* Streams Steam and all of your games from your PC to your embedded system.
|
* Streams Steam and all of your games from your PC to your embedded system.
|
||||||
|
* Use mDNS to scan for compatible GeForce Experience (GFE) machines on the network.
|
||||||
##Installation
|
* Qwerty Keyboard, Mouse and Gamepad support
|
||||||
|
* Support Raspberry Pi and i.MX 6 devices
|
||||||
* Download [GeForce Experience](http://www.geforce.com/geforce-experience) and install on your Windows PC
|
|
||||||
* Download the compiled version from the [GitHub releases page](https://github.com/irtimmer/moonlight-embedded/releases)
|
|
||||||
* Install libopus0 (Debian/Raspbian) or opus (Arch Linux/Fedora/Pidora)
|
|
||||||
* [Configure sound](http://elinux.org/R-Pi_Troubleshooting#Sound)
|
|
||||||
|
|
||||||
##Requirements
|
##Requirements
|
||||||
|
|
||||||
@ -50,10 +31,12 @@ implementation.
|
|||||||
* Play games!
|
* Play games!
|
||||||
|
|
||||||
##Usage
|
##Usage
|
||||||
|
|
||||||
Usage: moonlight [options] host
|
Usage: moonlight [options] host
|
||||||
|
|
||||||
Actions:
|
Actions:
|
||||||
|
|
||||||
|
map Create mapping file for gamepad
|
||||||
pair Pair device with computer
|
pair Pair device with computer
|
||||||
stream Stream computer to device
|
stream Stream computer to device
|
||||||
list List available games and applications
|
list List available games and applications
|
||||||
@ -71,23 +54,117 @@ implementation.
|
|||||||
-bitrate <bitrate> Specify the bitrate in Kbps
|
-bitrate <bitrate> Specify the bitrate in Kbps
|
||||||
-packetsize <size> Specify the maximum packetsize in bytes
|
-packetsize <size> Specify the maximum packetsize in bytes
|
||||||
-app <app> Name of app to stream
|
-app <app> Name of app to stream
|
||||||
|
-nosops Don't allow GFE to modify game settings
|
||||||
|
-input <device> Use <device> as input. Can be used multiple times
|
||||||
|
-mapping <file> Use <file> as gamepad mapping configuration file (use before -input)
|
||||||
|
-audio <device> Use <device> as ALSA audio output device (default sysdefault)
|
||||||
|
-localaudio Play audio locally
|
||||||
|
|
||||||
Use ctrl-c to exit application
|
Use ctrl-c to exit application
|
||||||
|
|
||||||
##Compile
|
## Packages
|
||||||
|
Prebuilt binary packages for Raspbian Wheezy are available, add this line to your */etc/apt/sources.list*
|
||||||
|
```
|
||||||
|
deb http://archive.itimmer.nl/raspbian/moonlight wheezy main
|
||||||
|
```
|
||||||
|
|
||||||
* Install cmake
|
Install package using the following commands
|
||||||
* Install cryptographics libraries libssl-dev (Debian/Raspbian) or openssl-devel (Fedora/Pidora) or openssl (Arch Linux)
|
```
|
||||||
* Install audio libraries libopus-dev and libasound2-dev (Debian/Raspbian) or opus-devel and alsa-lib-devel (Fedora/Pidora) or opus and alsa-lib (Arch Linux)
|
apt-get update
|
||||||
|
apt-get install moonlight-embedded
|
||||||
|
```
|
||||||
|
|
||||||
|
Source package for ArchLinux is available in [AUR](https://aur.archlinux.org/packages/moonlight-embedded/)
|
||||||
|
|
||||||
|
Prebuilt binary packages for ArchLinux ARM are available, add those lines to you */etc/pacman.conf*
|
||||||
|
```
|
||||||
|
[moonlight]
|
||||||
|
Server = http://archive.itimmer.nl/archlinux/$repo/os/$arch
|
||||||
|
SigLevel = Optional
|
||||||
|
```
|
||||||
|
|
||||||
|
Install package using the following command
|
||||||
|
```
|
||||||
|
pacman -Sy moonlight-embedded
|
||||||
|
```
|
||||||
|
|
||||||
|
##Compile and install
|
||||||
|
|
||||||
|
* Download and extract Moonlight Embedded from release or git clone
|
||||||
|
* Install development dependencies (see Dependencies)
|
||||||
* Initialize the git submodules ``git submodule update --init``
|
* Initialize the git submodules ``git submodule update --init``
|
||||||
|
* Build and install using the following commands
|
||||||
|
|
||||||
```
|
```
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build/
|
cd build/
|
||||||
cmake ../
|
cmake ../
|
||||||
make
|
make
|
||||||
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
### ArchLinux
|
||||||
|
Install with
|
||||||
|
```
|
||||||
|
pacman -S (package list)
|
||||||
|
```
|
||||||
|
* opus
|
||||||
|
* expat
|
||||||
|
* openssl
|
||||||
|
* alsa-lib
|
||||||
|
* avahi
|
||||||
|
* libevdev
|
||||||
|
|
||||||
|
For compilation and development you also need:
|
||||||
|
* cmake
|
||||||
|
|
||||||
|
### Debian (Raspbian)
|
||||||
|
Install with
|
||||||
|
```
|
||||||
|
apt-get install (package list)
|
||||||
|
```
|
||||||
|
* libopus0
|
||||||
|
* libexpat1
|
||||||
|
* libasound2
|
||||||
|
* libudev0
|
||||||
|
* libavahi-client3
|
||||||
|
* libcurl3
|
||||||
|
* libevdev2
|
||||||
|
|
||||||
|
For compilation and development you also need:
|
||||||
|
* libssl-dev
|
||||||
|
* libopus-dev
|
||||||
|
* libasound2-dev
|
||||||
|
* libudev-dev
|
||||||
|
* libavahi-client-dev
|
||||||
|
* libcurl4-openssl-dev
|
||||||
|
* libevdev-dev
|
||||||
|
* cmake
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
[Moonlight-common-c](https://github.com/moonlight-stream/moonlight-common-c) is the shared codebase between
|
||||||
|
different C implementations of Moonlight
|
||||||
|
|
||||||
|
[Moonlight-common-c](https://github.com/irtimmer/moonlight-common-c) is the used fork used by Moonlight Embedded
|
||||||
|
|
||||||
|
[Moonlight-common](https://github.com/moonlight-stream/moonlight-common) is the shared codebase between
|
||||||
|
different Java implementations of Moonlight
|
||||||
|
|
||||||
|
[Moonlight](https://github.com/moonlight-stream/moonlight-android) also has an Android
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
[Moonlight-pc](https://github.com/moonlight-stream/moonlight-pc) also has an Linux/OSX/Windows
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
[Moonlight iOS](https://github.com/moonlight-stream/moonlight-ios) also has an iOS
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
[Moonlight Windows](https://github.com/moonlight-stream/moonlight-windows) also has an Windows and Windows Phone
|
||||||
|
implementation.
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
[XDA](http://forum.xda-developers.com/showthread.php?t=2505510)
|
[XDA](http://forum.xda-developers.com/showthread.php?t=2505510)
|
||||||
|
19
cmake/FindCEC.cmake
Normal file
19
cmake/FindCEC.cmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# - Try to find CEC
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# CEC_FOUND - system has libcec
|
||||||
|
# CEC_INCLUDE_DIRS - the libcec include directory
|
||||||
|
# CEC_LIBRARIES - The libcec libraries
|
||||||
|
|
||||||
|
if(PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules (CEC libcec>=3.0.0)
|
||||||
|
else()
|
||||||
|
find_path(CEC_INCLUDE_DIRS libcec/cec.h)
|
||||||
|
find_library(CEC_LIBRARIES cec)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(CEC DEFAULT_MSG CEC_INCLUDE_DIRS CEC_LIBRARIES)
|
||||||
|
|
||||||
|
list(APPEND CEC_DEFINITIONS -DHAVE_LIBCEC=1)
|
||||||
|
mark_as_advanced(CEC_INCLUDE_DIRS CEC_LIBRARIES CEC_DEFINITIONS)
|
1
common
1
common
@ -1 +0,0 @@
|
|||||||
Subproject commit fcd2a20e01c202558fc0b9b923a6612d3fce8d50
|
|
6
debian/changelog
vendored
Normal file
6
debian/changelog
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
moonlight-embedded (2.0.1-1) UNRELEASED; urgency=low
|
||||||
|
|
||||||
|
* Initial release
|
||||||
|
* This is my first Debian package
|
||||||
|
|
||||||
|
-- Iwan Timmer <irtimmer@gmail.com> Sat, 20 Jun 2015 11:58:32 +0000
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
14
debian/control
vendored
Normal file
14
debian/control
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Source: moonlight-embedded
|
||||||
|
Section: games
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Iwan Timmer <irtimmer@gmail.com>
|
||||||
|
Build-Depends: debhelper (>= 8.0.0), cmake, libopus-dev, libexpat1-dev, libasound2-dev, libudev-dev, libavahi-client-dev, libcurl4-openssl-dev, libevdev-dev, libraspberrypi-dev
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
Homepage: https://github.com/irtimmer/moonlight-embedded
|
||||||
|
|
||||||
|
Package: moonlight-embedded
|
||||||
|
Architecture: armhf
|
||||||
|
Depends: libopus0, libexpat1, libssl1.0.0, libasound2, libudev0, libavahi-client3, libcurl3, libevdev2, libraspberrypi0, ${shlibs:Depends}, ${misc:Depends}
|
||||||
|
Description: GameStream client for Linux
|
||||||
|
Game streaming client for Nvidia's GameStream.
|
||||||
|
Stream games from your Windows computer with Nvidia graphic card to your linux box.
|
22
debian/copyright
vendored
Normal file
22
debian/copyright
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: moonlight-embedded
|
||||||
|
Source: https://github.com/irtimmer/moonlight-embedded
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2014, 2015 Iwan Timmer <irtimmer@gmail.com>
|
||||||
|
License: GPL-3+
|
||||||
|
This package 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.
|
||||||
|
.
|
||||||
|
This package 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 this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
.
|
||||||
|
On Debian systems, the complete text of the GNU General
|
||||||
|
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
32
debian/patches/install.patch
vendored
Normal file
32
debian/patches/install.patch
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
Compile using older version (2.8) of CMake
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
project(moonlight-embedded C)
|
||||||
|
-cmake_minimum_required(VERSION 3.1)
|
||||||
|
+cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
@@ -44,18 +44,18 @@
|
||||||
|
|
||||||
|
if(BROADCOM_FOUND)
|
||||||
|
include_directories(./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS})
|
||||||
|
- target_link_libraries (moonlight PUBLIC ${BROADCOM_LIBRARIES})
|
||||||
|
+ target_link_libraries (moonlight ${BROADCOM_LIBRARIES})
|
||||||
|
list(APPEND MOONLIGHT_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FREESCALE_FOUND)
|
||||||
|
include_directories(${FREESCALE_INCLUDE_DIRS})
|
||||||
|
- target_link_libraries (moonlight PUBLIC ${FREESCALE_LIBRARIES})
|
||||||
|
+ target_link_libraries (moonlight ${FREESCALE_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${MOONLIGHT_DEFINITIONS})
|
||||||
|
include_directories(./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${AVAHI_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS})
|
||||||
|
-target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||||
|
+target_link_libraries (moonlight ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||||
|
|
||||||
|
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
|
||||||
|
install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_BINDIR})
|
1
debian/patches/series
vendored
Normal file
1
debian/patches/series
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
install.patch
|
8
debian/rules
vendored
Executable file
8
debian/rules
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
export DEB_CFLAGS_MAINT_APPEND = -std=gnu99
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with quilt
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (quilt)
|
@ -36,7 +36,6 @@ static OpusDecoder* decoder;
|
|||||||
static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT];
|
static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT];
|
||||||
|
|
||||||
static void audio_renderer_init() {
|
static void audio_renderer_init() {
|
||||||
printf("audio_renderer_init\n");
|
|
||||||
int rc;
|
int rc;
|
||||||
decoder = opus_decoder_create(SAMPLE_RATE, CHANNEL_COUNT, &rc);
|
decoder = opus_decoder_create(SAMPLE_RATE, CHANNEL_COUNT, &rc);
|
||||||
|
|
||||||
@ -72,8 +71,7 @@ static void audio_renderer_init() {
|
|||||||
CHECK_RETURN(snd_pcm_prepare(handle));
|
CHECK_RETURN(snd_pcm_prepare(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_renderer_release() {
|
static void audio_renderer_cleanup() {
|
||||||
printf("audio_renderer_release\n");
|
|
||||||
if (decoder != NULL)
|
if (decoder != NULL)
|
||||||
opus_decoder_destroy(decoder);
|
opus_decoder_destroy(decoder);
|
||||||
|
|
||||||
@ -101,8 +99,6 @@ static void audio_renderer_decode_and_play_sample(char* data, int length) {
|
|||||||
|
|
||||||
AUDIO_RENDERER_CALLBACKS audio_callbacks = {
|
AUDIO_RENDERER_CALLBACKS audio_callbacks = {
|
||||||
.init = audio_renderer_init,
|
.init = audio_renderer_init,
|
||||||
.start = NULL,
|
.cleanup = audio_renderer_cleanup,
|
||||||
.stop = NULL,
|
|
||||||
.release = audio_renderer_release,
|
|
||||||
.decodeAndPlaySample = audio_renderer_decode_and_play_sample,
|
.decodeAndPlaySample = audio_renderer_decode_and_play_sample,
|
||||||
};
|
};
|
||||||
|
37
src/client.c
37
src/client.c
@ -72,8 +72,9 @@ static void client_load_unique_id() {
|
|||||||
static void client_load_cert() {
|
static void client_load_cert() {
|
||||||
FILE *fd = fopen(certificateFileName, "r");
|
FILE *fd = fopen(certificateFileName, "r");
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
printf("Generating certificate\n");
|
printf("Generating certificate...");
|
||||||
struct CertKeyPair cert = generateCertKeyPair();
|
struct CertKeyPair cert = generateCertKeyPair();
|
||||||
|
printf("done\n");
|
||||||
saveCertKeyPair(certificateFileName, p12FileName, keyFileName, cert);
|
saveCertKeyPair(certificateFileName, p12FileName, keyFileName, cert);
|
||||||
freeCertKeyPair(cert);
|
freeCertKeyPair(cert);
|
||||||
fd = fopen(certificateFileName, "r");
|
fd = fopen(certificateFileName, "r");
|
||||||
@ -85,7 +86,7 @@ static void client_load_cert() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(cert = PEM_read_X509(fd, NULL, NULL, NULL))) {
|
if (!(cert = PEM_read_X509(fd, NULL, NULL, NULL))) {
|
||||||
printf("Error loading cert into memory.\n");
|
fprintf(stderr, "Error loading cert into memory.\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +124,10 @@ static void client_load_server_status(const char *address) {
|
|||||||
|
|
||||||
paired = pairedText != NULL && strcmp(pairedText, "1") == 0;
|
paired = pairedText != NULL && strcmp(pairedText, "1") == 0;
|
||||||
currentGame = currentGameText == NULL ? 0 : atoi(currentGameText);
|
currentGame = currentGameText == NULL ? 0 : atoi(currentGameText);
|
||||||
strstr(versionText, ".")[0] = 0;
|
char *versionSep = strstr(versionText, ".");
|
||||||
|
if (versionSep != NULL) {
|
||||||
|
*versionSep = 0;
|
||||||
|
}
|
||||||
serverMajorVersion = atoi(versionText);
|
serverMajorVersion = atoi(versionText);
|
||||||
|
|
||||||
free(pairedText);
|
free(pairedText);
|
||||||
@ -146,62 +150,62 @@ static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *sl
|
|||||||
|
|
||||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
printf("EVP_MD_CTX_create failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_MD_CTX_create failed, error 0x%lx\n", ERR_get_error());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EVP_MD *md = EVP_get_digestbyname("SHA256");
|
const EVP_MD *md = EVP_get_digestbyname("SHA256");
|
||||||
if (md == NULL) {
|
if (md == NULL) {
|
||||||
printf("EVP_get_digestbyname failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_get_digestbyname failed, error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = EVP_DigestInit_ex(ctx, md, NULL);
|
int rc = EVP_DigestInit_ex(ctx, md, NULL);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
printf("EVP_DigestInit_ex failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_DigestInit_ex failed, error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
|
rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
printf("EVP_DigestSignInit failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_DigestSignInit failed, error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = EVP_DigestSignUpdate(ctx, msg, mlen);
|
rc = EVP_DigestSignUpdate(ctx, msg, mlen);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
printf("EVP_DigestSignUpdate failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_DigestSignUpdate failed, error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t req = 0;
|
size_t req = 0;
|
||||||
rc = EVP_DigestSignFinal(ctx, NULL, &req);
|
rc = EVP_DigestSignFinal(ctx, NULL, &req);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
printf("EVP_DigestSignFinal failed (1), error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_DigestSignFinal failed (1), error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(req > 0)) {
|
if (!(req > 0)) {
|
||||||
printf("EVP_DigestSignFinal failed (2), error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "EVP_DigestSignFinal failed (2), error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
*sig = OPENSSL_malloc(req);
|
*sig = OPENSSL_malloc(req);
|
||||||
if (*sig == NULL) {
|
if (*sig == NULL) {
|
||||||
printf("OPENSSL_malloc failed, error 0x%lx\n", ERR_get_error());
|
fprintf(stderr, "OPENSSL_malloc failed, error 0x%lx\n", ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
*slen = req;
|
*slen = req;
|
||||||
rc = EVP_DigestSignFinal(ctx, *sig, slen);
|
rc = EVP_DigestSignFinal(ctx, *sig, slen);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
printf("EVP_DigestSignFinal failed (3), return code %d, error 0x%lx\n", rc,
|
fprintf(stderr, "EVP_DigestSignFinal failed (3), return code %d, error 0x%lx\n", rc,
|
||||||
ERR_get_error());
|
ERR_get_error());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req != *slen) {
|
if (req != *slen) {
|
||||||
printf("EVP_DigestSignFinal failed, mismatched signature sizes %ld, %ld\n",
|
fprintf(stderr, "EVP_DigestSignFinal failed, mismatched signature sizes %ld, %ld\n",
|
||||||
req, *slen);
|
req, *slen);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -223,6 +227,11 @@ void client_pair(const char *address) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentGame != 0) {
|
||||||
|
fprintf(stderr, "The computer is currently in a game. You must close the game before pairing.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
char pin[5];
|
char pin[5];
|
||||||
sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10);
|
sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10);
|
||||||
printf("Please enter the following PIN on the target PC: %s\n", pin);
|
printf("Please enter the following PIN on the target PC: %s\n", pin);
|
||||||
@ -305,7 +314,7 @@ void client_pair(const char *address) {
|
|||||||
sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, unique_id, client_pairing_secret_hex);
|
sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, unique_id, client_pairing_secret_hex);
|
||||||
http_request(url, data);
|
http_request(url, data);
|
||||||
|
|
||||||
sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", address, unique_id, challenge_response_hex);
|
sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", address, unique_id);
|
||||||
http_request(url, data);
|
http_request(url, data);
|
||||||
http_free_data(data);
|
http_free_data(data);
|
||||||
|
|
||||||
|
@ -18,49 +18,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void connection_stage_starting(int stage)
|
|
||||||
{
|
|
||||||
printf("connection_stage_starting %d\n", stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void connection_stage_complete(int stage)
|
|
||||||
{
|
|
||||||
printf("connection_stage_complete %d\n", stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void connection_stage_failed(int stage, long iets)
|
|
||||||
{
|
|
||||||
printf("connection_stage_failed %d\n", stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void connection_connection_started()
|
|
||||||
{
|
|
||||||
printf("connection_connection_started\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void connection_connection_terminated()
|
void connection_connection_terminated()
|
||||||
{
|
{
|
||||||
printf("connection_connection_terminated\n");
|
quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_display_message(char *msg)
|
void connection_display_message(char *msg)
|
||||||
{
|
{
|
||||||
printf("connection_display_message: %s\n", msg);
|
printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_display_transient_message(char *msg)
|
void connection_display_transient_message(char *msg)
|
||||||
{
|
{
|
||||||
printf("connection_display_transient_message: %s\n", msg);
|
printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
CONNECTION_LISTENER_CALLBACKS connection_callbacks = {
|
CONNECTION_LISTENER_CALLBACKS connection_callbacks = {
|
||||||
.stageStarting = connection_stage_starting,
|
.stageStarting = NULL,
|
||||||
.stageComplete = connection_stage_complete,
|
.stageComplete = NULL,
|
||||||
.stageFailed = connection_stage_failed,
|
.stageFailed = NULL,
|
||||||
.connectionStarted = connection_connection_started,
|
.connectionStarted = NULL,
|
||||||
.connectionTerminated = connection_connection_terminated,
|
.connectionTerminated = connection_connection_terminated,
|
||||||
.displayMessage = connection_display_message,
|
.displayMessage = connection_display_message,
|
||||||
.displayTransientMessage = connection_display_transient_message,
|
.displayTransientMessage = connection_display_transient_message,
|
||||||
|
27
src/global.c
Normal file
27
src/global.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Moonlight Embedded.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Iwan Timmer
|
||||||
|
*
|
||||||
|
* Moonlight 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.
|
||||||
|
*
|
||||||
|
* Moonlight 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 Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
pthread_t main_thread_id;
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
pthread_kill(main_thread_id, SIGTERM);
|
||||||
|
}
|
24
src/global.h
Normal file
24
src/global.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Moonlight Embedded.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Iwan Timmer
|
||||||
|
*
|
||||||
|
* Moonlight 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.
|
||||||
|
*
|
||||||
|
* Moonlight 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 Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
extern pthread_t main_thread_id;
|
||||||
|
|
||||||
|
void quit();
|
@ -56,6 +56,7 @@ void http_init() {
|
|||||||
curl_easy_setopt(curl, CURLOPT_SSLKEY, pKeyFile);
|
curl_easy_setopt(curl, CURLOPT_SSLKEY, pKeyFile);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request(char* url, struct http_data* data) {
|
int http_request(char* url, struct http_data* data) {
|
||||||
|
215
src/input.c
215
src/input.c
@ -19,21 +19,30 @@
|
|||||||
|
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "mapping.h"
|
#include "mapping.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
#include "libevdev/libevdev.h"
|
#include "libevdev/libevdev.h"
|
||||||
#include "limelight-common/Limelight.h"
|
#include "limelight-common/Limelight.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCEC
|
||||||
|
#include <ceccloader.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
struct input_abs_parms {
|
struct input_abs_parms {
|
||||||
int min, max;
|
int min, max;
|
||||||
@ -51,7 +60,7 @@ struct input_device {
|
|||||||
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
||||||
short controllerId;
|
short controllerId;
|
||||||
int buttonFlags;
|
int buttonFlags;
|
||||||
short leftTrigger, rightTrigger;
|
char leftTrigger, rightTrigger;
|
||||||
short leftStickX, leftStickY;
|
short leftStickX, leftStickY;
|
||||||
short rightStickX, rightStickY;
|
short rightStickX, rightStickY;
|
||||||
bool gamepadModified;
|
bool gamepadModified;
|
||||||
@ -74,6 +83,91 @@ static struct udev *udev;
|
|||||||
static struct udev_monitor *udev_mon;
|
static struct udev_monitor *udev_mon;
|
||||||
static int udev_fdindex;
|
static int udev_fdindex;
|
||||||
|
|
||||||
|
static int sig_fdindex;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCEC
|
||||||
|
static libcec_configuration g_config;
|
||||||
|
static char g_strPort[50] = { 0 };
|
||||||
|
static libcec_interface_t g_iface;
|
||||||
|
static ICECCallbacks g_callbacks;
|
||||||
|
|
||||||
|
static int on_cec_keypress(void* userdata, const cec_keypress key) {
|
||||||
|
char value;
|
||||||
|
switch (key.keycode) {
|
||||||
|
case CEC_USER_CONTROL_CODE_UP:
|
||||||
|
value = KEY_UP;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_DOWN:
|
||||||
|
value = KEY_DOWN;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_LEFT:
|
||||||
|
value = KEY_LEFT;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_RIGHT:
|
||||||
|
value = KEY_RIGHT;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_ENTER:
|
||||||
|
case CEC_USER_CONTROL_CODE_SELECT:
|
||||||
|
value = KEY_ENTER;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_ROOT_MENU:
|
||||||
|
value = KEY_TAB;
|
||||||
|
break;
|
||||||
|
case CEC_USER_CONTROL_CODE_AN_RETURN:
|
||||||
|
case CEC_USER_CONTROL_CODE_EXIT:
|
||||||
|
value = KEY_ESC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != 0) {
|
||||||
|
short code = 0x80 << 8 | keyCodes[value];
|
||||||
|
LiSendKeyboardEvent(code, (key.duration > 0)?KEY_ACTION_DOWN:KEY_ACTION_UP, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_cec() {
|
||||||
|
libcecc_reset_configuration(&g_config);
|
||||||
|
g_config.clientVersion = LIBCEC_VERSION_CURRENT;
|
||||||
|
g_config.bActivateSource = 0;
|
||||||
|
g_callbacks.CBCecKeyPress = &on_cec_keypress;
|
||||||
|
g_config.callbacks = &g_callbacks;
|
||||||
|
snprintf(g_config.strDeviceName, sizeof(g_config.strDeviceName), "Moonlight");
|
||||||
|
g_config.callbacks = &g_callbacks;
|
||||||
|
g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
|
||||||
|
|
||||||
|
if (libcecc_initialise(&g_config, &g_iface, NULL) != 1) {
|
||||||
|
fprintf(stderr, "Failed to initialize libcec interface\n");
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_iface.init_video_standalone(g_iface.connection);
|
||||||
|
|
||||||
|
cec_adapter devices[10];
|
||||||
|
int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL);
|
||||||
|
|
||||||
|
if (iDevicesFound <= 0) {
|
||||||
|
fprintf(stderr, "No CEC devices found\n");
|
||||||
|
fflush(stderr);
|
||||||
|
libcecc_destroy(&g_iface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(g_strPort, devices[0].comm);
|
||||||
|
if (!g_iface.open(g_iface.connection, g_strPort, 5000)) {
|
||||||
|
fprintf(stderr, "Unable to open the device on port %s\n", g_strPort);
|
||||||
|
fflush(stderr);
|
||||||
|
libcecc_destroy(&g_iface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_iface.set_active_source(g_iface.connection, g_config.deviceTypes.types[0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void input_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
|
static void input_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
|
||||||
parms->flat = libevdev_get_abs_flat(dev->dev, code);
|
parms->flat = libevdev_get_abs_flat(dev->dev, code);
|
||||||
parms->min = libevdev_get_abs_minimum(dev->dev, code);
|
parms->min = libevdev_get_abs_minimum(dev->dev, code);
|
||||||
@ -109,6 +203,7 @@ void input_create(const char* device, char* mapFile) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&devices[dev], 0, sizeof(devices[0]));
|
||||||
devices[dev].fd = fd;
|
devices[dev].fd = fd;
|
||||||
devices[dev].dev = libevdev_new();
|
devices[dev].dev = libevdev_new();
|
||||||
libevdev_set_fd(devices[dev].dev, devices[dev].fd);
|
libevdev_set_fd(devices[dev].dev, devices[dev].fd);
|
||||||
@ -141,11 +236,15 @@ static void input_remove(int devindex) {
|
|||||||
if (fdindex != numFds && numFds > 0) {
|
if (fdindex != numFds && numFds > 0) {
|
||||||
memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd));
|
memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd));
|
||||||
if (numFds == udev_fdindex)
|
if (numFds == udev_fdindex)
|
||||||
udev_fdindex = numFds;
|
udev_fdindex = fdindex;
|
||||||
|
else if (numFds == sig_fdindex)
|
||||||
|
sig_fdindex = fdindex;
|
||||||
else {
|
else {
|
||||||
for (int i=0;i<numDevices;i++) {
|
for (int i=0;i<numDevices;i++) {
|
||||||
if (devices[i].fdindex == numFds)
|
if (devices[i].fdindex == numFds) {
|
||||||
devices[i].fdindex = fdindex;
|
devices[i].fdindex = fdindex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,13 +255,18 @@ static void input_remove(int devindex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void input_init(char* mapfile) {
|
void input_init(char* mapfile) {
|
||||||
|
#ifdef HAVE_LIBCEC
|
||||||
|
init_cec();
|
||||||
|
#endif
|
||||||
|
|
||||||
udev = udev_new();
|
udev = udev_new();
|
||||||
if (!udev) {
|
if (!udev) {
|
||||||
fprintf(stderr, "Can't create udev\n");
|
fprintf(stderr, "Can't create udev\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoadd = numDevices == 0) {
|
autoadd = (numDevices == 0);
|
||||||
|
if (autoadd) {
|
||||||
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
|
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
|
||||||
udev_enumerate_add_match_subsystem(enumerate, "input");
|
udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||||
udev_enumerate_scan_devices(enumerate);
|
udev_enumerate_scan_devices(enumerate);
|
||||||
@ -187,11 +291,11 @@ void input_init(char* mapfile) {
|
|||||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "input", NULL);
|
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "input", NULL);
|
||||||
udev_monitor_enable_receiving(udev_mon);
|
udev_monitor_enable_receiving(udev_mon);
|
||||||
|
|
||||||
int udev_fdindex = numFds;
|
udev_fdindex = numFds++;
|
||||||
numFds++;
|
sig_fdindex = numFds++;
|
||||||
|
|
||||||
if (fds == NULL)
|
if (fds == NULL)
|
||||||
fds = malloc(sizeof(struct pollfd));
|
fds = malloc(sizeof(struct pollfd)*numFds);
|
||||||
else
|
else
|
||||||
fds = realloc(fds, sizeof(struct pollfd)*numFds);
|
fds = realloc(fds, sizeof(struct pollfd)*numFds);
|
||||||
|
|
||||||
@ -203,6 +307,17 @@ void input_init(char* mapfile) {
|
|||||||
defaultMapfile = mapfile;
|
defaultMapfile = mapfile;
|
||||||
fds[udev_fdindex].fd = udev_monitor_get_fd(udev_mon);
|
fds[udev_fdindex].fd = udev_monitor_get_fd(udev_mon);
|
||||||
fds[udev_fdindex].events = POLLIN;
|
fds[udev_fdindex].events = POLLIN;
|
||||||
|
|
||||||
|
main_thread_id = pthread_self();
|
||||||
|
sigset_t sigset;
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGHUP);
|
||||||
|
sigaddset(&sigset, SIGTERM);
|
||||||
|
sigaddset(&sigset, SIGINT);
|
||||||
|
sigaddset(&sigset, SIGQUIT);
|
||||||
|
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
||||||
|
fds[sig_fdindex].fd = signalfd(-1, &sigset, 0);
|
||||||
|
fds[sig_fdindex].events = POLLIN | POLLERR | POLLHUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_destroy() {
|
void input_destroy() {
|
||||||
@ -216,10 +331,10 @@ static short input_convert_value(struct input_event *ev, struct input_device *de
|
|||||||
return reverse?SHRT_MIN:SHRT_MAX;
|
return reverse?SHRT_MIN:SHRT_MAX;
|
||||||
else if (ev->value < parms->min)
|
else if (ev->value < parms->min)
|
||||||
return reverse?SHRT_MAX:SHRT_MIN;
|
return reverse?SHRT_MAX:SHRT_MIN;
|
||||||
else {
|
else if (reverse)
|
||||||
int value = ev->value + (ev->value<parms->avg?parms->flat:-parms->flat);
|
return (parms->max - (ev->value<parms->avg?parms->flat*2:0) - ev->value) * (SHRT_MAX-SHRT_MIN) / (parms->max-parms->min-parms->flat*2) - SHRT_MIN;
|
||||||
return (value-parms->avg) * SHRT_MAX / ((reverse?-parms->range-1:parms->range) - parms->flat);
|
else
|
||||||
}
|
return (ev->value - (ev->value>parms->avg?parms->flat*2:0) - parms->min) * (SHRT_MAX-SHRT_MIN) / (parms->max-parms->min-parms->flat*2) - SHRT_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char input_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) {
|
static char input_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) {
|
||||||
@ -228,7 +343,7 @@ static char input_convert_value_byte(struct input_event *ev, struct input_device
|
|||||||
else if (ev->value>parms->max)
|
else if (ev->value>parms->max)
|
||||||
return UCHAR_MAX;
|
return UCHAR_MAX;
|
||||||
else {
|
else {
|
||||||
int value = ev->value + parms->flat;
|
int value = ev->value - parms->flat;
|
||||||
return (value-parms->min) * UCHAR_MAX / (parms->diff-parms->flat);
|
return (value-parms->min) * UCHAR_MAX / (parms->diff-parms->flat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,20 +460,20 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
gamepadCode = SPECIAL_FLAG;
|
gamepadCode = SPECIAL_FLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouseCode > 0) {
|
if (mouseCode != 0) {
|
||||||
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
|
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
|
||||||
} else {
|
} else {
|
||||||
gamepadModified = true;
|
gamepadModified = true;
|
||||||
|
|
||||||
if (gamepadCode > 0) {
|
if (gamepadCode != 0) {
|
||||||
if (ev->value)
|
if (ev->value)
|
||||||
dev->buttonFlags |= gamepadCode;
|
dev->buttonFlags |= gamepadCode;
|
||||||
else
|
else
|
||||||
dev->buttonFlags &= ~gamepadCode;
|
dev->buttonFlags &= ~gamepadCode;
|
||||||
} else if (ev->code == dev->map.btn_tl2)
|
} else if (ev->code == dev->map.btn_tl2)
|
||||||
dev->leftTrigger = ev->value?USHRT_MAX:0;
|
dev->leftTrigger = ev->value?UCHAR_MAX:0;
|
||||||
else if (ev->code == dev->map.btn_tr2)
|
else if (ev->code == dev->map.btn_tr2)
|
||||||
dev->rightTrigger = ev->value?USHRT_MAX:0;
|
dev->rightTrigger = ev->value?UCHAR_MAX:0;
|
||||||
else
|
else
|
||||||
gamepadModified = false;
|
gamepadModified = false;
|
||||||
}
|
}
|
||||||
@ -372,7 +487,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
case REL_Y:
|
case REL_Y:
|
||||||
dev->mouseDeltaY = ev->value;
|
dev->mouseDeltaY = ev->value;
|
||||||
break;
|
break;
|
||||||
case REL_Z:
|
case REL_WHEEL:
|
||||||
dev->mouseScroll = ev->value;
|
dev->mouseScroll = ev->value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -396,7 +511,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
if (dir == 1) {
|
if (dir == 1) {
|
||||||
dev->buttonFlags |= RIGHT_FLAG;
|
dev->buttonFlags |= RIGHT_FLAG;
|
||||||
dev->buttonFlags &= ~LEFT_FLAG;
|
dev->buttonFlags &= ~LEFT_FLAG;
|
||||||
} else if (dir == -1) {
|
} else if (dir == 0) {
|
||||||
dev->buttonFlags &= ~RIGHT_FLAG;
|
dev->buttonFlags &= ~RIGHT_FLAG;
|
||||||
dev->buttonFlags &= ~LEFT_FLAG;
|
dev->buttonFlags &= ~LEFT_FLAG;
|
||||||
} else {
|
} else {
|
||||||
@ -406,11 +521,11 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
} else if (ev->code == dev->map.abs_dpad_y) {
|
} else if (ev->code == dev->map.abs_dpad_y) {
|
||||||
int dir = input_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y);
|
int dir = input_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y);
|
||||||
if (dir == 1) {
|
if (dir == 1) {
|
||||||
dev->buttonFlags |= UP_FLAG;
|
dev->buttonFlags |= DOWN_FLAG;
|
||||||
dev->buttonFlags &= ~DOWN_FLAG;
|
|
||||||
} else if (dir == -1) {
|
|
||||||
dev->buttonFlags &= ~UP_FLAG;
|
dev->buttonFlags &= ~UP_FLAG;
|
||||||
|
} else if (dir == 0) {
|
||||||
dev->buttonFlags &= ~DOWN_FLAG;
|
dev->buttonFlags &= ~DOWN_FLAG;
|
||||||
|
dev->buttonFlags &= ~UP_FLAG;
|
||||||
} else {
|
} else {
|
||||||
dev->buttonFlags &= ~DOWN_FLAG;
|
dev->buttonFlags &= ~DOWN_FLAG;
|
||||||
dev->buttonFlags |= UP_FLAG;
|
dev->buttonFlags |= UP_FLAG;
|
||||||
@ -454,7 +569,14 @@ static bool input_handle_mapping_event(struct input_event *ev, struct input_devi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_poll(bool (*handler) (struct input_event*, struct input_device*)) {
|
static void input_drain(void) {
|
||||||
|
for (int i = 0; i < numDevices; i++) {
|
||||||
|
struct input_event ev;
|
||||||
|
while (libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev) >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool input_poll(bool (*handler) (struct input_event*, struct input_device*)) {
|
||||||
while (poll(fds, numFds, -1)) {
|
while (poll(fds, numFds, -1)) {
|
||||||
if (fds[udev_fdindex].revents > 0) {
|
if (fds[udev_fdindex].revents > 0) {
|
||||||
struct udev_device *dev = udev_monitor_receive_device(udev_mon);
|
struct udev_device *dev = udev_monitor_receive_device(udev_mon);
|
||||||
@ -469,6 +591,17 @@ static void input_poll(bool (*handler) (struct input_event*, struct input_device
|
|||||||
}
|
}
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
}
|
}
|
||||||
|
} else if (fds[sig_fdindex].revents > 0) {
|
||||||
|
struct signalfd_siginfo info;
|
||||||
|
read(fds[sig_fdindex].fd, &info, sizeof(info));
|
||||||
|
|
||||||
|
switch (info.ssi_signo) {
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGHUP:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i=0;i<numDevices;i++) {
|
for (int i=0;i<numDevices;i++) {
|
||||||
if (fds[devices[i].fdindex].revents > 0) {
|
if (fds[devices[i].fdindex].revents > 0) {
|
||||||
@ -479,7 +612,7 @@ static void input_poll(bool (*handler) (struct input_event*, struct input_device
|
|||||||
fprintf(stderr, "Error: cannot keep up\n");
|
fprintf(stderr, "Error: cannot keep up\n");
|
||||||
else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
|
else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
|
||||||
if (!handler(&ev, &devices[i]))
|
if (!handler(&ev, &devices[i]))
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rc == -ENODEV) {
|
if (rc == -ENODEV) {
|
||||||
@ -491,6 +624,8 @@ static void input_poll(bool (*handler) (struct input_event*, struct input_device
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_map_key(char* keyName, short* key) {
|
static void input_map_key(char* keyName, short* key) {
|
||||||
@ -498,38 +633,50 @@ static void input_map_key(char* keyName, short* key) {
|
|||||||
currentKey = key;
|
currentKey = key;
|
||||||
currentAbs = NULL;
|
currentAbs = NULL;
|
||||||
*key = -1;
|
*key = -1;
|
||||||
input_poll(input_handle_mapping_event);
|
if (!input_poll(input_handle_mapping_event))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
usleep(250000);
|
||||||
|
input_drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_map_abs(char* keyName, short* abs, bool* reverse) {
|
static void input_map_abs(char* keyName, short* abs, bool* reverse) {
|
||||||
printf("%s\n", keyName);
|
printf("Move %s\n", keyName);
|
||||||
currentKey = NULL;
|
currentKey = NULL;
|
||||||
currentAbs = abs;
|
currentAbs = abs;
|
||||||
currentReverse = reverse;
|
currentReverse = reverse;
|
||||||
*abs = -1;
|
*abs = -1;
|
||||||
input_poll(input_handle_mapping_event);
|
if (!input_poll(input_handle_mapping_event))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
usleep(250000);
|
||||||
|
input_drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_map_abskey(char* keyName, short* key, short* abs, bool* reverse) {
|
static void input_map_abskey(char* keyName, short* key, short* abs, bool* reverse) {
|
||||||
printf("%s\n", keyName);
|
printf("Press %s\n", keyName);
|
||||||
currentKey = key;
|
currentKey = key;
|
||||||
currentAbs = abs;
|
currentAbs = abs;
|
||||||
currentReverse = reverse;
|
currentReverse = reverse;
|
||||||
*key = -1;
|
*key = -1;
|
||||||
*abs = -1;
|
*abs = -1;
|
||||||
*currentReverse = false;
|
*currentReverse = false;
|
||||||
input_poll(input_handle_mapping_event);
|
if (!input_poll(input_handle_mapping_event))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
usleep(250000);
|
||||||
|
input_drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_map(char* fileName) {
|
void input_map(char* fileName) {
|
||||||
struct mapping map;
|
struct mapping map;
|
||||||
|
|
||||||
input_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x));
|
input_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x));
|
||||||
input_map_abs("Left Stick Down", &(map.abs_y), &(map.reverse_y));
|
input_map_abs("Left Stick Up", &(map.abs_y), &(map.reverse_y));
|
||||||
input_map_key("Left Stick Button", &(map.btn_thumbl));
|
input_map_key("Left Stick Button", &(map.btn_thumbl));
|
||||||
|
|
||||||
input_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx));
|
input_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx));
|
||||||
input_map_abs("Right Stick Down", &(map.abs_ry), &(map.reverse_ry));
|
input_map_abs("Right Stick Up", &(map.abs_ry), &(map.reverse_ry));
|
||||||
input_map_key("Right Stick Button", &(map.btn_thumbr));
|
input_map_key("Right Stick Button", &(map.btn_thumbr));
|
||||||
|
|
||||||
input_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x));
|
input_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x));
|
||||||
@ -553,11 +700,11 @@ void input_map(char* fileName) {
|
|||||||
input_map_key("Special Button", &(map.btn_mode));
|
input_map_key("Special Button", &(map.btn_mode));
|
||||||
|
|
||||||
bool ignored;
|
bool ignored;
|
||||||
input_map_abskey("Left Trigger", &(map.btn_tl), &(map.abs_z), &ignored);
|
input_map_abskey("Left Trigger", &(map.btn_tl2), &(map.abs_z), &ignored);
|
||||||
input_map_abskey("Right Trigger", &(map.btn_tr), &(map.abs_rz), &ignored);
|
input_map_abskey("Right Trigger", &(map.btn_tr2), &(map.abs_rz), &ignored);
|
||||||
|
|
||||||
input_map_key("Left Bumper", &(map.btn_tl2));
|
input_map_key("Left Bumper", &(map.btn_tl));
|
||||||
input_map_key("Right Bumper", &(map.btn_tr2));
|
input_map_key("Right Bumper", &(map.btn_tr));
|
||||||
mapping_save(fileName, &map);
|
mapping_save(fileName, &map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/main.c
21
src/main.c
@ -53,7 +53,7 @@ static void applist(const char* address) {
|
|||||||
static void stream(STREAM_CONFIGURATION* config, const char* address, const char* app, bool sops, bool localaudio) {
|
static void stream(STREAM_CONFIGURATION* config, const char* address, const char* app, bool sops, bool localaudio) {
|
||||||
int appId = client_get_app_id(address, app);
|
int appId = client_get_app_id(address, app);
|
||||||
if (appId<0) {
|
if (appId<0) {
|
||||||
printf("Can't find app %s\n", app);
|
fprintf(stderr, "Can't find app %s\n", app);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,20 +61,7 @@ static void stream(STREAM_CONFIGURATION* config, const char* address, const char
|
|||||||
|
|
||||||
video_init();
|
video_init();
|
||||||
|
|
||||||
struct addrinfo hints, *res;
|
LiStartConnection(address, config, &connection_callbacks, decoder_callbacks, &audio_callbacks, NULL, NULL, 0, client_get_server_version());
|
||||||
memset(&hints, 0, sizeof(hints));
|
|
||||||
hints.ai_family = AF_INET;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
int err = getaddrinfo(address, NULL, &hints, &res);
|
|
||||||
if (err<0 || res == NULL) {
|
|
||||||
printf("Can't resolve host: %s\n", address);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in*)res->ai_addr;
|
|
||||||
LiStartConnection(addr->sin_addr.s_addr, config, NULL, decoder_callbacks,
|
|
||||||
&audio_callbacks, NULL, NULL, 0, client_get_server_version());
|
|
||||||
freeaddrinfo(res);
|
|
||||||
|
|
||||||
input_loop();
|
input_loop();
|
||||||
|
|
||||||
@ -147,7 +134,7 @@ char* get_path(char* name) {
|
|||||||
|
|
||||||
static void pair_check(void) {
|
static void pair_check(void) {
|
||||||
if (!client_is_paired(NULL)) {
|
if (!client_is_paired(NULL)) {
|
||||||
printf("You must pair with the PC first\n");
|
fprintf(stderr, "You must pair with the PC first\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,7 +252,7 @@ int main(int argc, char* argv[]) {
|
|||||||
address[0] = 0;
|
address[0] = 0;
|
||||||
discover_server(address);
|
discover_server(address);
|
||||||
if (address[0] == 0) {
|
if (address[0] == 0) {
|
||||||
perror("Can't find server");
|
fprintf(stderr, "Autodiscovery failed. Specify an IP address next time.\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,11 +100,11 @@ void mapping_load(char* fileName, struct mapping* map) {
|
|||||||
else if (strcmp("reverse_ry", key) == 0)
|
else if (strcmp("reverse_ry", key) == 0)
|
||||||
map->reverse_ry = strcmp("true", value) == 0;
|
map->reverse_ry = strcmp("true", value) == 0;
|
||||||
else if (strcmp("reverse_dpad_x", key) == 0)
|
else if (strcmp("reverse_dpad_x", key) == 0)
|
||||||
map->reverse_x = strcmp("true", value) == 0;
|
map->reverse_dpad_x = strcmp("true", value) == 0;
|
||||||
else if (strcmp("reverse_dpad_y", key) == 0)
|
else if (strcmp("reverse_dpad_y", key) == 0)
|
||||||
map->reverse_y = strcmp("true", value) == 0;
|
map->reverse_dpad_y = strcmp("true", value) == 0;
|
||||||
else
|
else
|
||||||
printf("Can't map (%s)\n", key);
|
fprintf(stderr, "Can't map (%s)\n", key);
|
||||||
}
|
}
|
||||||
if (key != NULL)
|
if (key != NULL)
|
||||||
free(key);
|
free(key);
|
||||||
|
@ -49,7 +49,7 @@ struct CertKeyPair generateCertKeyPair() {
|
|||||||
|
|
||||||
p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
|
p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
|
||||||
if (p12 == NULL) {
|
if (p12 == NULL) {
|
||||||
printf("Error generating a valid PKCS12 certificate.\n");
|
fprintf(stderr, "Error generating a valid PKCS12 certificate.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
19
src/video.c
19
src/video.c
@ -27,7 +27,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
DECODER_RENDERER_CALLBACKS *decoder_callbacks;
|
DECODER_RENDERER_CALLBACKS *decoder_callbacks;
|
||||||
char* decoder_output_name;
|
|
||||||
|
|
||||||
static int decoder_level;
|
static int decoder_level;
|
||||||
|
|
||||||
@ -37,22 +36,14 @@ void video_init() {
|
|||||||
#else
|
#else
|
||||||
decoder_callbacks = &decoder_callbacks_fake;
|
decoder_callbacks = &decoder_callbacks_fake;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_IMX
|
||||||
|
if (dlsym(RTLD_DEFAULT, "vpu_Init") != NULL && video_imx_init()) {
|
||||||
|
decoder_callbacks = &decoder_callbacks_imx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_OMX
|
#ifdef HAVE_OMX
|
||||||
if (dlsym(RTLD_DEFAULT, "bcm_host_init") != NULL) {
|
if (dlsym(RTLD_DEFAULT, "bcm_host_init") != NULL) {
|
||||||
decoder_callbacks = &decoder_callbacks_omx;
|
decoder_callbacks = &decoder_callbacks_omx;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_IMX
|
|
||||||
if (dlsym(RTLD_DEFAULT, "vpu_Init") != NULL) {
|
|
||||||
decoder_callbacks = &decoder_callbacks_imx;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int video_add_output(int level, char* name, DECODER_RENDERER_CALLBACKS *callbacks) {
|
|
||||||
if (level > decoder_level) {
|
|
||||||
decoder_output_name = name;
|
|
||||||
decoder_level = level;
|
|
||||||
decoder_callbacks = callbacks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "limelight-common/Limelight.h"
|
#include "limelight-common/Limelight.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern DECODER_RENDERER_CALLBACKS *decoder_callbacks;
|
extern DECODER_RENDERER_CALLBACKS *decoder_callbacks;
|
||||||
|
|
||||||
void video_init();
|
void video_init();
|
||||||
@ -31,5 +33,6 @@ extern DECODER_RENDERER_CALLBACKS decoder_callbacks_sdl;
|
|||||||
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_omx;
|
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_omx;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_IMX
|
#ifdef HAVE_IMX
|
||||||
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_omx;
|
extern DECODER_RENDERER_CALLBACKS decoder_callbacks_imx;
|
||||||
|
bool video_imx_init();
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,12 +25,10 @@ static FILE* fd;
|
|||||||
static const char* fileName = "fake.h264";
|
static const char* fileName = "fake.h264";
|
||||||
|
|
||||||
void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
||||||
printf("decoder_renderer_setup %dx%d %dfps\n", width, height, redrawRate);
|
|
||||||
fd = fopen(fileName, "w");
|
fd = fopen(fileName, "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
void decoder_renderer_release() {
|
void decoder_renderer_cleanup() {
|
||||||
printf("decoder_renderer_release\n");
|
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +43,6 @@ int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
|||||||
|
|
||||||
DECODER_RENDERER_CALLBACKS decoder_callbacks_fake = {
|
DECODER_RENDERER_CALLBACKS decoder_callbacks_fake = {
|
||||||
.setup = decoder_renderer_setup,
|
.setup = decoder_renderer_setup,
|
||||||
.start = NULL,
|
.cleanup = decoder_renderer_cleanup,
|
||||||
.stop = NULL,
|
|
||||||
.release = decoder_renderer_release,
|
|
||||||
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
||||||
};
|
};
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
#include "../video.h"
|
#include "../video.h"
|
||||||
|
|
||||||
#include "vpu_io.h"
|
|
||||||
#include "vpu_lib.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -43,6 +40,9 @@
|
|||||||
#include <linux/v4l2-controls.h>
|
#include <linux/v4l2-controls.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
#include <vpu_io.h>
|
||||||
|
#include <vpu_lib.h>
|
||||||
|
|
||||||
#define STREAM_BUF_SIZE 0x200000
|
#define STREAM_BUF_SIZE 0x200000
|
||||||
#define PS_SAVE_SIZE 0x080000
|
#define PS_SAVE_SIZE 0x080000
|
||||||
|
|
||||||
@ -72,6 +72,10 @@ static int disp_clr_index = 0;
|
|||||||
static FrameBuffer *fb;
|
static FrameBuffer *fb;
|
||||||
static struct v4l2_buffer dbuf;
|
static struct v4l2_buffer dbuf;
|
||||||
|
|
||||||
|
bool video_imx_init() {
|
||||||
|
return vpu_Init(NULL) == RETCODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
static void decoder_renderer_setup(int width, int height, int redrawRate, void* context, int drFlags) {
|
||||||
struct mxcfb_gbl_alpha alpha;
|
struct mxcfb_gbl_alpha alpha;
|
||||||
|
|
||||||
@ -94,11 +98,6 @@ static void decoder_renderer_setup(int width, int height, int redrawRate, void*
|
|||||||
|
|
||||||
close(fd_fb);
|
close(fd_fb);
|
||||||
|
|
||||||
if (vpu_Init(NULL) != RETCODE_SUCCESS){
|
|
||||||
fprintf(stderr, "Can't intialize VPU\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_desc.size = STREAM_BUF_SIZE;
|
mem_desc.size = STREAM_BUF_SIZE;
|
||||||
if (IOGetPhyMem(&mem_desc)){
|
if (IOGetPhyMem(&mem_desc)){
|
||||||
fprintf(stderr, "Can't get physical memory address\n");
|
fprintf(stderr, "Can't get physical memory address\n");
|
||||||
@ -413,7 +412,7 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
|||||||
return DR_OK;
|
return DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decoder_renderer_release() {
|
static void decoder_renderer_cleanup() {
|
||||||
IOFreePhyMem(&ps_mem_desc);
|
IOFreePhyMem(&ps_mem_desc);
|
||||||
IOFreePhyMem(&slice_mem_desc);
|
IOFreePhyMem(&slice_mem_desc);
|
||||||
|
|
||||||
@ -424,8 +423,6 @@ static void decoder_renderer_release() {
|
|||||||
|
|
||||||
DECODER_RENDERER_CALLBACKS decoder_callbacks_imx = {
|
DECODER_RENDERER_CALLBACKS decoder_callbacks_imx = {
|
||||||
.setup = decoder_renderer_setup,
|
.setup = decoder_renderer_setup,
|
||||||
.start = NULL,
|
.cleanup = decoder_renderer_cleanup,
|
||||||
.stop = NULL,
|
|
||||||
.release = decoder_renderer_release,
|
|
||||||
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
||||||
};
|
};
|
||||||
|
@ -30,14 +30,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "../video.h"
|
#include "../video.h"
|
||||||
|
|
||||||
#include "bcm_host.h"
|
|
||||||
#include "ilclient.h"
|
|
||||||
#include "h264_stream.h"
|
#include "h264_stream.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ilclient.h>
|
||||||
|
#include <bcm_host.h>
|
||||||
|
|
||||||
static TUNNEL_T tunnel[2];
|
static TUNNEL_T tunnel[2];
|
||||||
static COMPONENT_T *list[3];
|
static COMPONENT_T *list[3];
|
||||||
static ILCLIENT_T *client;
|
static ILCLIENT_T *client;
|
||||||
@ -129,7 +130,7 @@ static void decoder_renderer_setup(int width, int height, int redrawRate, void*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decoder_renderer_stop() {
|
static void decoder_renderer_cleanup() {
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
buf->nFilledLen = 0;
|
buf->nFilledLen = 0;
|
||||||
@ -144,9 +145,7 @@ static void decoder_renderer_stop() {
|
|||||||
ilclient_flush_tunnels(tunnel, 0);
|
ilclient_flush_tunnels(tunnel, 0);
|
||||||
|
|
||||||
ilclient_disable_port_buffers(list[0], 130, NULL, NULL, NULL);
|
ilclient_disable_port_buffers(list[0], 130, NULL, NULL, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
static void decoder_renderer_release() {
|
|
||||||
ilclient_disable_tunnel(tunnel);
|
ilclient_disable_tunnel(tunnel);
|
||||||
ilclient_teardown_tunnels(tunnel);
|
ilclient_teardown_tunnels(tunnel);
|
||||||
|
|
||||||
@ -227,8 +226,6 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
|||||||
|
|
||||||
DECODER_RENDERER_CALLBACKS decoder_callbacks_omx = {
|
DECODER_RENDERER_CALLBACKS decoder_callbacks_omx = {
|
||||||
.setup = decoder_renderer_setup,
|
.setup = decoder_renderer_setup,
|
||||||
.start = NULL,
|
.cleanup = decoder_renderer_cleanup,
|
||||||
.stop = decoder_renderer_stop,
|
|
||||||
.release = decoder_renderer_release,
|
|
||||||
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
.submitDecodeUnit = decoder_renderer_submit_decode_unit,
|
||||||
};
|
};
|
||||||
|
@ -61,7 +61,7 @@ static void sdl_setup(int width, int height, int redrawRate, void* context, int
|
|||||||
screen_height = height;
|
screen_height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_release() {
|
static void sdl_cleanup() {
|
||||||
ffmpeg_destroy();
|
ffmpeg_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +109,6 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) {
|
|||||||
|
|
||||||
DECODER_RENDERER_CALLBACKS decoder_callbacks_sdl = {
|
DECODER_RENDERER_CALLBACKS decoder_callbacks_sdl = {
|
||||||
.setup = sdl_setup,
|
.setup = sdl_setup,
|
||||||
.start = NULL,
|
.cleanup = sdl_cleanup,
|
||||||
.stop = NULL,
|
|
||||||
.release = sdl_release,
|
|
||||||
.submitDecodeUnit = sdl_submit_decode_unit,
|
.submitDecodeUnit = sdl_submit_decode_unit,
|
||||||
};
|
};
|
||||||
|
@ -92,7 +92,7 @@ int xml_search(char* data, size_t len, char* node, char** result) {
|
|||||||
struct xml_query search;
|
struct xml_query search;
|
||||||
search.data = node;
|
search.data = node;
|
||||||
search.start = 0;
|
search.start = 0;
|
||||||
search.memory = malloc(1);
|
search.memory = calloc(1, 1);
|
||||||
search.size = 0;
|
search.size = 0;
|
||||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||||
XML_SetUserData(parser, &search);
|
XML_SetUserData(parser, &search);
|
||||||
@ -100,7 +100,7 @@ int xml_search(char* data, size_t len, char* node, char** result) {
|
|||||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||||
if (! XML_Parse(parser, data, len, 1)) {
|
if (! XML_Parse(parser, data, len, 1)) {
|
||||||
int code = XML_GetErrorCode(parser);
|
int code = XML_GetErrorCode(parser);
|
||||||
printf("%s\n", XML_ErrorString(code));
|
fprintf(stderr, "XML Error: %s\n", XML_ErrorString(code));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
*result = search.memory;
|
*result = search.memory;
|
||||||
@ -110,7 +110,7 @@ int xml_search(char* data, size_t len, char* node, char** result) {
|
|||||||
|
|
||||||
struct app_list* xml_applist(char* data, size_t len) {
|
struct app_list* xml_applist(char* data, size_t len) {
|
||||||
struct xml_query query;
|
struct xml_query query;
|
||||||
query.memory = malloc(1);
|
query.memory = calloc(1, 1);
|
||||||
query.size = 0;
|
query.size = 0;
|
||||||
query.start = 0;
|
query.start = 0;
|
||||||
query.data = NULL;
|
query.data = NULL;
|
||||||
@ -120,7 +120,7 @@ struct app_list* xml_applist(char* data, size_t len) {
|
|||||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||||
if (! XML_Parse(parser, data, len, 1)) {
|
if (! XML_Parse(parser, data, len, 1)) {
|
||||||
int code = XML_GetErrorCode(parser);
|
int code = XML_GetErrorCode(parser);
|
||||||
printf("%s\n", XML_ErrorString(code));
|
fprintf(stderr, "XML Error %s\n", XML_ErrorString(code));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
306
third_party/libcec/ceccloader.h
vendored
Normal file
306
third_party/libcec/ceccloader.h
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* This file is part of the libCEC(R) library.
|
||||||
|
*
|
||||||
|
* libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
|
||||||
|
* libCEC(R) is an original work, containing original code.
|
||||||
|
*
|
||||||
|
* libCEC(R) is a trademark of Pulse-Eight Limited.
|
||||||
|
*
|
||||||
|
* This program is dual-licensed; 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 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Alternatively, you can license this library under a commercial license,
|
||||||
|
* please contact Pulse-Eight Licensing for more information.
|
||||||
|
*
|
||||||
|
* For more information contact:
|
||||||
|
* Pulse-Eight Licensing <license@pulse-eight.com>
|
||||||
|
* http://www.pulse-eight.com/
|
||||||
|
* http://www.pulse-eight.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cecc.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <conio.h>
|
||||||
|
typedef HINSTANCE libcecc_lib_instance_t;
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
typedef void* libcecc_lib_instance_t;
|
||||||
|
#ifndef CDECL
|
||||||
|
#define CDECL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static libcecc_lib_instance_t libcecc_load_library(const char* strLib);
|
||||||
|
static void libcecc_close_library(libcecc_lib_instance_t lib);
|
||||||
|
static void* libcecc_resolve(void* lib, const char* name);
|
||||||
|
|
||||||
|
#define _libcecc_resolve(lib, tar, name, method) \
|
||||||
|
do { \
|
||||||
|
tar = (method) libcecc_resolve(lib, name); \
|
||||||
|
if (tar == NULL) \
|
||||||
|
{ \
|
||||||
|
libcecc_close_library(lib); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
libcec_connection_t connection;
|
||||||
|
libcecc_lib_instance_t lib_instance;
|
||||||
|
void (CDECL *destroy)(libcec_connection_t connection);
|
||||||
|
int (CDECL *open)(libcec_connection_t connection, const char* strPort, uint32_t iTimeout);
|
||||||
|
void (CDECL *close)(libcec_connection_t connection);
|
||||||
|
void (CDECL *clear_configuration)(CEC_NAMESPACE libcec_configuration* configuration);
|
||||||
|
int (CDECL *enable_callbacks)(libcec_connection_t connection, void* cbParam, CEC_NAMESPACE ICECCallbacks* callbacks);
|
||||||
|
int8_t (CDECL *find_adapters)(libcec_connection_t connection, CEC_NAMESPACE cec_adapter* deviceList, uint8_t iBufSize, const char* strDevicePath);
|
||||||
|
int (CDECL *ping_adapters)(libcec_connection_t connection);
|
||||||
|
int (CDECL *start_bootloader)(libcec_connection_t connection);
|
||||||
|
int (CDECL *power_on_devices)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
|
||||||
|
int (CDECL *standby_devices)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
|
||||||
|
int (CDECL *set_active_source)(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
|
||||||
|
int (CDECL *set_deck_control_mode)(libcec_connection_t connection, CEC_NAMESPACE cec_deck_control_mode mode, int bSendUpdate);
|
||||||
|
int (CDECL *set_deck_info)(libcec_connection_t connection, CEC_NAMESPACE cec_deck_info info, int bSendUpdate);
|
||||||
|
int (CDECL *set_inactive_view)(libcec_connection_t connection);
|
||||||
|
int (CDECL *set_menu_state)(libcec_connection_t connection, CEC_NAMESPACE cec_menu_state state, int bSendUpdate);
|
||||||
|
int (CDECL *transmit)(libcec_connection_t connection, const CEC_NAMESPACE cec_command* data);
|
||||||
|
int (CDECL *set_logical_address)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
int (CDECL *set_physical_address)(libcec_connection_t connection, uint16_t iPhysicalAddress);
|
||||||
|
int (CDECL *set_osd_string)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_display_control duration, const char* strMessage);
|
||||||
|
int (CDECL *switch_monitoring)(libcec_connection_t connection, int bEnable);
|
||||||
|
CEC_NAMESPACE cec_version (CDECL *get_device_cec_version)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
int (CDECL *get_device_menu_language)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_menu_language* language);
|
||||||
|
uint64_t (CDECL *get_device_vendor_id)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
uint16_t (CDECL *get_device_physical_address)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
CEC_NAMESPACE cec_logical_address (CDECL *get_active_source)(libcec_connection_t connection);
|
||||||
|
int (CDECL *is_active_source)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
|
||||||
|
CEC_NAMESPACE cec_power_status (CDECL *get_device_power_status)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
int (CDECL *poll_device)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
|
||||||
|
CEC_NAMESPACE cec_logical_addresses (CDECL *get_active_devices)(libcec_connection_t connection);
|
||||||
|
int (CDECL *is_active_device)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
|
||||||
|
int (CDECL *is_active_device_type)(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
|
||||||
|
int (CDECL *set_hdmi_port)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address baseDevice, uint8_t iPort);
|
||||||
|
int (CDECL *volume_up)(libcec_connection_t connection, int bSendRelease);
|
||||||
|
int (CDECL *volume_down)(libcec_connection_t connection, int bSendRelease);
|
||||||
|
int (CDECL *mute_audio)(libcec_connection_t connection, int bSendRelease);
|
||||||
|
int (CDECL *send_keypress)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, CEC_NAMESPACE cec_user_control_code key, int bWait);
|
||||||
|
int (CDECL *send_key_release)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, int bWait);
|
||||||
|
CEC_NAMESPACE cec_osd_name (CDECL *get_device_osd_name)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
|
||||||
|
int (CDECL *set_stream_path_logical)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
|
||||||
|
int (CDECL *set_stream_path_physical)(libcec_connection_t connection, uint16_t iPhysicalAddress);
|
||||||
|
CEC_NAMESPACE cec_logical_addresses (CDECL *get_logical_addresses)(libcec_connection_t connection);
|
||||||
|
int (CDECL *get_current_configuration)(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
|
||||||
|
int (CDECL *can_persist_configuration)(libcec_connection_t connection);
|
||||||
|
int (CDECL *persist_configuration)(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
|
||||||
|
int (CDECL *set_configuration)(libcec_connection_t connection, const CEC_NAMESPACE libcec_configuration* configuration);
|
||||||
|
void (CDECL *rescan_devices)(libcec_connection_t connection);
|
||||||
|
int (CDECL *is_libcec_active_source)(libcec_connection_t connection);
|
||||||
|
int (CDECL *get_device_information)(libcec_connection_t connection, const char* strPort, CEC_NAMESPACE libcec_configuration* config, uint32_t iTimeoutMs);
|
||||||
|
const char* (CDECL *get_lib_info)(libcec_connection_t connection);
|
||||||
|
void (CDECL *init_video_standalone)(libcec_connection_t connection);
|
||||||
|
uint16_t (CDECL *get_adapter_vendor_id)(libcec_connection_t connection);
|
||||||
|
uint16_t (CDECL *get_adapter_product_id)(libcec_connection_t connection);
|
||||||
|
uint8_t (CDECL *audio_toggle_mute)(libcec_connection_t connection);
|
||||||
|
uint8_t (CDECL *audio_mute)(libcec_connection_t connection);
|
||||||
|
uint8_t (CDECL *audio_unmute)(libcec_connection_t connection);
|
||||||
|
uint8_t (CDECL *audio_get_status)(libcec_connection_t connection);
|
||||||
|
int8_t (CDECL *detect_adapters)(libcec_connection_t connection, CEC_NAMESPACE cec_adapter_descriptor* deviceList, uint8_t iBufSize, const char* strDevicePath, int bQuickScan);
|
||||||
|
void (CDECL *menu_state_to_string)(const CEC_NAMESPACE cec_menu_state state, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *cec_version_to_string)(const CEC_NAMESPACE cec_version version, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *power_status_to_string)(const CEC_NAMESPACE cec_power_status status, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *logical_address_to_string)(const CEC_NAMESPACE cec_logical_address address, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *deck_control_mode_to_string)(const CEC_NAMESPACE cec_deck_control_mode mode, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *deck_status_to_string)(const CEC_NAMESPACE cec_deck_info status, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *opcode_to_string)(const CEC_NAMESPACE cec_opcode opcode, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *system_audio_status_to_string)(const CEC_NAMESPACE cec_system_audio_status mode, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *audio_status_to_string)(const CEC_NAMESPACE cec_audio_status status, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *vendor_id_to_string)(const CEC_NAMESPACE cec_vendor_id vendor, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *user_control_key_to_string)(const CEC_NAMESPACE cec_user_control_code key, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *adapter_type_to_string)(const CEC_NAMESPACE cec_adapter_type type, char* buf, size_t bufsize);
|
||||||
|
void (CDECL *version_to_string)(uint32_t version, char* buf, size_t bufsize);
|
||||||
|
} libcec_interface_t;
|
||||||
|
|
||||||
|
static int libcecc_resolve_all(void* lib, libcec_interface_t* iface)
|
||||||
|
{
|
||||||
|
if (!lib || !iface)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
_libcecc_resolve(lib, iface->destroy, "libcec_destroy", void(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->open, "libcec_open", int(CDECL *)(libcec_connection_t, const char*, uint32_t));
|
||||||
|
_libcecc_resolve(lib, iface->close, "libcec_close", void(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->clear_configuration, "libcec_clear_configuration", void(CDECL *)(CEC_NAMESPACE libcec_configuration*));
|
||||||
|
_libcecc_resolve(lib, iface->enable_callbacks, "libcec_enable_callbacks", int(CDECL *)(libcec_connection_t, void*, CEC_NAMESPACE ICECCallbacks*));
|
||||||
|
_libcecc_resolve(lib, iface->find_adapters, "libcec_find_adapters", int8_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_adapter*, uint8_t, const char*));
|
||||||
|
_libcecc_resolve(lib, iface->ping_adapters, "libcec_ping_adapters", int(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->start_bootloader, "libcec_start_bootloader", int(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->power_on_devices, "libcec_power_on_devices", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->standby_devices, "libcec_standby_devices", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->set_active_source, "libcec_set_active_source", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_device_type));
|
||||||
|
_libcecc_resolve(lib, iface->set_deck_control_mode, "libcec_set_deck_control_mode", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_deck_control_mode, int));
|
||||||
|
_libcecc_resolve(lib, iface->set_deck_info, "libcec_set_deck_info", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_deck_info, int));
|
||||||
|
_libcecc_resolve(lib, iface->set_inactive_view, "libcec_set_inactive_view", int(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->set_menu_state, "libcec_set_menu_state", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_menu_state, int));
|
||||||
|
_libcecc_resolve(lib, iface->transmit, "libcec_transmit", int(CDECL *)(libcec_connection_t, const CEC_NAMESPACE cec_command*));
|
||||||
|
_libcecc_resolve(lib, iface->set_logical_address, "libcec_set_logical_address", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->set_physical_address, "libcec_set_physical_address", int(CDECL *)(libcec_connection_t, uint16_t));
|
||||||
|
_libcecc_resolve(lib, iface->set_osd_string, "libcec_set_osd_string", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_display_control, const char*));
|
||||||
|
_libcecc_resolve(lib, iface->switch_monitoring, "libcec_switch_monitoring", int(CDECL *)(libcec_connection_t, int));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_cec_version, "libcec_get_device_cec_version", CEC_NAMESPACE cec_version(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_menu_language, "libcec_get_device_menu_language", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_menu_language*));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_vendor_id, "libcec_get_device_vendor_id", uint64_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_physical_address, "libcec_get_device_physical_address", uint16_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->get_active_source, "libcec_get_active_source", CEC_NAMESPACE cec_logical_address(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->is_active_source, "libcec_is_active_source", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_power_status, "libcec_get_device_power_status", CEC_NAMESPACE cec_power_status(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->poll_device, "libcec_poll_device", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->get_active_devices, "libcec_get_active_devices", CEC_NAMESPACE cec_logical_addresses(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->is_active_device, "libcec_is_active_device", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->is_active_device_type, "libcec_is_active_device_type", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_device_type));
|
||||||
|
_libcecc_resolve(lib, iface->set_hdmi_port, "libcec_set_hdmi_port", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, uint8_t));
|
||||||
|
_libcecc_resolve(lib, iface->volume_up, "libcec_volume_up", int(CDECL *)(libcec_connection_t, int));
|
||||||
|
_libcecc_resolve(lib, iface->volume_down, "libcec_volume_down", int(CDECL *)(libcec_connection_t, int));
|
||||||
|
_libcecc_resolve(lib, iface->mute_audio, "libcec_mute_audio", int(CDECL *)(libcec_connection_t, int));
|
||||||
|
_libcecc_resolve(lib, iface->send_keypress, "libcec_send_keypress", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_user_control_code, int));
|
||||||
|
_libcecc_resolve(lib, iface->send_key_release, "libcec_send_key_release", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, int));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_osd_name, "libcec_get_device_osd_name", CEC_NAMESPACE cec_osd_name(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->set_stream_path_logical, "libcec_set_stream_path_logical", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
|
||||||
|
_libcecc_resolve(lib, iface->set_stream_path_physical, "libcec_set_stream_path_physical", int(CDECL *)(libcec_connection_t, uint16_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_logical_addresses, "libcec_get_logical_addresses", CEC_NAMESPACE cec_logical_addresses(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_current_configuration, "libcec_get_current_configuration", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE libcec_configuration*));
|
||||||
|
_libcecc_resolve(lib, iface->can_persist_configuration, "libcec_can_persist_configuration", int(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->persist_configuration, "libcec_persist_configuration", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE libcec_configuration*));
|
||||||
|
_libcecc_resolve(lib, iface->set_configuration, "libcec_set_configuration", int(CDECL *)(libcec_connection_t, const CEC_NAMESPACE libcec_configuration*));
|
||||||
|
_libcecc_resolve(lib, iface->rescan_devices, "libcec_rescan_devices", void(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->is_libcec_active_source, "libcec_is_libcec_active_source", int(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_device_information, "libcec_get_device_information", int(CDECL *)(libcec_connection_t, const char*, CEC_NAMESPACE libcec_configuration*, uint32_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_lib_info, "libcec_get_lib_info", const char*(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->init_video_standalone, "libcec_init_video_standalone", void(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_adapter_vendor_id, "libcec_get_adapter_vendor_id", uint16_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->get_adapter_product_id, "libcec_get_adapter_product_id", uint16_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->audio_toggle_mute, "libcec_audio_toggle_mute", uint8_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->audio_mute, "libcec_audio_mute", uint8_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->audio_unmute, "libcec_audio_unmute", uint8_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->audio_get_status, "libcec_audio_get_status", uint8_t(CDECL *)(libcec_connection_t));
|
||||||
|
_libcecc_resolve(lib, iface->detect_adapters, "libcec_detect_adapters", int8_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_adapter_descriptor*, uint8_t, const char*, int));
|
||||||
|
_libcecc_resolve(lib, iface->menu_state_to_string, "libcec_menu_state_to_string", void(CDECL *)(const CEC_NAMESPACE cec_menu_state, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->cec_version_to_string, "libcec_cec_version_to_string", void(CDECL *)(const CEC_NAMESPACE cec_version, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->power_status_to_string, "libcec_power_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_power_status, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->logical_address_to_string, "libcec_logical_address_to_string", void(CDECL *)(const CEC_NAMESPACE cec_logical_address, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->deck_control_mode_to_string, "libcec_deck_control_mode_to_string", void(CDECL *)(const CEC_NAMESPACE cec_deck_control_mode, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->deck_status_to_string, "libcec_deck_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_deck_info, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->opcode_to_string, "libcec_opcode_to_string", void(CDECL *)(const CEC_NAMESPACE cec_opcode, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->system_audio_status_to_string, "libcec_system_audio_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_system_audio_status, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->audio_status_to_string, "libcec_audio_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_audio_status, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->vendor_id_to_string, "libcec_vendor_id_to_string", void(CDECL *)(const CEC_NAMESPACE cec_vendor_id, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->user_control_key_to_string, "libcec_user_control_key_to_string", void(CDECL *)(const CEC_NAMESPACE cec_user_control_code, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->adapter_type_to_string, "libcec_adapter_type_to_string", void(CDECL *)(const CEC_NAMESPACE cec_adapter_type, char*, size_t));
|
||||||
|
_libcecc_resolve(lib, iface->version_to_string, "libcec_version_to_string", void(CDECL *)(uint32_t, char*, size_t));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static libcecc_lib_instance_t libcecc_load_library(const char* strLib)
|
||||||
|
{
|
||||||
|
libcecc_lib_instance_t lib;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
lib = LoadLibrary(strLib ? strLib : "cec.dll");
|
||||||
|
if (lib == NULL)
|
||||||
|
printf("failed to load cec.dll\n");
|
||||||
|
#else
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
lib = dlopen(strLib ? strLib : "libcec." CEC_LIB_VERSION_MAJOR_STR ".dylib", RTLD_LAZY);
|
||||||
|
#else
|
||||||
|
lib = dlopen(strLib ? strLib : "libcec.so." CEC_LIB_VERSION_MAJOR_STR ".0", RTLD_LAZY);
|
||||||
|
#endif
|
||||||
|
if (lib == NULL)
|
||||||
|
printf("%s\n", dlerror());
|
||||||
|
#endif
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libcecc_close_library(libcecc_lib_instance_t lib)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
FreeLibrary(lib);
|
||||||
|
#else
|
||||||
|
dlclose(lib);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* libcecc_resolve(void* lib, const char* name)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
return GetProcAddress(lib, name);
|
||||||
|
#else
|
||||||
|
return dlsym(lib, name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void libcecc_reset_configuration(CEC_NAMESPACE libcec_configuration* configuration)
|
||||||
|
{
|
||||||
|
void(CDECL * _clear_configuration)(CEC_NAMESPACE libcec_configuration*);
|
||||||
|
libcecc_lib_instance_t lib;
|
||||||
|
|
||||||
|
memset(configuration, 0, sizeof(CEC_NAMESPACE libcec_configuration));
|
||||||
|
lib = libcecc_load_library(NULL);
|
||||||
|
if (lib == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_clear_configuration = (void(CDECL *)(CEC_NAMESPACE libcec_configuration*)) libcecc_resolve(lib, "libcec_clear_configuration");
|
||||||
|
if (_clear_configuration)
|
||||||
|
_clear_configuration(configuration);
|
||||||
|
|
||||||
|
libcecc_close_library(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Create a new libCEC instance.
|
||||||
|
* @param configuration The configuration to pass to libCEC
|
||||||
|
* @param strLib The name of and/or path to libCEC
|
||||||
|
* @return 1 when loaded, 0 if libCEC failed to initialise, -1 if methods failed to be resolved
|
||||||
|
*/
|
||||||
|
int libcecc_initialise(CEC_NAMESPACE libcec_configuration* configuration, libcec_interface_t* iface, const char* strLib)
|
||||||
|
{
|
||||||
|
void* (CDECL *_cec_initialise)(CEC_NAMESPACE libcec_configuration*);
|
||||||
|
|
||||||
|
libcecc_lib_instance_t lib;
|
||||||
|
lib = libcecc_load_library(strLib);
|
||||||
|
if (lib == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
_libcecc_resolve(lib, _cec_initialise, "libcec_initialise", void* (CDECL *)(CEC_NAMESPACE libcec_configuration*));
|
||||||
|
|
||||||
|
iface->lib_instance = lib;
|
||||||
|
iface->connection = _cec_initialise(configuration);
|
||||||
|
|
||||||
|
return iface->connection ?
|
||||||
|
libcecc_resolve_all(lib, iface) :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Destroy an instance of libCEC.
|
||||||
|
* @param device The instance to destroy.
|
||||||
|
*/
|
||||||
|
void libcecc_destroy(libcec_interface_t* iface)
|
||||||
|
{
|
||||||
|
if (iface->destroy)
|
||||||
|
iface->destroy(iface->connection);
|
||||||
|
libcecc_close_library(iface->lib_instance);
|
||||||
|
memset(iface, 0, sizeof(libcec_interface_t));
|
||||||
|
}
|
1
third_party/moonlight-common-c
vendored
Submodule
1
third_party/moonlight-common-c
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 678afd9c300ae4591aa53e3bbf0e14783803671e
|
Loading…
x
Reference in New Issue
Block a user