mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
Compare commits
151 commits
Author | SHA1 | Date | |
---|---|---|---|
|
937747fd4d | ||
|
c9c8bd7a7a | ||
|
430b1a39b8 | ||
|
a67a182a05 | ||
|
aecd52a354 | ||
|
c664d1ba27 | ||
|
faea95fbfa | ||
|
1df6392a23 | ||
|
210ef327ce | ||
|
c83802fd06 | ||
|
af6ab257ea | ||
|
fdb8671c40 | ||
|
850a1c6f7c | ||
|
f3debd5678 | ||
|
279303d0d6 | ||
|
c803c88572 | ||
|
3018aac1f2 | ||
|
a36e9bd19f | ||
|
439dac09c5 | ||
|
31f7fbba33 | ||
|
abc9b2f92c | ||
|
314aa5aed5 | ||
|
66c86f2971 | ||
|
788d37d7d2 | ||
|
20816ad138 | ||
|
c215f05d5d | ||
|
f9a61faaa2 | ||
|
8cd144271a | ||
|
7135a99e71 | ||
|
42c5bda976 | ||
|
f740af2655 | ||
|
175495c729 | ||
|
72f61549d9 | ||
|
380504b0f8 | ||
|
b46679d5a4 | ||
|
6f84dc8b7d | ||
|
85723432f9 | ||
|
7f263b06b4 | ||
|
a1590ecc17 | ||
|
43505ab3dd | ||
|
e816de93d3 | ||
|
c42624885b | ||
|
3ab7d5913f | ||
|
0b72e0b435 | ||
|
125f4a847f | ||
|
264a222d24 | ||
|
4b229dc282 | ||
|
5ac3e0593f | ||
|
e25d8d5a0b | ||
|
df12df656c | ||
|
65a7a0aad1 | ||
|
3f5270ee7a | ||
|
506f1e7b28 | ||
|
7739a9cee0 | ||
|
a66b998883 | ||
|
0481252438 | ||
|
a13c1b7c33 | ||
|
62c5b8daa8 | ||
|
8d6530ebc9 | ||
|
3b3531de5c | ||
|
92a8b0b2c6 | ||
|
058c9cc309 | ||
|
c864ff6246 | ||
|
4f37045eea | ||
|
be54804768 | ||
|
57d05a1808 | ||
|
9edb225905 | ||
|
2ef4c1f40f | ||
|
4111333521 | ||
|
58dd6c411e | ||
|
960a785e10 | ||
|
59df9a4a3f | ||
|
3a459e5316 | ||
|
46089b18f0 | ||
|
c3c868e523 | ||
|
8151bb8cbd | ||
|
4e67272f2f | ||
|
8b76e3c212 | ||
|
ec7e11c8bf | ||
|
5bfc97a72c | ||
|
34595f035e | ||
|
1d01ae2117 | ||
|
76f0189829 | ||
|
0c3f02e97b | ||
|
a395c3c7af | ||
|
3dec3e9b83 | ||
|
eceb252ec7 | ||
|
20036e77dc | ||
|
92ab7eb2d3 | ||
|
033690b7fb | ||
|
68802bb592 | ||
|
a6f672311e | ||
|
6b5907ad45 | ||
|
fe9a39bee8 | ||
|
c3f6b7f683 | ||
|
b8de12cab3 | ||
|
04a1ec8aa3 | ||
|
1bc0648f4b | ||
|
3dfa75d90b | ||
|
a2735d9b4d | ||
|
bc9ebcc849 | ||
|
dec8ee0c07 | ||
|
52cd3f0f28 | ||
|
a9da0067e3 | ||
|
2aeec41290 | ||
|
3628f789b4 | ||
|
016159bb1e | ||
|
c0f49c3b9c | ||
|
2757c4f5e6 | ||
|
e5795edd04 | ||
|
cedfeeebe1 | ||
|
472fbf4a24 | ||
|
5e93ad0638 | ||
|
cd23da3c74 | ||
|
142ba08987 | ||
|
3886dcb7c7 | ||
|
a9266e5055 | ||
|
1cc667a00c | ||
|
36be37ed8b | ||
|
28252707a2 | ||
|
011d7e7fba | ||
|
59ea55c28c | ||
|
c412cdb846 | ||
|
866f90f92a | ||
|
b6400aa14a | ||
|
3f800251a9 | ||
|
c7b49c9fbd | ||
|
4601514799 | ||
|
7fc8d0884c | ||
|
70ffd2d532 | ||
|
6dd107a2fd | ||
|
99ed3efd88 | ||
|
091d7092dc | ||
|
fc6f19d132 | ||
|
e863a4498d | ||
|
44625ff4fc | ||
|
7228c3e63d | ||
|
412ce067b6 | ||
|
3f2266e254 | ||
|
42820c00ba | ||
|
349db0f04a | ||
|
0ac755a765 | ||
|
1e69dd6dae | ||
|
4637409d0b | ||
|
c6d645d720 | ||
|
442103a333 | ||
|
a95de6395e | ||
|
c94be167c8 | ||
|
1cbfa5b42a | ||
|
ce1cbba7d5 | ||
|
72fee8ea0e |
85 changed files with 4085 additions and 848 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -26,6 +26,7 @@ miracle-dhcp
|
|||
miracle-sinkctl
|
||||
miracle-wifictl
|
||||
miracle-wifid
|
||||
miracle-uibcctl
|
||||
miraclectl
|
||||
miracled
|
||||
stamp-h1
|
||||
|
@ -35,3 +36,9 @@ test_valgrind
|
|||
test_wpas
|
||||
wpa_cli
|
||||
wpa_supplicant
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
CMakeCache.txt
|
||||
libmiracle-shared.a
|
||||
install_manifest.txt
|
||||
/build/
|
||||
|
|
35
.semaphore/semaphore.yml
Normal file
35
.semaphore/semaphore.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
version: v1.0
|
||||
name: Docker
|
||||
|
||||
agent:
|
||||
machine:
|
||||
type: e1-standard-2
|
||||
os_image: ubuntu1804
|
||||
|
||||
global_job_config:
|
||||
secrets:
|
||||
- name: dockerhub
|
||||
|
||||
blocks:
|
||||
- name: Checkout
|
||||
task:
|
||||
jobs:
|
||||
- name: Checkout
|
||||
commands:
|
||||
- checkout
|
||||
- name: Build
|
||||
task:
|
||||
jobs:
|
||||
- name: Autotools
|
||||
commands:
|
||||
- checkout
|
||||
- docker build -t autotools -f autotools.Dockerfile .
|
||||
- name: Cmake
|
||||
commands:
|
||||
- checkout
|
||||
- docker build -t cmake -f cmake.Dockerfile .
|
||||
- name: meson
|
||||
commands:
|
||||
- checkout
|
||||
- docker build -t meson -f meson.Dockerfile .
|
||||
|
16
.travis.yml
Normal file
16
.travis.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
language: c
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: autotools
|
||||
script:
|
||||
docker build -t autotools -f autotools.Dockerfile .
|
||||
- stage: cmake
|
||||
script:
|
||||
docker build -t cmake -f cmake.Dockerfile .
|
||||
- stage: meson
|
||||
script:
|
||||
docker build -t meson -f meson.Dockerfile .
|
|
@ -1,28 +1,63 @@
|
|||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake
|
||||
${CMAKE_MODULE_PATH})
|
||||
|
||||
set(CMAKE_C_FLAGS "-std=gnu11")
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(Miraclecast)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(res)
|
||||
add_subdirectory(test)
|
||||
|
||||
SET(BUILD_BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
OPTION(BUILD_ENABLE_DEBUG "Enable Debug" ON )
|
||||
OPTION(RELY_UDEV "Rely in udev tag to select device" OFF )
|
||||
OPTION(BUILD_TESTS "Enable TEST" ON )
|
||||
|
||||
SET(PACKAGE_NAME miraclecast)
|
||||
SET(PACKAGE_VERSION 1)
|
||||
SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake
|
||||
${CMAKE_MODULE_PATH})
|
||||
|
||||
set(CMAKE_C_FLAGS "-std=gnu11 ${CMAKE_C_FLAGS}")
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
OPTION(ENABLE_SYSTEMD "Enable Systemd" ON)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
if(ENABLE_SYSTEMD)
|
||||
pkg_check_modules (SYSTEMD REQUIRED libsystemd>=213)
|
||||
SET(SESSION_LIBRARIES "${SYSTEMD_LIBRARIES}")
|
||||
else(ENABLE_SYSTEMD)
|
||||
pkg_check_modules (ELOGIND REQUIRED libelogind>=213)
|
||||
include_directories ("${ELOGIND_INCLUDEDIR}")
|
||||
SET(SESSION_LIBRARIES "${ELOGIND_LIBRARIES}")
|
||||
endif(ENABLE_SYSTEMD)
|
||||
|
||||
SET(BUILD_BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
OPTION(BUILD_ENABLE_DEBUG "Enable Debug" ON )
|
||||
OPTION(RELY_UDEV "Rely in udev tag to select device" OFF )
|
||||
OPTION(BUILD_TESTS "Enable TEST" ON )
|
||||
OPTION(BUILD_ENABLE_CPPCHECK "Enable CPPCheck static analysis" OFF )
|
||||
SET(IP_BINARY "/bin/ip" CACHE STRING "Path to ip binary")
|
||||
|
||||
if(BUILD_ENABLE_DEBUG)
|
||||
add_definitions(-DBUILD_ENABLE_DEBUG)
|
||||
endif()
|
||||
|
||||
set(SYSCONFDIR "/etc" CACHE STRING "system config dir")
|
||||
set(DATADIR "${CMAKE_INSTALL_PREFIX}/share" CACHE STRING "shared data dir")
|
||||
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
pkg_check_modules (UDEV REQUIRED libudev)
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_BINARY_DIR}/config.h)
|
||||
|
||||
if(BUILD_ENABLE_CPPCHECK)
|
||||
find_program(CMAKE_C_CPPCHECK NAMES cppcheck)
|
||||
if (CMAKE_C_CPPCHECK)
|
||||
list(
|
||||
APPEND CMAKE_C_CPPCHECK
|
||||
"--enable=warning"
|
||||
"--inline-suppr"
|
||||
"--std=c11"
|
||||
"-D__SIZEOF_POINTER__=8"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(res)
|
||||
add_subdirectory(test)
|
||||
|
||||
|
|
2
COPYING
2
COPYING
|
@ -8,7 +8,7 @@ This software was written by:
|
|||
This software is licensed under the terms of the LGPL. Please see each source
|
||||
file for the related copyright notice and license.
|
||||
|
||||
If a file does not contain a copright notice, the following notice shall apply:
|
||||
If a file does not contain a copyright notice, the following notice shall apply:
|
||||
|
||||
MiracleCast - Wifi-Display/Miracast Implementation
|
||||
|
||||
|
|
18
Makefile.am
18
Makefile.am
|
@ -4,3 +4,21 @@ EXTRA_DIST = README.md \
|
|||
NEWS
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
.PHONY: lcov genlcov lcov-clean
|
||||
|
||||
lcov:
|
||||
-$(MAKE) $(AM_MAKEFLAGS) -k check
|
||||
$(MAKE) $(AM_MAKEFLAGS) genlcov
|
||||
|
||||
# we have to massage the lcov.info file slightly to hide the effect of libtool
|
||||
# placing the objects files in the .libs/ directory separate from the *.c
|
||||
genlcov:
|
||||
$(LTP) --directory $(top_builddir) --capture --output-file miraclecast-lcov.info --test-name GLIB_PERF --no-checksum
|
||||
LANG=C $(LTP_GENHTML) --prefix $(top_builddir) --output-directory miraclecast-lcov --title "Miraclecast Code Coverage" --legend --show-details miraclecast-lcov.info
|
||||
|
||||
lcov-clean:
|
||||
-$(LTP) --directory $(top_builddir) -z
|
||||
-rm -rf miraclecast-lcov.info miraclecast-lcov
|
||||
-find -name '*.gcda' -print | xargs -Ix rm x
|
||||
|
||||
|
|
86
README.md
86
README.md
|
@ -1,61 +1,46 @@
|
|||
# MiracleCast - Wifi-Display/Miracast Implementation
|
||||
|
||||
[](https://gitter.im/albfan/miraclecast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://albfan.semaphoreci.com/projects/miraclecast)
|
||||
[](https://travis-ci.org/albfan/miraclecast)
|
||||
[](https://coveralls.io/github/albfan/miraclecast?branch=master)
|
||||
|
||||
The MiracleCast project provides software to connect external monitors to your system via Wi-Fi. It is compatible to the Wifi-Display specification also known as Miracast. MiracleCast implements the Display-Source as well as Display-Sink side.
|
||||
|
||||
The Display-Source side allows you to connect external displays to your system and stream local content to the device. A lot of effort is put into making this as easy as connecting external displays via HDMI.
|
||||
The Display-Source side allows you to connect external displays to your system and stream local content to the device. A lot of effort is put into making this as easy as connecting external displays via HDMI. *Note: This is not implemented yet. Please see [#4](../../issues/4).*
|
||||
|
||||
On the other hand, the Display-Sink side allows you to create wifi-capable external displays yourself. You can use it on your embedded devices or even on full desktops to allow other systems to use your device as external display.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
The MiracleCast projects requires the following software to be installed:
|
||||
- **systemd**: A system management daemon. It is used for device-management (udev), dbus management (sd-bus) and service management.
|
||||
Systemd must be compiled with --enable-kdbus, even though kdbus isn't used, but only the independent, experimental sd-libraries.
|
||||
Systemd >= 221 will work out of the box. For earlier versions systemd must be compiled with --enable-kdbus, even though kdbus isn't used, but only the independent, experimental sd-libraries.
|
||||
*required*: >=systemd-213
|
||||
|
||||
- **glib**: A utility library. Used by the current DHCP implementation. Will be removed once sd-dns gains DHCP-server capabilities.
|
||||
*required*: ~=glib2-2.38 (might work with older releases, untested..)
|
||||
|
||||
- **gstreamer**: MiracleCast rely on gstreamer to show cast its output. You can test if all needed is installed launching [res/test-viewer.sh](https://github.com/albfan/miraclecast/blob/master/res/test-viewer.sh)
|
||||
|
||||
- **wpa_supplicant**: MiracleCast spawns wpa_supplicant with a custom config.
|
||||
|
||||
- **P2P Wi-Fi device** Although widespread these days, there are some devices not compatible with [Wi-Fi Direct](http://en.wikipedia.org/wiki/Wi-Fi_Direct) (prior know as Wi-Fi P2P). Test yours with [res/test-hardware-capabilities.sh](https://github.com/albfan/miraclecast/blob/master/res/test-hardware-capabilities.sh)
|
||||
|
||||
- **check**: Test-suite for C programs. Used for optional tests of the MiracleCast code base.
|
||||
*optional*: ~=check-0.9.11 (might work with older releases, untested..)
|
||||
|
||||
- **gstreamer**: MiracleCast relay on gstreamer to show cast its output. You can test if all needed is installed launching [res/test-viewer.sh](https://github.com/albfan/miraclecast/blob/master/res/test-viewer.sh)
|
||||
|
||||
- **P2P Wi-Fi device** Although widespread this days, there are some devices not compatible with [Wi-Fi Direct](http://en.wikipedia.org/wiki/Wi-Fi_Direct) (prior know as Wi-Fi P2P). Test yours with [res/test-hardware-capabilities.sh](https://github.com/albfan/miraclecast/blob/master/res/test-hardware-capabilities.sh)
|
||||
|
||||
- copy the dbus policy **res/org.freedesktop.miracle.conf** to `/etc/dbus-1/system.d/`
|
||||
|
||||
## Install
|
||||
## Build and install
|
||||
|
||||
To compile MiracleCast, you can choose from [autotools](http://en.wikipedia.org/wiki/GNU_build_system) or [cmake](http://en.wikipedia.org/wiki/CMake):
|
||||
To compile MiracleCast, you can choose from:
|
||||
|
||||
Autotools:
|
||||
- [autotools](http://en.wikipedia.org/wiki/GNU_build_system)
|
||||
- [cmake](http://en.wikipedia.org/wiki/CMake)
|
||||
- [meson](http://mesonbuild.com/)
|
||||
|
||||
$ ./autogen.sh
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../configure --prefix=/usr/local #avoid --prefix for a standard install
|
||||
|
||||
Cmake:
|
||||
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ..
|
||||
|
||||
Compile
|
||||
|
||||
$ make
|
||||
|
||||
Test
|
||||
|
||||
$ make check #only with autotools by now
|
||||
|
||||
Install
|
||||
|
||||
$ sudo make install
|
||||
See more info on wiki [Building](https://github.com/albfan/miraclecast/wiki/Building)
|
||||
|
||||
## Automatic interface selection with udev
|
||||
|
||||
|
@ -69,17 +54,23 @@ You can also choose the interface with `--interface` option for miracle-wifid.
|
|||
|
||||
### Ubuntu
|
||||
|
||||
This specific linux flavour is so hard to get miraclecast dependencies that an alternative repo was created to install systemd with dbus
|
||||
Check your systemd version with:
|
||||
|
||||
$ systemctl --version
|
||||
|
||||
If you are on 221 or above your systemd has kdbus enabled.
|
||||
|
||||
If you are below 221, an alternative repo was created to install systemd with dbus
|
||||
|
||||
https://github.com/albfan/systemd-ubuntu-with-dbus
|
||||
|
||||
At this time, ubuntu is on version 15.04 and systemd is stick on 219 version, use branch [systemd-219](https://github.com/albfan/miraclecast/tree/systemd-219) to compile miraclecast
|
||||
See there was interface changes on systemd 219, if you are below that version, use branch [systemd-219](https://github.com/albfan/miraclecast/tree/systemd-219) to compile miraclecast
|
||||
|
||||
> See specific instructions on that repo
|
||||
|
||||
### Arch linux
|
||||
|
||||
Use existing [AUR package](https://aur.archlinux.org/packages/miraclecast/). Remember to enable kdus to systemd-git dependency
|
||||
Use existing [AUR package](https://aur.archlinux.org/packages/miraclecast-git/). Remember to enable kdbus to systemd-git dependency if you are below 221 systemd.
|
||||
|
||||
$ export _systemd_git_kdbus=--enable-kdbus
|
||||
|
||||
|
@ -94,15 +85,12 @@ If you feel confidence enough (since systemd is the entrypoint for an OS) extrac
|
|||
|
||||
## Documentation
|
||||
|
||||
Steps to use it as sink:
|
||||
### Steps to use it as sink
|
||||
|
||||
1. shutdown wpa_supplicant
|
||||
1. shutdown wpa_supplicant and NetworkManager
|
||||
|
||||
$ sudo kill -9 $(ps -ef | grep wpa_supplican[t] | awk '{print $2}')
|
||||
# now you can use `res/kill-wpa.sh`
|
||||
|
||||
>Remember to save your config to use with `res/normal-wifi.sh`
|
||||
>it will be easily located with `ps -ef | grep wpa_supplicant` on `-c` option.
|
||||
$ systemctl stop NetworkManager.service
|
||||
$ systemctl stop wpa_supplicant.service
|
||||
|
||||
2. launch wifi daemon
|
||||
|
||||
|
@ -121,7 +109,7 @@ Steps to use it as sink:
|
|||
|
||||
6. See your screen device on this machine
|
||||
|
||||
Steps to use it as peer:
|
||||
### Steps to use it as peer
|
||||
|
||||
1. Repeat steps 1 and 2 from "use as sink"
|
||||
|
||||
|
@ -133,9 +121,15 @@ Steps to use it as peer:
|
|||
|
||||
4. Locate them using scanning
|
||||
|
||||
> psp-scan
|
||||
> p2p-scan
|
||||
|
||||
5. Apart from list, or show info with peer <mac> there's nothing useful here by now.
|
||||
5. Apart from list, or show info with peer <mac> there's nothing useful here by now. For a Q&D see [Using as peer](https://github.com/albfan/miraclecast/issues/4)
|
||||
|
||||
## UIBC
|
||||
|
||||
> The User Input Back Channel (UIBC) is an optional WFD feature that when implemented facilitates communication of user inputs to a User Interface, present at the WFD Sink, to the WFD Source.
|
||||
|
||||
To use it just add `--uibc` on `miracle-sinkctl` startup. Single mouse events and key events are implemented.
|
||||
|
||||
## Autocompletion
|
||||
|
||||
|
@ -158,4 +152,4 @@ If you have any questions, do not hesitate to contact one of the maintainers.
|
|||
- Website: http://www.freedesktop.org/wiki/Software/miracle
|
||||
- Original repo: git://people.freedesktop.org/~dvdhrm/miracle
|
||||
- Fork repo: https://github.com/albfan/miraclecast
|
||||
|
||||
- Technical spec: https://www.wi-fi.org/file/wi-fi-display-technical-specification-v11 (free registration required)
|
||||
|
|
68
autogen.sh
68
autogen.sh
|
@ -1,2 +1,68 @@
|
|||
#!/bin/sh
|
||||
autoreconf -f --install
|
||||
|
||||
set -e
|
||||
|
||||
oldpwd=$(pwd)
|
||||
topdir=$(dirname $0)
|
||||
cd $topdir
|
||||
|
||||
#intltoolize --force --automake
|
||||
autoreconf --force --install --symlink
|
||||
|
||||
libdir() {
|
||||
echo $(cd "$1/$(gcc -print-multi-os-directory)"; pwd)
|
||||
}
|
||||
|
||||
args="\
|
||||
--sysconfdir=/etc \
|
||||
--localstatedir=/var \
|
||||
--libdir=$(libdir /usr/lib) \
|
||||
"
|
||||
|
||||
if [ -f "$topdir/.config.args" ]; then
|
||||
args="$args $(cat $topdir/.config.args)"
|
||||
fi
|
||||
|
||||
cd $oldpwd
|
||||
|
||||
if [ "x$1" = "xc" ]; then
|
||||
shift
|
||||
args="$args $@"
|
||||
$topdir/configure CFLAGS='-g -O0 -ftrapv' $args
|
||||
elif [ "x$1" = "xg" ]; then
|
||||
shift
|
||||
args="$args $@"
|
||||
$topdir/configure CFLAGS='-g -O0 -ftrapv' $args
|
||||
elif [ "x$1" = "xa" ]; then
|
||||
shift
|
||||
args="$args $@"
|
||||
$topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' $args
|
||||
elif [ "x$1" = "xl" ]; then
|
||||
shift
|
||||
args="$args $@"
|
||||
$topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' $args
|
||||
elif [ "x$1" = "xs" ]; then
|
||||
shift
|
||||
args="$args $@"
|
||||
scan-build $topdir/configure CFLAGS='-std=gnu99 -g -O0 -ftrapv' $args
|
||||
scan-build make
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
----------------------------------------------------------------
|
||||
Initialized build system. For a common configuration please run:
|
||||
----------------------------------------------------------------
|
||||
|
||||
$topdir/configure CFLAGS='-g -O0 -ftrapv' $args
|
||||
|
||||
or run $0 with param:
|
||||
|
||||
- c: compilation
|
||||
- g: debugging
|
||||
- a: pure/const warning
|
||||
- l: clang build
|
||||
- s: scan-build reporting
|
||||
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
|
11
autotools.Dockerfile
Normal file
11
autotools.Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
FROM docker.io/albfan/miraclecast-ci
|
||||
|
||||
COPY . ./
|
||||
|
||||
RUN rm -rf build-autotools ; \
|
||||
mkdir build-autotools; \
|
||||
cd build-autotools; \
|
||||
../autogen.sh; \
|
||||
../configure; \
|
||||
make; \
|
||||
make check
|
9
cmake.Dockerfile
Normal file
9
cmake.Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM docker.io/albfan/miraclecast-ci
|
||||
|
||||
RUN mkdir src
|
||||
|
||||
COPY . ./src
|
||||
|
||||
WORKDIR src
|
||||
|
||||
RUN cmake -Bbuild . && make -C build
|
|
@ -10,8 +10,7 @@ AM_CFLAGS = -Wall \
|
|||
|
||||
AM_CPPFLAGS = -include $(top_builddir)/config.h \
|
||||
-I $(top_srcdir)/src \
|
||||
-I $(top_srcdir)/src/shared \
|
||||
'-DBUILD_BINDIR="$(bindir)"'
|
||||
-I $(top_srcdir)/src/shared
|
||||
|
||||
AM_LDFLAGS = -Wl,--as-needed \
|
||||
-Wl,--gc-sections \
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#cmakedefine BUILD_ENABLE_DEBUG
|
||||
#cmakedefine ENABLE_SYSTEMD
|
||||
|
||||
#cmakedefine BUILD_BINDIR "@BUILD_BINDIR@"
|
||||
#cmakedefine RELY_UDEV @RELY_UDEV@
|
||||
#cmakedefine IP_BINARY @IP_BINARY@
|
||||
|
||||
#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@"
|
||||
|
||||
|
|
120
configure.ac
120
configure.ac
|
@ -35,17 +35,45 @@ AC_PROG_AWK
|
|||
|
||||
LT_PREREQ(2.2)
|
||||
LT_INIT
|
||||
LT_LIB_M
|
||||
|
||||
AC_ARG_ENABLE([rely-udev],
|
||||
AS_HELP_STRING([--enable-rely-udev], [Use tagged device with miraclecast]), AC_DEFINE([RELY_UDEV], [], [Rely on udev to find miraclecast device]))
|
||||
AC_ARG_ENABLE([log-debug],
|
||||
AS_HELP_STRING([--disable-log-debug], [Disable log debug]), , AC_DEFINE([BUILD_ENABLE_DEBUG], [], [Enable debug log level]))
|
||||
AC_ARG_VAR(IP_BINARY, [Path for ip binary])
|
||||
if test -z "$IP_BINARY"; then
|
||||
IP_BINARY=/bin/ip
|
||||
fi
|
||||
AC_ARG_ENABLE([systemd],
|
||||
AS_HELP_STRING([--disable-systemd], [Disable systemd]),
|
||||
[case "${enableval}" in
|
||||
yes) use_libsystemd=yes ;;
|
||||
no) use_libsystemd=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-systemd]) ;;
|
||||
esac],
|
||||
[use_libsystemd=yes])
|
||||
|
||||
AC_DEFINE_UNQUOTED([IP_BINARY], [$IP_BINARY], [Path for ip binary])
|
||||
|
||||
#
|
||||
# Mandatory dependencies
|
||||
#
|
||||
|
||||
PKG_CHECK_MODULES([DEPS], [libudev libsystemd > 219])
|
||||
PKG_CHECK_MODULES([GDHCP], [glib-2.0])
|
||||
AS_IF([test "$use_libsystemd" = "yes"],
|
||||
[
|
||||
AC_DEFINE([ENABLE_SYSTEMD], [], [Use systemd])
|
||||
m4_ifdef([PKG_CHECK_MODULES], [
|
||||
PKG_CHECK_MODULES([DEPS], [libudev libsystemd > 219])
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0])
|
||||
])
|
||||
],
|
||||
[
|
||||
m4_ifdef([PKG_CHECK_MODULES], [
|
||||
PKG_CHECK_MODULES([DEPS], [libudev libelogind])
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0])
|
||||
])
|
||||
])
|
||||
|
||||
AC_CHECK_HEADERS(readline/readline.h,, AC_MSG_ERROR(GNU readline not found))
|
||||
|
||||
|
@ -54,10 +82,84 @@ AC_CHECK_HEADERS(readline/readline.h,, AC_MSG_ERROR(GNU readline not found))
|
|||
# all tests.
|
||||
#
|
||||
|
||||
PKG_CHECK_MODULES([CHECK], [check],
|
||||
[have_check=yes], [have_check=no])
|
||||
m4_ifdef([PKG_CHECK_MODULES], [
|
||||
PKG_CHECK_MODULES([CHECK], [check],
|
||||
[have_check=yes], [have_check=no])
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_HAVE_CHECK], [test "x$have_check" = "xyes"])
|
||||
|
||||
if test "x$have_check" = "xyes"
|
||||
then
|
||||
|
||||
dnl ************************************
|
||||
dnl *** Enable lcov coverage reports ***
|
||||
dnl ************************************
|
||||
|
||||
AC_ARG_ENABLE(gcov,
|
||||
AS_HELP_STRING([--enable-gcov],
|
||||
[Enable gcov]),
|
||||
[use_gcov=$enableval], [use_gcov=no])
|
||||
|
||||
if test "x$use_gcov" = "xyes"; then
|
||||
dnl we need gcc:
|
||||
if test "$GCC" != "yes"; then
|
||||
AC_MSG_ERROR([GCC is required for --enable-gcov])
|
||||
fi
|
||||
|
||||
dnl Check if ccache is being used
|
||||
AC_CHECK_PROG(SHTOOL, shtool, shtool)
|
||||
case `$SHTOOL path $CC` in
|
||||
*ccache*[)] gcc_ccache=yes;;
|
||||
*[)] gcc_ccache=no;;
|
||||
esac
|
||||
|
||||
if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then
|
||||
AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
|
||||
fi
|
||||
|
||||
ltp_version_list="1.6 1.7 1.8 1.10 1.11 1.12"
|
||||
AC_CHECK_PROG(LTP, lcov, lcov)
|
||||
AC_CHECK_PROG(LTP_GENHTML, genhtml, genhtml)
|
||||
|
||||
if test "$LTP"; then
|
||||
AC_CACHE_CHECK([for ltp version], glib_cv_ltp_version, [
|
||||
glib_cv_ltp_version=invalid
|
||||
ltp_version=`$LTP -v 2>/dev/null | $SED -e 's/^.* //'`
|
||||
for ltp_check_version in $ltp_version_list; do
|
||||
if test "$ltp_version" = "$ltp_check_version"; then
|
||||
glib_cv_ltp_version="$ltp_check_version (ok)"
|
||||
fi
|
||||
done
|
||||
])
|
||||
else
|
||||
ltp_msg="To enable code coverage reporting you must have one of the following LTP versions installed: $ltp_version_list"
|
||||
AC_MSG_ERROR([$ltp_msg])
|
||||
fi
|
||||
|
||||
case $glib_cv_ltp_version in
|
||||
""|invalid[)]
|
||||
ltp_msg="You must have one of the following versions of LTP: $ltp_version_list (found: $ltp_version)."
|
||||
AC_MSG_ERROR([$ltp_msg])
|
||||
LTP="exit 0;"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -z "$LTP_GENHTML"; then
|
||||
AC_MSG_ERROR([Could not find genhtml from the LTP package])
|
||||
fi
|
||||
|
||||
AC_DEFINE(HAVE_GCOV, 1, [Whether you have gcov])
|
||||
|
||||
dnl Remove all optimization flags from CFLAGS
|
||||
changequote({,})
|
||||
CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
|
||||
changequote([,])
|
||||
|
||||
dnl Add the special gcc flags
|
||||
CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage"
|
||||
LDFLAGS="$LDFLAGS -lgcov"
|
||||
fi
|
||||
fi
|
||||
#
|
||||
# Makefile vars
|
||||
# After everything is configured, we create all makefiles.
|
||||
|
@ -70,6 +172,7 @@ AC_CONFIG_FILES([Makefile
|
|||
src/dhcp/Makefile
|
||||
src/shared/Makefile
|
||||
src/wifi/Makefile
|
||||
src/uibc/Makefile
|
||||
test/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
|
@ -87,12 +190,15 @@ AC_MSG_NOTICE([Build configuration:
|
|||
bindir: $bindir
|
||||
libdir: $libdir
|
||||
includedir: $includedir
|
||||
sysconfdir: $sysconfdir
|
||||
ip-binary: $IP_BINARY
|
||||
|
||||
Miscellaneous Options:
|
||||
building tests: $have_check
|
||||
code coverage: $use_gcov
|
||||
rely udev: ${enable_rely_udev:-no}
|
||||
|
||||
Compilation
|
||||
mkdir build && cd build
|
||||
"${MAKE-make}" to start compilation process
|
||||
"${MAKE-make}" check to pass test])
|
||||
else
|
||||
|
@ -102,11 +208,13 @@ AC_MSG_NOTICE([Build configuration:
|
|||
bindir: $bindir
|
||||
libdir: $libdir
|
||||
includedir: $includedir
|
||||
sysconfdir: $sysconfdir
|
||||
ip-binary: $IP_BINARY
|
||||
|
||||
Miscellaneous Options:
|
||||
building tests: $have_check
|
||||
rely udev: ${enable_rely_udev:-no}
|
||||
|
||||
Compilation
|
||||
mkdir build && cd build
|
||||
"${MAKE-make}" to start compilation process])
|
||||
fi
|
||||
|
|
7
meson.Dockerfile
Normal file
7
meson.Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
|||
FROM docker.io/albfan/miraclecast-ci
|
||||
|
||||
COPY . ./
|
||||
|
||||
RUN rm -rf build-meson; \
|
||||
meson build-meson; \
|
||||
ninja -C build-meson
|
55
meson.build
Normal file
55
meson.build
Normal file
|
@ -0,0 +1,55 @@
|
|||
project('Miraclecast',
|
||||
'c',
|
||||
version: '1',
|
||||
meson_version: '>=0.39',
|
||||
default_options: ['buildtype=debugoptimized', 'c_std=gnu11']
|
||||
)
|
||||
|
||||
add_project_arguments('-D_GNU_SOURCE', language: 'c')
|
||||
|
||||
conf_data = configuration_data()
|
||||
conf_data.set_quoted('BUILD_BINDIR',
|
||||
join_paths(get_option('prefix'), get_option('bindir'))
|
||||
)
|
||||
conf_data.set_quoted('PACKAGE_STRING',
|
||||
'@0@ @1@'.format(meson.project_name(), meson.project_version())
|
||||
)
|
||||
configure_file(output: 'config.h',
|
||||
configuration: conf_data
|
||||
)
|
||||
|
||||
c_compiler = meson.get_compiler('c')
|
||||
readline = c_compiler.find_library('readline', required: true)
|
||||
if readline.found()
|
||||
add_project_arguments('-DHAVE_READLINE', language: 'c')
|
||||
endif
|
||||
|
||||
if get_option('build-enable-debug')
|
||||
add_project_arguments('-DBUILD_ENABLE_DEBUG', language: 'c')
|
||||
endif
|
||||
|
||||
if get_option('rely-udev')
|
||||
add_project_arguments('-DRELY_UDEV', language: 'c')
|
||||
endif
|
||||
|
||||
if get_option('enable-systemd')
|
||||
add_project_arguments('-DENABLE_SYSTEMD', language: 'c')
|
||||
libsystemd = dependency('libsystemd')
|
||||
else
|
||||
libsystemd = dependency('libelogind')
|
||||
endif
|
||||
|
||||
add_project_arguments('-DIP_BINARY='+get_option('ip-binary'), language: 'c')
|
||||
|
||||
glib2 = dependency('glib-2.0')
|
||||
udev = dependency('libudev')
|
||||
|
||||
m = c_compiler.find_library('m', required: false)
|
||||
|
||||
subdir('src')
|
||||
subdir('res')
|
||||
|
||||
if get_option('build-tests')
|
||||
subdir('test')
|
||||
endif
|
||||
|
20
meson_options.txt
Normal file
20
meson_options.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
option('build-enable-debug',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable Debug')
|
||||
option('rely-udev',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Rely in udev tag to select device')
|
||||
option('build-tests',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Enable TEST')
|
||||
option('ip-binary',
|
||||
type: 'string',
|
||||
value: '/bin/ip',
|
||||
description: 'Path for ip binary')
|
||||
option('enable-systemd',
|
||||
type: 'boolean',
|
||||
value: 'true',
|
||||
description: 'Enable systemd')
|
|
@ -1,11 +1,14 @@
|
|||
INSTALL(
|
||||
PROGRAMS miracle-gst gstplayer uibc-viewer
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
########### install files ###############
|
||||
INSTALL(
|
||||
FILES org.freedesktop.miracle.conf
|
||||
DESTINATION ${SYSCONFDIR}/dbus-1/system.d
|
||||
)
|
||||
|
||||
install(FILES miracle-gst.sh DESTINATION bin)
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#bin_SCRIPTS = miracle-gst.sh
|
||||
#EXTRA_DIST = wpa.conf
|
||||
INSTALL(
|
||||
FILES miracle-wifid miracle-sinkctl miracle-wifictl
|
||||
DESTINATION ${DATADIR}/bash-completion/completions
|
||||
)
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
bin_SCRIPTS = miracle-gst.sh
|
||||
bin_SCRIPTS = miracle-gst gstplayer uibc-viewer miracle-omxplayer
|
||||
EXTRA_DIST = wpa.conf
|
||||
|
||||
dbuspolicydir=$(sysconfdir)/dbus-1/system.d
|
||||
dbuspolicy_DATA = org.freedesktop.miracle.conf
|
||||
|
||||
bashcompletiondir=${datadir}/bash-completion/completions
|
||||
bashcompletion_DATA=miracle-wifid miracle-sinkctl miracle-wifictl
|
||||
|
||||
|
|
223
res/gstplayer
Executable file
223
res/gstplayer
Executable file
|
@ -0,0 +1,223 @@
|
|||
#!/usr/bin/python3 -u
|
||||
|
||||
import gi
|
||||
import argparse
|
||||
|
||||
gi.require_version('Gst', '1.0')
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GstVideo', '1.0')
|
||||
gi.require_version('GdkX11', '3.0')
|
||||
|
||||
from gi.repository import GObject, Gst, Gtk, Gdk, GLib
|
||||
|
||||
# Needed for window.get_xid(), xvimagesink.set_window_handle(), respectively:
|
||||
from gi.repository import GdkX11, GstVideo
|
||||
|
||||
GObject.threads_init()
|
||||
Gst.init(None)
|
||||
|
||||
class Player(object):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
resolution = kwargs.get("resolution")
|
||||
if resolution:
|
||||
split = resolution.split("x")
|
||||
self.width = int(split[0])
|
||||
self.height = int(split[1])
|
||||
|
||||
scale = kwargs.get("scale")
|
||||
if scale:
|
||||
split = scale.split("x")
|
||||
self.width = int(split[0])
|
||||
self.height = int(split[1])
|
||||
|
||||
debug = kwargs.get("debug")
|
||||
if debug:
|
||||
Gst.debug_set_active(True)
|
||||
Gst.debug_set_threshold_from_string(debug, True)
|
||||
|
||||
port = kwargs.get("port")
|
||||
|
||||
uri = kwargs.get("uri")
|
||||
|
||||
self.window = Gtk.Window()
|
||||
self.window.set_name('gstplayer')
|
||||
self.window.connect('destroy', self.quit)
|
||||
|
||||
title = kwargs.get("title")
|
||||
if title:
|
||||
self.window.set_title(title)
|
||||
|
||||
if hasattr(self,'width') and hasattr(self,'height'):
|
||||
self.window.set_default_size(self.width, self.height)
|
||||
|
||||
self.drawingarea = Gtk.DrawingArea()
|
||||
self.window.add(self.drawingarea)
|
||||
|
||||
if hasattr(self,'width') and hasattr(self,'height'):
|
||||
self.drawingarea.set_size_request(self.width,self.height)
|
||||
self.drawingarea.add_events(Gdk.EventMask.BUTTON_PRESS_MASK|Gdk.EventMask.BUTTON_RELEASE_MASK)
|
||||
self.drawingarea.connect('button-press-event', self.on_mouse_pressed)
|
||||
self.drawingarea.connect('button-release-event', self.on_mouse_pressed)
|
||||
self.drawingarea.add_events(Gdk.EventMask.KEY_PRESS_MASK)
|
||||
self.window.connect('key-press-event', self.on_key_pressed)
|
||||
|
||||
audio = kwargs.get("audio")
|
||||
|
||||
self.playbin = None
|
||||
|
||||
#Create GStreamer pipeline
|
||||
if uri is not None:
|
||||
self.pipeline = Gst.Pipeline()
|
||||
|
||||
# Create GStreamer elements
|
||||
self.playbin = Gst.ElementFactory.make('playbin', "source")
|
||||
|
||||
if not uri.startswith("http://") or not uri.startswith("http://") or not uri.startswith("file://"):
|
||||
if not uri.startswith("/"):
|
||||
import os
|
||||
uri = os.path.abspath(uri)
|
||||
uri = "file://"+uri
|
||||
|
||||
# Set properties
|
||||
self.playbin.set_property('uri', uri)
|
||||
|
||||
|
||||
# Add playbin to the pipeline
|
||||
self.pipeline.add(self.playbin)
|
||||
else:
|
||||
gstcommand = "udpsrc port="+str(port)+" caps=\"application/x-rtp, media=video\" ! rtpjitterbuffer latency=100 ! rtpmp2tdepay ! tsdemux "
|
||||
|
||||
if audio:
|
||||
gstcommand += "name=demuxer demuxer. "
|
||||
|
||||
gstcommand += "! queue max-size-buffers=0 max-size-time=0 ! h264parse ! avdec_h264 ! videoconvert ! "
|
||||
|
||||
if scale:
|
||||
gstcommand += "videoscale method=1 ! video/x-raw,width="+str(self.width)+",height="+str(self.height)+" ! "
|
||||
|
||||
gstcommand += "autovideosink "
|
||||
|
||||
if audio:
|
||||
gstcommand += "demuxer. ! queue max-size-buffers=0 max-size-time=0 ! aacparse ! avdec_aac ! audioconvert ! audioresample ! autoaudiosink "
|
||||
|
||||
self.pipeline = Gst.parse_launch(gstcommand)
|
||||
|
||||
|
||||
# Create bus to get events from GStreamer pipeline
|
||||
self.bus = self.pipeline.get_bus()
|
||||
self.bus.add_signal_watch()
|
||||
self.bus.connect('message::eos', self.on_eos)
|
||||
self.bus.connect('message::error', self.on_error)
|
||||
|
||||
# This is needed to make the video output in our DrawingArea:
|
||||
self.bus.enable_sync_message_emission()
|
||||
self.bus.connect('sync-message::element', self.on_sync_message)
|
||||
self.bus.connect('message', self.on_message)
|
||||
|
||||
self.success = False
|
||||
|
||||
def on_message(self, bus, message):
|
||||
if self.playbin:
|
||||
videoPad = self.playbin.emit("get-video-pad", 0)
|
||||
if videoPad and not self.success:
|
||||
videoPadCapabilities = videoPad.get_current_caps()
|
||||
if videoPadCapabilities:
|
||||
(self.success, self.videoWidth) = \
|
||||
videoPadCapabilities.get_structure(0).get_int("width")
|
||||
(self.success, self.videoHeight) = \
|
||||
videoPadCapabilities.get_structure(0).get_int("height")
|
||||
if self.success:
|
||||
print("{0} {1}".format(self.videoWidth, self.videoHeight))
|
||||
self.drawingarea.set_size_request(self.videoWidth, self.videoHeight)
|
||||
|
||||
def on_mouse_pressed(self, widget, event):
|
||||
#<type>,<count>,<id>,<x>,<y>
|
||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
type = 0
|
||||
else:
|
||||
type = 1
|
||||
|
||||
width = self.drawingarea.get_allocation().width
|
||||
height = self.drawingarea.get_allocation().height
|
||||
half_area_width = width / 2
|
||||
half_area_height = height / 2
|
||||
|
||||
half_def_width = self.width / 2
|
||||
half_def_height = self.height / 2
|
||||
|
||||
min_hor_pos = half_area_width - half_def_width
|
||||
max_hor_pos = half_area_width + half_def_width
|
||||
min_ver_pos = half_area_height - half_def_height
|
||||
max_ver_pos = half_area_height + half_def_height
|
||||
|
||||
pos_event_x = event.x
|
||||
pos_event_y = event.y
|
||||
|
||||
|
||||
if min_hor_pos <= pos_event_x <= max_hor_pos and min_ver_pos <= pos_event_y <= max_ver_pos:
|
||||
uibc_x = int(pos_event_x - (half_area_width - half_def_width))
|
||||
uibc_y = int(pos_event_y - (half_area_height - half_def_height))
|
||||
print('{0},1,0,{1},{2}'.format(type, uibc_x , uibc_y))
|
||||
|
||||
def on_key_pressed(self, widget, event):
|
||||
print("3,0x%04X,0x0000" % event.keyval)
|
||||
|
||||
def run(self):
|
||||
self.window.show_all()
|
||||
# You need to get the XID after window.show_all(). You shouldn't get it
|
||||
# in the on_sync_message() handler because threading issues will cause
|
||||
# segfaults there.
|
||||
window = self.drawingarea.get_property('window')
|
||||
if hasattr(window,'get_xid'):
|
||||
self.xid = self.drawingarea.get_property('window').get_xid()
|
||||
|
||||
self.pipeline.set_state(Gst.State.PLAYING)
|
||||
Gtk.main()
|
||||
|
||||
|
||||
def quit(self, window):
|
||||
self.pipeline.set_state(Gst.State.NULL)
|
||||
Gtk.main_quit()
|
||||
|
||||
def on_sync_message(self, bus, msg):
|
||||
if msg.get_structure().get_name() == 'prepare-window-handle':
|
||||
print(self.drawingarea.get_allocation())
|
||||
if hasattr(self,'xid'):
|
||||
msg.src.set_window_handle(self.xid)
|
||||
|
||||
def on_eos(self, bus, msg):
|
||||
print('on_eos(): seeking to start of video')
|
||||
self.pipeline.seek_simple(
|
||||
Gst.Format.TIME,
|
||||
Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
|
||||
0
|
||||
)
|
||||
|
||||
def on_error(self, bus, msg):
|
||||
print('on_error():', msg.parse_error())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("uri", nargs="?", help="Uri to play")
|
||||
parser.add_argument("-v", "--version", help="Show package version")
|
||||
parser.add_argument("--log-level", metavar="lvl", help="Maximum level for log messages")
|
||||
parser.add_argument("-p", "--port", type=int, default=7236, help="Port for rtsp")
|
||||
parser.add_argument("-a", "--audio", dest="audio", action="store_true", help="Enable audio support")
|
||||
parser.add_argument("-s", "--scale", metavar="WxH", help="Scale to resolution")
|
||||
parser.add_argument("-d", "--debug", help="Debug")
|
||||
parser.add_argument("--uibc", help="Enable UIBC")
|
||||
parser.add_argument("--title", help="set player title")
|
||||
parser.add_argument("--res", metavar="n,n,n", help="Supported resolutions masks (CEA, VESA, HH)")
|
||||
# res
|
||||
# " default CEA %08X\n"
|
||||
# " default VESA %08X\n"
|
||||
# " default HH %08X\n"
|
||||
parser.add_argument("-r", "--resolution", help="Resolution")
|
||||
parser.set_defaults(audio=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
p = Player(**vars(args))
|
||||
p.run()
|
|
@ -1,8 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
. miracle-utils.sh
|
||||
DIRNAME=$(dirname $0)
|
||||
|
||||
kill_ubuntu_network_manager
|
||||
. $DIRNAME/miracle-utils.sh
|
||||
|
||||
kill_network_manager
|
||||
|
||||
WPA_PID=$(find_wpa_supplicant_pid)
|
||||
if [ -n "$WPA_PID" ]
|
||||
|
|
13
res/meson.build
Normal file
13
res/meson.build
Normal file
|
@ -0,0 +1,13 @@
|
|||
install_data(
|
||||
'org.freedesktop.miracle.conf',
|
||||
install_dir: join_paths(get_option('sysconfdir'), 'dbus-1', 'system.d')
|
||||
)
|
||||
|
||||
install_data('miracle-gst', 'gstplayer', 'uibc-viewer',
|
||||
install_dir: get_option('bindir'),
|
||||
install_mode: 'rwxr-xr-x')
|
||||
|
||||
install_data(
|
||||
'miracle-wifid', 'miracle-sinkctl', 'miracle-wifictl',
|
||||
install_dir: join_paths(get_option('datadir'), 'bash-completion', 'completions')
|
||||
)
|
|
@ -1,12 +1,46 @@
|
|||
#!/bin/bash
|
||||
|
||||
function help {
|
||||
local scriptname="$(basename $0)"
|
||||
cat >&2 <<EOF
|
||||
|
||||
$scriptname [options]
|
||||
|
||||
play rtp stream
|
||||
|
||||
Options:
|
||||
-r Resolution
|
||||
-s <Width>x<height> Scale
|
||||
-d <level> Log level for gst
|
||||
-p <port> Port for stream
|
||||
-a Enables audio
|
||||
-h Show this help
|
||||
|
||||
Examples:
|
||||
|
||||
# play stream on port 7236
|
||||
$ $scriptname -p 7236
|
||||
# play stream with resolution 800x600
|
||||
$ $scriptname -s 800x600
|
||||
# play stream with audio
|
||||
$ $scriptname -a
|
||||
# play stream with debug level 3
|
||||
$ $scriptname -d 3
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
DEBUG='0'
|
||||
AUDIO='0'
|
||||
SCALE='0'
|
||||
|
||||
while getopts "r:d:as:" optname
|
||||
while getopts "r:d:as:p:h" optname
|
||||
do
|
||||
case "$optname" in
|
||||
"h")
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
"d")
|
||||
DEBUG=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
|
@ -16,6 +50,9 @@ while getopts "r:d:as:" optname
|
|||
"a")
|
||||
AUDIO='1'
|
||||
;;
|
||||
"p")
|
||||
PORT=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"s")
|
||||
SCALE='1'
|
||||
WIDTH=`echo ${OPTARG} | tr -d ' ' | cut -dx -f 1`
|
||||
|
@ -25,8 +62,9 @@ while getopts "r:d:as:" optname
|
|||
echo "Unknown option $OPTARG"
|
||||
;;
|
||||
*)
|
||||
# Should not occur
|
||||
echo "Unknown error while processing options"
|
||||
echo "Unknown parameter $OPTARG"
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
@ -37,7 +75,7 @@ then
|
|||
RUN+="--gst-debug=${DEBUG} "
|
||||
fi
|
||||
|
||||
RUN+="udpsrc port=1991 caps=\"application/x-rtp, media=video\" ! rtpjitterbuffer latency=100 ! rtpmp2tdepay ! tsdemux "
|
||||
RUN+="udpsrc port=$PORT caps=\"application/x-rtp, media=video\" ! rtpjitterbuffer latency=100 ! rtpmp2tdepay ! tsdemux "
|
||||
|
||||
if [ $AUDIO == '1' ]
|
||||
then
|
69
res/miracle-omxplayer
Executable file
69
res/miracle-omxplayer
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
function help {
|
||||
local scriptname="$(basename $0)"
|
||||
cat >&2 <<EOF
|
||||
|
||||
$scriptname [options]
|
||||
|
||||
play rtp stream with omxplayer
|
||||
|
||||
Options:
|
||||
-r Resolution
|
||||
-s <Width>x<height> Scale
|
||||
-d <level> Log level for gst
|
||||
-p <port> Port for stream
|
||||
-a Enables audio
|
||||
-h Show this help
|
||||
|
||||
Examples:
|
||||
|
||||
# play stream on port 7236
|
||||
$ $scriptname -p 7236
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
DEBUG='0'
|
||||
AUDIO='0'
|
||||
SCALE='0'
|
||||
|
||||
while getopts "r:d:as:p:h" optname
|
||||
do
|
||||
case "$optname" in
|
||||
"h")
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
"d")
|
||||
DEBUG=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"r")
|
||||
RESOLUTION=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"a")
|
||||
AUDIO='1'
|
||||
;;
|
||||
"p")
|
||||
PORT=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"s")
|
||||
SCALE='1'
|
||||
WIDTH=`echo ${OPTARG} | tr -d ' ' | cut -dx -f 1`
|
||||
HEIGHT=`echo ${OPTARG} | tr -d ' ' | cut -dx -f 2`
|
||||
;;
|
||||
"?")
|
||||
echo "Unknown option $OPTARG"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown parameter $OPTARG"
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
RUN="omxplayer -live -b -o hdmi rtp://@:$PORT"
|
||||
|
||||
echo "running: $RUN"
|
||||
exec ${RUN}
|
85
res/miracle-sinkctl
Executable file
85
res/miracle-sinkctl
Executable file
|
@ -0,0 +1,85 @@
|
|||
#
|
||||
# Autocompletion for miraclecast commands
|
||||
#
|
||||
# Maintainer: Alberto Fanjul <albertofanjul@gmail.com>
|
||||
#
|
||||
|
||||
function _miracle-sinkctl() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-sinkctl) $(_parse_short_help miracle-sinkctl)" -- "$cur"))
|
||||
}
|
||||
|
||||
_parse_short_help ()
|
||||
{
|
||||
eval local cmd=$( quote "$1" );
|
||||
local line;
|
||||
{
|
||||
case $cmd in
|
||||
-)
|
||||
cat
|
||||
;;
|
||||
*)
|
||||
LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1
|
||||
;;
|
||||
esac
|
||||
} | while read -r line; do
|
||||
[[ $line == *([[:blank:]])-* ]] || continue;
|
||||
while [[ $line =~ ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do
|
||||
line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"};
|
||||
done;
|
||||
__parse_short_options "${line// or /, }";
|
||||
done
|
||||
}
|
||||
|
||||
__parse_short_options ()
|
||||
{
|
||||
local option option2 i IFS='
|
||||
,/|';
|
||||
option=;
|
||||
local -a array;
|
||||
read -a array <<< "$1";
|
||||
for i in "${array[@]}";
|
||||
do
|
||||
case "$i" in
|
||||
---*)
|
||||
break
|
||||
;;
|
||||
--?*)
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
option=$i;
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac;
|
||||
done;
|
||||
[[ -n $option ]] || return;
|
||||
IFS='
|
||||
';
|
||||
if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
|
||||
option2=${option/"${BASH_REMATCH[1]}"/};
|
||||
option2=${option2%%[<{().[]*};
|
||||
printf '%s\n' "${option2/=*/=}";
|
||||
option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"};
|
||||
fi;
|
||||
option=${option%%[<{().[]*};
|
||||
printf '%s\n' "${option/=*/=}"
|
||||
}
|
||||
|
||||
complete -F _miracle-sinkctl miracle-sinkctl
|
||||
|
||||
# ex: filetype=sh
|
|
@ -27,6 +27,13 @@ function find_wireless_network_interfaces {
|
|||
done
|
||||
}
|
||||
|
||||
#
|
||||
# show pci slot
|
||||
#
|
||||
function show_pci_slot {
|
||||
basename $(readlink /sys/class/net/$1/device) | cut -d: -f2 | sed 's/^0*//'
|
||||
}
|
||||
|
||||
#
|
||||
# test if interface is connected
|
||||
#
|
||||
|
@ -34,6 +41,26 @@ function is_interface_connected {
|
|||
test x$( cat /sys/class/net/$1/carrier 2>/dev/null) = x1
|
||||
}
|
||||
|
||||
#
|
||||
# find wireless pci slot
|
||||
#
|
||||
function find_wireless_pci_slot {
|
||||
for i in $( find_wireless_network_interfaces )
|
||||
do
|
||||
show_pci_slot $i
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# find wireless pci slot
|
||||
#
|
||||
function find_wireless_ifindex {
|
||||
for i in $( find_wireless_network_interfaces )
|
||||
do
|
||||
show_ifindex $i
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# find wireless connected interfaces
|
||||
#
|
||||
|
@ -52,12 +79,23 @@ function find_wireless_connected_network_interfaces {
|
|||
#
|
||||
function find_physical_for_network_interface {
|
||||
PHY_INDEX=$(iw dev $1 info | grep wiphy | awk '{print $2}')
|
||||
if [ -n $PHY_INDEX ]
|
||||
if [ -n "$PHY_INDEX" ]
|
||||
then
|
||||
echo phy$PHY_INDEX
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# find interface index for interface
|
||||
#
|
||||
function show_ifindex {
|
||||
IF_INDEX=$(iw dev $1 info | grep ifindex | awk '{print $2}')
|
||||
if [ -n "$IF_INDEX" ]
|
||||
then
|
||||
echo $IF_INDEX
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Check interface for P2P capabilities
|
||||
#
|
||||
|
@ -65,6 +103,12 @@ function search_p2p_capabilities {
|
|||
WI_DEVICE=$1
|
||||
PHY_DEVICE=$(find_physical_for_network_interface $WI_DEVICE)
|
||||
|
||||
if [ -z "$PHY_DEVICE" ]
|
||||
then
|
||||
echo "cannot find physical device for $WI_DEVICE"
|
||||
return
|
||||
fi
|
||||
|
||||
if iw phy $PHY_DEVICE info | grep -Pzo "(?s)Supported interface modes.*Supported commands" | grep "P2P" &> /dev/null
|
||||
then
|
||||
echo $WI_DEVICE supports P2P
|
||||
|
@ -95,31 +139,55 @@ function find_wpa_supplicant_pid {
|
|||
show_wpa_supplicant_process | awk '{print $2}'
|
||||
}
|
||||
|
||||
#
|
||||
# checking if distro is archlinux
|
||||
#
|
||||
function check_archlinux_distro {
|
||||
test -f "/etc/arch-release"
|
||||
}
|
||||
#
|
||||
# checking if distro is ubuntu
|
||||
#
|
||||
function check_ubuntu_distro {
|
||||
cat /proc/version | grep -i ubuntu
|
||||
}
|
||||
#
|
||||
# checking if distro is debian
|
||||
#
|
||||
function check_debian_distro {
|
||||
cat /proc/version | grep -i debian
|
||||
}
|
||||
|
||||
#
|
||||
# ubuntu manager restarts automatically wpa_supplicant
|
||||
# kills network manager
|
||||
#
|
||||
function kill_ubuntu_network_manager {
|
||||
if check_ubuntu_distro
|
||||
function kill_network_manager {
|
||||
echo stopping NetworkManager
|
||||
if check_ubuntu_distro || check_debian_distro
|
||||
then
|
||||
echo stopping NetworkManager
|
||||
# ubuntu manager restarts automatically wpa_supplicant
|
||||
sudo service NetworkManager stop
|
||||
elif check_archlinux_distro
|
||||
then
|
||||
sudo systemctl stop Network.service
|
||||
else
|
||||
sudo systemctl stop NetworkManager
|
||||
sudo systemctl stop wpa_supplicant
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# start ubuntu manager
|
||||
# start network manager
|
||||
#
|
||||
function start_ubuntu_network_manager {
|
||||
if check_ubuntu_distro
|
||||
function start_network_manager {
|
||||
echo starting NetworkManager
|
||||
if check_ubuntu_distro || check_debian_distro
|
||||
then
|
||||
echo starting NetworkManager
|
||||
sudo service NetworkManager start
|
||||
elif check_archlinux_distro
|
||||
then
|
||||
sudo systemctl start Network.service
|
||||
else
|
||||
sudo service NetworkManager start
|
||||
fi
|
||||
}
|
||||
|
|
69
res/miracle-vlc
Executable file
69
res/miracle-vlc
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
function help {
|
||||
local scriptname="$(basename $0)"
|
||||
cat >&2 <<EOF
|
||||
|
||||
$scriptname [options]
|
||||
|
||||
play rtp stream with vlc
|
||||
|
||||
Options:
|
||||
-r Resolution
|
||||
-s <Width>x<height> Scale
|
||||
-d <level> Log level for gst
|
||||
-p <port> Port for stream
|
||||
-a Enables audio
|
||||
-h Show this help
|
||||
|
||||
Examples:
|
||||
|
||||
# play stream on port 7236
|
||||
$ $scriptname -p 7236
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
DEBUG='0'
|
||||
AUDIO='0'
|
||||
SCALE='0'
|
||||
|
||||
while getopts "r:d:as:p:h" optname
|
||||
do
|
||||
case "$optname" in
|
||||
"h")
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
"d")
|
||||
DEBUG=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"r")
|
||||
RESOLUTION=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"a")
|
||||
AUDIO='1'
|
||||
;;
|
||||
"p")
|
||||
PORT=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"s")
|
||||
SCALE='1'
|
||||
WIDTH=`echo ${OPTARG} | tr -d ' ' | cut -dx -f 1`
|
||||
HEIGHT=`echo ${OPTARG} | tr -d ' ' | cut -dx -f 2`
|
||||
;;
|
||||
"?")
|
||||
echo "Unknown option $OPTARG"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown parameter $OPTARG"
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
RUN="vlc rtp://@:$PORT"
|
||||
|
||||
echo "running: $RUN"
|
||||
exec ${RUN}
|
85
res/miracle-wifictl
Executable file
85
res/miracle-wifictl
Executable file
|
@ -0,0 +1,85 @@
|
|||
#
|
||||
# Autocompletion for miracle-wifictl
|
||||
#
|
||||
# Maintainer: Alberto Fanjul <albertofanjul@gmail.com>
|
||||
#
|
||||
|
||||
function _miracle-wifictl() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-wifictl) $(_parse_short_help miracle-wifictl)" -- "$cur"))
|
||||
}
|
||||
|
||||
_parse_short_help ()
|
||||
{
|
||||
eval local cmd=$( quote "$1" );
|
||||
local line;
|
||||
{
|
||||
case $cmd in
|
||||
-)
|
||||
cat
|
||||
;;
|
||||
*)
|
||||
LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1
|
||||
;;
|
||||
esac
|
||||
} | while read -r line; do
|
||||
[[ $line == *([[:blank:]])-* ]] || continue;
|
||||
while [[ $line =~ ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do
|
||||
line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"};
|
||||
done;
|
||||
__parse_short_options "${line// or /, }";
|
||||
done
|
||||
}
|
||||
|
||||
__parse_short_options ()
|
||||
{
|
||||
local option option2 i IFS='
|
||||
,/|';
|
||||
option=;
|
||||
local -a array;
|
||||
read -a array <<< "$1";
|
||||
for i in "${array[@]}";
|
||||
do
|
||||
case "$i" in
|
||||
---*)
|
||||
break
|
||||
;;
|
||||
--?*)
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
option=$i;
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac;
|
||||
done;
|
||||
[[ -n $option ]] || return;
|
||||
IFS='
|
||||
';
|
||||
if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
|
||||
option2=${option/"${BASH_REMATCH[1]}"/};
|
||||
option2=${option2%%[<{().[]*};
|
||||
printf '%s\n' "${option2/=*/=}";
|
||||
option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"};
|
||||
fi;
|
||||
option=${option%%[<{().[]*};
|
||||
printf '%s\n' "${option/=*/=}"
|
||||
}
|
||||
|
||||
complete -F _miracle-wifictl miracle-wifictl
|
||||
|
||||
# ex: filetype=sh
|
95
res/miracle-wifid
Executable file
95
res/miracle-wifid
Executable file
|
@ -0,0 +1,95 @@
|
|||
#
|
||||
# Autocompletion for miracle-wifid
|
||||
#
|
||||
# Maintainer: Alberto Fanjul <albertofanjul@gmail.com>
|
||||
#
|
||||
|
||||
function _miracle-wifid() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--config-methods)
|
||||
COMPREPLY=($(compgen -W 'pbc pin usba ethernet label display ext_nfc_token int_nfc_token nfc_interface push_button keypad virtual_display physical_display virtual_push_button physical_push_button' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
--wpa-loglevel)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-wifid) $(_parse_short_help miracle-wifid)" -- "$cur"))
|
||||
}
|
||||
|
||||
|
||||
_parse_short_help ()
|
||||
{
|
||||
eval local cmd=$( quote "$1" );
|
||||
local line;
|
||||
{
|
||||
case $cmd in
|
||||
-)
|
||||
cat
|
||||
;;
|
||||
*)
|
||||
LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1
|
||||
;;
|
||||
esac
|
||||
} | while read -r line; do
|
||||
[[ $line == *([[:blank:]])-* ]] || continue;
|
||||
while [[ $line =~ ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do
|
||||
line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"};
|
||||
done;
|
||||
__parse_short_options "${line// or /, }";
|
||||
done
|
||||
}
|
||||
|
||||
__parse_short_options ()
|
||||
{
|
||||
local option option2 i IFS='
|
||||
,/|';
|
||||
option=;
|
||||
local -a array;
|
||||
read -a array <<< "$1";
|
||||
for i in "${array[@]}";
|
||||
do
|
||||
case "$i" in
|
||||
---*)
|
||||
break
|
||||
;;
|
||||
--?*)
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
option=$i;
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac;
|
||||
done;
|
||||
[[ -n $option ]] || return;
|
||||
IFS='
|
||||
';
|
||||
if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
|
||||
option2=${option/"${BASH_REMATCH[1]}"/};
|
||||
option2=${option2%%[<{().[]*};
|
||||
printf '%s\n' "${option2/=*/=}";
|
||||
option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"};
|
||||
fi;
|
||||
option=${option%%[<{().[]*};
|
||||
printf '%s\n' "${option/=*/=}"
|
||||
}
|
||||
|
||||
complete -F _miracle-wifid miracle-wifid
|
||||
|
||||
|
||||
# ex: filetype=sh
|
18
res/miraclecast-ci.Dockerfile
Normal file
18
res/miraclecast-ci.Dockerfile
Normal file
|
@ -0,0 +1,18 @@
|
|||
FROM debian:buster-slim
|
||||
|
||||
RUN dpkg --add-architecture i386
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
systemd \
|
||||
libglib2.0-dev \
|
||||
libreadline-dev \
|
||||
libudev-dev \
|
||||
libsystemd-dev \
|
||||
libusb-dev \
|
||||
automake \
|
||||
autoconf \
|
||||
libtool \
|
||||
cmake \
|
||||
meson
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
function _miracle-wifid() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
--wpa-loglevel)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-wifid)" -- "$cur"))
|
||||
}
|
||||
|
||||
complete -F _miracle-wifid miracle-wifid
|
||||
|
||||
function _miracle-sinkctl() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-sinkctl)" -- "$cur"))
|
||||
}
|
||||
|
||||
complete -F _miracle-sinkctl miracle-sinkctl
|
||||
|
||||
function _miracle-wifictl() {
|
||||
local cur prev
|
||||
|
||||
_get_comp_words_by_ref cur
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
case "$prev" in
|
||||
--log-level)
|
||||
COMPREPLY=($(compgen -W 'fatal alert critical error warning notice info debug trace 1 2 3 4 5 6 7 8' -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=($(compgen -W "$(_parse_help miracle-wifictl)" -- "$cur"))
|
||||
}
|
||||
|
||||
complete -F _miracle-wifictl miracle-wifictl
|
68
res/miraclecast.spec
Normal file
68
res/miraclecast.spec
Normal file
|
@ -0,0 +1,68 @@
|
|||
%global commit 264a222d242734da369ca287aa6cfc6ca4f1f7bf
|
||||
%global shortcommit %(c=%{commit}; echo ${c:0:7})
|
||||
|
||||
Name: miraclecast
|
||||
Version: 1.0
|
||||
Release: 2.git%{shortcommit}%{?dist}
|
||||
Summary: Connect external monitors to your system via Wi-Fi Display (miracast)
|
||||
License: LGPLv2
|
||||
URL: https://github.com/albfan/miraclecast
|
||||
Source0: https://github.com/albfan/miraclecast/archive/%{commit}/%{name}-%{shortcommit}.tar.gz
|
||||
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
|
||||
BuildRequires: glib2-devel
|
||||
BuildRequires: readline-devel
|
||||
BuildRequires: systemd-devel
|
||||
|
||||
# "Recommends" is stronger than "Suggests", and gets installed by default by DNF.
|
||||
|
||||
# for gstplayer
|
||||
Recommends: python3-gobject-base
|
||||
|
||||
# for miracle-gst (/usr/bin/gst-launch-1.0)
|
||||
Suggests: gstreamer
|
||||
|
||||
# for miracle-omxplayer
|
||||
Suggests: omxplayer
|
||||
|
||||
%description
|
||||
The MiracleCast project provides software to connect external monitors to your
|
||||
system via Wi-Fi. It is compatible to the Wi-Fi Display specification also
|
||||
known as Miracast. MiracleCast implements the Display-Source as well as
|
||||
Display-Sink side.
|
||||
|
||||
The Display-Source side allows you to connect external displays to your system
|
||||
and stream local content to the device. A lot of effort is put into making
|
||||
this as easy as connecting external displays via HDMI.
|
||||
|
||||
On the other hand, the Display-Sink side allows you to create Wi-Fi capable
|
||||
external displays yourself. You can use it on your embedded devices or even on
|
||||
full desktops to allow other systems to use your device as external display.
|
||||
|
||||
%prep
|
||||
%autosetup -n %{name}-%{commit}
|
||||
|
||||
%build
|
||||
autoreconf -fiv
|
||||
%configure
|
||||
%make_build
|
||||
|
||||
%install
|
||||
%make_install
|
||||
|
||||
%files
|
||||
%license COPYING LICENSE_gdhcp LICENSE_htable LICENSE_lgpl
|
||||
%doc README.md
|
||||
%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.miracle.conf
|
||||
%{_bindir}/*
|
||||
%{_datadir}/bash-completion/completions/*
|
||||
|
||||
%changelog
|
||||
* Wed Jan 05 2022 Korenberg Mark
|
||||
- Fix .spec-file, bump version
|
||||
|
||||
* Wed Nov 21 2018 Graham White
|
||||
- first build
|
24
res/miraclecast.spec-README.md
Normal file
24
res/miraclecast.spec-README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
This file can be used with the rpmbuild or mock commands to create a binary RPM. Tested and working on Fedora 28 x86\_64.
|
||||
|
||||
Example usage (for Fedora 28 systems):
|
||||
1. Create a tar.gz file of the source code and add the short name of the commit to the tar file, for the most recent commit at the time of writing this would be:
|
||||
* `git clone https://github.com/albfan/miraclecast.git miraclecast-c3c868e`
|
||||
* `tar -zcf miraclecast-c3c868e.tar.gz miraclecast-c3c868e`
|
||||
|
||||
2. Create a Source RPM
|
||||
* `rpmbuild -bs miraclecast.spec --define "_sourcedir $PWD"`
|
||||
|
||||
Then build the RPM with one of the following:
|
||||
|
||||
* Using mock (assuming you're in the dir where the .src.rpm file is):
|
||||
* `mock --arch=x86_64 -r fedora-28-x86_64 --resultdir=results miraclecast-1.0-1.gitc3c868e.fc28.src.rpm`
|
||||
|
||||
OR
|
||||
|
||||
* Using rpmbuild (assuming you're in the dir where the .src.rpm file is):
|
||||
* `rpmbuild -ra miraclecast-1.0-1.gitc3c868e.fc28.src.rpm`
|
||||
|
||||
OR
|
||||
|
||||
* Using rpmbuild (assuming you're in the dir where the .spec and .tar.gz files are):
|
||||
* `rpmbuild -bs miraclecast.spec --define "_sourcedir $PWD"``
|
|
@ -1,57 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
./kill-wpa.sh
|
||||
DIRNAME=$(dirname $0)
|
||||
|
||||
. miracle-utils.sh
|
||||
. $DIRNAME/miracle-utils.sh
|
||||
|
||||
ETHER_NAMES=$(find_choosable_networknames)
|
||||
|
||||
ETHER_COUNT=$(echo "$ETHER_NAMES" | wc -l)
|
||||
|
||||
if [ 0 = $ETHER_COUNT ]
|
||||
then
|
||||
echo There is no net devices avaliable
|
||||
exit 1
|
||||
elif [ 1 = $ETHER_COUNT ]
|
||||
then
|
||||
ETHERNAME="$ETHER_NAMES"
|
||||
elif [ 2 -le $ETHER_COUNT ]
|
||||
then
|
||||
echo choose device for normal connection:
|
||||
QUIT="exit"
|
||||
select et_name in $ETHER_NAMES $QUIT
|
||||
do
|
||||
case $et_name
|
||||
in
|
||||
"$QUIT")
|
||||
exit
|
||||
;;
|
||||
"")
|
||||
if [ "$REPLY" = $QUIT ]
|
||||
then
|
||||
exit
|
||||
else
|
||||
echo unknow $REPLY
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
ETHERNAME=$et_name
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# default path for config file
|
||||
CONFIG_FILE=${1:-/run/network/wpa_supplicant_${ETHERNAME}.conf}
|
||||
|
||||
|
||||
echo starting wpa_supplicant for normal connection
|
||||
if check_ubuntu_distro
|
||||
then
|
||||
start_ubuntu_network_manager
|
||||
sudo wpa_supplicant -B -u -s -O /var/run/wpa_supplicant
|
||||
else
|
||||
sudo wpa_supplicant -B -u -P /run/wpa_supplicant_${ETHERNAME}pid -i ${ETHERNAME} -D nl80211 -c$CONFIG_FILE
|
||||
fi
|
||||
./$DIRNAME/kill-wpa.sh
|
||||
|
||||
start_network_manager
|
||||
|
|
18
res/sinkctl.protocol-extension.example
Normal file
18
res/sinkctl.protocol-extension.example
Normal file
|
@ -0,0 +1,18 @@
|
|||
#Example of extra parameters to extend sink request
|
||||
|
||||
[sinkctl]
|
||||
extends.wfd_video_formats=40 00 01 10 0001bdeb 051557ff 00000fff 10 0000 001f 11 0780 0438, 02 10 0001bdeb 155557ff 00000fff 10 0000 001f 11 0780 0438
|
||||
extends.wfd_audio_codecs=LPCM 00000003 00, AAC 0000000f 00, AC3 00000007 00
|
||||
extends.wfd_display_edid=0001 00ffffffffffff0051f38f50010000000e100104a51d10ff2f0000a057499b2610484f000000010101010101010101010101010101011a36809c70381f403020350025a510000018000000fc00496e7465726e616c204c43440a000000fd003c3c9a9a0e00000000000000000000000000000000000000000000000000000030
|
||||
extends.wfd_connector_type=05
|
||||
extends.microsoft_cursor=none
|
||||
extends.microsoft_rtcp_capability=none
|
||||
extends.wfd_idr_request_capability=1
|
||||
extends.microsoft_latency_management_capability=none
|
||||
extends.microsoft_format_change_capability=none
|
||||
extends.microsoft_diagnostics_capability=none
|
||||
extends.intel_friendly_name=miraclecast
|
||||
extends.intel_sink_manufacturer_name=GNU Linux
|
||||
extends.intel_sink_model_name=Arch linux
|
||||
extends.intel_sink_device_URL=http://github.com/albfan/miraclecast
|
||||
extends.wfd_uibc_capability=input_category_list=GENERIC, HIDC;generic_cap_list=Keyboard;hidc_cap_list=Keyboard/USB, Mouse/USB, MultiTouch/USB, Gesture/USB, RemoteControl/USB;port=none
|
|
@ -1,18 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
. miracle-utils.sh
|
||||
eval SCRIPT_DEBUG="\$$(basename $0 .sh | tr - _)_DEBUG"
|
||||
SCRIPT_DEBUG=${SCRIPT_DEBUG:--1}
|
||||
|
||||
WIFI_NAMES=$(find_wireless_network_interfaces)
|
||||
WIFI_COUNT=$(echo "$WIFI_NAMES" | wc -l)
|
||||
if [ "$SCRIPT_DEBUG" -ge 1 ]
|
||||
then
|
||||
set -x
|
||||
fi
|
||||
if [ "$SCRIPT_DEBUG" -ge 10 ]
|
||||
then
|
||||
set -v
|
||||
fi
|
||||
|
||||
. ./miracle-utils.sh
|
||||
|
||||
WIFI_COUNT=0
|
||||
WIFI_NAMES="$(find_wireless_network_interfaces)"
|
||||
if [ -n "$WIFI_NAMES" ]
|
||||
then
|
||||
WIFI_COUNT=$(echo "$WIFI_NAMES" | wc -l)
|
||||
fi
|
||||
|
||||
if [ 0 = $WIFI_COUNT ]
|
||||
then
|
||||
echo There is no wireless devices avaliable
|
||||
echo There is no wireless devices available
|
||||
exit 1
|
||||
elif [ 1 = $WIFI_COUNT ]
|
||||
then
|
||||
WIFI_NAME="$WIFI_NAMES"
|
||||
elif [ 2 -ge $WIFI_COUNT ]
|
||||
elif [ 2 -le $WIFI_COUNT ]
|
||||
then
|
||||
echo Choose wireless device:
|
||||
PS3="device: "
|
||||
|
|
|
@ -35,7 +35,7 @@ Try installing packages "gst-plugins-bad, gst-plugins-base, gst-plugins-base-lib
|
|||
|
||||
If that fails too, try:
|
||||
|
||||
$ vlc rtp://@1991
|
||||
$ vlc rtp://@:7236
|
||||
|
||||
EOF
|
||||
else
|
||||
|
|
19
res/uibc-viewer
Executable file
19
res/uibc-viewer
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
function kill_child() {
|
||||
CHILDREN="$(ps -o pid= --ppid $$)"
|
||||
echo killing $CHILDREN
|
||||
kill $CHILDREN
|
||||
}
|
||||
|
||||
IP=$1
|
||||
shift
|
||||
UIBC_PORT=$1
|
||||
shift
|
||||
|
||||
echo $$
|
||||
|
||||
trap 'kill_child' SIGTERM
|
||||
|
||||
gstplayer $@ | miracle-uibcctl $IP $UIBC_PORT --daemon &
|
||||
wait
|
|
@ -8,7 +8,7 @@ ETHER_COUNT=$(echo "$ETHER_NAMES" | wc -l)
|
|||
|
||||
if [ 0 = $ETHER_COUNT ]
|
||||
then
|
||||
echo There is no net devices avaliable
|
||||
echo There is no net devices available
|
||||
exit 1
|
||||
elif [ 1 = $ETHER_COUNT ]
|
||||
then
|
||||
|
|
|
@ -1,37 +1,15 @@
|
|||
set(CMAKE_C_FLAGS "-std=gnu11")
|
||||
set(CMAKE_C_FLAGS "-std=gnu11 ${CMAKE_C_FLAGS}")
|
||||
|
||||
add_subdirectory(shared)
|
||||
add_subdirectory(wifi)
|
||||
add_subdirectory(dhcp)
|
||||
add_subdirectory(ctl)
|
||||
add_subdirectory(uibc)
|
||||
|
||||
set(miracled_SRCS miracled.h miracled.c)
|
||||
add_executable(miracled ${miracled_SRCS})
|
||||
target_link_libraries(miracled miracle-shared)
|
||||
target_link_libraries(miracled m)
|
||||
install(TARGETS miracled DESTINATION bin)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#SUBDIRS = shared wifi dhcp ctl
|
||||
#
|
||||
#bin_PROGRAMS = miracled
|
||||
#
|
||||
#miracled_SOURCES = \
|
||||
# miracled.h \
|
||||
# miracled.c
|
||||
#miracled_CPPFLAGS = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS)
|
||||
#miracled_LDADD = \
|
||||
# shared/libmiracle-shared.la \
|
||||
# $(DEPS_LIBS)
|
||||
#
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
include $(top_srcdir)/common.am
|
||||
SUBDIRS = shared wifi dhcp ctl
|
||||
SUBDIRS = shared wifi dhcp ctl uibc
|
||||
|
||||
bin_PROGRAMS = miracled
|
||||
|
||||
|
|
BIN
src/ctl/.ctl-sink.c.swo
Normal file
BIN
src/ctl/.ctl-sink.c.swo
Normal file
Binary file not shown.
|
@ -1,6 +1,9 @@
|
|||
|
||||
find_package(Readline)
|
||||
########### next target ###############
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
link_directories( ${GLIB2_LIBRARY_DIRS})
|
||||
include_directories( ${GLIB2_INCLUDE_DIRS})
|
||||
find_package(Readline REQUIRED)
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
|
||||
set(miracle-wifictl_SRCS ctl.h
|
||||
ctl-cli.c
|
||||
|
@ -20,17 +23,20 @@ if(READLINE_FOUND)
|
|||
endif(READLINE_FOUND)
|
||||
|
||||
target_link_libraries(miracle-wifictl miracle-shared)
|
||||
########### next target ###############
|
||||
target_link_libraries(miracle-wifictl m)
|
||||
target_link_libraries(miracle-wifictl ${GLIB2_LIBRARIES})
|
||||
|
||||
set(miracle-sinkctl_SRCS ctl.h
|
||||
ctl-cli.c
|
||||
ctl-sink.h
|
||||
ctl-sink.c
|
||||
ctl-wifi.c
|
||||
sinkctl.c
|
||||
wfd.c)
|
||||
|
||||
|
||||
add_executable(miracle-sinkctl ${miracle-sinkctl_SRCS})
|
||||
target_link_libraries(miracle-sinkctl ${GLIB2_LIBRARIES})
|
||||
target_link_libraries(miracle-sinkctl m)
|
||||
|
||||
install(TARGETS miracle-sinkctl DESTINATION bin)
|
||||
|
||||
|
@ -45,42 +51,3 @@ endif(READLINE_FOUND)
|
|||
target_link_libraries(miracle-sinkctl miracle-shared)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#bin_PROGRAMS = miracle-wifictl miracle-sinkctl
|
||||
#
|
||||
#miracle_wifictl_SOURCES = \
|
||||
# ctl.h \
|
||||
# ctl-cli.c \
|
||||
# ctl-wifi.c \
|
||||
# wifictl.c
|
||||
#miracle_wifictl_CPPFLAGS = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS)
|
||||
#miracle_wifictl_LDADD = \
|
||||
# ../shared/libmiracle-shared.la \
|
||||
# -lreadline \
|
||||
# $(DEPS_LIBS)
|
||||
#
|
||||
#miracle_sinkctl_SOURCES = \
|
||||
# ctl.h \
|
||||
# ctl-cli.c \
|
||||
# ctl-sink.c \
|
||||
# ctl-wifi.c \
|
||||
# sinkctl.c
|
||||
#miracle_sinkctl_CPPFLAGS = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS)
|
||||
#miracle_sinkctl_LDADD = \
|
||||
# ../shared/libmiracle-shared.la \
|
||||
# -lreadline \
|
||||
# $(DEPS_LIBS)
|
||||
#
|
||||
#
|
||||
|
|
|
@ -8,7 +8,8 @@ miracle_wifictl_SOURCES = \
|
|||
wifictl.c
|
||||
miracle_wifictl_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS)
|
||||
$(DEPS_CFLAGS) \
|
||||
$(GLIB_CFLAGS)
|
||||
miracle_wifictl_LDADD = \
|
||||
../shared/libmiracle-shared.la \
|
||||
-lreadline \
|
||||
|
@ -17,16 +18,19 @@ miracle_wifictl_LDADD = \
|
|||
miracle_sinkctl_SOURCES = \
|
||||
ctl.h \
|
||||
ctl-cli.c \
|
||||
ctl-sink.h \
|
||||
ctl-sink.c \
|
||||
ctl-wifi.c \
|
||||
wfd.c \
|
||||
sinkctl.c
|
||||
miracle_sinkctl_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS)
|
||||
$(DEPS_CFLAGS) \
|
||||
$(GLIB_CFLAGS)
|
||||
miracle_sinkctl_LDADD = \
|
||||
../shared/libmiracle-shared.la \
|
||||
-lreadline \
|
||||
$(DEPS_LIBS)
|
||||
$(DEPS_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
|
||||
|
||||
|
|
|
@ -27,15 +27,15 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include "ctl.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "shl_log.h"
|
||||
#include <math.h>
|
||||
|
||||
/* *sigh* readline doesn't include all their deps, so put them last */
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
/*
|
||||
* Helpers for interactive commands
|
||||
|
@ -47,14 +47,14 @@ static sd_event_source *cli_sigs[_NSIG];
|
|||
static sd_event_source *cli_stdin;
|
||||
static bool cli_rl;
|
||||
static const struct cli_cmd *cli_cmds;
|
||||
int cli_max_sev = LOG_NOTICE;
|
||||
unsigned int cli_max_sev = LOG_NOTICE;
|
||||
|
||||
static bool is_cli(void)
|
||||
{
|
||||
return cli_rl;
|
||||
}
|
||||
|
||||
void cli_printv(const char *fmt, va_list args)
|
||||
void cli_printv(const char *fmt, bool prefix_time, va_list args)
|
||||
{
|
||||
SHL_PROTECT_ERRNO;
|
||||
_shl_free_ char *line = NULL;
|
||||
|
@ -73,6 +73,10 @@ void cli_printv(const char *fmt, va_list args)
|
|||
rl_redisplay();
|
||||
}
|
||||
|
||||
if (prefix_time) {
|
||||
cli_printf_time_prefix();
|
||||
}
|
||||
|
||||
vprintf(fmt, args);
|
||||
|
||||
if (async) {
|
||||
|
@ -83,24 +87,65 @@ void cli_printv(const char *fmt, va_list args)
|
|||
}
|
||||
}
|
||||
|
||||
void cli_printf_time_prefix(const char *fmt, va_list args)
|
||||
{
|
||||
long long sec, usec;
|
||||
time_t now;
|
||||
struct tm *timeinfo;
|
||||
struct timeval tv;
|
||||
char buffertmp[80];
|
||||
char buffer[120];
|
||||
int millisec;
|
||||
|
||||
|
||||
log__time(&sec, &usec);
|
||||
|
||||
if (log_date_time) {
|
||||
gettimeofday(&tv, NULL);
|
||||
millisec = lrint(tv.tv_usec/1000.0);
|
||||
if (millisec>=1000) {
|
||||
millisec -=1000;
|
||||
tv.tv_sec++;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
timeinfo = localtime(&now);
|
||||
|
||||
strftime(buffertmp, 80, "%x - %X.%03d", timeinfo);
|
||||
sprintf(buffer, "%s.%03d", buffertmp, millisec);
|
||||
}
|
||||
|
||||
if (log_date_time)
|
||||
printf("[%s] ", buffer);
|
||||
else if (log__have_time())
|
||||
printf("[%.4lld.%.6lld] ", sec, usec);
|
||||
}
|
||||
|
||||
void cli_command_printf(const char *fmt, ...)
|
||||
{
|
||||
SHL_PROTECT_ERRNO;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
cli_printv(fmt, false, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void cli_printf(const char *fmt, ...)
|
||||
{
|
||||
SHL_PROTECT_ERRNO;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
cli_printv(fmt, args);
|
||||
cli_printv(fmt, true, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int cli_help(const struct cli_cmd *cmds)
|
||||
int cli_help(const struct cli_cmd *cmds, int whitespace)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!is_cli()) {
|
||||
cli_fn_help();
|
||||
}
|
||||
cli_printf("Available commands:\n");
|
||||
cli_command_printf("Available commands:\n");
|
||||
|
||||
for (i = 0; cmds[i].cmd; ++i) {
|
||||
if (!cmds[i].desc)
|
||||
|
@ -110,11 +155,11 @@ int cli_help(const struct cli_cmd *cmds)
|
|||
if (!is_cli() && cmds[i].cli_cmp == CLI_Y)
|
||||
continue;
|
||||
|
||||
cli_printf(" %s %-*s %s\n",
|
||||
cmds[i].cmd,
|
||||
(int)(40 - strlen(cmds[i].cmd)),
|
||||
cmds[i].args ? : "",
|
||||
cmds[i].desc ? : "");
|
||||
cli_command_printf(" %s %-*s %s\n",
|
||||
cmds[i].cmd,
|
||||
(int)(whitespace - strlen(cmds[i].cmd)),
|
||||
cmds[i].args ? : "",
|
||||
cmds[i].desc ? : "");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -143,21 +188,21 @@ int cli_do(const struct cli_cmd *cmds, char **args, unsigned int n)
|
|||
switch (cmds[i].argc_cmp) {
|
||||
case CLI_EQUAL:
|
||||
if (n != cmds[i].argc) {
|
||||
cli_printf("Invalid number of arguments\n");
|
||||
cli_command_printf("Invalid number of arguments\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
case CLI_MORE:
|
||||
if (n < cmds[i].argc) {
|
||||
cli_printf("too few arguments\n");
|
||||
cli_command_printf("too few arguments\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
case CLI_LESS:
|
||||
if (n > cmds[i].argc) {
|
||||
cli_printf("too many arguments\n");
|
||||
cli_command_printf("too many arguments\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -173,7 +218,7 @@ int cli_do(const struct cli_cmd *cmds, char **args, unsigned int n)
|
|||
}
|
||||
|
||||
if (!strcmp(cmd, "help"))
|
||||
return cli_help(cmds);
|
||||
return cli_help(cmds, 40);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@ -198,12 +243,15 @@ static void cli_handler_fn(char *input)
|
|||
else if (!r)
|
||||
return;
|
||||
|
||||
add_history(original);
|
||||
if (!(strcmp(original, "quit") == 0 || strcmp(original, "exit") == 0)) {
|
||||
add_history(original);
|
||||
write_history(get_history_filename());
|
||||
}
|
||||
r = cli_do(cli_cmds, args, r);
|
||||
if (r != -EAGAIN)
|
||||
return;
|
||||
|
||||
cli_printf("Command not found\n");
|
||||
cli_command_printf("Command not found\n");
|
||||
}
|
||||
|
||||
static int cli_stdin_fn(sd_event_source *source,
|
||||
|
@ -277,6 +325,312 @@ void cli_destroy(void)
|
|||
cli_event = NULL;
|
||||
}
|
||||
|
||||
char *yes_no_options[] = {"yes", "no", NULL};
|
||||
|
||||
char *
|
||||
yes_no_generator (const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
const char *name;
|
||||
|
||||
/* If this is a new word to complete, initialize now. This includes
|
||||
saving the length of TEXT for efficiency, and initializing the index
|
||||
variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
|
||||
/* Return the next name which partially matches from the command list. */
|
||||
while ((name = yes_no_options[list_index]) != NULL)
|
||||
{
|
||||
list_index++;
|
||||
|
||||
if (strncmp (name, text, len) == 0)
|
||||
return (strdup(name));
|
||||
}
|
||||
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
links_peers_generator (const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
size_t peer_cnt = 0;
|
||||
size_t link_cnt = 0;
|
||||
struct shl_dlist *i, *j;
|
||||
struct ctl_link *l;
|
||||
struct ctl_peer *p;
|
||||
|
||||
/* If this is a new word to complete, initialize now. This includes
|
||||
saving the length of TEXT for efficiency, and initializing the index
|
||||
variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
|
||||
shl_dlist_for_each(i, &get_wifi()->links) {
|
||||
l = link_from_dlist(i);
|
||||
|
||||
char *name = l->label;
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (link_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
link_cnt++;
|
||||
}
|
||||
|
||||
name = l->friendly_name;
|
||||
if (!shl_isempty(name))
|
||||
{
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (link_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
link_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peer_cnt = link_cnt;
|
||||
|
||||
shl_dlist_for_each(i, &get_wifi()->links) {
|
||||
l = link_from_dlist(i);
|
||||
|
||||
shl_dlist_for_each(j, &l->peers) {
|
||||
p = peer_from_dlist(j);
|
||||
char *name = p->label;
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (peer_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
peer_cnt++;
|
||||
}
|
||||
name = p->friendly_name;
|
||||
if (!shl_isempty(name))
|
||||
{
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (peer_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
peer_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
peers_generator (const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
size_t peer_cnt = 0;
|
||||
struct shl_dlist *i, *j;
|
||||
struct ctl_link *l;
|
||||
struct ctl_peer *p;
|
||||
|
||||
/* If this is a new word to complete, initialize now. This includes
|
||||
saving the length of TEXT for efficiency, and initializing the index
|
||||
variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
|
||||
shl_dlist_for_each(i, &get_wifi()->links) {
|
||||
l = link_from_dlist(i);
|
||||
|
||||
shl_dlist_for_each(j, &l->peers) {
|
||||
p = peer_from_dlist(j);
|
||||
char *name = p->label;
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (peer_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
peer_cnt++;
|
||||
}
|
||||
name = p->friendly_name;
|
||||
if (!shl_isempty(name))
|
||||
{
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (peer_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
peer_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
links_generator (const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
size_t link_cnt = 0;
|
||||
struct shl_dlist *i;
|
||||
struct ctl_link *l;
|
||||
|
||||
|
||||
/* If this is a new word to complete, initialize now. This includes
|
||||
saving the length of TEXT for efficiency, and initializing the index
|
||||
variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
|
||||
shl_dlist_for_each(i, &get_wifi()->links) {
|
||||
l = link_from_dlist(i);
|
||||
|
||||
|
||||
char *name = l->label;
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (link_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
link_cnt++;
|
||||
}
|
||||
name = l->friendly_name;
|
||||
if (!shl_isempty(name))
|
||||
{
|
||||
if (strncmp (name, text, len) == 0)
|
||||
{
|
||||
if (link_cnt == list_index)
|
||||
{
|
||||
list_index++;
|
||||
return strdup(name);
|
||||
}
|
||||
link_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* Generator function for command completion. STATE lets us know whether
|
||||
* to start from scratch; without any state (i.e. STATE == 0), then we
|
||||
* start at the top of the list.
|
||||
*/
|
||||
|
||||
char *
|
||||
command_generator (const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
const char *name;
|
||||
|
||||
/* If this is a new word to complete, initialize now. This includes
|
||||
saving the length of TEXT for efficiency, and initializing the index
|
||||
variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen (text);
|
||||
}
|
||||
|
||||
/* Return the next name which partially matches from the command list. */
|
||||
while ((name = cli_cmds[list_index].cmd) != NULL)
|
||||
{
|
||||
list_index++;
|
||||
|
||||
if (strncmp (name, text, len) == 0)
|
||||
return (strdup(name));
|
||||
}
|
||||
|
||||
/* If no names matched, then return NULL. */
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
int get_args(char* line)
|
||||
{
|
||||
char* tmp = line;
|
||||
char* last_delim = tmp;
|
||||
int count = 0;
|
||||
|
||||
/* Count how many elements will be extracted. */
|
||||
while (*tmp)
|
||||
{
|
||||
if (' ' == *tmp)
|
||||
{
|
||||
if (last_delim+1 < tmp)
|
||||
count++;
|
||||
last_delim = tmp;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
if (' ' != *last_delim)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to complete on the contents of TEXT. START and END bound the
|
||||
* region of rl_line_buffer that contains the word to complete. TEXT is
|
||||
* the word to complete. We can use the entire contents of rl_line_buffer
|
||||
* in case we want to do some simple parsing. Return the array of matches,
|
||||
* or NULL if there aren't any.
|
||||
*/
|
||||
char **
|
||||
completion_fn (const char *text, int start, int end)
|
||||
{
|
||||
char **matches;
|
||||
|
||||
rl_attempted_completion_over = 1;
|
||||
if (start == 0)
|
||||
matches = rl_completion_matches (text, command_generator);
|
||||
else
|
||||
{
|
||||
matches = (char **)NULL;
|
||||
struct cli_cmd cmd;
|
||||
int cmd_pos = 0;
|
||||
while ((cmd = cli_cmds[cmd_pos++]).cmd)
|
||||
{
|
||||
if (strncmp(cmd.cmd, rl_line_buffer, strlen(cmd.cmd)) == 0)
|
||||
{
|
||||
int nargs = get_args(rl_line_buffer);
|
||||
rl_compentry_func_t* completion_fn = cmd.completion_fns[nargs-2];
|
||||
if (completion_fn)
|
||||
matches = rl_completion_matches (text, completion_fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (matches);
|
||||
}
|
||||
|
||||
int cli_init(sd_bus *bus, const struct cli_cmd *cmds)
|
||||
{
|
||||
static const int sigs[] = {
|
||||
|
@ -320,27 +674,31 @@ int cli_init(sd_bus *bus, const struct cli_cmd *cmds)
|
|||
}
|
||||
}
|
||||
|
||||
r = sd_event_add_io(cli_event,
|
||||
if (isatty(fileno(stdin))) {
|
||||
r = sd_event_add_io(cli_event,
|
||||
&cli_stdin,
|
||||
fileno(stdin),
|
||||
EPOLLHUP | EPOLLERR | EPOLLIN,
|
||||
cli_stdin_fn,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
cli_vERR(r);
|
||||
goto error;
|
||||
if (r < 0) {
|
||||
cli_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
cli_rl = true;
|
||||
|
||||
rl_erase_empty_line = 1;
|
||||
rl_attempted_completion_function = completion_fn;
|
||||
rl_callback_handler_install(get_cli_prompt(), cli_handler_fn);
|
||||
using_history();
|
||||
read_history(get_history_filename());
|
||||
rl_end_of_history(0, 0);
|
||||
|
||||
printf("\r");
|
||||
rl_on_new_line();
|
||||
rl_redisplay();
|
||||
}
|
||||
|
||||
cli_rl = true;
|
||||
|
||||
rl_erase_empty_line = 1;
|
||||
rl_callback_handler_install(NULL, cli_handler_fn);
|
||||
|
||||
rl_set_prompt(CLI_PROMPT);
|
||||
printf("\r");
|
||||
rl_on_new_line();
|
||||
rl_redisplay();
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -17,49 +17,7 @@
|
|||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "ctl.h"
|
||||
#include "rtsp.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "wfd.h"
|
||||
|
||||
struct ctl_sink {
|
||||
sd_event *event;
|
||||
|
||||
char *target;
|
||||
char *session;
|
||||
char *url;
|
||||
struct sockaddr_storage addr;
|
||||
size_t addr_size;
|
||||
int fd;
|
||||
sd_event_source *fd_source;
|
||||
|
||||
struct rtsp *rtsp;
|
||||
|
||||
bool connected : 1;
|
||||
bool hup : 1;
|
||||
|
||||
uint32_t resolutions_cea;
|
||||
uint32_t resolutions_vesa;
|
||||
uint32_t resolutions_hh;
|
||||
|
||||
int hres;
|
||||
int vres;
|
||||
};
|
||||
#include "ctl-sink.h"
|
||||
|
||||
/*
|
||||
* RTSP Session
|
||||
|
@ -119,53 +77,92 @@ static void sink_handle_options(struct ctl_sink *s,
|
|||
}
|
||||
|
||||
static void sink_handle_get_parameter(struct ctl_sink *s,
|
||||
struct rtsp_message *m)
|
||||
struct rtsp_message *m)
|
||||
{
|
||||
_rtsp_message_unref_ struct rtsp_message *rep = NULL;
|
||||
int r;
|
||||
_rtsp_message_unref_ struct rtsp_message *rep = NULL;
|
||||
int r;
|
||||
|
||||
r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
|
||||
/* wfd_content_protection */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_content_protection") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_content_protection: none");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_video_formats */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_video_formats") >= 0) {
|
||||
char wfd_video_formats[128];
|
||||
sprintf(wfd_video_formats,
|
||||
"wfd_video_formats: 00 00 03 10 %08x %08x %08x 00 0000 0000 10 none none",
|
||||
s->resolutions_cea, s->resolutions_vesa, s->resolutions_hh);
|
||||
r = rtsp_message_append(rep, "{&}", wfd_video_formats);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_audio_codecs */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_audio_codecs") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_audio_codecs: AAC 00000007 00");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_client_rtp_ports */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_client_rtp_ports") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_client_rtp_ports: RTP/AVP/UDP;unicast 1991 0 mode=play");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_content_protection */
|
||||
check_and_response_option("wfd_content_protection", "none");
|
||||
GHashTable* protocol_extensions = s->protocol_extensions;
|
||||
/* wfd_video_formats */
|
||||
gchar* wfd_video_formats = NULL;
|
||||
if (protocol_extensions != NULL) {
|
||||
gchar* wfd_video_formats_extension = g_hash_table_lookup(protocol_extensions, WFD_VIDEO_FORMATS);
|
||||
if (wfd_video_formats_extension != NULL) {
|
||||
wfd_video_formats = wfd_video_formats_extension;
|
||||
}
|
||||
}
|
||||
bool create_wfd_video_formats = wfd_video_formats == NULL;
|
||||
if (create_wfd_video_formats) {
|
||||
gchar video_formats[128];
|
||||
sprintf(video_formats, "00 00 03 10 %08x %08x %08x 00 0000 0000 10 none none",
|
||||
s->resolutions_cea, s->resolutions_vesa, s->resolutions_hh);
|
||||
wfd_video_formats = strdup(video_formats);
|
||||
}
|
||||
check_and_response_option(WFD_VIDEO_FORMATS, wfd_video_formats);
|
||||
if (create_wfd_video_formats) {
|
||||
g_free(wfd_video_formats);
|
||||
}
|
||||
|
||||
rtsp_message_seal(rep);
|
||||
cli_debug("OUTGOING: %s\n", rtsp_message_get_raw(rep));
|
||||
/* wfd_audio_codecs */
|
||||
gchar* wfd_audio_codecs = "AAC 00000007 00";
|
||||
if (protocol_extensions != NULL) {
|
||||
gchar* wfd_audio_codecs_extension = g_hash_table_lookup(protocol_extensions, WFD_AUDIO_CODECS);
|
||||
if (wfd_audio_codecs_extension != NULL) {
|
||||
wfd_audio_codecs = wfd_audio_codecs_extension;
|
||||
}
|
||||
}
|
||||
check_and_response_option(WFD_AUDIO_CODECS, wfd_audio_codecs);
|
||||
|
||||
r = rtsp_send(s->rtsp, rep);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
/* wfd_client_rtp_ports */
|
||||
char wfd_client_rtp_ports[128];
|
||||
sprintf(wfd_client_rtp_ports, "RTP/AVP/UDP;unicast %d 0 mode=play", rstp_port);
|
||||
check_and_response_option("wfd_client_rtp_ports", wfd_client_rtp_ports);
|
||||
|
||||
if (protocol_extensions != NULL) {
|
||||
GList* extension_keys = g_hash_table_get_keys(protocol_extensions);
|
||||
for (int i = 0; i<g_list_length(extension_keys); i++) {
|
||||
gchar* key = g_list_nth_data(extension_keys, i);
|
||||
if (g_strcmp0(key, WFD_VIDEO_FORMATS) == 0
|
||||
|| g_strcmp0(key, WFD_AUDIO_CODECS) == 0
|
||||
|| g_strcmp0(key, WFD_UIBC_CAPABILITY) == 0) {
|
||||
continue;
|
||||
}
|
||||
gchar* value = g_hash_table_lookup(protocol_extensions, key);
|
||||
check_and_response_option(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* wfd_uibc_capability */
|
||||
if (uibc_option) {
|
||||
gchar* wfd_uibc_capability = "input_category_list=GENERIC;"
|
||||
"generic_cap_list=Mouse,SingleTouch;"
|
||||
"hidc_cap_list=none;"
|
||||
"port=none";
|
||||
if (protocol_extensions != NULL) {
|
||||
gchar* wfd_uibc_capability_extension = g_hash_table_lookup(protocol_extensions, WFD_UIBC_CAPABILITY);
|
||||
if (wfd_uibc_capability_extension != NULL) {
|
||||
wfd_uibc_capability = wfd_uibc_capability_extension;
|
||||
}
|
||||
}
|
||||
check_and_response_option(WFD_UIBC_CAPABILITY, wfd_uibc_capability);
|
||||
}
|
||||
|
||||
rtsp_message_seal(rep);
|
||||
cli_debug("OUTGOING: %s\n", rtsp_message_get_raw(rep));
|
||||
|
||||
r = rtsp_send(s->rtsp, rep);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
|
||||
bool check_rtsp_option(struct rtsp_message *m, char *option) {
|
||||
return rtsp_message_read(m, "{<>}", option) >= 0;
|
||||
}
|
||||
|
||||
static int sink_setup_fn(struct rtsp *bus, struct rtsp_message *m, void *data)
|
||||
|
@ -227,7 +224,7 @@ static int sink_set_format(struct ctl_sink *s,
|
|||
if (hres && vres) {
|
||||
s->hres = hres;
|
||||
s->vres = vres;
|
||||
ctl_fn_sink_resolution_set(s, hres, vres);
|
||||
ctl_fn_sink_resolution_set(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +238,8 @@ static void sink_handle_set_parameter(struct ctl_sink *s,
|
|||
_rtsp_message_unref_ struct rtsp_message *rep = NULL;
|
||||
const char *trigger;
|
||||
const char *url;
|
||||
char *uibc_config;
|
||||
const char *uibc_setting;
|
||||
char *nu;
|
||||
unsigned int cea_res, vesa_res, hh_res;
|
||||
int r;
|
||||
|
@ -273,6 +272,49 @@ static void sink_handle_set_parameter(struct ctl_sink *s,
|
|||
}
|
||||
}
|
||||
|
||||
/* M4 (or any other) can pass presentation URLs */
|
||||
r = rtsp_message_read(m, "{<&>}", "wfd_uibc_capability", &uibc_config);
|
||||
if (r >= 0) {
|
||||
if (!s->uibc_config || strcmp(s->uibc_config, uibc_config)) {
|
||||
nu = strdup(uibc_config);
|
||||
if (!nu)
|
||||
return cli_vENOMEM();
|
||||
|
||||
free(s->uibc_config);
|
||||
s->uibc_config = nu;
|
||||
|
||||
if (!strcasecmp(uibc_config, "none")) {
|
||||
uibc_enabled = false;
|
||||
} else {
|
||||
char* token = strtok(uibc_config, ";");
|
||||
|
||||
while (token) {
|
||||
if (sscanf(token, "port=%d", &uibc_port)) {
|
||||
log_debug("UIBC port: %d\n", uibc_port);
|
||||
if (uibc_option) {
|
||||
uibc_enabled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
token = strtok(0, ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* M4 (or any other) can pass presentation URLs */
|
||||
r = rtsp_message_read(m, "{<s>}", "wfd_uibc_setting", &uibc_setting);
|
||||
if (r >= 0) {
|
||||
if (!s->uibc_setting || strcmp(s->uibc_setting, uibc_setting)) {
|
||||
nu = strdup(uibc_setting);
|
||||
if (!nu)
|
||||
return cli_vENOMEM();
|
||||
|
||||
free(s->uibc_setting);
|
||||
s->uibc_setting = nu;
|
||||
cli_debug("uibc setting: %s\n", s->uibc_setting);
|
||||
}
|
||||
}
|
||||
/* M4 again */
|
||||
r = rtsp_message_read(m, "{<****hhh>}", "wfd_video_formats",
|
||||
&cea_res, &vesa_res, &hh_res);
|
||||
|
@ -300,9 +342,9 @@ static void sink_handle_set_parameter(struct ctl_sink *s,
|
|||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
|
||||
r = rtsp_message_append(rep, "<s>",
|
||||
"Transport",
|
||||
"RTP/AVP/UDP;unicast;client_port=1991");
|
||||
char rtsp_setup[128];
|
||||
sprintf(rtsp_setup, "RTP/AVP/UDP;unicast;client_port=%d", rstp_port);
|
||||
r = rtsp_message_append(rep, "<s>", "Transport", rtsp_setup);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
|
||||
|
@ -528,6 +570,8 @@ void ctl_sink_free(struct ctl_sink *s)
|
|||
free(s->session);
|
||||
free(s->url);
|
||||
sd_event_unref(s->event);
|
||||
if (s->protocol_extensions)
|
||||
g_hash_table_destroy(s->protocol_extensions);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
|
92
src/ctl/ctl-sink.h
Normal file
92
src/ctl/ctl-sink.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MiracleCast 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CTL_SINK_H
|
||||
#define CTL_SINK_H
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
#include "ctl.h"
|
||||
|
||||
#include "rtsp.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "wfd.h"
|
||||
|
||||
#define WFD_VIDEO_FORMATS "wfd_video_formats"
|
||||
#define WFD_AUDIO_CODECS "wfd_audio_codecs"
|
||||
#define WFD_UIBC_CAPABILITY "wfd_uibc_capability"
|
||||
|
||||
extern int rstp_port;
|
||||
extern bool uibc_option;
|
||||
extern bool uibc_enabled;
|
||||
extern int uibc_port;
|
||||
|
||||
struct ctl_sink {
|
||||
sd_event *event;
|
||||
|
||||
char *target;
|
||||
char *session;
|
||||
char *url;
|
||||
char *uibc_config;
|
||||
char *uibc_setting;
|
||||
struct sockaddr_storage addr;
|
||||
size_t addr_size;
|
||||
int fd;
|
||||
sd_event_source *fd_source;
|
||||
|
||||
struct rtsp *rtsp;
|
||||
|
||||
bool connected : 1;
|
||||
bool hup : 1;
|
||||
|
||||
uint32_t resolutions_cea;
|
||||
uint32_t resolutions_vesa;
|
||||
uint32_t resolutions_hh;
|
||||
|
||||
int hres;
|
||||
int vres;
|
||||
|
||||
GHashTable* protocol_extensions;
|
||||
};
|
||||
|
||||
bool check_rtsp_option(struct rtsp_message *m, char *option);
|
||||
|
||||
#define check_and_response_option(option, response) \
|
||||
if (check_rtsp_option(m, option)) { \
|
||||
char option_response[512]; \
|
||||
sprintf(option_response, "%s: %s", option, response); \
|
||||
r = rtsp_message_append(rep, "{&}", option_response); \
|
||||
if (r < 0) {\
|
||||
return cli_vERR(r); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* CTL_SINK_H */
|
|
@ -414,6 +414,8 @@ static int ctl_link_parse_properties(struct ctl_link *l,
|
|||
bool p2p_scanning_set = false;
|
||||
char *tmp;
|
||||
int p2p_scanning, r;
|
||||
bool managed_set = false;
|
||||
int managed;
|
||||
|
||||
if (!l || !m)
|
||||
return cli_EINVAL();
|
||||
|
@ -444,6 +446,13 @@ static int ctl_link_parse_properties(struct ctl_link *l,
|
|||
&friendly_name);
|
||||
if (r < 0)
|
||||
return cli_log_parser(r);
|
||||
} else if (!strcmp(t, "Managed")) {
|
||||
r = bus_message_read_basic_variant(m, "b",
|
||||
&managed);
|
||||
if (r < 0)
|
||||
return cli_log_parser(r);
|
||||
|
||||
managed_set = true;
|
||||
} else if (!strcmp(t, "P2PScanning")) {
|
||||
r = bus_message_read_basic_variant(m, "b",
|
||||
&p2p_scanning);
|
||||
|
@ -494,6 +503,9 @@ static int ctl_link_parse_properties(struct ctl_link *l,
|
|||
}
|
||||
}
|
||||
|
||||
if (managed_set)
|
||||
l->managed = managed;
|
||||
|
||||
if (p2p_scanning_set)
|
||||
l->p2p_scanning = p2p_scanning;
|
||||
|
||||
|
@ -620,6 +632,63 @@ int ctl_link_set_wfd_subelements(struct ctl_link *l, const char *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ctl_link_set_managed(struct ctl_link *l, bool val)
|
||||
{
|
||||
_sd_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
_sd_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
|
||||
_shl_free_ char *node = NULL;
|
||||
int r;
|
||||
|
||||
if (!l)
|
||||
return cli_EINVAL();
|
||||
if (l->managed == val)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/link",
|
||||
l->label,
|
||||
&node);
|
||||
if (r < 0)
|
||||
return cli_ERR(r);
|
||||
|
||||
r = sd_bus_message_new_method_call(l->w->bus,
|
||||
&m,
|
||||
"org.freedesktop.miracle.wifi",
|
||||
node,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Set");
|
||||
if (r < 0)
|
||||
return cli_log_create(r);
|
||||
|
||||
r = sd_bus_message_append(m, "ss",
|
||||
"org.freedesktop.miracle.wifi.Link",
|
||||
"Managed");
|
||||
if (r < 0)
|
||||
return cli_log_create(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "b");
|
||||
if (r < 0)
|
||||
return cli_log_create(r);
|
||||
|
||||
r = sd_bus_message_append(m, "b", val);
|
||||
if (r < 0)
|
||||
return cli_log_create(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return cli_log_create(r);
|
||||
|
||||
r = sd_bus_call(l->w->bus, m, 0, &err, NULL);
|
||||
if (r < 0) {
|
||||
cli_error("cannot change managed state on link %s to %d: %s",
|
||||
l->label, val, bus_error_message(&err, r));
|
||||
return r;
|
||||
}
|
||||
|
||||
l->managed = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctl_link_set_p2p_scanning(struct ctl_link *l, bool val)
|
||||
{
|
||||
_sd_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
|
@ -754,7 +823,7 @@ static int ctl_wifi_parse_peer(struct ctl_wifi *w,
|
|||
|
||||
l = ctl_wifi_find_link_by_peer(w, label);
|
||||
if (!l)
|
||||
return cli_EINVAL();
|
||||
return 0;
|
||||
|
||||
r = ctl_peer_new(&p, l, label);
|
||||
if (r < 0)
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CTL_CTL_H
|
||||
#define CTL_CTL_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -29,13 +32,22 @@
|
|||
#include "shl_dlist.h"
|
||||
#include "shl_log.h"
|
||||
|
||||
#ifndef CTL_CTL_H
|
||||
#define CTL_CTL_H
|
||||
/* *sigh* readline doesn't include all their deps, so put them last */
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/rltypedefs.h>
|
||||
|
||||
struct ctl_wifi;
|
||||
struct ctl_link;
|
||||
struct ctl_peer;
|
||||
|
||||
char* get_history_filename ();
|
||||
struct ctl_wifi * get_wifi ();
|
||||
char * links_peers_generator (const char *text, int state);
|
||||
char * links_generator (const char *text, int state);
|
||||
char * peers_generator (const char *text, int state);
|
||||
char * yes_no_generator (const char *text, int state);
|
||||
|
||||
/* wifi handling */
|
||||
|
||||
struct ctl_peer {
|
||||
|
@ -71,6 +83,7 @@ struct ctl_link {
|
|||
unsigned int ifindex;
|
||||
char *ifname;
|
||||
char *friendly_name;
|
||||
bool managed;
|
||||
char *wfd_subelements;
|
||||
bool p2p_scanning;
|
||||
};
|
||||
|
@ -78,6 +91,7 @@ struct ctl_link {
|
|||
#define link_from_dlist(_l) shl_dlist_entry((_l), struct ctl_link, list);
|
||||
|
||||
int ctl_link_set_friendly_name(struct ctl_link *l, const char *name);
|
||||
int ctl_link_set_managed(struct ctl_link *l, bool val);
|
||||
int ctl_link_set_wfd_subelements(struct ctl_link *l, const char *val);
|
||||
int ctl_link_set_p2p_scanning(struct ctl_link *l, bool val);
|
||||
|
||||
|
@ -120,9 +134,11 @@ bool ctl_sink_is_closed(struct ctl_sink *s);
|
|||
|
||||
/* CLI handling */
|
||||
|
||||
extern int cli_max_sev;
|
||||
void cli_printv(const char *fmt, va_list args);
|
||||
extern unsigned int cli_max_sev;
|
||||
void cli_printv(const char *fmt, bool prefix_time, va_list args);
|
||||
void cli_printf_time_prefix();
|
||||
void cli_printf(const char *fmt, ...);
|
||||
void cli_command_printf(const char *fmt, ...);
|
||||
|
||||
#define cli_log(_fmt, ...) \
|
||||
cli_printf(_fmt "\n", ##__VA_ARGS__)
|
||||
|
@ -186,7 +202,6 @@ void cli_printf(const char *fmt, ...);
|
|||
#define CLI_BLUE "\x1B[0;94m"
|
||||
#define CLI_BOLDGRAY "\x1B[1;30m"
|
||||
#define CLI_BOLDWHITE "\x1B[1;37m"
|
||||
#define CLI_PROMPT CLI_BLUE "[miraclectl] # " CLI_DEFAULT
|
||||
|
||||
struct cli_cmd {
|
||||
const char *cmd;
|
||||
|
@ -204,6 +219,7 @@ struct cli_cmd {
|
|||
int argc;
|
||||
int (*fn) (char **args, unsigned int n);
|
||||
const char *desc;
|
||||
rl_compentry_func_t *completion_fns[2];
|
||||
};
|
||||
|
||||
extern sd_event *cli_event;
|
||||
|
@ -213,13 +229,14 @@ extern unsigned int wfd_supported_res_cea;
|
|||
extern unsigned int wfd_supported_res_vesa;
|
||||
extern unsigned int wfd_supported_res_hh;
|
||||
|
||||
char* get_cli_prompt();
|
||||
int cli_init(sd_bus *bus, const struct cli_cmd *cmds);
|
||||
void cli_destroy(void);
|
||||
int cli_run(void);
|
||||
void cli_exit(void);
|
||||
bool cli_running(void);
|
||||
|
||||
int cli_help(const struct cli_cmd *cmds);
|
||||
int cli_help(const struct cli_cmd *cmds, int whitespace);
|
||||
int cli_do(const struct cli_cmd *cmds, char **args, unsigned int n);
|
||||
|
||||
/* callback functions */
|
||||
|
@ -240,7 +257,7 @@ void ctl_fn_link_free(struct ctl_link *l);
|
|||
|
||||
void ctl_fn_sink_connected(struct ctl_sink *s);
|
||||
void ctl_fn_sink_disconnected(struct ctl_sink *s);
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s, int hres, int vres);
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s);
|
||||
|
||||
void cli_fn_help(void);
|
||||
|
||||
|
|
24
src/ctl/meson.build
Normal file
24
src/ctl/meson.build
Normal file
|
@ -0,0 +1,24 @@
|
|||
inc = include_directories('../..')
|
||||
deps = [libsystemd, libmiracle_shared_dep, glib2, m]
|
||||
if readline.found()
|
||||
deps += readline
|
||||
endif
|
||||
|
||||
miracle_wifictl_srcs = ['ctl-cli.c', 'ctl-wifi.c', 'wifictl.c']
|
||||
executable('miracle-wifictl', miracle_wifictl_srcs,
|
||||
install: true,
|
||||
include_directories: inc,
|
||||
dependencies: deps
|
||||
)
|
||||
|
||||
miracle_sinkctl_srcs = ['ctl-cli.c',
|
||||
'ctl-sink.c',
|
||||
'ctl-wifi.c',
|
||||
'sinkctl.c',
|
||||
'wfd.c'
|
||||
]
|
||||
executable('miracle-sinkctl', miracle_sinkctl_srcs,
|
||||
install: true,
|
||||
include_directories: inc,
|
||||
dependencies: deps
|
||||
)
|
|
@ -17,6 +17,8 @@
|
|||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
|
@ -30,15 +32,27 @@
|
|||
#include <sys/time.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
#include <systemd/sd-journal.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "ctl.h"
|
||||
#include "ctl-sink.h"
|
||||
#include "wfd.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <readline/readline.h>
|
||||
|
||||
#define HISTORY_FILENAME ".miracle-sink.history"
|
||||
|
||||
#define CLI_PROMPT "\001" CLI_BLUE "\002" "[sinkctl] # " "\001" CLI_DEFAULT "\002"
|
||||
|
||||
static sd_bus *bus;
|
||||
static struct ctl_wifi *wifi;
|
||||
static struct ctl_sink *sink;
|
||||
|
@ -53,11 +67,41 @@ static struct ctl_link *running_link;
|
|||
static struct ctl_peer *running_peer;
|
||||
static struct ctl_peer *pending_peer;
|
||||
|
||||
void launch_player(struct ctl_sink *s);
|
||||
|
||||
char *gst_scale_res;
|
||||
int gst_audio_en = 1;
|
||||
unsigned int wfd_supported_res_cea = 0x0000001f; /* up to 720x576 */
|
||||
unsigned int wfd_supported_res_vesa = 0x00000003; /* up to 800x600 */
|
||||
unsigned int wfd_supported_res_hh = 0x00000000; /* not supported */
|
||||
static const int DEFAULT_RSTP_PORT = 7236;
|
||||
bool uibc_option;
|
||||
bool uibc_enabled;
|
||||
bool external_player;
|
||||
int rstp_port;
|
||||
int uibc_port;
|
||||
char* player;
|
||||
GHashTable* protocol_extensions;
|
||||
|
||||
unsigned int wfd_supported_res_cea = 0x0001ffff;
|
||||
unsigned int wfd_supported_res_vesa = 0x1fffffff;
|
||||
unsigned int wfd_supported_res_hh = 0x00001fff;
|
||||
|
||||
struct ctl_wifi *get_wifi()
|
||||
{
|
||||
return wifi;
|
||||
}
|
||||
|
||||
char* get_cli_prompt()
|
||||
{
|
||||
return CLI_PROMPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* get history filename
|
||||
*/
|
||||
|
||||
char* get_history_filename()
|
||||
{
|
||||
return HISTORY_FILENAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd list
|
||||
|
@ -72,27 +116,28 @@ static int cmd_list(char **args, unsigned int n)
|
|||
|
||||
/* list links */
|
||||
|
||||
cli_printf("%6s %-24s %-30s\n",
|
||||
"LINK", "INTERFACE", "FRIENDLY-NAME");
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
"LINK", "INTERFACE", "FRIENDLY-NAME", "MANAGED");
|
||||
|
||||
shl_dlist_for_each(i, &wifi->links) {
|
||||
l = link_from_dlist(i);
|
||||
++link_cnt;
|
||||
|
||||
cli_printf("%6s %-24s %-30s\n",
|
||||
l->label,
|
||||
shl_isempty(l->ifname) ?
|
||||
"<unknown>" : l->ifname,
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
l->label,
|
||||
shl_isempty(l->ifname) ?
|
||||
"<unknown>" : l->ifname,
|
||||
shl_isempty(l->friendly_name) ?
|
||||
"<unknown>" : l->friendly_name);
|
||||
"<unknown>" : l->friendly_name,
|
||||
l->managed ? "yes": "no");
|
||||
}
|
||||
|
||||
cli_printf("\n");
|
||||
cli_command_printf("\n");
|
||||
|
||||
/* list peers */
|
||||
|
||||
cli_printf("%6s %-24s %-30s %-10s\n",
|
||||
"LINK", "PEER-ID", "FRIENDLY-NAME", "CONNECTED");
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
"LINK", "PEER-ID", "FRIENDLY-NAME", "CONNECTED");
|
||||
|
||||
shl_dlist_for_each(i, &wifi->links) {
|
||||
l = link_from_dlist(i);
|
||||
|
@ -101,16 +146,16 @@ static int cmd_list(char **args, unsigned int n)
|
|||
p = peer_from_dlist(j);
|
||||
++peer_cnt;
|
||||
|
||||
cli_printf("%6s %-24s %-30s %-10s\n",
|
||||
p->l->label,
|
||||
p->label,
|
||||
shl_isempty(p->friendly_name) ?
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
p->l->label,
|
||||
p->label,
|
||||
shl_isempty(p->friendly_name) ?
|
||||
"<unknown>" : p->friendly_name,
|
||||
p->connected ? "yes" : "no");
|
||||
}
|
||||
}
|
||||
|
||||
cli_printf("\n %u peers and %u links listed.\n", peer_cnt, link_cnt);
|
||||
cli_command_printf("\n %u peers and %u links listed.\n", peer_cnt, link_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -129,45 +174,81 @@ static int cmd_show(char **args, unsigned int n)
|
|||
!(p = ctl_wifi_find_peer(wifi, args[0])) &&
|
||||
!(l = ctl_wifi_search_link(wifi, args[0])) &&
|
||||
!(p = ctl_wifi_search_peer(wifi, args[0]))) {
|
||||
cli_error("unknown link or peer %s", args[0]);
|
||||
cli_error("unknown %s", args[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (l) {
|
||||
cli_printf("Link=%s\n", l->label);
|
||||
cli_command_printf("Link=%s\n", l->label);
|
||||
if (l->ifindex > 0)
|
||||
cli_printf("InterfaceIndex=%u\n", l->ifindex);
|
||||
cli_command_printf("InterfaceIndex=%u\n", l->ifindex);
|
||||
if (l->ifname && *l->ifname)
|
||||
cli_printf("InterfaceName=%s\n", l->ifname);
|
||||
cli_command_printf("InterfaceName=%s\n", l->ifname);
|
||||
if (l->friendly_name && *l->friendly_name)
|
||||
cli_printf("FriendlyName=%s\n", l->friendly_name);
|
||||
cli_printf("P2PScanning=%d\n", l->p2p_scanning);
|
||||
cli_command_printf("FriendlyName=%s\n", l->friendly_name);
|
||||
cli_command_printf("P2PScanning=%d\n", l->p2p_scanning);
|
||||
if (l->wfd_subelements && *l->wfd_subelements)
|
||||
cli_printf("WfdSubelements=%s\n", l->wfd_subelements);
|
||||
cli_command_printf("WfdSubelements=%s\n", l->wfd_subelements);
|
||||
cli_command_printf("Managed=%d\n", l->managed);
|
||||
} else if (p) {
|
||||
cli_printf("Peer=%s\n", p->label);
|
||||
cli_command_printf("Peer=%s\n", p->label);
|
||||
if (p->p2p_mac && *p->p2p_mac)
|
||||
cli_printf("P2PMac=%s\n", p->p2p_mac);
|
||||
cli_command_printf("P2PMac=%s\n", p->p2p_mac);
|
||||
if (p->friendly_name && *p->friendly_name)
|
||||
cli_printf("FriendlyName=%s\n", p->friendly_name);
|
||||
cli_printf("Connected=%d\n", p->connected);
|
||||
cli_command_printf("FriendlyName=%s\n", p->friendly_name);
|
||||
cli_command_printf("Connected=%d\n", p->connected);
|
||||
if (p->interface && *p->interface)
|
||||
cli_printf("Interface=%s\n", p->interface);
|
||||
cli_command_printf("Interface=%s\n", p->interface);
|
||||
if (p->local_address && *p->local_address)
|
||||
cli_printf("LocalAddress=%s\n", p->local_address);
|
||||
cli_command_printf("LocalAddress=%s\n", p->local_address);
|
||||
if (p->remote_address && *p->remote_address)
|
||||
cli_printf("RemoteAddress=%s\n", p->remote_address);
|
||||
cli_command_printf("RemoteAddress=%s\n", p->remote_address);
|
||||
if (p->wfd_subelements && *p->wfd_subelements)
|
||||
cli_printf("WfdSubelements=%s\n", p->wfd_subelements);
|
||||
cli_command_printf("WfdSubelements=%s\n", p->wfd_subelements);
|
||||
} else {
|
||||
cli_printf("Show what?\n");
|
||||
cli_command_printf("Show what?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: set-friendly-name
|
||||
*/
|
||||
|
||||
static int cmd_set_friendly_name(char **args, unsigned int n)
|
||||
{
|
||||
struct ctl_link *l = NULL;
|
||||
const char *name;
|
||||
|
||||
if (n < 1) {
|
||||
cli_command_printf("To what?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
l = ctl_wifi_search_link(wifi, args[0]);
|
||||
if (!l) {
|
||||
cli_error("unknown link %s", args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = args[1];
|
||||
} else {
|
||||
name = args[0];
|
||||
}
|
||||
|
||||
l = l ? : running_link;
|
||||
if (!l) {
|
||||
cli_error("no running link");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctl_link_set_friendly_name(l, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: run
|
||||
*/
|
||||
|
@ -198,6 +279,11 @@ static int cmd_run(char **args, unsigned int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!l->managed) {
|
||||
cli_printf("link %s not managed\n", l->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
run_on(l);
|
||||
|
||||
return 0;
|
||||
|
@ -228,11 +314,37 @@ static int cmd_bind(char **args, unsigned int n)
|
|||
if (!l)
|
||||
return 0;
|
||||
|
||||
if (!l->managed) {
|
||||
cli_printf("link %s not managed\n", l->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
run_on(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: set-managed
|
||||
*/
|
||||
|
||||
static int cmd_set_managed(char **args, unsigned int n)
|
||||
{
|
||||
struct ctl_link *l = NULL;
|
||||
bool managed = true;
|
||||
|
||||
l = ctl_wifi_search_link(wifi, args[0]);
|
||||
if (!l) {
|
||||
cli_error("unknown link %s", args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(args[1], "no")) {
|
||||
managed = false;
|
||||
}
|
||||
return ctl_link_set_managed(l, managed);
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: quit/exit
|
||||
*/
|
||||
|
@ -325,22 +437,22 @@ static int sink_timeout_fn(sd_event_source *s, uint64_t usec, void *data)
|
|||
}
|
||||
|
||||
static const struct cli_cmd cli_cmds[] = {
|
||||
{ "list", NULL, CLI_M, CLI_LESS, 0, cmd_list, "List all objects" },
|
||||
{ "show", "<link|peer>", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information" },
|
||||
{ "run", "<link>", CLI_M, CLI_EQUAL, 1, cmd_run, "Run sink on given link" },
|
||||
{ "bind", "<link>", CLI_M, CLI_EQUAL, 1, cmd_bind, "Like 'run' but bind the link name to run when it is hotplugged" },
|
||||
{ "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program" },
|
||||
{ "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL },
|
||||
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" },
|
||||
{ "list", NULL, CLI_M, CLI_LESS, 0, cmd_list, "List all objects", {NULL} },
|
||||
{ "show", "<link|peer>", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information", {links_peers_generator, NULL} },
|
||||
{ "run", "<link>", CLI_M, CLI_EQUAL, 1, cmd_run, "Run sink on given link", {links_generator, NULL} },
|
||||
{ "bind", "<link>", CLI_M, CLI_EQUAL, 1, cmd_bind, "Like 'run' but bind the link name to run when it is hotplugged", {links_generator, NULL} },
|
||||
{ "set-friendly-name", "[link] <name>", CLI_M, CLI_LESS, 2, cmd_set_friendly_name, "Set friendly name of an object", {links_generator, NULL} },
|
||||
{ "set-managed", "<link> <yes|no>", CLI_M, CLI_EQUAL, 2, cmd_set_managed, "Manage or unmnage a link", {links_generator, yes_no_generator} },
|
||||
{ "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program", {NULL} },
|
||||
{ "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL, {NULL} },
|
||||
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help", {NULL} },
|
||||
{ },
|
||||
};
|
||||
|
||||
static void spawn_gst(int hres, int vres)
|
||||
static void spawn_gst(struct ctl_sink *s)
|
||||
{
|
||||
char *argv[64];
|
||||
char resolution[64];
|
||||
pid_t pid;
|
||||
int fd_journal, i;
|
||||
int fd_journal;
|
||||
sigset_t mask;
|
||||
|
||||
if (sink_pid > 0)
|
||||
|
@ -355,43 +467,113 @@ static void spawn_gst(int hres, int vres)
|
|||
sigemptyset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
/* redirect stdout/stderr to journal */
|
||||
fd_journal = sd_journal_stream_fd("miracle-sinkctl-gst",
|
||||
LOG_INFO,
|
||||
LOG_DEBUG,
|
||||
false);
|
||||
if (fd_journal >= 0) {
|
||||
/* dup journal-fd to stdout and stderr */
|
||||
dup2(fd_journal, 1);
|
||||
dup2(fd_journal, 2);
|
||||
} else {
|
||||
#endif
|
||||
/* no journal? redirect stdout to parent's stderr */
|
||||
dup2(2, 1);
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
}
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
argv[i++] = (char*) BUILD_BINDIR "/miracle-gst.sh";
|
||||
if (cli_max_sev >= 7)
|
||||
argv[i++] = "-d 3";
|
||||
if (gst_audio_en)
|
||||
argv[i++] = "-a";
|
||||
if (gst_scale_res) {
|
||||
argv[i++] = "-s";
|
||||
argv[i++] = gst_scale_res;
|
||||
}
|
||||
if (hres && vres) {
|
||||
sprintf(resolution, "%dx%d", hres, vres);
|
||||
argv[i++] = "-r";
|
||||
argv[i++] = resolution;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
execve(argv[0], argv, environ);
|
||||
launch_player(s);
|
||||
_exit(1);
|
||||
} else {
|
||||
sink_pid = pid;
|
||||
}
|
||||
}
|
||||
|
||||
void launch_player(struct ctl_sink *s) {
|
||||
char *argv[64];
|
||||
char resolution[64];
|
||||
char port[64];
|
||||
char uibc_portStr[64];
|
||||
int i = 0;
|
||||
if (!external_player) {
|
||||
if (uibc_enabled) {
|
||||
player = "uibc-viewer";
|
||||
} else {
|
||||
player = "miracle-gst";
|
||||
}
|
||||
}
|
||||
|
||||
argv[i++] = player;
|
||||
if (uibc_enabled) {
|
||||
argv[i++] = s->target;
|
||||
sprintf(uibc_portStr, "%d", uibc_port);
|
||||
argv[i++] = uibc_portStr;
|
||||
}
|
||||
if (gst_debug) {
|
||||
argv[i++] = "-d";
|
||||
argv[i++] = gst_debug;
|
||||
} else if (cli_max_sev >= LOG_DEBUG) {
|
||||
argv[i++] = "-d";
|
||||
argv[i++] = "3";
|
||||
}
|
||||
if (gst_audio_en)
|
||||
argv[i++] = "-a";
|
||||
if (gst_scale_res) {
|
||||
argv[i++] = "-s";
|
||||
argv[i++] = gst_scale_res;
|
||||
}
|
||||
argv[i++] = "-p";
|
||||
sprintf(port, "%d", rstp_port);
|
||||
argv[i++] = port;
|
||||
|
||||
if (s->hres && s->vres) {
|
||||
sprintf(resolution, "%dx%d", s->hres, s->vres);
|
||||
argv[i++] = "-r";
|
||||
argv[i++] = resolution;
|
||||
}
|
||||
|
||||
argv[i] = NULL;
|
||||
|
||||
i = 0;
|
||||
size_t size = 0;
|
||||
while (argv[i]) {
|
||||
size += strlen(argv[i++]) + 1;
|
||||
}
|
||||
|
||||
char* player_command = malloc(size);
|
||||
i = 0;
|
||||
strcpy(player_command, argv[i++]);
|
||||
while (argv[i]) {
|
||||
strcat(player_command, " ");
|
||||
strcat(player_command, argv[i++]);
|
||||
}
|
||||
log_debug("player command: %s", player_command);
|
||||
if (execvpe(argv[0], argv, environ) < 0) {
|
||||
cli_debug("stream player failed (%d): %m", errno);
|
||||
int i = 0;
|
||||
cli_debug("printing environment: ");
|
||||
while (environ[i]) {
|
||||
cli_debug("%s", environ[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void launch_uibc_daemon(int port) {
|
||||
char *argv[64];
|
||||
char portStr[64];
|
||||
int i = 0;
|
||||
argv[i++] = "miracle-uibcctl";
|
||||
argv[i++] = "localhost";
|
||||
sprintf(portStr, "%d", port);
|
||||
argv[i++] = portStr;
|
||||
argv[i] = NULL;
|
||||
|
||||
cli_debug("uibc daemon: %s", argv[0]);
|
||||
execvpe(argv[0], argv, environ);
|
||||
}
|
||||
|
||||
static void kill_gst(void)
|
||||
{
|
||||
if (sink_pid <= 0)
|
||||
|
@ -418,11 +600,11 @@ void ctl_fn_sink_disconnected(struct ctl_sink *s)
|
|||
}
|
||||
}
|
||||
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s, int hres, int vres)
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s)
|
||||
{
|
||||
cli_printf("SINK set resolution %dx%d\n", hres, vres);
|
||||
cli_printf("SINK set resolution %dx%d\n", s->hres, s->vres);
|
||||
if (sink_connected)
|
||||
spawn_gst(hres, vres);
|
||||
spawn_gst(s);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_new(struct ctl_peer *p)
|
||||
|
@ -601,20 +783,29 @@ void cli_fn_help()
|
|||
*/
|
||||
printf("%s [OPTIONS...] ...\n\n"
|
||||
"Control a dedicated local sink via MiracleCast.\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --audio <0/1> Enable audio support (default %d)\n"
|
||||
" --scale WxH Scale to resolution\n"
|
||||
" --res <n,n,n> Supported resolutions masks (CEA, VESA, HH)\n"
|
||||
" default CEA %08X\n"
|
||||
" default VESA %08X\n"
|
||||
" default HH %08X\n"
|
||||
" -h --help Show this help\n"
|
||||
" --help-commands Show available commands\n"
|
||||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
" --log-date-time Prefix log-messages with date time\n"
|
||||
"\n"
|
||||
, program_invocation_short_name, gst_audio_en,
|
||||
" --log-journal-level <lvl> Maximum level for journal log messages\n"
|
||||
" --gst-debug [cat:]lvl[,...] List of categories an level of debug\n"
|
||||
" --audio <0/1> Enable audio support (default %d)\n"
|
||||
" --scale WxH Scale to resolution\n"
|
||||
" -p --port <port> Port for rtsp (default %d)\n"
|
||||
" --uibc Enables UIBC\n"
|
||||
" -e --external-player Configure player to use\n"
|
||||
" --res <n,n,n> Supported resolutions masks (CEA, VESA, HH)\n"
|
||||
" default CEA %08X\n"
|
||||
" default VESA %08X\n"
|
||||
" default HH %08X\n"
|
||||
" --help-res Shows available values for res\n"
|
||||
"\n"
|
||||
, program_invocation_short_name, gst_audio_en, DEFAULT_RSTP_PORT,
|
||||
wfd_supported_res_cea, wfd_supported_res_vesa, wfd_supported_res_hh
|
||||
);
|
||||
wfd_print_resolutions();
|
||||
/*
|
||||
* 80-char barrier:
|
||||
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||
|
@ -632,6 +823,7 @@ static int ctl_interactive(char **argv, int argc)
|
|||
r = ctl_sink_new(&sink, cli_event);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
sink->protocol_extensions = protocol_extensions;
|
||||
|
||||
r = ctl_wifi_fetch(wifi);
|
||||
if (r < 0)
|
||||
|
@ -657,12 +849,19 @@ static int ctl_main(int argc, char *argv[])
|
|||
struct ctl_link *l;
|
||||
int r, left;
|
||||
|
||||
if (getuid() != 0) {
|
||||
r = EACCES;
|
||||
log_notice("Must run as root");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = ctl_wifi_new(&wifi, bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
left = argc - optind;
|
||||
r = ctl_interactive(argv + optind, left <= 0 ? 0 : left);
|
||||
left = argc - optind;
|
||||
left = left <= 0 ? 0 : left;
|
||||
r = ctl_interactive(argv + optind, left);
|
||||
|
||||
/* stop all scans */
|
||||
shl_dlist_for_each(i, &wifi->links) {
|
||||
|
@ -680,31 +879,70 @@ static int parse_argv(int argc, char *argv[])
|
|||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
ARG_LOG_DATE_TIME,
|
||||
ARG_JOURNAL_LEVEL,
|
||||
ARG_GST_DEBUG,
|
||||
ARG_AUDIO,
|
||||
ARG_SCALE,
|
||||
ARG_RES,
|
||||
ARG_HELP_RES,
|
||||
ARG_UIBC,
|
||||
ARG_HELP_COMMANDS,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "help-commands", no_argument, NULL, ARG_HELP_COMMANDS },
|
||||
{ "version" , no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "log-date-time", no_argument, NULL, ARG_LOG_DATE_TIME },
|
||||
{ "log-journal-level", required_argument, NULL, ARG_JOURNAL_LEVEL },
|
||||
{ "gst-debug", required_argument, NULL, ARG_GST_DEBUG },
|
||||
{ "audio", required_argument, NULL, ARG_AUDIO },
|
||||
{ "scale", required_argument, NULL, ARG_SCALE },
|
||||
{ "res", required_argument, NULL, ARG_RES },
|
||||
{ "help-res", no_argument, NULL, ARG_HELP_RES },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "uibc", no_argument, NULL, ARG_UIBC },
|
||||
{ "external-player", required_argument, NULL, 'e' },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||
uibc_option = false;
|
||||
uibc_enabled = false;
|
||||
external_player = false;
|
||||
rstp_port = DEFAULT_RSTP_PORT;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "he:p:", options, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
return cli_help(cli_cmds);
|
||||
cli_fn_help();
|
||||
return 0;
|
||||
case ARG_HELP_COMMANDS:
|
||||
return cli_help(cli_cmds, 20);
|
||||
case ARG_HELP_RES:
|
||||
wfd_print_resolutions("");
|
||||
return 0;
|
||||
case ARG_VERSION:
|
||||
puts(PACKAGE_STRING);
|
||||
return 0;
|
||||
case ARG_LOG_LEVEL:
|
||||
cli_max_sev = log_parse_arg(optarg);
|
||||
break;
|
||||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
case ARG_LOG_DATE_TIME:
|
||||
log_date_time = true;
|
||||
break;
|
||||
case ARG_GST_DEBUG:
|
||||
gst_debug = optarg;
|
||||
break;
|
||||
case ARG_JOURNAL_LEVEL:
|
||||
log_max_sev = log_parse_arg(optarg);
|
||||
break;
|
||||
case ARG_AUDIO:
|
||||
gst_audio_en = atoi(optarg);
|
||||
break;
|
||||
|
@ -717,6 +955,16 @@ static int parse_argv(int argc, char *argv[])
|
|||
&wfd_supported_res_vesa,
|
||||
&wfd_supported_res_hh);
|
||||
break;
|
||||
case 'p':
|
||||
rstp_port = atoi(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
external_player = true;
|
||||
player = optarg;
|
||||
break;
|
||||
case ARG_UIBC:
|
||||
uibc_option = true;
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -728,9 +976,75 @@ static int parse_argv(int argc, char *argv[])
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
bool free_argv = false;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
GKeyFile* gkf = load_ini_file();
|
||||
|
||||
gchar** autocmds_free = NULL;
|
||||
if (gkf) {
|
||||
player = g_key_file_get_string (gkf, "sinkctl", "external-player", NULL);
|
||||
if (player) {
|
||||
external_player = true;
|
||||
}
|
||||
gchar* log_level;
|
||||
log_level = g_key_file_get_string (gkf, "sinkctl", "log-journal-level", NULL);
|
||||
if (log_level) {
|
||||
log_max_sev = log_parse_arg(log_level);
|
||||
g_free(log_level);
|
||||
}
|
||||
log_level = g_key_file_get_string (gkf, "sinkctl", "log-level", NULL);
|
||||
if (log_level) {
|
||||
cli_max_sev = log_parse_arg(log_level);
|
||||
g_free(log_level);
|
||||
}
|
||||
gchar* rstp_port_str = g_key_file_get_string (gkf, "sinkctl", "rstp-port", NULL);
|
||||
if (rstp_port_str) {
|
||||
rstp_port = atoi(rstp_port_str);
|
||||
g_free(rstp_port_str);
|
||||
}
|
||||
gchar* autocmd;
|
||||
autocmd = g_key_file_get_string (gkf, "sinkctl", "autocmd", NULL);
|
||||
if (autocmd) {
|
||||
gchar** autocmds = g_strsplit(autocmd, " ", -1);
|
||||
autocmds_free = autocmds;
|
||||
while (*autocmds) {
|
||||
if (strcmp(*autocmds, "") != 0) {
|
||||
gchar **newv = malloc((argc + 2) * sizeof(gchar*));
|
||||
memmove(newv, argv, sizeof(gchar*) * argc);
|
||||
newv[argc] = *autocmds;
|
||||
newv[argc+1] = NULL;
|
||||
argc++;
|
||||
if (free_argv) {
|
||||
free(argv);
|
||||
}
|
||||
argv = newv;
|
||||
free_argv = true;
|
||||
}
|
||||
autocmds++;
|
||||
}
|
||||
g_free(autocmd);
|
||||
}
|
||||
gchar** sinkctl_keys;
|
||||
gsize len = 0;
|
||||
protocol_extensions = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
sinkctl_keys = g_key_file_get_keys (gkf,
|
||||
"sinkctl",
|
||||
&len,
|
||||
NULL);
|
||||
for (int i = 0; i < (int)len; i++) {
|
||||
if (g_str_has_prefix(sinkctl_keys[i], "extends.")) {
|
||||
gchar* orig_key = sinkctl_keys[i];
|
||||
gchar* key = orig_key+8;
|
||||
gchar* value = g_key_file_get_string (gkf, "sinkctl", orig_key, NULL);
|
||||
g_hash_table_insert(protocol_extensions, key, value);
|
||||
}
|
||||
}
|
||||
g_key_file_free(gkf);
|
||||
}
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
@ -744,6 +1058,10 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
r = ctl_main(argc, argv);
|
||||
g_strfreev(autocmds_free);
|
||||
if (free_argv) {
|
||||
free(argv);
|
||||
}
|
||||
sd_bus_unref(bus);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
|
|
@ -103,27 +103,27 @@ struct resolution_bitmap resolutions_hh[] = {
|
|||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
void wfd_print_resolutions(void)
|
||||
void wfd_print_resolutions(char * prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("CEA resolutions:\n");
|
||||
printf("%sCEA resolutions:\n", prefix);
|
||||
for (i = 0; resolutions_cea[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
printf("%s\t%2d %08x %4dx%4d@%d\n", prefix,
|
||||
resolutions_cea[i].index, 1 << resolutions_cea[i].index,
|
||||
resolutions_cea[i].hres, resolutions_cea[i].vres,
|
||||
resolutions_cea[i].fps);
|
||||
}
|
||||
printf("VESA resolutions:\n");
|
||||
printf("%sVESA resolutions:\n", prefix);
|
||||
for (i = 0; resolutions_vesa[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
printf("%s\t%2d %08x %4dx%4d@%d\n", prefix,
|
||||
resolutions_vesa[i].index, 1 << resolutions_vesa[i].index,
|
||||
resolutions_vesa[i].hres, resolutions_vesa[i].vres,
|
||||
resolutions_vesa[i].fps);
|
||||
}
|
||||
printf("HH resolutions:\n");
|
||||
printf("%sHH resolutions:\n", prefix);
|
||||
for (i = 0; resolutions_hh[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
printf("%s\t%2d %08x %4dx%4d@%d\n", prefix,
|
||||
resolutions_hh[i].index, 1 << resolutions_hh[i].index,
|
||||
resolutions_hh[i].hres, resolutions_hh[i].vres,
|
||||
resolutions_hh[i].fps);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#ifndef WFD_H
|
||||
#define WFD_H
|
||||
|
||||
void wfd_print_resolutions(void);
|
||||
void wfd_print_resolutions(char * prefix);
|
||||
int vfd_get_cea_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int vfd_get_vesa_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int vfd_get_hh_resolution(uint32_t mask, int *hres, int *vres);
|
||||
|
|
|
@ -31,13 +31,39 @@
|
|||
#include "ctl.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <readline/readline.h>
|
||||
|
||||
#define HISTORY_FILENAME ".miracle-wifi.history"
|
||||
|
||||
#define CLI_PROMPT "\001" CLI_BLUE "\002" "[wifictl] # " "\001" CLI_DEFAULT "\002"
|
||||
|
||||
static sd_bus *bus;
|
||||
static struct ctl_wifi *wifi;
|
||||
|
||||
static struct ctl_link *selected_link;
|
||||
|
||||
char* get_cli_prompt()
|
||||
{
|
||||
return CLI_PROMPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* get history filename
|
||||
*/
|
||||
|
||||
char* get_history_filename()
|
||||
{
|
||||
return HISTORY_FILENAME;
|
||||
}
|
||||
|
||||
struct ctl_wifi *get_wifi()
|
||||
{
|
||||
return wifi;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd list
|
||||
*/
|
||||
|
@ -51,26 +77,27 @@ static int cmd_list(char **args, unsigned int n)
|
|||
|
||||
/* list links */
|
||||
|
||||
cli_printf("%6s %-24s %-30s\n",
|
||||
"LINK", "INTERFACE", "FRIENDLY-NAME");
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
"LINK", "INTERFACE", "FRIENDLY-NAME", "MANAGED");
|
||||
|
||||
shl_dlist_for_each(i, &wifi->links) {
|
||||
l = link_from_dlist(i);
|
||||
++link_cnt;
|
||||
|
||||
cli_printf("%6s %-24s %-30s\n",
|
||||
l->label,
|
||||
shl_isempty(l->ifname) ?
|
||||
"<unknown>" : l->ifname,
|
||||
shl_isempty(l->friendly_name) ?
|
||||
"<unknown>" : l->friendly_name);
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
l->label,
|
||||
shl_isempty(l->ifname) ?
|
||||
"<unknown>" : l->ifname,
|
||||
shl_isempty(l->friendly_name) ?
|
||||
"<unknown>" : l->friendly_name,
|
||||
l->managed ? "yes": "no");
|
||||
}
|
||||
|
||||
cli_printf("\n");
|
||||
cli_command_printf("\n");
|
||||
|
||||
/* list peers */
|
||||
|
||||
cli_printf("%6s %-24s %-30s %-10s\n",
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
"LINK", "PEER-ID", "FRIENDLY-NAME", "CONNECTED");
|
||||
|
||||
shl_dlist_for_each(i, &wifi->links) {
|
||||
|
@ -80,16 +107,16 @@ static int cmd_list(char **args, unsigned int n)
|
|||
p = peer_from_dlist(j);
|
||||
++peer_cnt;
|
||||
|
||||
cli_printf("%6s %-24s %-30s %-10s\n",
|
||||
p->l->label,
|
||||
p->label,
|
||||
shl_isempty(p->friendly_name) ?
|
||||
"<unknown>" : p->friendly_name,
|
||||
p->connected ? "yes" : "no");
|
||||
cli_command_printf("%6s %-24s %-30s %-10s\n",
|
||||
p->l->label,
|
||||
p->label,
|
||||
shl_isempty(p->friendly_name) ?
|
||||
"<unknown>" : p->friendly_name,
|
||||
p->connected ? "yes" : "no");
|
||||
}
|
||||
}
|
||||
|
||||
cli_printf("\n %u peers and %u links listed.\n", peer_cnt, link_cnt);
|
||||
cli_command_printf("\n %u peers and %u links listed.\n", peer_cnt, link_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -119,6 +146,7 @@ static int cmd_select(char **args, unsigned int n)
|
|||
}
|
||||
|
||||
selected_link = l;
|
||||
ctl_link_set_wfd_subelements(l, "000600111c4400c8");
|
||||
cli_printf("link %s selected\n", selected_link->label);
|
||||
|
||||
return 0;
|
||||
|
@ -146,33 +174,34 @@ static int cmd_show(char **args, unsigned int n)
|
|||
}
|
||||
|
||||
if (l) {
|
||||
cli_printf("Link=%s\n", l->label);
|
||||
cli_command_printf("Link=%s\n", l->label);
|
||||
if (l->ifindex > 0)
|
||||
cli_printf("InterfaceIndex=%u\n", l->ifindex);
|
||||
cli_command_printf("InterfaceIndex=%u\n", l->ifindex);
|
||||
if (l->ifname && *l->ifname)
|
||||
cli_printf("InterfaceName=%s\n", l->ifname);
|
||||
cli_command_printf("InterfaceName=%s\n", l->ifname);
|
||||
if (l->friendly_name && *l->friendly_name)
|
||||
cli_printf("FriendlyName=%s\n", l->friendly_name);
|
||||
cli_printf("P2PScanning=%d\n", l->p2p_scanning);
|
||||
cli_command_printf("FriendlyName=%s\n", l->friendly_name);
|
||||
cli_command_printf("P2PScanning=%d\n", l->p2p_scanning);
|
||||
if (l->wfd_subelements && *l->wfd_subelements)
|
||||
cli_printf("WfdSubelements=%s\n", l->wfd_subelements);
|
||||
cli_command_printf("WfdSubelements=%s\n", l->wfd_subelements);
|
||||
cli_command_printf("Managed=%d\n", l->managed);
|
||||
} else if (p) {
|
||||
cli_printf("Peer=%s\n", p->label);
|
||||
cli_command_printf("Peer=%s\n", p->label);
|
||||
if (p->p2p_mac && *p->p2p_mac)
|
||||
cli_printf("P2PMac=%s\n", p->p2p_mac);
|
||||
cli_command_printf("P2PMac=%s\n", p->p2p_mac);
|
||||
if (p->friendly_name && *p->friendly_name)
|
||||
cli_printf("FriendlyName=%s\n", p->friendly_name);
|
||||
cli_printf("Connected=%d\n", p->connected);
|
||||
cli_command_printf("FriendlyName=%s\n", p->friendly_name);
|
||||
cli_command_printf("Connected=%d\n", p->connected);
|
||||
if (p->interface && *p->interface)
|
||||
cli_printf("Interface=%s\n", p->interface);
|
||||
cli_command_printf("Interface=%s\n", p->interface);
|
||||
if (p->local_address && *p->local_address)
|
||||
cli_printf("LocalAddress=%s\n", p->local_address);
|
||||
cli_command_printf("LocalAddress=%s\n", p->local_address);
|
||||
if (p->remote_address && *p->remote_address)
|
||||
cli_printf("RemoteAddress=%s\n", p->remote_address);
|
||||
cli_command_printf("RemoteAddress=%s\n", p->remote_address);
|
||||
if (p->wfd_subelements && *p->wfd_subelements)
|
||||
cli_printf("WfdSubelements=%s\n", p->wfd_subelements);
|
||||
cli_command_printf("WfdSubelements=%s\n", p->wfd_subelements);
|
||||
} else {
|
||||
cli_printf("Show what?\n");
|
||||
cli_command_printf("Show what?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -189,7 +218,7 @@ static int cmd_set_friendly_name(char **args, unsigned int n)
|
|||
const char *name;
|
||||
|
||||
if (n < 1) {
|
||||
cli_printf("To what?\n");
|
||||
cli_command_printf("To what?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -214,6 +243,45 @@ static int cmd_set_friendly_name(char **args, unsigned int n)
|
|||
return ctl_link_set_friendly_name(l, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: set-managed
|
||||
*/
|
||||
|
||||
static int cmd_set_managed(char **args, unsigned int n)
|
||||
{
|
||||
struct ctl_link *l = NULL;
|
||||
const char *value;
|
||||
bool managed = true;
|
||||
|
||||
if (n < 1) {
|
||||
cli_command_printf("To what?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
l = ctl_wifi_search_link(wifi, args[0]);
|
||||
if (!l) {
|
||||
cli_error("unknown link %s", args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = args[1];
|
||||
} else {
|
||||
value = args[0];
|
||||
}
|
||||
|
||||
l = l ? : selected_link;
|
||||
if (!l) {
|
||||
cli_error("no link selected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(value, "no")) {
|
||||
managed = false;
|
||||
}
|
||||
return ctl_link_set_managed(l, managed);
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd: p2p-scan
|
||||
*/
|
||||
|
@ -242,6 +310,11 @@ static int cmd_p2p_scan(char **args, unsigned int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!l->managed) {
|
||||
cli_printf("link %s not managed\n", l->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctl_link_set_p2p_scanning(l, !stop);
|
||||
}
|
||||
|
||||
|
@ -263,7 +336,7 @@ static int cmd_connect(char **args, unsigned int n)
|
|||
const char *prov, *pin;
|
||||
|
||||
if (n < 1) {
|
||||
cli_printf("To whom?\n");
|
||||
cli_command_printf("To whom?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -289,6 +362,11 @@ static int cmd_connect(char **args, unsigned int n)
|
|||
pin = "";
|
||||
}
|
||||
|
||||
if (!p->l->managed) {
|
||||
cli_printf("link %s not managed\n", p->l->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctl_peer_connect(p, prov, pin);
|
||||
}
|
||||
|
||||
|
@ -301,7 +379,7 @@ static int cmd_disconnect(char **args, unsigned int n)
|
|||
struct ctl_peer *p;
|
||||
|
||||
if (n < 1) {
|
||||
cli_printf("From whom?\n");
|
||||
cli_command_printf("From whom?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -311,6 +389,11 @@ static int cmd_disconnect(char **args, unsigned int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!p->l->managed) {
|
||||
cli_printf("link %s not managed\n", p->l->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctl_peer_disconnect(p);
|
||||
}
|
||||
|
||||
|
@ -329,16 +412,17 @@ static int cmd_quit(char **args, unsigned int n)
|
|||
*/
|
||||
|
||||
static const struct cli_cmd cli_cmds[] = {
|
||||
{ "list", NULL, CLI_M, CLI_LESS, 0, cmd_list, "List all objects" },
|
||||
{ "select", "[link]", CLI_Y, CLI_LESS, 1, cmd_select, "Select default link" },
|
||||
{ "show", "[link|peer]", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information" },
|
||||
{ "set-friendly-name", "[link] <name>", CLI_M, CLI_LESS, 2, cmd_set_friendly_name, "Set friendly name of an object" },
|
||||
{ "p2p-scan", "[link] [stop]", CLI_Y, CLI_LESS, 2, cmd_p2p_scan, "Control neighborhood P2P scanning" },
|
||||
{ "connect", "<peer> [provision] [pin]", CLI_M, CLI_LESS, 3, cmd_connect, "Connect to peer" },
|
||||
{ "disconnect", "<peer>", CLI_M, CLI_EQUAL, 1, cmd_disconnect, "Disconnect from peer" },
|
||||
{ "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program" },
|
||||
{ "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL },
|
||||
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" },
|
||||
{ "list", NULL, CLI_M, CLI_LESS, 0, cmd_list, "List all objects", {NULL}},
|
||||
{ "select", "[link]", CLI_Y, CLI_LESS, 1, cmd_select, "Select default link", {links_generator, NULL} },
|
||||
{ "show", "[link|peer]", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information", {links_peers_generator, NULL} },
|
||||
{ "set-friendly-name", "[link] <name>", CLI_M, CLI_LESS, 2, cmd_set_friendly_name, "Set friendly name of an object", {links_generator, yes_no_generator} },
|
||||
{ "set-managed", "[link] <yes|no>", CLI_M, CLI_LESS, 2, cmd_set_managed, "Manage or unmnage a link" },
|
||||
{ "p2p-scan", "[link] [stop]", CLI_Y, CLI_LESS, 2, cmd_p2p_scan, "Control neighborhood P2P scanning", {links_generator, NULL} },
|
||||
{ "connect", "<peer> [provision] [pin]", CLI_M, CLI_LESS, 3, cmd_connect, "Connect to peer", {peers_generator, NULL} },
|
||||
{ "disconnect", "<peer>", CLI_M, CLI_EQUAL, 1, cmd_disconnect, "Disconnect from peer", {peers_generator, NULL} },
|
||||
{ "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program", {NULL} },
|
||||
{ "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL , {NULL}},
|
||||
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" , {NULL} },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -419,9 +503,13 @@ void cli_fn_help()
|
|||
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
|
||||
"Send control command to or query the MiracleCast Wifi-Manager. If no arguments\n"
|
||||
"are given, an interactive command-line tool is provided.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" -h --help Show this help\n"
|
||||
" --help-commands Show available commands\n"
|
||||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
" --log-date-time Prefix log-messages with date time\n"
|
||||
" --log-journal-level <lvl> Maximum level for journal log messages\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
, program_invocation_short_name);
|
||||
|
@ -497,11 +585,19 @@ static int parse_argv(int argc, char *argv[])
|
|||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
ARG_LOG_DATE_TIME,
|
||||
ARG_JOURNAL_LEVEL,
|
||||
ARG_HELP_COMMANDS,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "help-commands", no_argument, NULL, ARG_HELP_COMMANDS },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "log-date-time", no_argument, NULL, ARG_LOG_DATE_TIME },
|
||||
{ "log-journal-level", required_argument, NULL, ARG_JOURNAL_LEVEL },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
@ -509,13 +605,25 @@ static int parse_argv(int argc, char *argv[])
|
|||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
return cli_help(cli_cmds);
|
||||
cli_fn_help();
|
||||
return 0;
|
||||
case ARG_HELP_COMMANDS:
|
||||
return cli_help(cli_cmds, 20);
|
||||
case ARG_VERSION:
|
||||
puts(PACKAGE_STRING);
|
||||
return 0;
|
||||
case ARG_LOG_LEVEL:
|
||||
cli_max_sev = log_parse_arg(optarg);
|
||||
break;
|
||||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
case ARG_LOG_DATE_TIME:
|
||||
log_date_time = true;
|
||||
break;
|
||||
case ARG_JOURNAL_LEVEL:
|
||||
log_max_sev = log_parse_arg(optarg);
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -530,6 +638,23 @@ int main(int argc, char **argv)
|
|||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
GKeyFile* gkf = load_ini_file();
|
||||
|
||||
if (gkf) {
|
||||
gchar* log_level;
|
||||
log_level = g_key_file_get_string (gkf, "wifictl", "log-journal-level", NULL);
|
||||
if (log_level) {
|
||||
log_max_sev = log_parse_arg(log_level);
|
||||
g_free(log_level);
|
||||
}
|
||||
log_level = g_key_file_get_string (gkf, "wifictl", "log-level", NULL);
|
||||
if (log_level) {
|
||||
cli_max_sev = log_parse_arg(log_level);
|
||||
g_free(log_level);
|
||||
}
|
||||
g_key_file_free(gkf);
|
||||
}
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
########### next target ###############
|
||||
|
||||
set(miracle-dhcp_SRCS dhcp.c
|
||||
gdhcp.h
|
||||
unaligned.h
|
||||
|
@ -16,47 +13,15 @@ add_executable(miracle-dhcp ${miracle-dhcp_SRCS})
|
|||
find_package(PkgConfig)
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
pkg_check_modules (UDEV REQUIRED libudev)
|
||||
target_link_libraries(miracle-dhcp miracle-shared)
|
||||
link_directories( ${UDEV_LIBRARY_DIRS})
|
||||
include_directories( ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(miracle-dhcp ${UDEV_LIBRARIES})
|
||||
target_link_libraries(miracle-dhcp m)
|
||||
link_directories( ${GLIB2_LIBRARY_DIRS})
|
||||
include_directories( ${GLIB2_INCLUDE_DIRS})
|
||||
target_link_libraries(miracle-dhcp ${GLIB2_LIBRARIES})
|
||||
|
||||
target_link_libraries(miracle-dhcp miracle-shared)
|
||||
|
||||
install(TARGETS miracle-dhcp DESTINATION bin)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#bin_PROGRAMS = miracle-dhcp
|
||||
#
|
||||
#miracle_dhcp_SOURCES = \
|
||||
# dhcp.c \
|
||||
# gdhcp.h \
|
||||
# unaligned.h \
|
||||
# common.h \
|
||||
# common.c \
|
||||
# ipv4ll.h \
|
||||
# ipv4ll.c \
|
||||
# client.c \
|
||||
# server.c
|
||||
#miracle_dhcp_CPPFLAGS = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS) \
|
||||
# $(GDHCP_CFLAGS)
|
||||
#miracle_dhcp_LDADD = \
|
||||
# ../shared/libmiracle-shared.la \
|
||||
# $(DEPS_LIBS) \
|
||||
# $(GDHCP_LIBS)
|
||||
#
|
||||
#
|
||||
#
|
||||
|
|
|
@ -14,11 +14,11 @@ miracle_dhcp_SOURCES = \
|
|||
miracle_dhcp_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS) \
|
||||
$(GDHCP_CFLAGS)
|
||||
$(GLIB_CFLAGS)
|
||||
miracle_dhcp_LDADD = \
|
||||
../shared/libmiracle-shared.la \
|
||||
$(DEPS_LIBS) \
|
||||
$(GDHCP_LIBS)
|
||||
$(GLIB_LIBS)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2785,7 +2785,7 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
|
|||
addr = ntohl(inet_addr(last_address));
|
||||
if (addr == 0xFFFFFFFF) {
|
||||
addr = 0;
|
||||
} else {
|
||||
} else if (dhcp_client->last_address != last_address) { // Avoiding use-after-free
|
||||
g_free(dhcp_client->last_address);
|
||||
dhcp_client->last_address = g_strdup(last_address);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
* of Wifi-P2P support in common network managers. Once they gain proper
|
||||
* support, we will drop this helper!
|
||||
*
|
||||
* The "ip" invokation is quite fragile and ugly. However, performing these
|
||||
* The "ip" invocation is quite fragile and ugly. However, performing these
|
||||
* steps directly involves netlink operations and more. As no-one came up with
|
||||
* patches, yet, we keep the hack. To anyone trying to fix it: Please, spend
|
||||
* this time hacking on NetworkManager, connman and friends instead! If they
|
||||
|
@ -67,8 +67,11 @@
|
|||
#include "shl_log.h"
|
||||
#include "config.h"
|
||||
|
||||
#define XSTR(x) STR(x)
|
||||
#define STR(x) #x
|
||||
|
||||
static const char *arg_netdev;
|
||||
static const char *arg_ip_binary = "/bin/ip";
|
||||
static const char *arg_ip_binary = XSTR(IP_BINARY);
|
||||
static bool arg_server;
|
||||
static char arg_local[INET_ADDRSTRLEN];
|
||||
static char arg_gateway[INET_ADDRSTRLEN];
|
||||
|
@ -747,9 +750,10 @@ static int help(void)
|
|||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
" --log-date-time Prefix log-messages with date time\n"
|
||||
"\n"
|
||||
" --netdev <dev> Network device to run on\n"
|
||||
" --ip-binary <path> Path to 'ip' binary [default: /bin/ip]\n"
|
||||
" --ip-binary <path> Path to 'ip' binary [default: "XSTR(IP_BINARY)"]\n"
|
||||
" --comm-fd <int> Comm-socket FD passed through execve()\n"
|
||||
"\n"
|
||||
"Server Options:\n"
|
||||
|
@ -772,6 +776,7 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
ARG_LOG_DATE_TIME,
|
||||
|
||||
ARG_NETDEV,
|
||||
ARG_IP_BINARY,
|
||||
|
@ -787,10 +792,11 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_TO,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "log-date-time", no_argument, NULL, ARG_LOG_DATE_TIME },
|
||||
|
||||
{ "netdev", required_argument, NULL, ARG_NETDEV },
|
||||
{ "ip-binary", required_argument, NULL, ARG_IP_BINARY },
|
||||
|
@ -823,6 +829,9 @@ static int parse_argv(int argc, char *argv[])
|
|||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
case ARG_LOG_DATE_TIME:
|
||||
log_date_time = true;
|
||||
break;
|
||||
case ARG_NETDEV:
|
||||
arg_netdev = optarg;
|
||||
break;
|
||||
|
|
11
src/dhcp/meson.build
Normal file
11
src/dhcp/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
|||
miracle_dhcp_srcs = ['dhcp.c',
|
||||
'common.c',
|
||||
'ipv4ll.c',
|
||||
'client.c',
|
||||
'server.c'
|
||||
]
|
||||
executable('miracle-dhcp', miracle_dhcp_srcs,
|
||||
install: true,
|
||||
include_directories: include_directories('../..'),
|
||||
dependencies: [glib2, udev, libmiracle_shared_dep, m]
|
||||
)
|
11
src/meson.build
Normal file
11
src/meson.build
Normal file
|
@ -0,0 +1,11 @@
|
|||
subdir('shared')
|
||||
subdir('wifi')
|
||||
subdir('dhcp')
|
||||
subdir('ctl')
|
||||
subdir('uibc')
|
||||
|
||||
executable('miracled', 'miracled.c',
|
||||
dependencies: [libmiracle_shared_dep, m],
|
||||
include_directories: include_directories('..'),
|
||||
install: true
|
||||
)
|
|
@ -66,6 +66,7 @@ static int help(void)
|
|||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
" --log-date-time Prefix log-messages with date time\n"
|
||||
, program_invocation_short_name);
|
||||
/*
|
||||
* 80-char barrier:
|
||||
|
@ -81,12 +82,14 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
ARG_LOG_DATE_TIME,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "log-date-time", no_argument, NULL, ARG_LOG_DATE_TIME },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
@ -104,6 +107,9 @@ static int parse_argv(int argc, char *argv[])
|
|||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
case ARG_LOG_DATE_TIME:
|
||||
log_date_time = true;
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
set(CMAKE_C_FLAGS "-std=gnu11")
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules (SYSTEMD REQUIRED systemd>=213)
|
||||
set(miracle-shared_SOURCES rtsp.h
|
||||
rtsp.c
|
||||
shl_dlist.h
|
||||
|
@ -18,36 +16,4 @@ set(miracle-shared_SOURCES rtsp.h
|
|||
wpas.h
|
||||
wpas.c)
|
||||
add_library(miracle-shared STATIC ${miracle-shared_SOURCES})
|
||||
target_link_libraries (miracle-shared systemd)
|
||||
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#noinst_LTLIBRARIES = libmiracle-shared.la
|
||||
#
|
||||
#libmiracle_shared_la_SOURCES = \
|
||||
# rtsp.h \
|
||||
# rtsp.c \
|
||||
# shl_dlist.h \
|
||||
# shl_htable.h \
|
||||
# shl_htable.c \
|
||||
# shl_log.h \
|
||||
# shl_log.c \
|
||||
# shl_macro.h \
|
||||
# shl_ring.h \
|
||||
# shl_ring.c \
|
||||
# shl_util.h \
|
||||
# shl_util.c \
|
||||
# util.h \
|
||||
# wpas.h \
|
||||
# wpas.c
|
||||
#libmiracle_shared_la_LIBADD = -lsystemd
|
||||
#
|
||||
#
|
||||
#
|
||||
target_link_libraries (miracle-shared ${SESSION_LIBRARIES})
|
||||
|
|
|
@ -17,7 +17,8 @@ libmiracle_shared_la_SOURCES = \
|
|||
util.h \
|
||||
wpas.h \
|
||||
wpas.c
|
||||
libmiracle_shared_la_LIBADD = -lsystemd
|
||||
|
||||
|
||||
libmiracle_shared_la_LIBADD = \
|
||||
$(DEPS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(LIBM)
|
||||
|
||||
|
|
22
src/shared/meson.build
Normal file
22
src/shared/meson.build
Normal file
|
@ -0,0 +1,22 @@
|
|||
libmiracle_shared = static_library('miracle-shared',
|
||||
'rtsp.h',
|
||||
'rtsp.c',
|
||||
'shl_dlist.h',
|
||||
'shl_htable.h',
|
||||
'shl_htable.c',
|
||||
'shl_log.h',
|
||||
'shl_log.c',
|
||||
'shl_macro.h',
|
||||
'shl_ring.h',
|
||||
'shl_ring.c',
|
||||
'shl_util.h',
|
||||
'shl_util.c',
|
||||
'util.h',
|
||||
'wpas.h',
|
||||
'wpas.c',
|
||||
dependencies: [libsystemd]
|
||||
)
|
||||
libmiracle_shared_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
link_with: libmiracle_shared
|
||||
)
|
|
@ -2169,7 +2169,6 @@ static int parser_submit_data(struct rtsp *bus, uint8_t *p)
|
|||
p,
|
||||
dec->data_size);
|
||||
if (r < 0) {
|
||||
free(p);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -2717,7 +2716,7 @@ error:
|
|||
return r;
|
||||
}
|
||||
|
||||
static void rtsp_unlink_waiting(struct rtsp_message *m)
|
||||
static bool rtsp_unlink_waiting(struct rtsp_message *m)
|
||||
{
|
||||
if (m->is_waiting) {
|
||||
sd_event_source_unref(m->timer_source);
|
||||
|
@ -2726,7 +2725,9 @@ static void rtsp_unlink_waiting(struct rtsp_message *m)
|
|||
m->is_waiting = false;
|
||||
--m->bus->waiting_cnt;
|
||||
rtsp_message_unref(m);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void rtsp_link_outgoing(struct rtsp_message *m)
|
||||
|
@ -2737,7 +2738,7 @@ static void rtsp_link_outgoing(struct rtsp_message *m)
|
|||
rtsp_message_ref(m);
|
||||
}
|
||||
|
||||
static void rtsp_unlink_outgoing(struct rtsp_message *m)
|
||||
static bool rtsp_unlink_outgoing(struct rtsp_message *m)
|
||||
{
|
||||
if (m->is_outgoing) {
|
||||
shl_dlist_unlink(&m->list);
|
||||
|
@ -2745,7 +2746,9 @@ static void rtsp_unlink_outgoing(struct rtsp_message *m)
|
|||
m->is_sending = false;
|
||||
--m->bus->outgoing_cnt;
|
||||
rtsp_message_unref(m);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int rtsp_incoming_message(struct rtsp_message *m)
|
||||
|
@ -2823,10 +2826,11 @@ static int rtsp_write_message(struct rtsp_message *m)
|
|||
if (m->sent >= m->raw_size) {
|
||||
/* no need to wait for answer if no-body listens */
|
||||
if (!m->cb_fn)
|
||||
rtsp_unlink_waiting(m);
|
||||
|
||||
if (rtsp_unlink_waiting(m))
|
||||
m = NULL;
|
||||
/* might destroy the message */
|
||||
rtsp_unlink_outgoing(m);
|
||||
if (m)
|
||||
rtsp_unlink_outgoing(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3246,10 +3250,12 @@ static void rtsp_drop_message(struct rtsp_message *m)
|
|||
|
||||
/* never interrupt messages while being partly sent */
|
||||
if (!m->is_sending)
|
||||
rtsp_unlink_outgoing(m);
|
||||
if (rtsp_unlink_outgoing(m))
|
||||
m = NULL;
|
||||
|
||||
/* remove from waiting list so neither timeouts nor completions fire */
|
||||
rtsp_unlink_waiting(m);
|
||||
if (m)
|
||||
rtsp_unlink_waiting(m);
|
||||
}
|
||||
|
||||
void rtsp_call_async_cancel(struct rtsp *bus, uint64_t cookie)
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include "shl_log.h"
|
||||
|
||||
/*
|
||||
|
@ -36,7 +39,7 @@ static inline void log_unlock()
|
|||
|
||||
static struct timeval log__ftime;
|
||||
|
||||
static bool log__have_time(void)
|
||||
bool log__have_time(void)
|
||||
{
|
||||
return !(log__ftime.tv_sec == 0 && log__ftime.tv_usec == 0);
|
||||
}
|
||||
|
@ -47,7 +50,7 @@ void log_init_time(void)
|
|||
gettimeofday(&log__ftime, NULL);
|
||||
}
|
||||
|
||||
static void log__time(long long *sec, long long *usec)
|
||||
void log__time(long long *sec, long long *usec)
|
||||
{
|
||||
struct timeval t;
|
||||
|
||||
|
@ -83,6 +86,9 @@ const char *LOG_SUBSYSTEM = NULL;
|
|||
*/
|
||||
|
||||
unsigned int log_max_sev = LOG_NOTICE;
|
||||
bool log_date_time = false;
|
||||
|
||||
char *gst_debug = NULL;
|
||||
|
||||
/*
|
||||
* Forward declaration so we can use the locked-versions in other functions
|
||||
|
@ -135,25 +141,51 @@ static void log__submit(const char *file,
|
|||
const char *prefix = NULL;
|
||||
FILE *out;
|
||||
long long sec, usec;
|
||||
time_t now;
|
||||
struct tm *timeinfo;
|
||||
struct timeval tv;
|
||||
char buffertmp[80];
|
||||
char buffer[120];
|
||||
int millisec;
|
||||
|
||||
out = stderr;
|
||||
log__time(&sec, &usec);
|
||||
|
||||
if (sev < LOG_SEV_NUM && sev > log_max_sev)
|
||||
return;
|
||||
|
||||
log__time(&sec, &usec);
|
||||
|
||||
if (log_date_time) {
|
||||
gettimeofday(&tv, NULL);
|
||||
millisec = lrint(tv.tv_usec/1000.0);
|
||||
if (millisec>=1000) {
|
||||
millisec -=1000;
|
||||
tv.tv_sec++;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
timeinfo = localtime(&now);
|
||||
|
||||
strftime(buffertmp, 80, "%x - %X.%03d", timeinfo);
|
||||
sprintf(buffer, "%s.%03d", buffertmp, millisec);
|
||||
}
|
||||
|
||||
if (sev < LOG_SEV_NUM)
|
||||
prefix = log__sev2str[sev];
|
||||
|
||||
if (prefix) {
|
||||
if (subs) {
|
||||
if (log__have_time())
|
||||
if (log_date_time)
|
||||
fprintf(out, "[%s] %s: %s: ", buffer, prefix, subs);
|
||||
else if (log__have_time())
|
||||
fprintf(out, "[%.4lld.%.6lld] %s: %s: ",
|
||||
sec, usec, prefix, subs);
|
||||
else
|
||||
fprintf(out, "%s: %s: ", prefix, subs);
|
||||
} else {
|
||||
if (log__have_time())
|
||||
if (log_date_time)
|
||||
fprintf(out, "[%s] %s: ", buffer, prefix);
|
||||
else if (log__have_time())
|
||||
fprintf(out, "[%.4lld.%.6lld] %s: ",
|
||||
sec, usec, prefix);
|
||||
else
|
||||
|
@ -161,13 +193,18 @@ static void log__submit(const char *file,
|
|||
}
|
||||
} else {
|
||||
if (subs) {
|
||||
if (log__have_time())
|
||||
if (log_date_time)
|
||||
fprintf(out, "[%s] %s: ",
|
||||
buffer, subs);
|
||||
else if (log__have_time())
|
||||
fprintf(out, "[%.4lld.%.6lld] %s: ",
|
||||
sec, usec, subs);
|
||||
else
|
||||
fprintf(out, "%s: ", subs);
|
||||
} else {
|
||||
if (log__have_time())
|
||||
if (log_date_time)
|
||||
fprintf(out, "[%s] ", buffer);
|
||||
else if (log__have_time())
|
||||
fprintf(out, "[%.4lld.%.6lld] ", sec, usec);
|
||||
}
|
||||
}
|
||||
|
@ -239,9 +276,9 @@ void log_llog(void *data,
|
|||
log_submit(file, line, func, subs, sev, format, args);
|
||||
}
|
||||
|
||||
int log_parse_arg(char *optarg)
|
||||
unsigned int log_parse_arg(char *optarg)
|
||||
{
|
||||
int log_max_sev;
|
||||
unsigned int log_max_sev;
|
||||
if(!strcasecmp(optarg, "fatal")) {
|
||||
log_max_sev = LOG_FATAL;
|
||||
} else if(!strcasecmp(optarg, "alert")) {
|
||||
|
@ -261,7 +298,23 @@ int log_parse_arg(char *optarg)
|
|||
} else if(!strcasecmp(optarg, "trace")) {
|
||||
log_max_sev = LOG_TRACE;
|
||||
} else {
|
||||
log_max_sev = atoi(optarg);
|
||||
errno = 0;
|
||||
char *temp;
|
||||
long val = strtoul(optarg, &temp, 0);
|
||||
|
||||
if (temp == optarg || *temp != '\0'
|
||||
|| ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE)) {
|
||||
log_error("Could not convert '%s' to long and leftover string is: '%s'\n", optarg, temp);
|
||||
}
|
||||
if (val > INT_MAX) {
|
||||
errno = ERANGE;
|
||||
return INT_MAX;
|
||||
}
|
||||
if (val < INT_MIN) {
|
||||
errno = ERANGE;
|
||||
return INT_MIN;
|
||||
}
|
||||
log_max_sev = (unsigned int) val;
|
||||
}
|
||||
return log_max_sev;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,17 @@ enum log_severity {
|
|||
|
||||
extern unsigned int log_max_sev;
|
||||
|
||||
/*
|
||||
* Defines if log time should use local time
|
||||
* Default: false
|
||||
*/
|
||||
extern bool log_date_time;
|
||||
|
||||
/*
|
||||
* Defines the debug configuration for gstreamer
|
||||
*/
|
||||
extern char* gst_debug;
|
||||
|
||||
/*
|
||||
* Timestamping
|
||||
* Call this to initialize timestamps and cause all log-messages to be prefixed
|
||||
|
@ -69,6 +80,10 @@ extern unsigned int log_max_sev;
|
|||
|
||||
void log_init_time(void);
|
||||
|
||||
void log__time(long long *sec, long long *usec);
|
||||
|
||||
bool log__have_time(void);
|
||||
|
||||
/*
|
||||
* Log-Functions
|
||||
* These functions pass a log-message to the log-subsystem. Handy helpers are
|
||||
|
@ -116,7 +131,7 @@ void log_llog(void *data,
|
|||
const char *format,
|
||||
va_list args);
|
||||
|
||||
int log_parse_arg(char *optarg);
|
||||
unsigned int log_parse_arg(char *optarg);
|
||||
|
||||
static inline __attribute__((format(printf, 2, 3)))
|
||||
void log_dummyf(unsigned int sev, const char *format, ...)
|
||||
|
@ -226,4 +241,9 @@ extern const char *LOG_SUBSYSTEM;
|
|||
#define log_vERR(_r) \
|
||||
((void)log_ERR(_r))
|
||||
|
||||
#define log_EUNMANAGED() \
|
||||
(log_error("interface unmanaged"), -EFAULT)
|
||||
#define log_vEUNMANAGED() \
|
||||
((void)log_EUNMANAGED())
|
||||
|
||||
#endif /* SHL_LOG_H */
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* variants to allow these.
|
||||
* Base-prefix parsing is only done if base=0 is requested. Otherwise,
|
||||
* base-prefixes are forbidden.
|
||||
* The input string must be ASCII compatbile (which includes UTF8).
|
||||
* The input string must be ASCII compatible (which includes UTF8).
|
||||
*
|
||||
* We also always check for overflows and return errors (but continue parsing!)
|
||||
* so callers can catch it correctly.
|
||||
|
@ -826,8 +826,9 @@ int shl__mkdir_parents(const char *prefix, const char *path, mode_t mode)
|
|||
if (!e || e == path)
|
||||
return 0;
|
||||
|
||||
p = strndupa(path, e - path);
|
||||
p = strndup(path, e - path);
|
||||
r = shl__is_dir(p);
|
||||
free((char*)p);
|
||||
if (r > 0)
|
||||
return 0;
|
||||
if (r == 0)
|
||||
|
|
|
@ -31,6 +31,26 @@
|
|||
#include <systemd/sd-bus.h>
|
||||
#include <time.h>
|
||||
#include "shl_macro.h"
|
||||
#include <glib.h>
|
||||
|
||||
static inline GKeyFile* load_ini_file() {
|
||||
GKeyFile* gkf = NULL;
|
||||
gchar* config_file;
|
||||
|
||||
gkf = g_key_file_new();
|
||||
|
||||
config_file = g_build_filename(g_get_home_dir(), ".config", "miraclecastrc", NULL);
|
||||
if (!g_key_file_load_from_file(gkf, config_file, G_KEY_FILE_NONE, NULL)) {
|
||||
g_free(config_file);
|
||||
config_file = g_build_filename(g_get_home_dir(), ".miraclecast", NULL);
|
||||
if (!g_key_file_load_from_file(gkf, config_file, G_KEY_FILE_NONE, NULL)) {
|
||||
g_key_file_free(gkf);
|
||||
gkf = NULL;
|
||||
}
|
||||
}
|
||||
g_free(config_file);
|
||||
return gkf;
|
||||
}
|
||||
|
||||
static inline void cleanup_sd_bus_message(sd_bus_message **ptr)
|
||||
{
|
||||
|
|
|
@ -742,6 +742,7 @@ static int wpas__parse_message(struct wpas *w,
|
|||
const char *ifname = NULL;
|
||||
unsigned int level;
|
||||
char *pos;
|
||||
char *orig_raw = raw;
|
||||
int r, num;
|
||||
bool is_event = false;
|
||||
|
||||
|
@ -751,7 +752,7 @@ static int wpas__parse_message(struct wpas *w,
|
|||
ifname = pos;
|
||||
pos = strchrnul(pos, ' ');
|
||||
if (*pos)
|
||||
*pos++ = 0;
|
||||
pos++;
|
||||
|
||||
len -= pos - raw;
|
||||
raw = pos;
|
||||
|
@ -811,15 +812,12 @@ static int wpas__parse_message(struct wpas *w,
|
|||
|
||||
m->sealed = true;
|
||||
m->rawlen = len;
|
||||
m->raw = malloc(len + 1);
|
||||
m->raw = strdup(orig_raw);
|
||||
if (!m->raw)
|
||||
return -ENOMEM;
|
||||
|
||||
/* copy with 0-terminator */
|
||||
memcpy(m->raw, raw, len + 1);
|
||||
|
||||
if (ifname) {
|
||||
m->ifname = strdup(ifname);
|
||||
m->ifname = strndup(ifname, strchrnul(ifname, ' ') - ifname);
|
||||
if (!m->ifname)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -1056,7 +1054,7 @@ static int wpas__bind_server_socket(int fd, const char *ctrl_path, char *name)
|
|||
}
|
||||
}
|
||||
|
||||
strncpy(name, src.sun_path, UNIX_PATH_MAX - 1);
|
||||
strncpy(name, src.sun_path, UNIX_PATH_MAX);
|
||||
name[UNIX_PATH_MAX - 1] = 0;
|
||||
|
||||
return 0;
|
||||
|
|
10
src/uibc/CMakeLists.txt
Normal file
10
src/uibc/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
set(miracle-uibcctl_SRCS miracle-uibcctl.h
|
||||
miracle-uibcctl.c)
|
||||
|
||||
add_executable(miracle-uibcctl ${miracle-uibcctl_SRCS})
|
||||
target_link_libraries(miracle-uibcctl miracle-shared)
|
||||
target_link_libraries(miracle-uibcctl m)
|
||||
|
||||
install(TARGETS miracle-uibcctl DESTINATION bin)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
16
src/uibc/Makefile.am
Normal file
16
src/uibc/Makefile.am
Normal file
|
@ -0,0 +1,16 @@
|
|||
include $(top_srcdir)/common.am
|
||||
|
||||
bin_PROGRAMS = miracle-uibcctl
|
||||
|
||||
miracle_uibcctl_SOURCES = \
|
||||
miracle-uibcctl.h \
|
||||
miracle-uibcctl.c
|
||||
|
||||
miracle_uibctcl_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS)
|
||||
|
||||
miracle_uibcctl_LDADD = \
|
||||
../shared/libmiracle-shared.la \
|
||||
$(LIBM)
|
||||
|
4
src/uibc/meson.build
Normal file
4
src/uibc/meson.build
Normal file
|
@ -0,0 +1,4 @@
|
|||
executable('miracle-uibcctl', 'miracle-uibcctl.h', 'miracle-uibcctl.c',
|
||||
install: true,
|
||||
dependencies: [m, libmiracle_shared_dep]
|
||||
)
|
624
src/uibc/miracle-uibcctl.c
Normal file
624
src/uibc/miracle-uibcctl.c
Normal file
|
@ -0,0 +1,624 @@
|
|||
|
||||
#include "miracle-uibcctl.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
//TODO: Add miracle TUI interface
|
||||
//TODO: Add parsearg
|
||||
//--daemon (read stdin)
|
||||
|
||||
int portno;
|
||||
struct hostent *server;
|
||||
int sockfd;
|
||||
struct sockaddr_in serv_addr;
|
||||
char buffer[256];
|
||||
int r;
|
||||
|
||||
log_max_sev = LOG_INFO;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " %s <hostname> <port>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
server = gethostbyname(argv[1]);
|
||||
portno = atoi(argv[2]);
|
||||
|
||||
log_info("server %s port %d", argv[1], portno);
|
||||
|
||||
if (server == NULL) {
|
||||
fprintf(stderr,"ERROR, no such host\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd < 0) {
|
||||
perror("ERROR opening socket");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
bcopy(server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
|
||||
serv_addr.sin_port = htons(portno);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("ERROR connecting");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool daemon = true;
|
||||
while(1) {
|
||||
if (!daemon) {
|
||||
printf("enter event <type>,<count>,<id>,<x>,<y>: ");
|
||||
}
|
||||
bzero(buffer, 256);
|
||||
fgets(buffer, 255, stdin);
|
||||
if (strlen(buffer) == 0) {
|
||||
break;
|
||||
}
|
||||
if (!daemon) {
|
||||
printf("input: %s", buffer);
|
||||
}
|
||||
char type = buffer[0];
|
||||
UibcMessage uibcmessage;
|
||||
if (type == '0' || type == '1') {
|
||||
uibcmessage = buildUibcMessage(GENERIC_TOUCH_DOWN, buffer, 1, 1);
|
||||
} else if (type == '3' || type == '4') {
|
||||
uibcmessage = buildUibcMessage(GENERIC_KEY_DOWN, buffer, 1, 1);
|
||||
} else {
|
||||
if (!daemon) {
|
||||
printf("unknow event type: %s", buffer);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
r = sendUibcMessage(&uibcmessage, sockfd);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
const char *int2binary(int x, int padding)
|
||||
{
|
||||
char *b;
|
||||
int min_padding = x > 0 ? floor(log2(x)) : 0;
|
||||
if (padding < min_padding) {
|
||||
padding = min_padding;
|
||||
}
|
||||
|
||||
b = (char *)malloc (sizeof (char *) * padding + 1);
|
||||
strcpy(b, "");
|
||||
|
||||
int z;
|
||||
for (z = pow(2,padding); z > 0; z >>= 1) {
|
||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int sendUibcMessage(UibcMessage* uibcmessage, int sockfd) {
|
||||
ssize_t n;
|
||||
|
||||
printf("sending %zu bytes\n", uibcmessage->m_PacketDataLen);
|
||||
|
||||
n = write(sockfd, uibcmessage->m_PacketData , uibcmessage->m_PacketDataLen);
|
||||
|
||||
if (n < 0) {
|
||||
perror("ERROR writing to socket");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
UibcMessage buildUibcMessage(MessageType type,
|
||||
const char* inEventDesc,
|
||||
double widthRatio,
|
||||
double heightRatio) {
|
||||
UibcMessage uibcmessage;
|
||||
uibcmessage.m_PacketData = NULL;
|
||||
uibcmessage.m_PacketDataLen = 0;
|
||||
uibcmessage.m_DataValid = false;
|
||||
|
||||
switch (type) {
|
||||
case GENERIC_TOUCH_DOWN:
|
||||
case GENERIC_TOUCH_UP:
|
||||
case GENERIC_TOUCH_MOVE:
|
||||
getUIBCGenericTouchPacket(inEventDesc,
|
||||
&uibcmessage,
|
||||
widthRatio,
|
||||
heightRatio);
|
||||
break;
|
||||
|
||||
case GENERIC_KEY_DOWN:
|
||||
case GENERIC_KEY_UP:
|
||||
getUIBCGenericKeyPacket(inEventDesc, &uibcmessage);
|
||||
break;
|
||||
|
||||
case GENERIC_ZOOM:
|
||||
getUIBCGenericZoomPacket(inEventDesc, &uibcmessage);
|
||||
break;
|
||||
|
||||
case GENERIC_VERTICAL_SCROLL:
|
||||
case GENERIC_HORIZONTAL_SCROLL:
|
||||
getUIBCGenericScalePacket(inEventDesc, &uibcmessage);
|
||||
break;
|
||||
|
||||
case GENERIC_ROTATE:
|
||||
getUIBCGenericRotatePacket(inEventDesc, &uibcmessage);
|
||||
break;
|
||||
};
|
||||
return uibcmessage;
|
||||
}
|
||||
|
||||
|
||||
// format: "typeId, number of pointers, pointer Id1, X coordnate, Y coordinate, pointer Id2, X coordnate, Y coordnate,..."
|
||||
void getUIBCGenericTouchPacket(const char *inEventDesc,
|
||||
UibcMessage* uibcmessage,
|
||||
double widthRatio,
|
||||
double heightRatio) {
|
||||
log_info("getUIBCGenericTouchPacket (%s)", inEventDesc);
|
||||
char* outData;
|
||||
int32_t typeId = 0;
|
||||
int32_t numberOfPointers = 0;
|
||||
size_t uibcBodyLen = 0;
|
||||
int32_t genericPacketLen = 0;
|
||||
int32_t temp;
|
||||
size_t size;
|
||||
|
||||
char** splitedStr = str_split((char*)inEventDesc, ",", &size);
|
||||
|
||||
if ((int)size - 5 < 0 || ((int)size - 5) % 3 != 0) {
|
||||
log_error("getUIBCGenericTouchPacket (%s)", "bad input event");
|
||||
return;
|
||||
}
|
||||
int offset_split = 0;
|
||||
typeId = atoi(*(splitedStr + offset_split++));
|
||||
numberOfPointers = atoi(*(splitedStr + offset_split++));
|
||||
|
||||
genericPacketLen = numberOfPointers * 5 + 1;
|
||||
uibcBodyLen = genericPacketLen + 7; // Generic header length = 7
|
||||
//Padding to even number
|
||||
uibcBodyLen = (uibcBodyLen % 2 == 0) ? uibcBodyLen : (uibcBodyLen + 1);
|
||||
|
||||
outData = (char*)malloc(uibcBodyLen);
|
||||
// UIBC header Octets
|
||||
int offset_header = 0;
|
||||
//Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[offset_header++] = 0x00; // 000 0 0000
|
||||
outData[offset_header++] = 0x00; // 0000 0000
|
||||
|
||||
//Length(16 bits)
|
||||
outData[offset_header++] = (uibcBodyLen >> 8) & 0xFF; // first 8 bytes
|
||||
outData[offset_header++] = uibcBodyLen & 0xFF; // last 8 bytes
|
||||
|
||||
//Generic Input Body Format
|
||||
outData[offset_header++] = typeId & 0xFF; // Tyoe ID, 1 octet
|
||||
|
||||
// Length, 2 octets
|
||||
outData[offset_header++] = (genericPacketLen >> 8) & 0xFF; // first 8 bytes
|
||||
outData[offset_header++] = genericPacketLen & 0xFF; //last 8 bytes
|
||||
|
||||
// Number of pointers, 1 octet
|
||||
outData[offset_header++] = numberOfPointers & 0xFF;
|
||||
|
||||
int offset = 0;
|
||||
log_info("getUIBCGenericTouchPacket numberOfPointers=[%d]\n", numberOfPointers);
|
||||
for (int i = 0; i < numberOfPointers; i++) {
|
||||
int splitoffset = offset_split + (i * 3);
|
||||
temp = atoi(*(splitedStr + splitoffset++));
|
||||
offset = offset_header + ( i * 5);
|
||||
outData[offset++] = temp & 0xFF;
|
||||
log_info("getUIBCGenericTouchPacket PointerId=[%d]\n", temp);
|
||||
|
||||
temp = atoi(*(splitedStr + splitoffset++));
|
||||
temp = (int32_t)((double)temp / widthRatio);
|
||||
log_info("getUIBCGenericTouchPacket X-coordinate=[%d]\n", temp);
|
||||
outData[offset++] = (temp >> 8) & 0xFF;
|
||||
outData[offset++] = temp & 0xFF;
|
||||
|
||||
temp = atoi(*(splitedStr + splitoffset++));
|
||||
temp = (int32_t)((double)temp / heightRatio);
|
||||
log_info("getUIBCGenericTouchPacket Y-coordinate=[%d]\n", temp);
|
||||
outData[offset++] = (temp >> 8) & 0xFF;
|
||||
outData[offset++] = temp & 0xFF;
|
||||
}
|
||||
|
||||
while (offset <= uibcBodyLen) {
|
||||
outData[offset++] = 0x00;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
free(*(splitedStr + i));
|
||||
}
|
||||
free(splitedStr);
|
||||
|
||||
binarydump(outData, uibcBodyLen);
|
||||
uibcmessage->m_DataValid = true;
|
||||
uibcmessage->m_PacketData = outData;
|
||||
uibcmessage->m_PacketDataLen = uibcBodyLen;
|
||||
}
|
||||
|
||||
void hexdump(void *_data, size_t len)
|
||||
{
|
||||
unsigned char *data = _data;
|
||||
size_t count;
|
||||
|
||||
int line = 15;
|
||||
for (count = 0; count < len; count++) {
|
||||
if ((count & line) == 0) {
|
||||
fprintf(stderr,"%04zu: ", count);
|
||||
}
|
||||
fprintf(stderr,"%02x ", *data);
|
||||
data++;
|
||||
if ((count & line) == line) {
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
if ((count & line) != 0) {
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
void binarydump(void *_data, size_t len)
|
||||
{
|
||||
unsigned char *data = _data;
|
||||
size_t count;
|
||||
|
||||
int line = 7;
|
||||
for (count = 0; count < len; count++) {
|
||||
if ((count & line) == 0) {
|
||||
fprintf(stderr,"%04zu: ", count);
|
||||
}
|
||||
fprintf(stderr,"%s ", int2binary(*data, 8));
|
||||
data++;
|
||||
if ((count & line) == line) {
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
if ((count & line) != 0) {
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
}
|
||||
// format: "typeId, Key code 1(0x00), Key code 2(0x00)"
|
||||
void getUIBCGenericKeyPacket(const char *inEventDesc,
|
||||
UibcMessage* uibcmessage) {
|
||||
log_info("getUIBCGenericKeyPacket (%s)", inEventDesc);
|
||||
char* outData = uibcmessage->m_PacketData;
|
||||
int32_t typeId = 0;
|
||||
int32_t uibcBodyLen = 0;
|
||||
int32_t genericPacketLen = 0;
|
||||
int32_t temp = 0;
|
||||
size_t size;
|
||||
char** splitedStr = str_split((char*)inEventDesc, ",", &size);
|
||||
|
||||
if (size > 0) {
|
||||
|
||||
if (((int)size) % 3 != 0) {
|
||||
log_error("getUIBCGenericKeyPacket (%s)", "bad input event");
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
log_info("getUIBCGenericKeyPacket splitedStr tokens=[%s]\n", *(splitedStr + i));
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
typeId = atoi(*(splitedStr + i));
|
||||
log_info("getUIBCGenericKeyPacket typeId=[%d]\n", typeId);
|
||||
genericPacketLen = 5;
|
||||
uibcBodyLen = genericPacketLen + 7; // Generic header length = 7
|
||||
outData = (char*)malloc(uibcBodyLen + 1);
|
||||
// UIBC header
|
||||
outData[0] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[1] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[2] = (uibcBodyLen >> 8) & 0xFF; //Length(16 bits)
|
||||
outData[3] = uibcBodyLen & 0xFF; //Length(16 bits)
|
||||
//Generic Input Body Format
|
||||
outData[4] = typeId & 0xFF; // Tyoe ID, 1 octet
|
||||
outData[5] = (genericPacketLen >> 8) & 0xFF; // Length, 2 octets
|
||||
outData[6] = genericPacketLen & 0xFF; // Length, 2 octets
|
||||
outData[7] = 0x00; // reserved
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
sscanf(*(splitedStr + i), " 0x%04X", &temp);
|
||||
if (temp == 0) {
|
||||
outData[8] = 0x00;
|
||||
outData[9] = 0x00;
|
||||
}
|
||||
log_info("getUIBCGenericKeyPacket key code 1=[%d]\n", temp);
|
||||
outData[8] = (temp >> 8) & 0xFF;
|
||||
outData[9] = temp & 0xFF;
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
sscanf(*(splitedStr + i), " 0x%04X", &temp);
|
||||
if (temp == 0) {
|
||||
outData[10] = 0x00;
|
||||
outData[11] = 0x00;
|
||||
}
|
||||
log_info("getUIBCGenericKeyPacket key code 2=[%d]\n", temp);
|
||||
outData[10] = (temp >> 8) & 0xFF;
|
||||
outData[11] = temp & 0xFF;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(*(splitedStr + i));
|
||||
}
|
||||
}
|
||||
free(splitedStr);
|
||||
|
||||
binarydump(outData, uibcBodyLen);
|
||||
uibcmessage->m_DataValid = true;
|
||||
uibcmessage->m_PacketData = outData;
|
||||
uibcmessage->m_PacketDataLen = uibcBodyLen;
|
||||
}
|
||||
|
||||
// format: "typeId, X coordnate, Y coordnate, integer part, fraction part"
|
||||
void getUIBCGenericZoomPacket(const char *inEventDesc, UibcMessage* uibcmessage) {
|
||||
log_info("getUIBCGenericZoomPacket (%s)", inEventDesc);
|
||||
char* outData = uibcmessage->m_PacketData;
|
||||
int32_t typeId;
|
||||
int32_t uibcBodyLen, genericPacketLen;
|
||||
int32_t xCoord, yCoord, integerPart, FractionPart;
|
||||
size_t size;
|
||||
|
||||
char** splitedStr = str_split((char*)inEventDesc, ",", &size);
|
||||
|
||||
if (splitedStr) {
|
||||
int i;
|
||||
for (i = 0; * (splitedStr + i); i++) {
|
||||
//log_info("getUIBCGenericZoomPacket splitedStr tokens=[%s]\n", *(splitedStr + i));
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
typeId = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericZoomPacket typeId=[%d]\n", typeId);
|
||||
|
||||
genericPacketLen = 6;
|
||||
uibcBodyLen = genericPacketLen + 7; // Generic herder leh = 7
|
||||
outData = (char*)malloc(uibcBodyLen + 1);
|
||||
// UIBC header
|
||||
outData[0] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[1] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[2] = (uibcBodyLen >> 8) & 0xFF; //Length(16 bits)
|
||||
outData[3] = uibcBodyLen & 0xFF; //Length(16 bits)
|
||||
//Generic Input Body Format
|
||||
outData[4] = typeId & 0xFF; // Tyoe ID, 1 octet
|
||||
outData[5] = (genericPacketLen >> 8) & 0xFF; // Length, 2 octets
|
||||
outData[6] = genericPacketLen & 0xFF; // Length, 2 octets
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
xCoord = atoi(*(splitedStr + i));
|
||||
outData[7] = (xCoord >> 8) & 0xFF;
|
||||
outData[8] = xCoord & 0xFF;
|
||||
log_info("getUIBCGenericZoomPacket xCoord=[%d]\n", xCoord);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
yCoord = atoi(*(splitedStr + i));
|
||||
log_info("getUIBCGenericZoomPacket yCoord=[%d]\n", yCoord);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
integerPart = atoi(*(splitedStr + i));
|
||||
outData[11] = integerPart & 0xFF;
|
||||
//log_info("getUIBCGenericZoomPacket integerPart=[%d]\n", integerPart);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
FractionPart = atoi(*(splitedStr + i));
|
||||
outData[12] = FractionPart & 0xFF;
|
||||
//log_info("getUIBCGenericZoomPacket FractionPart=[%d]\n", FractionPart);
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(*(splitedStr + i));
|
||||
}
|
||||
free(splitedStr);
|
||||
}
|
||||
//hexdump(outData, uibcBodyLen);
|
||||
uibcmessage->m_DataValid = true;
|
||||
uibcmessage->m_PacketDataLen = uibcBodyLen;
|
||||
}
|
||||
|
||||
// format: "typeId, unit, direction, amount to scroll"
|
||||
void getUIBCGenericScalePacket(const char *inEventDesc, UibcMessage* uibcmessage) {
|
||||
log_info("getUIBCGenericScalePacket (%s)", inEventDesc);
|
||||
char* outData = uibcmessage->m_PacketData;
|
||||
int32_t typeId;
|
||||
int32_t uibcBodyLen, genericPacketLen;
|
||||
int32_t temp;
|
||||
size_t size;
|
||||
char** splitedStr = str_split((char*)inEventDesc, ",", &size);
|
||||
|
||||
if (splitedStr) {
|
||||
int i;
|
||||
for (i = 0; * (splitedStr + i); i++) {
|
||||
//log_info("getUIBCGenericScalePacket splitedStr tokens=[%s]\n", *(splitedStr + i));
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
typeId = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericScalePacket typeId=[%d]\n", typeId);
|
||||
genericPacketLen = 2;
|
||||
uibcBodyLen = genericPacketLen + 7; // Generic herder leh = 7
|
||||
outData = (char*)malloc(uibcBodyLen + 1);
|
||||
// UIBC header
|
||||
outData[0] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[1] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[2] = (uibcBodyLen >> 8) & 0xFF; //Length(16 bits)
|
||||
outData[3] = uibcBodyLen & 0xFF; //Length(16 bits)
|
||||
//Generic Input Body Format
|
||||
outData[4] = typeId & 0xFF; // Tyoe ID, 1 octet
|
||||
outData[5] = (genericPacketLen >> 8) & 0xFF; // Length, 2 octets
|
||||
outData[6] = genericPacketLen & 0xFF; // Length, 2 octets
|
||||
outData[7] = 0x00; // Clear the byte
|
||||
outData[8] = 0x00; // Clear the byte
|
||||
/*
|
||||
B15B14; Scroll Unit Indication bits.
|
||||
0b00; the unit is a pixel (normalized with respect to the WFD Source display resolution that is conveyed in an RTSP M4 request message).
|
||||
0b01; the unit is a mouse notch (where the application is responsible for representing the number of pixels per notch).
|
||||
0b10-0b11; Reserved.
|
||||
|
||||
B13; Scroll Direction Indication bit.
|
||||
0b0; Scrolling to the right. Scrolling to the right means the displayed content being shifted to the left from a user perspective.
|
||||
0b1; Scrolling to the left. Scrolling to the left means the displayed content being shifted to the right from a user perspective.
|
||||
|
||||
B12:B0; Number of Scroll bits.
|
||||
Number of units for a Horizontal scroll.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
temp = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericScalePacket unit=[%d]\n", temp);
|
||||
outData[7] = (temp >> 8) & 0xFF;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
temp = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericScalePacket direction=[%d]\n", temp);
|
||||
outData[7] |= ((temp >> 10) & 0xFF);
|
||||
break;
|
||||
|
||||
}
|
||||
case 3: {
|
||||
temp = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericScalePacket amount to scroll=[%d]\n", temp);
|
||||
outData[7] |= ((temp >> 12) & 0xFF);
|
||||
outData[8] = temp & 0xFF;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(*(splitedStr + i));
|
||||
}
|
||||
|
||||
free(splitedStr);
|
||||
}
|
||||
//hexdump(outData, uibcBodyLen);
|
||||
uibcmessage->m_DataValid = true;
|
||||
uibcmessage->m_PacketDataLen = uibcBodyLen;
|
||||
}
|
||||
|
||||
// format: "typeId, integer part, fraction part"
|
||||
void getUIBCGenericRotatePacket(const char * inEventDesc, UibcMessage* uibcmessage) {
|
||||
log_info("getUIBCGenericRotatePacket (%s)", inEventDesc);
|
||||
char* outData = uibcmessage->m_PacketData;
|
||||
int32_t typeId;
|
||||
int32_t uibcBodyLen, genericPacketLen;
|
||||
int32_t integerPart, FractionPart;
|
||||
size_t size;
|
||||
|
||||
char** splitedStr = str_split((char*)inEventDesc, ",", &size);
|
||||
|
||||
if (splitedStr) {
|
||||
int i;
|
||||
for (i = 0; * (splitedStr + i); i++) {
|
||||
//log_info("getUIBCGenericRotatePacket splitedStr tokens=[%s]\n", *(splitedStr + i));
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
typeId = atoi(*(splitedStr + i));
|
||||
//log_info("getUIBCGenericRotatePacket typeId=[%d]\n", typeId);
|
||||
genericPacketLen = 2;
|
||||
uibcBodyLen = genericPacketLen + 7; // Generic herder leh = 7
|
||||
outData = (char*)malloc(uibcBodyLen + 1);
|
||||
// UIBC header
|
||||
outData[0] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[1] = 0x00; //Version (3 bits),T (1 bit),Reserved(8 bits),Input Category (4 bits)
|
||||
outData[2] = (uibcBodyLen >> 8) & 0xFF; //Length(16 bits)
|
||||
outData[3] = uibcBodyLen & 0xFF; //Length(16 bits)
|
||||
//Generic Input Body Format
|
||||
outData[4] = typeId & 0xFF; // Tyoe ID, 1 octet
|
||||
outData[5] = (genericPacketLen >> 8) & 0xFF; // Length, 2 octets
|
||||
outData[6] = genericPacketLen & 0xFF; // Length, 2 octets
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
integerPart = atoi(*(splitedStr + i));
|
||||
outData[7] = integerPart & 0xFF;
|
||||
//log_info("getUIBCGenericRotatePacket integerPart=[%d]\n", integerPart);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
FractionPart = atoi(*(splitedStr + i));
|
||||
outData[8] = FractionPart & 0xFF;
|
||||
//log_info("getUIBCGenericRotatePacket FractionPart=[%d]\n", FractionPart);
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(*(splitedStr + i));
|
||||
}
|
||||
|
||||
free(splitedStr);
|
||||
}
|
||||
//hexdump(outData, uibcBodyLen);
|
||||
uibcmessage->m_DataValid = true;
|
||||
uibcmessage->m_PacketDataLen = uibcBodyLen;
|
||||
}
|
||||
|
||||
|
||||
char** str_split(char* pStr, const char* pDelim, size_t* size) {
|
||||
char** result = 0;
|
||||
size_t count = 0;
|
||||
char* tmp = pStr;
|
||||
char* tmpStr = NULL;
|
||||
char* last_comma = 0;
|
||||
|
||||
asprintf(&tmpStr, "%s", pStr);
|
||||
|
||||
/* Count how many elements will be extracted. */
|
||||
while (*tmp) {
|
||||
if (*pDelim == *tmp) {
|
||||
count++;
|
||||
last_comma = tmp;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
|
||||
/* Add space for trailing token. */
|
||||
count += last_comma < (pStr + strlen(pStr) - 1) ? 1 : 0;
|
||||
|
||||
result = (char**)malloc(sizeof(char*) * count);
|
||||
|
||||
*size = count;
|
||||
|
||||
tmp = tmpStr = strdup(pStr);
|
||||
size_t idx = 0;
|
||||
char* token;
|
||||
while ((token = strsep(&tmp, pDelim)) != NULL) {
|
||||
* (result + idx++) = strdup(token);
|
||||
}
|
||||
free(tmpStr);
|
||||
return result;
|
||||
}
|
48
src/uibc/miracle-uibcctl.h
Normal file
48
src/uibc/miracle-uibcctl.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
#ifndef MIRACLE_UIBCCTL_H
|
||||
#define MIRACLE_UIBCCTL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include<arpa/inet.h>
|
||||
#include <math.h>
|
||||
#include "shl_log.h"
|
||||
|
||||
typedef enum {
|
||||
GENERIC_TOUCH_DOWN = 0,
|
||||
GENERIC_TOUCH_UP,
|
||||
GENERIC_TOUCH_MOVE,
|
||||
GENERIC_KEY_DOWN,
|
||||
GENERIC_KEY_UP,
|
||||
GENERIC_ZOOM,
|
||||
GENERIC_VERTICAL_SCROLL,
|
||||
GENERIC_HORIZONTAL_SCROLL,
|
||||
GENERIC_ROTATE
|
||||
} MessageType;
|
||||
|
||||
typedef struct {
|
||||
char* m_PacketData;
|
||||
size_t m_PacketDataLen;
|
||||
bool m_DataValid;
|
||||
} UibcMessage;
|
||||
|
||||
UibcMessage buildUibcMessage(MessageType type, const char* inEventDesc, double widthRatio, double heightRatio);
|
||||
|
||||
static char** str_split(char* pStr, const char* pDelim, size_t* size);
|
||||
|
||||
void getUIBCGenericTouchPacket(const char *inEventDesc, UibcMessage* uibcmessage, double widthRatio, double heightRatio);
|
||||
void getUIBCGenericKeyPacket(const char *inEventDesc, UibcMessage* uibcmessage);
|
||||
void getUIBCGenericZoomPacket(const char *inEventDesc,UibcMessage* uibcmessage);
|
||||
void getUIBCGenericScalePacket(const char *inEventDesc, UibcMessage* uibcmessage);
|
||||
void getUIBCGenericRotatePacket(const char *inEventDesc, UibcMessage* uibcmessage);
|
||||
|
||||
void hexdump(void *_data, size_t len);
|
||||
void binarydump(void *_data, size_t len);
|
||||
|
||||
int sendUibcMessage(UibcMessage* uibcmessage, int sockfd);
|
||||
#endif
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
########### next target ###############
|
||||
|
||||
set(miracle-wifid_SRCS wifid.h
|
||||
wifid.c
|
||||
wifid-dbus.c
|
||||
|
@ -12,6 +9,7 @@ add_executable(miracle-wifid ${miracle-wifid_SRCS})
|
|||
|
||||
target_link_libraries(miracle-wifid ${KDE4_KDECORE_LIBS})
|
||||
|
||||
cmake_policy(SET CMP0015 NEW)
|
||||
include_directories(shared)
|
||||
link_directories(shared)
|
||||
target_link_libraries(miracle-wifid miracle-shared)
|
||||
|
@ -19,40 +17,11 @@ target_link_libraries(miracle-wifid miracle-shared)
|
|||
find_package(PkgConfig)
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
pkg_check_modules (UDEV REQUIRED libudev)
|
||||
#link_directories( ${UDEV_LIBRARY_DIRS})
|
||||
#include_directories( ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(miracle-wifid ${UDEV_LIBRARIES})
|
||||
#link_directories( ${GLIB2_LIBRARY_DIRS})
|
||||
#include_directories( ${GLIB2_INCLUDE_DIRS})
|
||||
target_link_libraries(miracle-wifid m)
|
||||
link_directories( ${GLIB2_LIBRARY_DIRS})
|
||||
include_directories( ${GLIB2_INCLUDE_DIRS})
|
||||
target_link_libraries(miracle-wifid ${GLIB2_LIBRARIES})
|
||||
|
||||
install(TARGETS miracle-wifid DESTINATION bin)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
########### install files ###############
|
||||
|
||||
#set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake-extensions/ )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#bin_PROGRAMS = miracle-wifid
|
||||
#
|
||||
#miracle_wifid_SOURCES = \
|
||||
# wifid.h \
|
||||
# wifid.c \
|
||||
# wifid-dbus.c \
|
||||
# wifid-link.c \
|
||||
# wifid-peer.c \
|
||||
# wifid-supplicant.c
|
||||
#miracle_wifid_CPPFLAGS = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS)
|
||||
#miracle_wifid_LDADD = \
|
||||
# ../shared/libmiracle-shared.la \
|
||||
# $(DEPS_LIBS)
|
||||
#
|
||||
|
|
|
@ -10,8 +10,10 @@ miracle_wifid_SOURCES = \
|
|||
wifid-supplicant.c
|
||||
miracle_wifid_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS)
|
||||
$(DEPS_CFLAGS) \
|
||||
$(GLIB_CFLAGS)
|
||||
miracle_wifid_LDADD = \
|
||||
../shared/libmiracle-shared.la \
|
||||
$(DEPS_LIBS)
|
||||
$(DEPS_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
|
||||
|
|
14
src/wifi/meson.build
Normal file
14
src/wifi/meson.build
Normal file
|
@ -0,0 +1,14 @@
|
|||
inc = include_directories('../..')
|
||||
miracle_wifid_src = ['wifid.h',
|
||||
'wifid.c',
|
||||
'wifid-dbus.c',
|
||||
'wifid-link.c',
|
||||
'wifid-peer.c',
|
||||
'wifid-supplicant.c'
|
||||
]
|
||||
executable('miracle-wifid', miracle_wifid_src,
|
||||
include_directories: inc,
|
||||
install: true,
|
||||
dependencies: [udev, glib2, libsystemd, libmiracle_shared_dep, m]
|
||||
)
|
||||
|
|
@ -309,6 +309,7 @@ static const sd_bus_vtable peer_dbus_vtable[] = {
|
|||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_SIGNAL("ProvisionDiscovery", "ss", 0),
|
||||
SD_BUS_SIGNAL("GoNegRequest", "ss", 0),
|
||||
SD_BUS_SIGNAL("FormationFailure", "s", 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -570,6 +571,42 @@ static int link_dbus_set_friendly_name(sd_bus *bus,
|
|||
return link_set_friendly_name(l, name);
|
||||
}
|
||||
|
||||
static int link_dbus_get_managed(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_append(reply, "b", link_get_managed(l));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_dbus_set_managed(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *value,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int val, r;
|
||||
|
||||
r = sd_bus_message_read(value, "b", &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_set_managed(l, val);
|
||||
}
|
||||
|
||||
static int link_dbus_get_p2p_scanning(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
|
@ -661,6 +698,12 @@ static const sd_bus_vtable link_dbus_vtable[] = {
|
|||
link_dbus_set_friendly_name,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("Managed",
|
||||
"b",
|
||||
link_dbus_get_managed,
|
||||
link_dbus_set_managed,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("P2PScanning",
|
||||
"b",
|
||||
link_dbus_get_p2p_scanning,
|
||||
|
@ -894,8 +937,12 @@ int manager_dbus_connect(struct manager *m)
|
|||
|
||||
r = sd_bus_request_name(m->bus, "org.freedesktop.miracle.wifi", 0);
|
||||
if (r < 0) {
|
||||
log_error("cannot claim org.freedesktop.miracle.wifi bus-name: %d",
|
||||
if (r == -EEXIST) {
|
||||
log_info("cannot claim org.freedesktop.miracle.wifi bus-name: it is already being acquired");
|
||||
} else {
|
||||
log_error("cannot claim org.freedesktop.miracle.wifi bus-name: %d",
|
||||
r);
|
||||
}
|
||||
goto error_silent;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ int link_new(struct manager *m,
|
|||
if (out)
|
||||
*out = l;
|
||||
|
||||
l->public = true;
|
||||
link_dbus_added(l);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
@ -116,6 +118,9 @@ void link_free(struct link *l)
|
|||
|
||||
link_set_managed(l, false);
|
||||
|
||||
link_dbus_removed(l);
|
||||
l->public = false;
|
||||
|
||||
if (shl_htable_remove_uint(&l->m->links, l->ifindex, NULL)) {
|
||||
log_info("remove link: %s", l->ifname);
|
||||
--l->m->link_cnt;
|
||||
|
@ -129,17 +134,66 @@ void link_free(struct link *l)
|
|||
free(l->wfd_subelements);
|
||||
free(l->friendly_name);
|
||||
free(l->ifname);
|
||||
free(l->config_methods);
|
||||
free(l->ip_binary);
|
||||
free(l);
|
||||
}
|
||||
|
||||
void link_set_managed(struct link *l, bool set)
|
||||
void link_use_dev(struct link *l)
|
||||
{
|
||||
l->use_dev = true;
|
||||
}
|
||||
|
||||
bool link_is_using_dev(struct link *l)
|
||||
{
|
||||
return l->use_dev;
|
||||
}
|
||||
|
||||
int link_set_config_methods(struct link *l, char *config_methods)
|
||||
{
|
||||
char *cm;
|
||||
|
||||
if (!config_methods)
|
||||
return log_EINVAL();
|
||||
|
||||
cm = strdup(config_methods);
|
||||
if (!cm)
|
||||
return log_ENOMEM();
|
||||
|
||||
free(l->config_methods);
|
||||
l->config_methods = cm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_set_ip_binary(struct link *l, const char *ip_binary)
|
||||
{
|
||||
char *ipb;
|
||||
|
||||
if (!ip_binary)
|
||||
return log_EINVAL();
|
||||
|
||||
ipb = strdup(ip_binary);
|
||||
if (!ipb)
|
||||
return log_ENOMEM();
|
||||
|
||||
free(l->ip_binary);
|
||||
l->ip_binary = ipb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool link_get_managed(struct link *l)
|
||||
{
|
||||
return l->managed;
|
||||
}
|
||||
|
||||
int link_set_managed(struct link *l, bool set)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!l)
|
||||
return log_vEINVAL();
|
||||
return log_EINVAL();
|
||||
if (l->managed == set)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (set) {
|
||||
log_info("manage link %s", l->ifname);
|
||||
|
@ -147,7 +201,7 @@ void link_set_managed(struct link *l, bool set)
|
|||
r = supplicant_start(l->s);
|
||||
if (r < 0) {
|
||||
log_error("cannot start supplicant on %s", l->ifname);
|
||||
return;
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
log_info("link %s no longer managed", l->ifname);
|
||||
|
@ -155,6 +209,7 @@ void link_set_managed(struct link *l, bool set)
|
|||
}
|
||||
|
||||
l->managed = set;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_renamed(struct link *l, const char *ifname)
|
||||
|
@ -224,6 +279,9 @@ int link_set_wfd_subelements(struct link *l, const char *val)
|
|||
if (!l || !val)
|
||||
return log_EINVAL();
|
||||
|
||||
if (!l->managed)
|
||||
return log_EUNMANAGED();
|
||||
|
||||
t = strdup(val);
|
||||
if (!t)
|
||||
return log_ENOMEM();
|
||||
|
@ -256,6 +314,9 @@ int link_set_p2p_scanning(struct link *l, bool set)
|
|||
if (!l)
|
||||
return log_EINVAL();
|
||||
|
||||
if (!l->managed)
|
||||
return log_EUNMANAGED();
|
||||
|
||||
if (set) {
|
||||
return supplicant_p2p_start_scan(l->s);
|
||||
} else {
|
||||
|
@ -266,7 +327,16 @@ int link_set_p2p_scanning(struct link *l, bool set)
|
|||
|
||||
bool link_get_p2p_scanning(struct link *l)
|
||||
{
|
||||
return l && supplicant_p2p_scanning(l->s);
|
||||
if (!l) {
|
||||
log_vEINVAL();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!l->managed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return supplicant_p2p_scanning(l->s);
|
||||
}
|
||||
|
||||
void link_supplicant_started(struct link *l)
|
||||
|
@ -274,9 +344,9 @@ void link_supplicant_started(struct link *l)
|
|||
if (!l || l->public)
|
||||
return;
|
||||
|
||||
log_debug("link %s started", l->ifname);
|
||||
l->public = true;
|
||||
link_dbus_added(l);
|
||||
if (l->m->friendly_name && l->managed)
|
||||
link_set_friendly_name(l, l->m->friendly_name);
|
||||
log_info("link %s managed", l->ifname);
|
||||
}
|
||||
|
||||
void link_supplicant_stopped(struct link *l)
|
||||
|
@ -284,9 +354,7 @@ void link_supplicant_stopped(struct link *l)
|
|||
if (!l || !l->public)
|
||||
return;
|
||||
|
||||
log_debug("link %s stopped", l->ifname);
|
||||
link_dbus_removed(l);
|
||||
l->public = false;
|
||||
log_info("link %s unmanaged", l->ifname);
|
||||
}
|
||||
|
||||
void link_supplicant_p2p_scan_changed(struct link *l, bool new_value)
|
||||
|
|
|
@ -61,7 +61,8 @@ int peer_new(struct link *l,
|
|||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
strncpy(p->p2p_mac, mac, MAC_STRLEN - 1);
|
||||
strncpy(p->p2p_mac, mac, MAC_STRLEN);
|
||||
p->p2p_mac[MAC_STRLEN - 1] = 0;
|
||||
|
||||
r = shl_htable_insert_str(&l->peers, &p->p2p_mac, NULL);
|
||||
if (r < 0) {
|
||||
|
|
|
@ -19,14 +19,21 @@
|
|||
|
||||
#define LOG_SUBSYSTEM "supplicant"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <systemd/sd-event.h>
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
#include <systemd/sd-journal.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include "shl_dlist.h"
|
||||
#include "shl_log.h"
|
||||
|
@ -34,7 +41,6 @@
|
|||
#include "util.h"
|
||||
#include "wifid.h"
|
||||
#include "wpas.h"
|
||||
#include "config.h"
|
||||
|
||||
struct supplicant_group {
|
||||
unsigned long users;
|
||||
|
@ -373,6 +379,7 @@ static int supplicant_group_spawn_dhcp_server(struct supplicant_group *g,
|
|||
sigemptyset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
/* redirect stdout/stderr to journal */
|
||||
sprintf(journal_id, "miracle-dhcp-%s", g->ifname);
|
||||
fd_journal = sd_journal_stream_fd(journal_id, LOG_INFO, false);
|
||||
|
@ -381,12 +388,15 @@ static int supplicant_group_spawn_dhcp_server(struct supplicant_group *g,
|
|||
dup2(fd_journal, 1);
|
||||
dup2(fd_journal, 2);
|
||||
} else {
|
||||
#endif
|
||||
/* no journal? redirect stdout to parent's stderr */
|
||||
dup2(2, 1);
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
}
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
argv[i++] = (char*) BUILD_BINDIR "/miracle-dhcp";
|
||||
argv[i++] = (char*) "miracle-dhcp";
|
||||
argv[i++] = "--server";
|
||||
argv[i++] = "--prefix";
|
||||
argv[i++] = prefix;
|
||||
|
@ -396,9 +406,15 @@ static int supplicant_group_spawn_dhcp_server(struct supplicant_group *g,
|
|||
argv[i++] = g->ifname;
|
||||
argv[i++] = "--comm-fd";
|
||||
argv[i++] = commfd;
|
||||
if (g->s->l->ip_binary) {
|
||||
argv[i++] = "--ip-binary";
|
||||
argv[i++] = g->s->l->ip_binary;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
execve(argv[0], argv, environ);
|
||||
if (execvpe(argv[0], argv, environ)< 0) {
|
||||
log_error("dhcp failed (%d): %m", errno);
|
||||
}
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
@ -435,6 +451,7 @@ static int supplicant_group_spawn_dhcp_client(struct supplicant_group *g)
|
|||
sigemptyset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
/* redirect stdout/stderr to journal */
|
||||
sprintf(journal_id, "miracle-dhcp-%s", g->ifname);
|
||||
fd_journal = sd_journal_stream_fd(journal_id, LOG_INFO, false);
|
||||
|
@ -443,21 +460,30 @@ static int supplicant_group_spawn_dhcp_client(struct supplicant_group *g)
|
|||
dup2(fd_journal, 1);
|
||||
dup2(fd_journal, 2);
|
||||
} else {
|
||||
#endif
|
||||
/* no journal? redirect stdout to parent's stderr */
|
||||
dup2(2, 1);
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
}
|
||||
#endif
|
||||
|
||||
i = 0;
|
||||
argv[i++] = (char*) BUILD_BINDIR "/miracle-dhcp";
|
||||
argv[i++] = (char*) "miracle-dhcp";
|
||||
argv[i++] = "--log-level";
|
||||
argv[i++] = loglevel;
|
||||
argv[i++] = "--netdev";
|
||||
argv[i++] = g->ifname;
|
||||
argv[i++] = "--comm-fd";
|
||||
argv[i++] = commfd;
|
||||
if (g->s->l->ip_binary) {
|
||||
argv[i++] = "--ip-binary";
|
||||
argv[i++] = g->s->l->ip_binary;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
execve(argv[0], argv, environ);
|
||||
if (execvpe(argv[0], argv, environ) < 0) {
|
||||
log_error("dhcp failed (%d): %m", errno);
|
||||
}
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
@ -504,7 +530,7 @@ static int supplicant_group_new(struct supplicant *s,
|
|||
j = shl_dlist_entry(i,
|
||||
struct supplicant_group,
|
||||
list);
|
||||
if (j->subnet == j->subnet)
|
||||
if (j->subnet == subnet)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -871,7 +897,7 @@ static void supplicant_parse_peer(struct supplicant *s,
|
|||
/* TODO: wfd_dev_info only contains the dev-info sub-elem,
|
||||
* while wfd_sublemens contains all. Fix that! The user has no
|
||||
* chance to distinguish both.
|
||||
* We currently use it only as boolen (set/unset) but once we
|
||||
* We currently use it only as boolean (set/unset) but once we
|
||||
* parse it we _definitely_ have to provide proper data. */
|
||||
r = wpas_message_dict_read(m, "wfd_dev_info", 's', &val);
|
||||
if (r >= 0) {
|
||||
|
@ -1287,6 +1313,20 @@ static void supplicant_event_p2p_group_removed(struct supplicant *s,
|
|||
supplicant_group_free(g);
|
||||
}
|
||||
|
||||
static void supplicant_event_p2p_go_neg_failure(struct supplicant *s,
|
||||
struct wpas_message *ev)
|
||||
{
|
||||
struct peer *p;
|
||||
|
||||
if (s->pending) {
|
||||
log_debug("peer %s group owner negotiation failed",
|
||||
s->pending->friendly_name);
|
||||
p = s->pending->p;
|
||||
s->pending = NULL;
|
||||
peer_supplicant_formation_failure(p, "group owner negotiation failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void supplicant_event_p2p_group_formation_failure(struct supplicant *s,
|
||||
struct wpas_message *ev)
|
||||
{
|
||||
|
@ -1432,7 +1472,6 @@ static void supplicant_event(struct supplicant *s, struct wpas_message *m)
|
|||
!strcmp(name, "WPS-AP-AVAILABLE-PIN") ||
|
||||
!strcmp(name, "CTRL-EVENT-EAP-STATUS") ||
|
||||
!strcmp(name, "CTRL-EVENT-EAP-METHOD") ||
|
||||
!strcmp(name, "CTRL-EVENT-EAP-STATUS") ||
|
||||
!strcmp(name, "WPS-CRED-RECEIVED") ||
|
||||
!strcmp(name, "WPS-AP-AVAILABLE") ||
|
||||
!strcmp(name, "WPS-REG-SUCCESS") ||
|
||||
|
@ -1467,6 +1506,8 @@ static void supplicant_event(struct supplicant *s, struct wpas_message *m)
|
|||
supplicant_event_p2p_group_started(s, m);
|
||||
else if (!strcmp(name, "P2P-GROUP-REMOVED"))
|
||||
supplicant_event_p2p_group_removed(s, m);
|
||||
else if (!strcmp(name, "P2P-GO-NEG-FAILURE"))
|
||||
supplicant_event_p2p_go_neg_failure(s, m);
|
||||
else if (!strcmp(name, "P2P-GROUP-FORMATION-FAILURE"))
|
||||
supplicant_event_p2p_group_formation_failure(s, m);
|
||||
else if (!strcmp(name, "AP-STA-CONNECTED"))
|
||||
|
@ -2142,6 +2183,9 @@ static int supplicant_global_fn(struct wpas *w,
|
|||
}
|
||||
|
||||
/* ignore events on the global-iface, we only listen on dev-iface */
|
||||
if(link_is_using_dev(s->l) && wpas_message_get_ifname(m)) {
|
||||
supplicant_event(s, m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -2188,7 +2232,7 @@ static int supplicant_global_attach_fn(struct wpas *w,
|
|||
* Devices with P2P_DEVICE support (instead of direct P2P_GO/CLIENT
|
||||
* support) are broken with a *lot* of wpa_supplicant versions on the
|
||||
* global interface. Therefore, try to open the p2p-dev-* interface
|
||||
* after the global-ATTACH succeded (which means the iface is properly
|
||||
* after the global-ATTACH succeeded (which means the iface is properly
|
||||
* set up). If this works, use the p2p-dev-* interface, otherwise, just
|
||||
* copy the global interface over to bus_dev.
|
||||
* Event-forwarding is broken on the global-interface in such cases,
|
||||
|
@ -2356,6 +2400,7 @@ static void supplicant_run(struct supplicant *s, const char *binary)
|
|||
sigemptyset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
/* redirect stdout/stderr to journal */
|
||||
sprintf(journal_id, "miracle-wifid-%s-%u",
|
||||
s->l->ifname, s->l->ifindex);
|
||||
|
@ -2365,9 +2410,12 @@ static void supplicant_run(struct supplicant *s, const char *binary)
|
|||
dup2(fd_journal, 1);
|
||||
dup2(fd_journal, 2);
|
||||
} else {
|
||||
#endif
|
||||
/* no journal? redirect stdout to parent's stderr */
|
||||
dup2(2, 1);
|
||||
#ifdef ENABLE_SYSTEMD
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize wpa_supplicant args */
|
||||
i = 0;
|
||||
|
@ -2391,12 +2439,60 @@ static void supplicant_run(struct supplicant *s, const char *binary)
|
|||
argv[i++] = s->l->ifname;
|
||||
argv[i++] = "-g";
|
||||
argv[i++] = s->global_ctrl;
|
||||
|
||||
if (arg_wpa_syslog) {
|
||||
argv[i++] = "-s";
|
||||
}
|
||||
|
||||
argv[i] = NULL;
|
||||
|
||||
/* execute wpa_supplicant; if it fails, the caller issues exit(1) */
|
||||
execve(argv[0], argv, environ);
|
||||
}
|
||||
|
||||
static int supplicant_find(char **binary)
|
||||
{
|
||||
_shl_free_ char *path = getenv("PATH");
|
||||
if(!path) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
path = strdup(path);
|
||||
if(!path) {
|
||||
return log_ENOMEM();
|
||||
}
|
||||
|
||||
struct stat bin_stat;
|
||||
char *curr = path, *next;
|
||||
while(1) {
|
||||
curr = strtok_r(curr, ":", &next);
|
||||
if(!curr) {
|
||||
break;
|
||||
}
|
||||
|
||||
_shl_free_ char *bin = shl_strcat(curr, "/wpa_supplicant");
|
||||
if (!bin)
|
||||
return log_ENOMEM();
|
||||
|
||||
if(stat(bin, &bin_stat) < 0) {
|
||||
if(ENOENT == errno || ENOTDIR == errno) {
|
||||
goto end;
|
||||
}
|
||||
return log_ERRNO();
|
||||
}
|
||||
|
||||
if (!access(bin, X_OK)) {
|
||||
*binary = strdup(bin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
end:
|
||||
curr = NULL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int supplicant_spawn(struct supplicant *s)
|
||||
{
|
||||
_shl_free_ char *binary = NULL;
|
||||
|
@ -2410,14 +2506,16 @@ static int supplicant_spawn(struct supplicant *s)
|
|||
|
||||
log_debug("spawn supplicant of %s", s->l->ifname);
|
||||
|
||||
binary = shl_strcat(arg_wpa_bindir, "/wpa_supplicant");
|
||||
if (!binary)
|
||||
return log_ENOMEM();
|
||||
|
||||
if (access(binary, X_OK) < 0) {
|
||||
log_error("execution of wpas (%s) not possible: %m", binary);
|
||||
return -EINVAL;
|
||||
if (supplicant_find(&binary) < 0) {
|
||||
if (binary != NULL) {
|
||||
log_error("execution of wpas (%s) not possible: %m", binary);
|
||||
} else {
|
||||
log_error("execution of wpas not possible: %m");
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_info("wpa_supplicant found: %s", binary);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
|
@ -2532,10 +2630,9 @@ static int supplicant_write_config(struct supplicant *s)
|
|||
"driver_param=%s\n"
|
||||
"ap_scan=%s\n"
|
||||
"# End of configuration\n",
|
||||
s->l->friendly_name ? : "unknown",
|
||||
s->l->friendly_name ?: "unknown",
|
||||
"1-0050F204-1",
|
||||
"pbc",
|
||||
//"pbc keypad pin display",
|
||||
s->l->config_methods ?: "pbc",
|
||||
"p2p_device=1",
|
||||
"1");
|
||||
if (r < 0) {
|
||||
|
|
110
src/wifi/wifid.c
110
src/wifi/wifid.c
|
@ -40,9 +40,16 @@
|
|||
#include "wifid.h"
|
||||
#include "config.h"
|
||||
|
||||
const char *arg_wpa_bindir = "/usr/bin";
|
||||
#define XSTR(x) STR(x)
|
||||
#define STR(x) #x
|
||||
const char *interface_name = NULL;
|
||||
const char *config_methods = NULL;
|
||||
unsigned int arg_wpa_loglevel = LOG_NOTICE;
|
||||
bool arg_wpa_syslog = false;
|
||||
bool use_dev = false;
|
||||
bool lazy_managed = false;
|
||||
const char *arg_ip_binary = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Manager Handling
|
||||
|
@ -101,13 +108,22 @@ static void manager_add_udev_link(struct manager *m,
|
|||
if (r < 0)
|
||||
return;
|
||||
|
||||
link_set_friendly_name(l, m->friendly_name);
|
||||
if (m->friendly_name && l->managed)
|
||||
link_set_friendly_name(l, m->friendly_name);
|
||||
if (m->config_methods)
|
||||
link_set_config_methods(l, m->config_methods);
|
||||
|
||||
if(use_dev)
|
||||
link_use_dev(l);
|
||||
if(arg_ip_binary)
|
||||
link_set_ip_binary(l, arg_ip_binary);
|
||||
|
||||
#ifdef RELY_UDEV
|
||||
if (udev_device_has_tag(d, "miracle")) {
|
||||
bool managed = udev_device_has_tag(d, "miracle") && !lazy_managed;
|
||||
#else
|
||||
if (!interface_name || !strcmp(interface_name, ifname)) {
|
||||
bool managed = (!interface_name || !strcmp(interface_name, ifname)) && !lazy_managed;
|
||||
#endif
|
||||
if (managed) {
|
||||
link_set_managed(l, true);
|
||||
} else {
|
||||
log_debug("ignored device: %s", ifname);
|
||||
|
@ -147,12 +163,12 @@ static int manager_udev_fn(sd_event_source *source,
|
|||
}
|
||||
|
||||
#ifdef RELY_UDEV
|
||||
if (udev_device_has_tag(d, "miracle"))
|
||||
if (udev_device_has_tag(d, "miracle") && !lazy_managed)
|
||||
link_set_managed(l, true);
|
||||
else
|
||||
link_set_managed(l, false);
|
||||
#else
|
||||
if (!interface_name || !strcmp(interface_name, ifname)) {
|
||||
if ((!interface_name || !strcmp(interface_name, ifname)) && !lazy_managed) {
|
||||
link_set_managed(l, true);
|
||||
} else {
|
||||
log_debug("ignored device: %s", ifname);
|
||||
|
@ -212,6 +228,7 @@ static void manager_free(struct manager *m)
|
|||
sd_event_unref(m->event);
|
||||
|
||||
free(m->friendly_name);
|
||||
free(m->config_methods);
|
||||
free(m);
|
||||
}
|
||||
|
||||
|
@ -224,6 +241,7 @@ static int manager_new(struct manager **out)
|
|||
unsigned int i;
|
||||
sigset_t mask;
|
||||
int r;
|
||||
char *cm;
|
||||
|
||||
m = calloc(1, sizeof(*m));
|
||||
if (!m)
|
||||
|
@ -231,6 +249,16 @@ static int manager_new(struct manager **out)
|
|||
|
||||
shl_htable_init_uint(&m->links);
|
||||
|
||||
|
||||
if (config_methods) {
|
||||
cm = strdup(config_methods);
|
||||
if (!cm)
|
||||
return log_ENOMEM();
|
||||
|
||||
free(m->config_methods);
|
||||
m->config_methods = cm;
|
||||
}
|
||||
|
||||
r = sd_event_default(&m->event);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
|
@ -454,11 +482,16 @@ static int help(void)
|
|||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
" --log-date-time Prefix log-messages with date time\n"
|
||||
"\n"
|
||||
" -i --interface Choose the interface to use\n"
|
||||
" --config-methods Define config methods for pairing, default 'pbc'\n"
|
||||
"\n"
|
||||
" --wpa-bindir <dir> wpa_supplicant binary dir [/usr/bin]\n"
|
||||
" --wpa-loglevel <lvl wpa_supplicant log-level\n"
|
||||
" --wpa-loglevel <lvl> wpa_supplicant log-level\n"
|
||||
" --wpa-syslog wpa_supplicant use syslog\n"
|
||||
" --use-dev enable workaround for 'no ifname' issue\n"
|
||||
" --lazy-managed manage interface only when user decide to do\n"
|
||||
" --ip-binary <path> path to 'ip' binary [default: "XSTR(IP_BINARY)"]\n"
|
||||
, program_invocation_short_name);
|
||||
/*
|
||||
* 80-char barrier:
|
||||
|
@ -474,19 +507,28 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
|
||||
ARG_WPA_BINDIR,
|
||||
ARG_LOG_DATE_TIME,
|
||||
ARG_WPA_LOGLEVEL,
|
||||
ARG_WPA_SYSLOG,
|
||||
ARG_USE_DEV,
|
||||
ARG_CONFIG_METHODS,
|
||||
ARG_LAZY_MANAGED,
|
||||
ARG_IP_BINARY,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
{ "log-date-time", no_argument, NULL, ARG_LOG_DATE_TIME },
|
||||
|
||||
{ "wpa-bindir", required_argument, NULL, ARG_WPA_BINDIR },
|
||||
{ "wpa-loglevel", required_argument, NULL, ARG_WPA_LOGLEVEL },
|
||||
{ "wpa-syslog", no_argument, NULL, ARG_WPA_SYSLOG },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "use-dev", no_argument, NULL, ARG_USE_DEV },
|
||||
{ "config-methods", required_argument, NULL, ARG_CONFIG_METHODS },
|
||||
{ "lazy-managed", no_argument, NULL, ARG_LAZY_MANAGED },
|
||||
{ "ip-binary", required_argument, NULL, ARG_IP_BINARY },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
@ -507,13 +549,27 @@ static int parse_argv(int argc, char *argv[])
|
|||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
|
||||
case ARG_WPA_BINDIR:
|
||||
arg_wpa_bindir = optarg;
|
||||
case ARG_LOG_DATE_TIME:
|
||||
log_date_time = true;
|
||||
break;
|
||||
case ARG_USE_DEV:
|
||||
use_dev = true;
|
||||
break;
|
||||
case ARG_CONFIG_METHODS:
|
||||
config_methods = optarg;
|
||||
break;
|
||||
case ARG_LAZY_MANAGED:
|
||||
lazy_managed = true;
|
||||
break;
|
||||
case ARG_WPA_LOGLEVEL:
|
||||
arg_wpa_loglevel = log_parse_arg(optarg);
|
||||
break;
|
||||
case ARG_WPA_SYSLOG:
|
||||
arg_wpa_syslog = true;
|
||||
break;
|
||||
case ARG_IP_BINARY:
|
||||
arg_ip_binary = optarg;
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -539,12 +595,30 @@ int main(int argc, char **argv)
|
|||
|
||||
srand(time(NULL));
|
||||
|
||||
GKeyFile* gkf = load_ini_file();
|
||||
|
||||
if (gkf) {
|
||||
gchar* log_level;
|
||||
log_level = g_key_file_get_string (gkf, "wifid", "log-level", NULL);
|
||||
if (log_level) {
|
||||
log_max_sev = log_parse_arg(log_level);
|
||||
g_free(log_level);
|
||||
}
|
||||
g_key_file_free(gkf);
|
||||
}
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
if (!r)
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
if (getuid() != 0) {
|
||||
r = EACCES;
|
||||
log_notice("Must run as root");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = manager_new(&m);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
|
|
@ -129,12 +129,15 @@ struct link {
|
|||
char *ifname;
|
||||
char *friendly_name;
|
||||
char *wfd_subelements;
|
||||
char *config_methods;
|
||||
char *ip_binary;
|
||||
|
||||
size_t peer_cnt;
|
||||
struct shl_htable peers;
|
||||
|
||||
bool managed : 1;
|
||||
bool public : 1;
|
||||
bool use_dev : 1;
|
||||
};
|
||||
|
||||
#define link_from_htable(_l) \
|
||||
|
@ -153,9 +156,17 @@ int link_new(struct manager *m,
|
|||
struct link **out);
|
||||
void link_free(struct link *l);
|
||||
|
||||
void link_set_managed(struct link *l, bool set);
|
||||
/* workaround for the 'no ifname' issue */
|
||||
void link_use_dev(struct link *l);
|
||||
bool link_is_using_dev(struct link *l);
|
||||
|
||||
int link_set_ip_binary(struct link *l, const char *ip_binary);
|
||||
|
||||
int link_set_managed(struct link *l, bool set);
|
||||
bool link_get_managed(struct link *l);
|
||||
int link_renamed(struct link *l, const char *ifname);
|
||||
|
||||
int link_set_config_methods(struct link *l, char *config_methods);
|
||||
int link_set_friendly_name(struct link *l, const char *name);
|
||||
const char *link_get_friendly_name(struct link *l);
|
||||
int link_set_wfd_subelements(struct link *l, const char *val);
|
||||
|
@ -183,6 +194,7 @@ struct manager {
|
|||
sd_event_source *udev_mon_source;
|
||||
|
||||
char *friendly_name;
|
||||
char *config_methods;
|
||||
|
||||
size_t link_cnt;
|
||||
struct shl_htable links;
|
||||
|
@ -203,7 +215,7 @@ void manager_dbus_disconnect(struct manager *m);
|
|||
|
||||
/* cli arguments */
|
||||
|
||||
extern const char *arg_wpa_bindir;
|
||||
extern unsigned int arg_wpa_loglevel;
|
||||
extern bool arg_wpa_syslog;
|
||||
|
||||
#endif /* WIFID_H */
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
|
||||
########### next target ###############
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules (CHECK check)
|
||||
|
||||
|
||||
if(CHECK_FOUND)
|
||||
|
||||
set(test_rtsp_SOURCES test_common.h test_rtsp.c)
|
||||
add_executable(test_rtsp ${test_rtsp_SOURCES})
|
||||
target_link_libraries(test_rtsp miracle-shared)
|
||||
target_link_libraries(test_rtsp ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_rtsp ${UDEV_LIBRARIES})
|
||||
target_link_libraries(test_rtsp ${GLIB2_LIBRARIES})
|
||||
|
||||
target_link_libraries(test_rtsp ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_rtsp ${CHECK_CFLAGS})
|
||||
|
||||
set(test_wpas_SOURCES test_common.h test_wpas.c)
|
||||
add_executable(test_wpas ${test_wpas_SOURCES})
|
||||
target_link_libraries(test_wpas miracle-shared)
|
||||
target_link_libraries(test_wpas ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_wpas ${UDEV_LIBRARIES})
|
||||
target_link_libraries(test_wpas ${GLIB2_LIBRARIES})
|
||||
target_link_libraries(test_wpas ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_wpas ${CHECK_CFLAGS})
|
||||
target_link_libraries(test_wpas m)
|
||||
|
||||
set(test_valgrind_SOURCES test_common.h test_valgrind.c)
|
||||
add_executable(test_valgrind ${test_valgrind_SOURCES})
|
||||
target_link_libraries(test_valgrind miracle-shared)
|
||||
target_link_libraries(test_valgrind ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_valgrind ${UDEV_LIBRARIES})
|
||||
target_link_libraries(test_valgrind ${GLIB2_LIBRARIES})
|
||||
target_link_libraries(test_valgrind ${CHECK_LIBRARIES})
|
||||
target_link_libraries(test_valgrind ${CHECK_CFLAGS})
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
|
@ -39,7 +39,7 @@ if(CHECK_FOUND)
|
|||
|
||||
add_custom_target(memcheck
|
||||
DEPENDS memcheck-verify
|
||||
COMMAND for i in $(MEMTESTS) |
|
||||
COMMAND for i in $$(MEMTESTS) |
|
||||
do |
|
||||
${VALGRIND} --log-file=${CMAKE_SOURCE_DIR}/$$i.memlog |
|
||||
${CMAKE_SOURCE_DIR}/$$i >/dev/null || (echo "memcheck failed on: $$i" ; exit 1) ; |
|
||||
|
@ -48,69 +48,3 @@ if(CHECK_FOUND)
|
|||
COMMENT "verify memcheck")
|
||||
|
||||
endif(CHECK_FOUND)
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
#include $(top_srcdir)/common.am
|
||||
#tests = \
|
||||
# test_rtsp \
|
||||
# test_wpas
|
||||
#
|
||||
#if BUILD_HAVE_CHECK
|
||||
#check_PROGRAMS = $(tests) test_valgrind
|
||||
#TESTS = $(tests) test_valgrind
|
||||
#MEMTESTS = $(tests)
|
||||
#endif
|
||||
#
|
||||
#test_sources = \
|
||||
# test_common.h
|
||||
#test_libs = \
|
||||
# ../src/shared/libmiracle-shared.la \
|
||||
# $(DEPS_LIBS) \
|
||||
# $(CHECK_LIBS)
|
||||
#test_cflags = \
|
||||
# $(AM_CPPFLAGS) \
|
||||
# $(DEPS_CFLAGS) \
|
||||
# $(CHECK_CFLAGS)
|
||||
#
|
||||
#test_rtsp_SOURCES = test_rtsp.c $(test_sources)
|
||||
#test_rtsp_CPPFLAGS = $(test_cflags)
|
||||
#test_rtsp_LDADD = $(test_libs)
|
||||
#
|
||||
#test_valgrind_SOURCES = test_valgrind.c $(test_sources)
|
||||
#test_valgrind_CPPFLAGS = $(test_cflags)
|
||||
#test_valgrind_LDADD = $(test_libs)
|
||||
#
|
||||
#test_wpas_SOURCES = test_wpas.c $(test_sources)
|
||||
#test_wpas_CPPFLAGS = $(test_cflags)
|
||||
#test_wpas_LDADD = $(test_libs)
|
||||
#
|
||||
### custom recipes
|
||||
#
|
||||
#VALGRIND = CK_FORK=no valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --leak-resolution=high --error-exitcode=1 --suppressions=$(top_builddir)/test.supp
|
||||
#
|
||||
## verify that test_valgrind actually leaks data
|
||||
#memcheck-verify: check
|
||||
# $(AM_V_GEN)$(VALGRIND) --log-file=/dev/null ./test_valgrind >/dev/null ; test 1 = $$?
|
||||
#
|
||||
## run memcheck tests via valgrind
|
||||
#memcheck: memcheck-verify
|
||||
# $(AM_V_GEN)for i in $(MEMTESTS) ; do \
|
||||
# $(VALGRIND) --log-file=$(top_builddir)/$$i.memlog \
|
||||
# $(top_builddir)/$$i >/dev/null || (echo "memcheck failed on: $$i" ; exit 1) ; \
|
||||
# done
|
||||
#
|
||||
#distcheck-hook: memcheck
|
||||
#AM_MAKEFLAGS = --no-print-directory
|
||||
#AUTOMAKE_OPTIONS = color-tests
|
||||
#
|
||||
##
|
||||
## Phony targets
|
||||
##
|
||||
#
|
||||
#.PHONY: memcheck-verify
|
||||
|
|
35
test/meson.build
Normal file
35
test/meson.build
Normal file
|
@ -0,0 +1,35 @@
|
|||
check = dependency('check', required: false)
|
||||
deps = [udev, glib2, check, libsystemd, libmiracle_shared_dep, m]
|
||||
|
||||
if check.found()
|
||||
test_rtsp = executable('test_rtsp', 'test_rtsp.c', dependencies: deps)
|
||||
|
||||
test_wpas = executable('test_wpas', 'test_wpas.c', dependencies: deps)
|
||||
|
||||
test_valgrind = executable('test_valgrind',
|
||||
'test_valgrind.c',
|
||||
dependencies: deps
|
||||
)
|
||||
|
||||
test('rtsp test', test_rtsp)
|
||||
test('wpas test', test_wpas)
|
||||
test('valgrind test', test_valgrind)
|
||||
|
||||
# set(VALGRIND CK_FORK=no valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --leak-resolution=high --error-exitcode=1 --suppressions=${CMAKE_SOURCE_DIR}/test.supp)
|
||||
#
|
||||
# add_custom_target(memcheck-verify
|
||||
# DEPENDS test_rtsp test_wpas test_valgrind
|
||||
# COMMAND ${VALGRIND} --log-file=/dev/null ./test_valgrind >/dev/null |
|
||||
# test 1 = $$?
|
||||
# COMMENT "verify memcheck")
|
||||
#
|
||||
# add_custom_target(memcheck
|
||||
# DEPENDS memcheck-verify
|
||||
# COMMAND for i in $(MEMTESTS) |
|
||||
# do |
|
||||
# ${VALGRIND} --log-file=${CMAKE_SOURCE_DIR}/$$i.memlog |
|
||||
# ${CMAKE_SOURCE_DIR}/$$i >/dev/null || (echo "memcheck failed on: $$i" ; exit 1) ; |
|
||||
# done
|
||||
# SOURCES test_rtsp test_valgrind test_wpas
|
||||
# COMMENT "verify memcheck")
|
||||
endif
|
Loading…
Add table
Add a link
Reference in a new issue