mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
rename miracle-wfdctl to miracle-dispd
This commit is contained in:
parent
5532bf14d1
commit
b21aa0d039
16 changed files with 44 additions and 47 deletions
|
|
@ -43,46 +43,8 @@ endif(READLINE_FOUND)
|
|||
|
||||
target_link_libraries(miracle-sinkctl miracle-shared)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
########### next target ###############
|
||||
set(miracle-wfdctl_SRCS ctl-cli.c
|
||||
ctl-wifi.c
|
||||
wfd-sink.c
|
||||
wfd-dbus.c
|
||||
wfd-session.c
|
||||
wfd-out-session.c
|
||||
wfdctl.c
|
||||
wfd.c
|
||||
wfd-arg.c)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR}
|
||||
${GSTREAMER_INCLUDE_DIRS}
|
||||
${GSTREAMER_BASE_INCLUDE_DIRS}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
add_executable(miracle-wfdctl ${miracle-wfdctl_SRCS})
|
||||
|
||||
install(TARGETS miracle-wfdctl DESTINATION bin)
|
||||
|
||||
if(READLINE_FOUND)
|
||||
message(STATUS "Compiling with Readline support")
|
||||
set_property(TARGET miracle-wfdctl
|
||||
APPEND
|
||||
PROPERTY COMPILE_DEFINITIONS HAVE_READLINE)
|
||||
target_link_libraries(miracle-wfdctl ${READLINE_LIBRARY})
|
||||
endif(READLINE_FOUND)
|
||||
|
||||
target_link_libraries(miracle-wfdctl
|
||||
miracle-shared
|
||||
${GSTREAMER_LIBRARIES}
|
||||
${GSTREAMER_BASE_LIBRARIES})
|
||||
|
||||
########### install files ###############
|
||||
|
||||
|
||||
|
||||
${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/shared)
|
||||
|
||||
#original Makefile.am contents follow:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "wfd-arg.h"
|
||||
|
||||
int wfd_arg_list_new(struct wfd_arg_list **out)
|
||||
{
|
||||
assert(out);
|
||||
|
||||
struct wfd_arg_list *l = calloc(1, sizeof(struct wfd_arg_list));
|
||||
if(!l) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
l->dynamic = true;
|
||||
|
||||
*out = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfd_arg_list_clear(struct wfd_arg_list *l)
|
||||
{
|
||||
int i;
|
||||
struct wfd_arg *arg;
|
||||
|
||||
if(!l || !l->dynamic) {
|
||||
return;
|
||||
}
|
||||
|
||||
arg = l->discrete ? l->argv : l->args;
|
||||
for(i = 0; i < l->len; i ++) {
|
||||
if((WFD_ARG_STR == arg->type || WFD_ARG_PTR == arg->type)
|
||||
&& arg->ptr && arg->free) {
|
||||
(*arg->free)(arg->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if(l->discrete) {
|
||||
free(l->argv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "shl_macro.h"
|
||||
|
||||
#ifndef CTL_ARG_H
|
||||
#define CTL_ARG_H
|
||||
|
||||
#define wfd_arg_i8(_v) { .type = WFD_ARG_I8, .i8 = (_v) }
|
||||
#define wfd_arg_u8(_v) { .type = WFD_ARG_U8, .u8 = (_v) }
|
||||
#define wfd_arg_i16(_v) { .type = WFD_ARG_I16, .i16 = (_v) }
|
||||
#define wfd_arg_u16(_v) { .type = WFD_ARG_U16, .u16 = (_v) }
|
||||
#define wfd_arg_i32(_v) { .type = WFD_ARG_I32, .i32 = (_v) }
|
||||
#define wfd_arg_u32(_v) { .type = WFD_ARG_U32, .u32 = (_v) }
|
||||
#define wfd_arg_i64(_v) { .type = WFD_ARG_I64, .i64 = (_v) }
|
||||
#define wfd_arg_u64(_v) { .type = WFD_ARG_U64, .u64 = (_v) }
|
||||
#define wfd_arg_cstr(_v) { .type = WFD_ARG_CSTR, .ptr = (_v) }
|
||||
#define wfd_arg_cptr(_v) { .type = WFD_ARG_CPTR, .ptr = (_v) }
|
||||
#define wfd_arg_arg_list(_v) { \
|
||||
.type = WFD_ARG_ARG_LIST, \
|
||||
.ptr = &(struct wfd_arg_list) wfd_arg_list(_v) \
|
||||
}
|
||||
#define wfd_arg_dict(_k, _v) { \
|
||||
.type = WFD_ARG_DICT, \
|
||||
.k = (struct wfd_arg[]){_k}, \
|
||||
.v = (struct wfd_arg[]){_v} \
|
||||
}
|
||||
|
||||
#if INT_MAX == INT64_MAX
|
||||
#define wfd_arg_i(_v) wfd_arg_i64(_v)
|
||||
#define wfd_arg_u(_v) wfd_arg_u64(_v)
|
||||
#elif INT_MAX == INT32_MAX
|
||||
#define wfd_arg_i(_v) wfd_arg_i32(_v)
|
||||
#define wfd_arg_u(_v) wfd_arg_u32(_v)
|
||||
#else
|
||||
#error unsupported int size
|
||||
#endif
|
||||
|
||||
#define wfd_arg_type_id(_t) _Generic((_t), \
|
||||
int8_t: WFD_ARG_I8, \
|
||||
uint8_t: WFD_ARG_U8, \
|
||||
int16_t: WFD_ARG_I16, \
|
||||
uint16_t: WFD_ARG_U16, \
|
||||
int32_t: WFD_ARG_I32, \
|
||||
uint32_t: WFD_ARG_U32, \
|
||||
int64_t: WFD_ARG_I64, \
|
||||
uint64_t: WFD_ARG_U64, \
|
||||
const char *: WFD_ARG_CSTR, \
|
||||
const wfd_arg_list *: WFD_ARG_ARG_LIST, \
|
||||
char *: WFD_ARG_STR, \
|
||||
void *: WFD_ARG_PTR, \
|
||||
default: WFD_ARG_CPTR \
|
||||
)
|
||||
|
||||
#define wfd_arg_list(...) { \
|
||||
.argv = (struct wfd_arg[]) { \
|
||||
__VA_ARGS__ \
|
||||
}, \
|
||||
.discrete = true, \
|
||||
.dynamic = false, \
|
||||
.len = (sizeof((struct wfd_arg[]){ __VA_ARGS__ })/sizeof(struct wfd_arg)) \
|
||||
}
|
||||
|
||||
#define wfd_arg_get(_a, _v) ({ \
|
||||
*(_v) = _Generic(*(_v), \
|
||||
int8_t: wfd_arg_get_i8, \
|
||||
uint8_t: wfd_arg_get_u8, \
|
||||
int16_t: wfd_arg_get_i16, \
|
||||
uint16_t: wfd_arg_get_u16, \
|
||||
int32_t: wfd_arg_get_i32, \
|
||||
uint32_t: wfd_arg_get_u32, \
|
||||
int64_t: wfd_arg_get_i64, \
|
||||
uint64_t: wfd_arg_get_u64, \
|
||||
char *: wfd_arg_get_str, \
|
||||
const struct wfd_arg_list *: wfd_arg_get_arg_list, \
|
||||
const char *: wfd_arg_get_cstr, \
|
||||
void *: wfd_arg_get_ptr, \
|
||||
default: wfd_arg_get_cptr \
|
||||
)(_a); \
|
||||
})
|
||||
|
||||
#define wfd_arg_get_dictk(_a, _k) ({ \
|
||||
assert(_a); \
|
||||
assert(WFD_ARG_DICT == (_a)->type); \
|
||||
wfd_arg_get((_a)->k, (_k)); \
|
||||
})
|
||||
|
||||
#define wfd_arg_get_dictv(_a, _v) ({ \
|
||||
assert(_a); \
|
||||
assert(WFD_ARG_DICT == (_a)->type); \
|
||||
wfd_arg_get((_a)->v, (_v)); \
|
||||
})
|
||||
|
||||
#define wfd_arg_get_dict(_a, _k, _v) ({ \
|
||||
assert(_a); \
|
||||
assert(WFD_ARG_DICT == (_a)->type); \
|
||||
wfd_arg_get_dictk(_a, _k); \
|
||||
wfd_arg_get_dictv(_a, _v); \
|
||||
})
|
||||
|
||||
#define wfd_arg_list_get(_l, _i, _v) ({ \
|
||||
wfd_arg_get(wfd_arg_list_at((_l), (_i)), (_v)); \
|
||||
})
|
||||
|
||||
#define wfd_arg_list_get_dictk(_l, _i, _k) ({ \
|
||||
wfd_arg_get_dictk(wfd_arg_list_at((_l), (_i)), (_k)); \
|
||||
})
|
||||
|
||||
#define wfd_arg_list_get_dictv(_l, _i, _v) ({ \
|
||||
wfd_arg_get_dictv(wfd_arg_list_at((_l), (_i)), (_v)); \
|
||||
})
|
||||
|
||||
#define wfd_arg_list_get_dict(_l, _i, _k, _v) ({ \
|
||||
wfd_arg_get_dict(wfd_arg_list_at((_l), (_i)), (_k), (_v)); \
|
||||
})
|
||||
|
||||
enum wfd_arg_type
|
||||
{
|
||||
WFD_ARG_NONE,
|
||||
WFD_ARG_I8,
|
||||
WFD_ARG_I16,
|
||||
WFD_ARG_I32,
|
||||
WFD_ARG_I64,
|
||||
WFD_ARG_U8,
|
||||
WFD_ARG_U16,
|
||||
WFD_ARG_U32,
|
||||
WFD_ARG_U64,
|
||||
WFD_ARG_STR,
|
||||
WFD_ARG_CSTR,
|
||||
WFD_ARG_PTR,
|
||||
WFD_ARG_CPTR,
|
||||
WFD_ARG_DICT,
|
||||
WFD_ARG_ARG_LIST,
|
||||
};
|
||||
|
||||
struct wfd_arg
|
||||
{
|
||||
enum wfd_arg_type type;
|
||||
union
|
||||
{
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
struct {
|
||||
void *ptr;
|
||||
void (*free)(void *);
|
||||
};
|
||||
struct {
|
||||
struct wfd_arg *k;
|
||||
struct wfd_arg *v;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct wfd_arg_list
|
||||
{
|
||||
size_t len: sizeof(size_t) - 2;
|
||||
bool discrete: 1;
|
||||
bool dynamic: 1;
|
||||
|
||||
union {
|
||||
struct wfd_arg * argv;
|
||||
struct wfd_arg args[0];
|
||||
};
|
||||
};
|
||||
|
||||
int wfd_arg_list_new(struct wfd_arg_list **out);
|
||||
void wfd_arg_list_clear(struct wfd_arg_list *l);
|
||||
static inline void wfd_arg_list_free(struct wfd_arg_list *l);
|
||||
static inline const struct wfd_arg * wfd_arg_list_at(const struct wfd_arg_list *l,
|
||||
int i);
|
||||
|
||||
static inline enum wfd_arg_type wfd_arg_get_type(struct wfd_arg *a);
|
||||
static inline void wfd_arg_free_ptr(struct wfd_arg *a);
|
||||
static inline void wfd_arg_clear(struct wfd_arg *a);
|
||||
|
||||
static inline int8_t wfd_arg_get_i8(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_i8(struct wfd_arg *a, int8_t v);
|
||||
|
||||
static inline uint8_t wfd_arg_get_u8(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_u8(struct wfd_arg *a, uint8_t v);
|
||||
|
||||
static inline int16_t wfd_arg_get_i16(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_i16(struct wfd_arg *a, int16_t v);
|
||||
|
||||
static inline uint16_t wfd_arg_get_u16(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_u16(struct wfd_arg *a, uint16_t v);
|
||||
|
||||
static inline int32_t wfd_arg_get_i32(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_i32(struct wfd_arg *a, int32_t v);
|
||||
|
||||
static inline uint32_t wfd_arg_get_u32(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_u32(struct wfd_arg *a, uint32_t v);
|
||||
|
||||
static inline int64_t wfd_arg_get_i64(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_i64(struct wfd_arg *a, int64_t v);
|
||||
|
||||
static inline uint64_t wfd_arg_get_u64(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_u64(struct wfd_arg *a, uint64_t v);
|
||||
|
||||
static inline const char * wfd_arg_get_cstr(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_cstr(struct wfd_arg *a, const char * v);
|
||||
|
||||
static inline void wfd_arg_take_str(struct wfd_arg *a, char *v);
|
||||
static inline char * wfd_arg_get_str(const struct wfd_arg *a);
|
||||
static inline int wfd_arg_set_str(struct wfd_arg *a, const char *v);;
|
||||
|
||||
static inline const void * wfd_arg_get_cptr(const struct wfd_arg *a);
|
||||
static inline void wfd_arg_set_cptr(struct wfd_arg *a, const void * v);
|
||||
|
||||
static inline void wfd_arg_take_ptr(struct wfd_arg *a, void *v, void (*f)(void *));
|
||||
static inline void * wfd_arg_get_ptr(const struct wfd_arg *a);
|
||||
|
||||
static inline void wfd_arg_take_arg_list(struct wfd_arg *a, struct wfd_arg_list *l);
|
||||
static inline const struct wfd_arg_list * wfd_arg_get_arg_list(const struct wfd_arg *a);
|
||||
|
||||
#include "wfd-arg.inc"
|
||||
|
||||
#endif /* CTL_ARG_H */
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#define wfd_arg_getter(_t, _s, _S) \
|
||||
static inline _t wfd_arg_get_##_s(const struct wfd_arg *a) \
|
||||
{ \
|
||||
assert(a); \
|
||||
assert(WFD_ARG_##_S == a->type); \
|
||||
return a->_s; \
|
||||
}
|
||||
|
||||
#define wfd_arg_setter(_t, _s, _S) \
|
||||
static inline void wfd_arg_set_##_s(struct wfd_arg *a, _t v) \
|
||||
{ \
|
||||
assert(a); \
|
||||
assert(!a->type || WFD_ARG_##_S == a->type); \
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_##_S, ._s = v }; \
|
||||
}
|
||||
|
||||
wfd_arg_getter(int8_t, i8, I8)
|
||||
wfd_arg_setter(int8_t, i8, I8)
|
||||
wfd_arg_getter(uint8_t, u8, U8)
|
||||
wfd_arg_setter(uint8_t, u8, U8)
|
||||
wfd_arg_getter(int16_t, i16, I16)
|
||||
wfd_arg_setter(int16_t, i16, I16)
|
||||
wfd_arg_getter(uint16_t, u16, U16)
|
||||
wfd_arg_setter(uint16_t, u16, U16)
|
||||
wfd_arg_getter(int32_t, i32, I32)
|
||||
wfd_arg_setter(int32_t, i32, I32)
|
||||
wfd_arg_getter(uint32_t, u32, U32)
|
||||
wfd_arg_setter(uint32_t, u32, U32)
|
||||
wfd_arg_getter(int64_t, i64, I64)
|
||||
wfd_arg_setter(int64_t, i64, I64)
|
||||
wfd_arg_getter(uint64_t, u64, U64)
|
||||
wfd_arg_setter(uint64_t, u64, U64)
|
||||
|
||||
static inline void wfd_arg_list_free(struct wfd_arg_list *l)
|
||||
{
|
||||
wfd_arg_list_clear(l);
|
||||
free(l);
|
||||
}
|
||||
|
||||
static inline const struct wfd_arg * wfd_arg_list_at(const struct wfd_arg_list *l,
|
||||
int i)
|
||||
{
|
||||
assert(l);
|
||||
assert(i >= 0 && i < l->len);
|
||||
return l->discrete ? &l->argv[i] : &l->args[i];
|
||||
}
|
||||
|
||||
static inline enum wfd_arg_type wfd_arg_get_type(struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
|
||||
return a->type;
|
||||
}
|
||||
|
||||
static inline void wfd_arg_free_ptr(struct wfd_arg *a)
|
||||
{
|
||||
if(!a || (WFD_ARG_STR != a->type && WFD_ARG_PTR != a->type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(a->ptr && a->free) {
|
||||
(*a->free)(a->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void wfd_arg_clear(struct wfd_arg *a)
|
||||
{
|
||||
if(a) {
|
||||
wfd_arg_free_ptr(a);
|
||||
memset(a, 0, sizeof(*a));
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char * wfd_arg_get_cstr(const struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
assert(WFD_ARG_CSTR == a->type || WFD_ARG_STR == a->type);
|
||||
|
||||
return a->ptr;
|
||||
}
|
||||
|
||||
static inline void wfd_arg_set_cstr(struct wfd_arg *a, const char * v)
|
||||
{
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_CSTR == a->type);
|
||||
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_CSTR, .ptr = (void *) v };
|
||||
}
|
||||
|
||||
static inline char * wfd_arg_get_str(const struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
assert(WFD_ARG_STR == a->type);
|
||||
|
||||
return a->ptr;
|
||||
}
|
||||
|
||||
static inline void wfd_arg_take_str(struct wfd_arg *a, char *v)
|
||||
{
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_STR == a->type || WFD_ARG_CSTR == a->type);
|
||||
|
||||
wfd_arg_free_ptr(a);
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_STR, .ptr = v, .free = free };
|
||||
}
|
||||
|
||||
static inline int wfd_arg_set_str(struct wfd_arg *a, const char *v)
|
||||
{
|
||||
char *s;
|
||||
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_STR == a->type);
|
||||
|
||||
s = strdup(v);
|
||||
if(!s) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wfd_arg_take_str(a, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const void * wfd_arg_get_cptr(const struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
assert(WFD_ARG_PTR <= a->type && WFD_ARG_CPTR == a->type);
|
||||
|
||||
return a->ptr;
|
||||
}
|
||||
|
||||
static inline void wfd_arg_set_cptr(struct wfd_arg *a, const void * v)
|
||||
{
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_CSTR == a->type);
|
||||
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_CPTR, .ptr = (void *) v };
|
||||
}
|
||||
|
||||
static inline void * wfd_arg_get_ptr(const struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
assert(WFD_ARG_PTR == a->type || WFD_ARG_STR == a->type);
|
||||
|
||||
return a->ptr;
|
||||
}
|
||||
|
||||
static inline void wfd_arg_take_ptr(struct wfd_arg *a, void *v, void (*f)(void *))
|
||||
{
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_PTR == a->type);
|
||||
|
||||
wfd_arg_free_ptr(a);
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_PTR, .ptr = v, .free = f };
|
||||
}
|
||||
|
||||
static inline void wfd_arg_take_arg_list(struct wfd_arg *a, struct wfd_arg_list *l)
|
||||
{
|
||||
assert(a);
|
||||
assert(!a->type || WFD_ARG_ARG_LIST == a->type);
|
||||
|
||||
wfd_arg_free_ptr(a);
|
||||
*a = (struct wfd_arg) { .type = WFD_ARG_ARG_LIST,
|
||||
.ptr = l,
|
||||
.free = (void (*)(void *)) wfd_arg_list_free };
|
||||
}
|
||||
|
||||
static inline const struct wfd_arg_list * wfd_arg_get_arg_list(const struct wfd_arg *a)
|
||||
{
|
||||
assert(a);
|
||||
assert(WFD_ARG_ARG_LIST == a->type);
|
||||
|
||||
return a->ptr;
|
||||
}
|
||||
|
|
@ -1,735 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include "ctl.h"
|
||||
#include "util.h"
|
||||
#include "wfd-dbus.h"
|
||||
|
||||
#define wfd_dbus_object_added(o, argv...) ({ \
|
||||
const char *ifaces[] = { argv }; \
|
||||
_wfd_dbus_object_added(wfd_dbus_get(), \
|
||||
(o), \
|
||||
ifaces, \
|
||||
SHL_ARRAY_LENGTH(ifaces)); \
|
||||
})
|
||||
#define wfd_dbus_object_removed(o, argv...) ({ \
|
||||
const char *ifaces[] = { argv }; \
|
||||
_wfd_dbus_object_removed(wfd_dbus_get(), \
|
||||
(o), \
|
||||
ifaces, \
|
||||
SHL_ARRAY_LENGTH(ifaces)); \
|
||||
})
|
||||
|
||||
struct wfd_dbus
|
||||
{
|
||||
sd_bus *bus;
|
||||
sd_event *loop;
|
||||
|
||||
bool exposed : 1;
|
||||
};
|
||||
|
||||
int wfd_dbus_new(struct wfd_dbus **out, sd_event *loop, sd_bus *bus)
|
||||
{
|
||||
struct wfd_dbus *wfd_dbus = calloc(1, sizeof(struct wfd_dbus));
|
||||
if(!wfd_dbus) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wfd_dbus->bus = sd_bus_ref(bus);
|
||||
wfd_dbus->loop = sd_event_ref(loop);
|
||||
|
||||
*out = wfd_dbus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfd_dbus_free(struct wfd_dbus *wfd_dbus)
|
||||
{
|
||||
if(!wfd_dbus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(wfd_dbus->exposed) {
|
||||
sd_bus_release_name(wfd_dbus->bus, "org.freedesktop.miracle.wfd");
|
||||
}
|
||||
|
||||
if(wfd_dbus->bus) {
|
||||
sd_bus_unref(wfd_dbus->bus);
|
||||
}
|
||||
|
||||
if(wfd_dbus->loop) {
|
||||
sd_event_unref(wfd_dbus->loop);
|
||||
}
|
||||
|
||||
free(wfd_dbus);
|
||||
}
|
||||
|
||||
static inline int wfd_dbus_get_sink_path(struct wfd_sink *s, char **out)
|
||||
{
|
||||
return sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink",
|
||||
wfd_sink_get_label(s),
|
||||
out);
|
||||
}
|
||||
|
||||
static inline int wfd_dbus_get_session_path(struct wfd_session *s, char **out)
|
||||
{
|
||||
char buf[64];
|
||||
int r = snprintf(buf, sizeof(buf), "%" PRIu64, wfd_session_get_id(s));
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_path_encode("/org/freedesktop/miracle/wfd/session",
|
||||
buf,
|
||||
out);
|
||||
}
|
||||
|
||||
static int wfd_dbus_enum(sd_bus *bus,
|
||||
const char *path,
|
||||
void *userdata,
|
||||
char ***out,
|
||||
sd_bus_error *out_error)
|
||||
{
|
||||
int r = 0, i = 0;
|
||||
char **nodes, *node;
|
||||
struct wfd_sink *sink;
|
||||
struct wfd_session *session;
|
||||
struct ctl_wfd *wfd = ctl_wfd_get();
|
||||
|
||||
if(strcmp("/org/freedesktop/miracle/wfd", path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!wfd->n_sinks) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nodes = malloc((wfd->n_sinks + wfd->n_sessions + 1) * sizeof(char *));
|
||||
if(!nodes) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctl_wfd_foreach_sink(sink, wfd) {
|
||||
r = wfd_dbus_get_sink_path(sink, &node);
|
||||
if(0 > r) {
|
||||
goto free_nodes;
|
||||
}
|
||||
nodes[i ++] = node;
|
||||
}
|
||||
|
||||
ctl_wfd_foreach_session(session, wfd) {
|
||||
r = wfd_dbus_get_session_path(session, &node);
|
||||
if(0 > r) {
|
||||
goto free_nodes;
|
||||
}
|
||||
nodes[i ++] = node;
|
||||
}
|
||||
|
||||
nodes[i ++] = NULL;
|
||||
*out = nodes;
|
||||
|
||||
return 0;
|
||||
|
||||
free_nodes:
|
||||
while(i --) {
|
||||
free(nodes[i]);
|
||||
}
|
||||
free(nodes);
|
||||
return r;
|
||||
}
|
||||
|
||||
int _wfd_dbus_object_removed(struct wfd_dbus *wfd_dbus,
|
||||
const char *path,
|
||||
const char **ifaces,
|
||||
size_t n_ifaces)
|
||||
{
|
||||
int i, r;
|
||||
_sd_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_signal(wfd_dbus->bus,
|
||||
&m,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
"org.freedesktop.DBus.ObjectManager",
|
||||
"InterfacesRemoved");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "o", path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "s");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
for(i = 0; i < n_ifaces; i ++) {
|
||||
r = sd_bus_message_append(m, "s", ifaces[i]);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_send(wfd_dbus->bus, m, NULL);
|
||||
}
|
||||
|
||||
int _wfd_dbus_object_added(struct wfd_dbus *wfd_dbus,
|
||||
const char *path,
|
||||
const char **ifaces,
|
||||
size_t n_ifaces)
|
||||
{
|
||||
int i, r;
|
||||
_sd_bus_message_unref_ sd_bus_message *m = NULL;
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_signal(wfd_dbus->bus,
|
||||
&m,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
"org.freedesktop.DBus.ObjectManager",
|
||||
"InterfacesAdded");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "o", path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
for(i = 0; i < n_ifaces; i ++) {
|
||||
r = sd_bus_message_append(m, "{sa{sv}}", ifaces[i], 0);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_send(wfd_dbus->bus, m, NULL);
|
||||
}
|
||||
|
||||
int wfd_fn_sink_new(struct wfd_sink *s)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r = wfd_dbus_get_sink_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return wfd_dbus_object_added(path, "org.freedesktop.miracle.wfd.Sink");
|
||||
}
|
||||
|
||||
int wfd_fn_sink_free(struct wfd_sink *s)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r = wfd_dbus_get_sink_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return wfd_dbus_object_removed(path, "org.freedesktop.miracle.wfd.Sink");
|
||||
}
|
||||
|
||||
int _wfd_fn_sink_properties_changed(struct wfd_sink *s, char **names)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
struct wfd_dbus *wfd_dbus = wfd_dbus_get();
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = wfd_dbus_get_sink_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_emit_properties_changed_strv(wfd_dbus->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.wfd.Sink",
|
||||
names);
|
||||
}
|
||||
|
||||
static int wfd_dbus_find_sink(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
void *userdata,
|
||||
void **ret_found,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
_shl_free_ char *node = NULL;
|
||||
struct wfd_sink *sink;
|
||||
int r = sd_bus_path_decode(path,
|
||||
"/org/freedesktop/miracle/wfd/sink",
|
||||
&node);
|
||||
if(0 >= r || !node) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = ctl_wfd_find_sink_by_label(ctl_wfd_get(), node, &sink);
|
||||
if(r) {
|
||||
*ret_found = sink;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int wfd_fn_session_new(struct wfd_session *s)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r = wfd_dbus_get_session_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return wfd_dbus_object_added(path, "org.freedesktop.miracle.wfd.Session");
|
||||
}
|
||||
|
||||
int wfd_fn_session_free(struct wfd_session *s)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r = wfd_dbus_get_session_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return wfd_dbus_object_removed(path,
|
||||
"org.freedesktop.miracle.wfd.Session");
|
||||
}
|
||||
|
||||
static int wfd_dbus_find_session(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
void *userdata,
|
||||
void **ret_found,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s;
|
||||
_shl_free_ char *node = NULL;
|
||||
int r = sd_bus_path_decode(path,
|
||||
"/org/freedesktop/miracle/wfd/session",
|
||||
&node);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = ctl_wfd_find_session_by_id(ctl_wfd_get(),
|
||||
strtoull(node, NULL, 10),
|
||||
&s);
|
||||
if(r) {
|
||||
*ret_found = s;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_dbus_sink_start_session(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_sink *sink = userdata;
|
||||
_wfd_session_free_ struct wfd_session *session = NULL;
|
||||
_shl_free_ char *path = NULL;
|
||||
const char *authority;
|
||||
const char *display;
|
||||
uint16_t x, y, width, height;
|
||||
const char *audio_dev;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(m,
|
||||
"ssqqqqs",
|
||||
&authority,
|
||||
&display,
|
||||
&x,
|
||||
&y,
|
||||
&width,
|
||||
&height,
|
||||
&audio_dev);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = wfd_sink_start_session(sink,
|
||||
&session,
|
||||
authority,
|
||||
display,
|
||||
x, y, width, height,
|
||||
audio_dev);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = wfd_dbus_get_session_path(session, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
session = NULL;
|
||||
|
||||
return sd_bus_reply_method_return(m, "o", path);
|
||||
}
|
||||
|
||||
//static int wfd_dbus_sink_get_audio_formats(sd_bus *bus,
|
||||
// const char *path,
|
||||
// const char *interface,
|
||||
// const char *property,
|
||||
// sd_bus_message *reply,
|
||||
// void *userdata,
|
||||
// sd_bus_error *ret_error)
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
//
|
||||
//static int wfd_dbus_sink_get_video_formats(sd_bus *bus,
|
||||
// const char *path,
|
||||
// const char *interface,
|
||||
// const char *property,
|
||||
// sd_bus_message *reply,
|
||||
// void *userdata,
|
||||
// sd_bus_error *ret_error)
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
//
|
||||
//static int wfd_dbus_sink_has_video(sd_bus *bus,
|
||||
// const char *path,
|
||||
// const char *interface,
|
||||
// const char *property,
|
||||
// sd_bus_message *reply,
|
||||
// void *userdata,
|
||||
// sd_bus_error *ret_error)
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
static int wfd_dbus_sink_get_session(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_sink *s = userdata;
|
||||
_shl_free_ char *session_path = NULL;
|
||||
int r;
|
||||
|
||||
if(s->session) {
|
||||
wfd_dbus_get_session_path(s->session, &session_path);
|
||||
}
|
||||
else {
|
||||
session_path = strdup("/");
|
||||
}
|
||||
if(!session_path) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(reply, "o", session_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wfd_dbus_sink_get_peer(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_sink *s = userdata;
|
||||
_shl_free_ char *peer_path = NULL;
|
||||
int r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/peer",
|
||||
s->label,
|
||||
&peer_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(reply, "o", peer_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//static int wfd_dbus_sink_has_audio(sd_bus *bus,
|
||||
// const char *path,
|
||||
// const char *interface,
|
||||
// const char *property,
|
||||
// sd_bus_message *reply,
|
||||
// void *userdata,
|
||||
// sd_bus_error *ret_error)
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
static int wfd_dbus_session_resume(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
int r;
|
||||
|
||||
if(wfd_session_is_established(s)) {
|
||||
r = wfd_session_resume(s);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_pause(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
int r;
|
||||
|
||||
if(wfd_session_is_established(s)) {
|
||||
r = wfd_session_pause(s);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_teardown(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
int r = wfd_session_teardown(s);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_get_sink(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
_shl_free_ char *sink_path = NULL;
|
||||
int r;
|
||||
|
||||
if(wfd_session_get_id(s) != WFD_SESSION_DIR_OUT) {
|
||||
sink_path = strdup("/");
|
||||
}
|
||||
else {
|
||||
wfd_dbus_get_sink_path(wfd_out_session_get_sink(s), &sink_path);
|
||||
}
|
||||
if(!sink_path) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(reply, "o", sink_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wfd_dbus_get_session_presentation_url(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
int r = sd_bus_message_append(reply,
|
||||
"s",
|
||||
wfd_session_get_stream_url(s) ? : "");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wfd_dbus_get_session_state(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
int r = sd_bus_message_append(reply, "i", wfd_session_get_state(s));
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wfd_fn_session_properties_changed(struct wfd_session *s, char **names)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
struct wfd_dbus *wfd_dbus = wfd_dbus_get();
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = wfd_dbus_get_session_path(s, &path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_emit_properties_changed_strv(wfd_dbus_get()->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.wfd.Session",
|
||||
names);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable wfd_dbus_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static const sd_bus_vtable wfd_dbus_sink_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("StartSession", "ssqqqqs", "o", wfd_dbus_sink_start_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
/*SD_BUS_PROPERTY("AudioFormats", "a{sv}", wfd_dbus_sink_get_audio_formats, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/
|
||||
/*SD_BUS_PROPERTY("VideoFormats", "a{sv}", wfd_dbus_sink_get_video_formats, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/
|
||||
/*SD_BUS_PROPERTY("HasAudio", "b", wfd_dbus_sink_has_audio, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/
|
||||
/*SD_BUS_PROPERTY("HasVideo", "b", wfd_dbus_sink_has_video, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/
|
||||
SD_BUS_PROPERTY("Session", "o", wfd_dbus_sink_get_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Peer", "o", wfd_dbus_sink_get_peer, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static const sd_bus_vtable wfd_dbus_session_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Resume", NULL, NULL, wfd_dbus_session_resume, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Pause", NULL, NULL, wfd_dbus_session_pause, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Teardown", NULL, NULL, wfd_dbus_session_teardown, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_PROPERTY("Sink", "o", wfd_dbus_session_get_sink, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Url", "s", wfd_dbus_get_session_presentation_url, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("State", "i", wfd_dbus_get_session_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
|
||||
{
|
||||
int r = sd_bus_add_object_vtable(wfd_dbus->bus,
|
||||
NULL,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
"org.freedesktop.miracle.wfd.Display",
|
||||
wfd_dbus_vtable,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_fallback_vtable(wfd_dbus->bus,
|
||||
NULL,
|
||||
"/org/freedesktop/miracle/wfd/sink",
|
||||
"org.freedesktop.miracle.wfd.Sink",
|
||||
wfd_dbus_sink_vtable,
|
||||
wfd_dbus_find_sink,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_fallback_vtable(wfd_dbus->bus,
|
||||
NULL,
|
||||
"/org/freedesktop/miracle/wfd/session",
|
||||
"org.freedesktop.miracle.wfd.Session",
|
||||
wfd_dbus_session_vtable,
|
||||
wfd_dbus_find_session,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_node_enumerator(wfd_dbus->bus,
|
||||
NULL,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
wfd_dbus_enum,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_object_manager(wfd_dbus->bus, NULL, "/org/freedesktop/miracle/wfd");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_request_name(wfd_dbus->bus, "org.freedesktop.miracle.wfd", 0);
|
||||
if(0 < r) {
|
||||
wfd_dbus->exposed = true;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#ifndef CTL_WFD_DBUS_H
|
||||
#define CTL_WFD_DBUS_H
|
||||
|
||||
#define wfd_fn_sink_properties_changed(s, namev...) ({ \
|
||||
char *names[] = { namev, NULL }; \
|
||||
_wfd_fn_sink_properties_changed((s), names); \
|
||||
})
|
||||
|
||||
#define wfd_fn_session_properties_changed(s, namev...) ({ \
|
||||
char *names[] = { namev, NULL }; \
|
||||
_wfd_fn_session_properties_changed((s), names); \
|
||||
})
|
||||
|
||||
struct wfd_dbus;
|
||||
struct wfd_session;
|
||||
struct wfd_sink;
|
||||
|
||||
struct wfd_dbus * wfd_dbus_get();
|
||||
int wfd_dbus_new(struct wfd_dbus **out, sd_event *loop, sd_bus *bus);
|
||||
void wfd_dbus_free(struct wfd_dbus *wfd_dbus);
|
||||
int wfd_dbus_expose(struct wfd_dbus *wfd_dbus);
|
||||
int _wfd_fn_sink_properties_changed(struct wfd_sink *s, char **names);
|
||||
int _wfd_fn_session_properties_changed(struct wfd_session *s, char **names);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,687 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#define LOG_SUBSYSTEM "wfd-session"
|
||||
|
||||
#include <time.h>
|
||||
#include "ctl.h"
|
||||
#include "rtsp.h"
|
||||
#include "wfd-dbus.h"
|
||||
#include "wfd-session.h"
|
||||
#include "shl_macro.h"
|
||||
|
||||
#define rtsp_message_id_is_valid(_id) ( \
|
||||
(_id) >= RTSP_M1_REQUEST_SINK_OPTIONS && \
|
||||
(_id) <= RTSP_M16_KEEPALIVE \
|
||||
)
|
||||
#define wfd_stream_id_is_valid(_id) ( \
|
||||
(_id) >= WFD_STREAM_ID_PRIMARY && \
|
||||
(_id) <= WFD_STREAM_ID_SECONDARY \
|
||||
)
|
||||
|
||||
static const char *rtsp_message_names[];
|
||||
extern const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[];
|
||||
|
||||
extern int wfd_out_session_initiate_io(struct wfd_session *s, int *out_fd, uint32_t *out_mask);
|
||||
extern int wfd_out_session_handle_io(struct wfd_session *s, int error, int *out_fd);
|
||||
extern int wfd_out_session_initiate_request(struct wfd_session *);
|
||||
extern int wfd_out_session_resume(struct wfd_session *);
|
||||
extern int wfd_out_session_pause(struct wfd_session *);
|
||||
extern int wfd_out_session_teardown(struct wfd_session *);
|
||||
extern void wfd_out_session_end(struct wfd_session *);
|
||||
extern void wfd_out_session_destroy(struct wfd_session *);
|
||||
static const char * rtsp_message_id_to_string(enum rtsp_message_id id);
|
||||
|
||||
const struct wfd_session_vtable session_vtbl[] = {
|
||||
[WFD_SESSION_DIR_OUT] = {
|
||||
.initiate_io = wfd_out_session_initiate_io,
|
||||
.handle_io = wfd_out_session_handle_io,
|
||||
.initiate_request = wfd_out_session_initiate_request,
|
||||
.resume = wfd_out_session_resume,
|
||||
.pause = wfd_out_session_pause,
|
||||
.teardown = wfd_out_session_teardown,
|
||||
.destroy = wfd_out_session_destroy,
|
||||
}
|
||||
};
|
||||
|
||||
static inline int wfd_session_do_request(struct wfd_session *s,
|
||||
enum rtsp_message_id id,
|
||||
const struct wfd_arg_list *args,
|
||||
struct rtsp_message **out)
|
||||
{
|
||||
if(!rtsp_message_id_is_valid(id)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(!s->rtsp_disp_tbl[id].request) {
|
||||
log_warning("!!! request not implemented !!!");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return (*s->rtsp_disp_tbl[id].request)(s, args, out);
|
||||
}
|
||||
|
||||
static inline int wfd_session_do_handle_request(struct wfd_session *s,
|
||||
enum rtsp_message_id id,
|
||||
struct rtsp_message *req,
|
||||
struct rtsp_message **out_rep)
|
||||
{
|
||||
if(!rtsp_message_id_is_valid(id)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(!s->rtsp_disp_tbl[id].handle_request) {
|
||||
log_warning("!!! request handler not implemented !!!");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return (*s->rtsp_disp_tbl[id].handle_request)(s,
|
||||
req,
|
||||
out_rep);
|
||||
}
|
||||
|
||||
static inline int wfd_session_do_handle_reply(struct wfd_session *s,
|
||||
enum rtsp_message_id id,
|
||||
struct rtsp_message *m)
|
||||
{
|
||||
if(!rtsp_message_id_is_valid(id)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(!s->rtsp_disp_tbl[id].handle_reply) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (*s->rtsp_disp_tbl[id].handle_reply)(s, m);
|
||||
}
|
||||
|
||||
uint64_t wfd_session_get_id(struct wfd_session *s)
|
||||
{
|
||||
return s->id;
|
||||
}
|
||||
|
||||
enum wfd_session_state wfd_session_get_state(struct wfd_session *s)
|
||||
{
|
||||
return s->state;
|
||||
}
|
||||
|
||||
void wfd_session_set_state(struct wfd_session *s,
|
||||
enum wfd_session_state state)
|
||||
{
|
||||
if(state == s->state) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->state = state;
|
||||
|
||||
wfd_fn_session_properties_changed(s, "State");
|
||||
}
|
||||
|
||||
int wfd_session_is_established(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
return WFD_SESSION_STATE_ESTABLISHED <= s->state;
|
||||
}
|
||||
|
||||
int wfd_session_resume(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
if(WFD_SESSION_STATE_PLAYING == s->state) {
|
||||
return 0;
|
||||
}
|
||||
else if(WFD_SESSION_STATE_PAUSED != s->state) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(!session_vtbl[s->dir].resume) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_vtbl[s->dir].resume(s);;
|
||||
}
|
||||
|
||||
int wfd_session_pause(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
if(WFD_SESSION_STATE_PAUSED == s->state) {
|
||||
return 0;
|
||||
}
|
||||
else if(WFD_SESSION_STATE_PLAYING != s->state) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(!session_vtbl[s->dir].pause) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_vtbl[s->dir].pause(s);;
|
||||
}
|
||||
|
||||
int wfd_session_teardown(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
/* notify and detach from sink */
|
||||
wfd_fn_out_session_ended(s);
|
||||
|
||||
if(wfd_session_is_established(s)) {
|
||||
if(!session_vtbl[s->dir].teardown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_vtbl[s->dir].teardown(s);;
|
||||
}
|
||||
|
||||
//wfd_session_free(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfd_session_free(struct wfd_session *s)
|
||||
{
|
||||
if(!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(session_vtbl[s->dir].destroy) {
|
||||
(*session_vtbl[s->dir].destroy)(s);
|
||||
}
|
||||
|
||||
if(s->vformats) {
|
||||
wfd_video_formats_free(s->vformats);
|
||||
s->vformats = NULL;
|
||||
}
|
||||
|
||||
if(s->acodecs) {
|
||||
wfd_audio_codecs_free(s->acodecs);
|
||||
s->acodecs = NULL;
|
||||
}
|
||||
|
||||
if(s->stream.url) {
|
||||
free(s->stream.url);
|
||||
s->stream.url = NULL;
|
||||
}
|
||||
|
||||
if(s->rtsp) {
|
||||
rtsp_detach_event(s->rtsp);
|
||||
rtsp_unref(s->rtsp);
|
||||
s->rtsp = NULL;
|
||||
}
|
||||
|
||||
s->rtp_ports[0] = 0;
|
||||
s->rtp_ports[1] = 0;
|
||||
s->last_request = RTSP_M_UNKNOWN;
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
enum wfd_session_dir wfd_session_get_dir(struct wfd_session *s)
|
||||
{
|
||||
return s->dir;
|
||||
}
|
||||
|
||||
unsigned int * wfd_session_to_htable(struct wfd_session *s)
|
||||
{
|
||||
return &s->id;
|
||||
}
|
||||
|
||||
struct wfd_session * wfd_session_from_htable(unsigned int *e)
|
||||
{
|
||||
return shl_htable_entry(e, struct wfd_session, id);
|
||||
}
|
||||
|
||||
const char * wfd_session_get_stream_url(struct wfd_session *s)
|
||||
{
|
||||
return s->stream.url;
|
||||
}
|
||||
|
||||
int wfd_session_gen_stream_url(struct wfd_session *s,
|
||||
const char *local_addr,
|
||||
enum wfd_stream_id id)
|
||||
{
|
||||
char *url;
|
||||
int r;
|
||||
|
||||
if(!wfd_stream_id_is_valid(id)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = asprintf(&url, "rtsp://%s/wfd1.0/streamid=%d", local_addr, id);
|
||||
if(0 <= r) {
|
||||
free(s->stream.url);
|
||||
s->stream.url = url;
|
||||
url = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static enum rtsp_message_id wfd_session_message_to_id(struct wfd_session *s,
|
||||
struct rtsp_message *m)
|
||||
{
|
||||
|
||||
const char *method = m ? rtsp_message_get_method(m) : NULL;
|
||||
if(!method) {
|
||||
return RTSP_M_UNKNOWN;
|
||||
}
|
||||
|
||||
if(!strcmp(method, "SET_PARAMETER")) {
|
||||
if(!rtsp_message_read(m, "{<>}", "wfd_trigger_method")) {
|
||||
return RTSP_M5_TRIGGER;
|
||||
}
|
||||
|
||||
if(!rtsp_message_read(m, "{<>}", "wfd_route")) {
|
||||
return RTSP_M10_SET_ROUTE;
|
||||
}
|
||||
|
||||
if(!rtsp_message_read(m, "{<>}", "wfd_connector_type")) {
|
||||
return RTSP_M11_SET_CONNECTOR_TYPE;
|
||||
}
|
||||
|
||||
if(!rtsp_message_read(m, "{<>}", "wfd_uibc_setting")) {
|
||||
return RTSP_M15_ENABLE_UIBC;
|
||||
}
|
||||
|
||||
if(!strncmp("wfd_standby", rtsp_message_get_body(m), 11)) {
|
||||
return RTSP_M12_SET_STANDBY;
|
||||
}
|
||||
|
||||
if(!strncmp("wfd_idr_request", rtsp_message_get_body(m), 15)) {
|
||||
return RTSP_M13_REQUEST_IDR;
|
||||
}
|
||||
|
||||
if(WFD_SESSION_STATE_CAPS_EXCHANGING == s->state) {
|
||||
return RTSP_M4_SET_PARAMETER;
|
||||
}
|
||||
|
||||
if(!rtsp_message_read(m, "{<>}", "wfd_uibc_capability")) {
|
||||
return RTSP_M14_ESTABLISH_UIBC;
|
||||
}
|
||||
|
||||
return RTSP_M_UNKNOWN;
|
||||
}
|
||||
|
||||
if(!strcmp(method, "OPTIONS")) {
|
||||
return wfd_is_out_session(s)
|
||||
? (RTSP_MESSAGE_REPLY == rtsp_message_get_type(m))
|
||||
? RTSP_M1_REQUEST_SINK_OPTIONS
|
||||
: RTSP_M2_REQUEST_SRC_OPTIONS
|
||||
: (RTSP_MESSAGE_REPLY == rtsp_message_get_type(m))
|
||||
? RTSP_M2_REQUEST_SRC_OPTIONS
|
||||
: RTSP_M1_REQUEST_SINK_OPTIONS;
|
||||
}
|
||||
else if(!strcmp(method, "GET_PARAMETER")) {
|
||||
if(rtsp_message_get_body_size(m)) {
|
||||
return RTSP_M3_GET_PARAMETER;
|
||||
}
|
||||
|
||||
return RTSP_M16_KEEPALIVE;
|
||||
}
|
||||
else if(!strcmp(method, "SETUP")) {
|
||||
return RTSP_M6_SETUP;
|
||||
}
|
||||
else if(!strcmp(method, "PLAY")) {
|
||||
return RTSP_M7_PLAY;
|
||||
}
|
||||
else if(!strcmp(method, "TEARDOWN")) {
|
||||
return RTSP_M8_TEARDOWN;
|
||||
}
|
||||
else if(!strcmp(method, "PAUSE")) {
|
||||
return RTSP_M9_PAUSE;
|
||||
}
|
||||
|
||||
return RTSP_M_UNKNOWN;
|
||||
}
|
||||
|
||||
static int wfd_session_post_handle_request_n_reply(struct wfd_session *s,
|
||||
enum rtsp_message_id ror)
|
||||
{
|
||||
const struct wfd_arg_list *args = &s->rtsp_disp_tbl[ror].rule;
|
||||
enum rtsp_message_id next_request = RTSP_M_UNKNOWN;
|
||||
enum wfd_session_arg_id arg_id;
|
||||
enum wfd_session_state new_state;
|
||||
const struct wfd_arg_list *req_args;
|
||||
int i;
|
||||
|
||||
if(!args->len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i = 0; i < args->len; i ++) {
|
||||
wfd_arg_list_get_dictk(args, i, &arg_id);
|
||||
switch(arg_id) {
|
||||
case WFD_SESSION_ARG_NEXT_REQUEST:
|
||||
wfd_arg_list_get_dictv(args, i, &next_request);
|
||||
break;
|
||||
case WFD_SESSION_ARG_NEW_STATE:
|
||||
wfd_arg_list_get_dictv(args, i, &new_state);
|
||||
wfd_session_set_state(s, new_state);
|
||||
break;
|
||||
case WFD_SESSION_ARG_REQUEST_ARGS:
|
||||
wfd_arg_list_get_dictv(args, i, &req_args);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(RTSP_M_UNKNOWN != next_request) {
|
||||
return wfd_session_request(s, next_request, req_args);
|
||||
}
|
||||
|
||||
if(WFD_SESSION_STATE_TEARING_DOWN == new_state) {
|
||||
wfd_fn_out_session_ended(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wfd_session_handle_request(struct rtsp *bus,
|
||||
struct rtsp_message *m,
|
||||
void *userdata)
|
||||
{
|
||||
_rtsp_message_unref_ struct rtsp_message *rep = NULL;
|
||||
struct wfd_session *s = userdata;
|
||||
enum rtsp_message_id id;
|
||||
char date[128];
|
||||
uint64_t usec;
|
||||
time_t sec;
|
||||
int r;
|
||||
|
||||
id = wfd_session_message_to_id(s, m);
|
||||
if(RTSP_M_UNKNOWN == id) {
|
||||
if(m) {
|
||||
log_debug("unable to map request to id: %s",
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
}
|
||||
r = -EPROTO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_trace("received %s (M%d) request: %s", rtsp_message_id_to_string(id),
|
||||
id,
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
r = wfd_session_do_handle_request(s,
|
||||
id,
|
||||
m,
|
||||
&rep);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
sec = usec / 1000 / 1000;
|
||||
strftime(date, sizeof(date),
|
||||
"%a, %d %b %Y %T %z",
|
||||
gmtime(&sec));
|
||||
|
||||
r = rtsp_message_append(rep, "<s>", "Date", date);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_message_seal(rep);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_send(bus, rep);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_trace("sending %s (M%d) reply: %s", rtsp_message_id_to_string(id),
|
||||
id,
|
||||
(char *) rtsp_message_get_raw(rep));
|
||||
|
||||
r = wfd_session_post_handle_request_n_reply(s, id);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
wfd_session_teardown(s);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static int wfd_session_handle_reply(struct rtsp *bus,
|
||||
struct rtsp_message *m,
|
||||
void *userdata)
|
||||
{
|
||||
int r;
|
||||
enum rtsp_message_id id;
|
||||
struct wfd_session *s = userdata;
|
||||
|
||||
if(!m) {
|
||||
r = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) {
|
||||
r = -EPROTO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
id = s->last_request;
|
||||
|
||||
log_trace("received %s (M%d) reply: %s",
|
||||
rtsp_message_id_to_string(id),
|
||||
id,
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
r = wfd_session_do_handle_reply(s, id, m);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = wfd_session_post_handle_request_n_reply(s, id);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
wfd_session_teardown(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int wfd_session_request(struct wfd_session *s,
|
||||
enum rtsp_message_id id,
|
||||
const struct wfd_arg_list *args)
|
||||
{
|
||||
int r;
|
||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
||||
|
||||
assert(s);
|
||||
|
||||
r = wfd_session_do_request(s, id, args, &m);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = rtsp_message_seal(m);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = rtsp_call_async(s->rtsp,
|
||||
m,
|
||||
wfd_session_handle_reply,
|
||||
s,
|
||||
0,
|
||||
NULL);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
s->last_request = id;
|
||||
|
||||
log_trace("sending %s (M%d) request: %s",
|
||||
rtsp_message_id_to_string(id),
|
||||
id,
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wfd_session_handle_io(sd_event_source *source,
|
||||
int fd,
|
||||
uint32_t mask,
|
||||
void *userdata)
|
||||
{
|
||||
int r, err = 0, conn;
|
||||
socklen_t len;
|
||||
struct wfd_session *s = userdata;
|
||||
_rtsp_unref_ struct rtsp *rtsp = NULL;
|
||||
|
||||
sd_event_source_set_enabled(source, SD_EVENT_OFF);
|
||||
sd_event_source_unref(source);
|
||||
|
||||
if (mask & EPOLLERR) {
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & EPOLLIN || mask & EPOLLOUT) {
|
||||
r = (*session_vtbl[s->dir].handle_io)(s, err, &conn);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = rtsp_open(&rtsp, conn);
|
||||
if (0 > r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
conn = -1;
|
||||
|
||||
r = rtsp_attach_event(rtsp, ctl_wfd_get_loop(), 0);
|
||||
if (0 > r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = rtsp_add_match(rtsp, wfd_session_handle_request, s);
|
||||
if (0 > r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
s->rtsp = rtsp;
|
||||
rtsp = NULL;
|
||||
|
||||
wfd_session_set_state(s, WFD_SESSION_STATE_CAPS_EXCHANGING);
|
||||
|
||||
r = (*session_vtbl[s->dir].initiate_request)(s);
|
||||
}
|
||||
|
||||
if(mask & EPOLLHUP) {
|
||||
r = -ESHUTDOWN;
|
||||
}
|
||||
|
||||
end:
|
||||
if (0 > r) {
|
||||
wfd_session_teardown(s);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int wfd_session_start(struct wfd_session *s, uint64_t id)
|
||||
{
|
||||
int r;
|
||||
_shl_close_ int fd = -1;
|
||||
uint32_t mask;
|
||||
|
||||
assert(wfd_is_session(s));
|
||||
assert(id);
|
||||
|
||||
if(WFD_SESSION_STATE_NULL != s->state) {
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
r = (*session_vtbl[s->dir].initiate_io)(s, &fd, &mask);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(ctl_wfd_get_loop(),
|
||||
NULL,
|
||||
fd,
|
||||
mask,
|
||||
wfd_session_handle_io,
|
||||
s);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
|
||||
s->id = id;
|
||||
wfd_session_set_state(s, WFD_SESSION_STATE_CONNECTING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfd_session_free_p(struct wfd_session **s)
|
||||
{
|
||||
wfd_session_free(*s);
|
||||
}
|
||||
|
||||
static const char * rtsp_message_id_to_string(enum rtsp_message_id id)
|
||||
{
|
||||
if(rtsp_message_id_is_valid(id)) {
|
||||
return rtsp_message_names[id];
|
||||
}
|
||||
|
||||
return rtsp_message_names[0];
|
||||
}
|
||||
|
||||
static const char *rtsp_message_names[] = {
|
||||
"UNKNOWN",
|
||||
"OPTIONS(src->sink)",
|
||||
"OPTIONS(sink->src)",
|
||||
"GET_PARAM",
|
||||
"SET_PARAM",
|
||||
"SET_PARAM(wfd-trigger-method)",
|
||||
"SETUP",
|
||||
"PLAY",
|
||||
"TEARDOWN",
|
||||
"PAUSE",
|
||||
"SET_PARAM(wfd-route)",
|
||||
"SET_PARAM(wfd-connector-type)",
|
||||
"SET_PARAM(wfd-standby)",
|
||||
"SET_PARAM(wfd-idr-request)",
|
||||
"SET_PARAM(wfd-uibc-cability)",
|
||||
"SET_PARAM(wfd-uibc-setting)",
|
||||
"GET_PARAM(keepalive)",
|
||||
};
|
||||
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include "ctl.h"
|
||||
#include "wfd-arg.h"
|
||||
|
||||
#ifndef CTL_WFD_SESSION_H
|
||||
#define CTL_WFD_SESSION_H
|
||||
|
||||
#define wfd_out_session(s) (assert(wfd_is_out_session(s)), (struct wfd_out_session *) (s))
|
||||
#define wfd_in_session(s) (assert(wfd_is_in_session(s)), (struct wfd_in_session *) (s))
|
||||
|
||||
struct wfd_session;
|
||||
struct wfd_sink;
|
||||
struct rtsp;
|
||||
struct rtsp_message;
|
||||
|
||||
enum rtsp_message_id
|
||||
{
|
||||
RTSP_M_UNKNOWN,
|
||||
RTSP_M1_REQUEST_SINK_OPTIONS,
|
||||
RTSP_M2_REQUEST_SRC_OPTIONS,
|
||||
RTSP_M3_GET_PARAMETER,
|
||||
RTSP_M4_SET_PARAMETER,
|
||||
RTSP_M5_TRIGGER,
|
||||
RTSP_M6_SETUP,
|
||||
RTSP_M7_PLAY,
|
||||
RTSP_M8_TEARDOWN,
|
||||
RTSP_M9_PAUSE,
|
||||
RTSP_M10_SET_ROUTE,
|
||||
RTSP_M11_SET_CONNECTOR_TYPE,
|
||||
RTSP_M12_SET_STANDBY,
|
||||
RTSP_M13_REQUEST_IDR,
|
||||
RTSP_M14_ESTABLISH_UIBC,
|
||||
RTSP_M15_ENABLE_UIBC,
|
||||
RTSP_M16_KEEPALIVE,
|
||||
};
|
||||
|
||||
enum wfd_stream_id
|
||||
{
|
||||
WFD_STREAM_ID_PRIMARY,
|
||||
WFD_STREAM_ID_SECONDARY,
|
||||
};
|
||||
|
||||
enum wfd_session_arg_id
|
||||
{
|
||||
WFD_SESSION_ARG_NEXT_REQUEST,
|
||||
WFD_SESSION_ARG_NEW_STATE,
|
||||
WFD_SESSION_ARG_REQUEST_ARGS,
|
||||
};
|
||||
|
||||
struct rtsp_dispatch_entry
|
||||
{
|
||||
union {
|
||||
int (*request)(struct wfd_session *s,
|
||||
const struct wfd_arg_list *args,
|
||||
struct rtsp_message **out);
|
||||
int (*handle_request)(struct wfd_session *s,
|
||||
struct rtsp_message *req,
|
||||
struct rtsp_message **out_rep);
|
||||
};
|
||||
int (*handle_reply)(struct wfd_session *s,
|
||||
struct rtsp_message *m);
|
||||
struct wfd_arg_list rule;
|
||||
};
|
||||
|
||||
struct wfd_session_vtable
|
||||
{
|
||||
int (*initiate_io)(struct wfd_session *s, int *out_fd, uint32_t *out_mask);
|
||||
int (*handle_io)(struct wfd_session *s, int error, int *out_fd);
|
||||
int (*initiate_request)(struct wfd_session *s);
|
||||
int (*resume)(struct wfd_session *);
|
||||
int (*pause)(struct wfd_session *);
|
||||
int (*teardown)(struct wfd_session *);
|
||||
void (*destroy)(struct wfd_session *s);
|
||||
};
|
||||
|
||||
struct wfd_session
|
||||
{
|
||||
enum wfd_session_dir dir;
|
||||
enum wfd_session_state state;
|
||||
enum rtsp_message_id last_request;
|
||||
const struct rtsp_dispatch_entry *rtsp_disp_tbl;
|
||||
|
||||
unsigned int id;
|
||||
struct rtsp *rtsp;
|
||||
uint16_t rtp_ports[2];
|
||||
struct wfd_video_formats *vformats;
|
||||
struct wfd_audio_codecs *acodecs;
|
||||
|
||||
struct {
|
||||
enum wfd_stream_id id;
|
||||
char *url;
|
||||
uint16_t rtp_port;
|
||||
uint16_t rtcp_port;
|
||||
} stream;
|
||||
};
|
||||
|
||||
int wfd_session_init(struct wfd_session *s);
|
||||
int wfd_session_gen_stream_url(struct wfd_session *s,
|
||||
const char *local_addr,
|
||||
enum wfd_stream_id id);
|
||||
int wfd_session_request(struct wfd_session *s,
|
||||
enum rtsp_message_id id,
|
||||
const struct wfd_arg_list *args);
|
||||
void wfd_session_end(struct wfd_session *s);
|
||||
struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s);
|
||||
void wfd_session_set_state(struct wfd_session *s,
|
||||
enum wfd_session_state state);
|
||||
|
||||
#endif /* CTL_WFD_SESSION_H */
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#define LOG_SUBSYSTEM "wfd-session"
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "ctl.h"
|
||||
#include "wfd-dbus.h"
|
||||
|
||||
static int wfd_sink_set_session(struct wfd_sink *sink,
|
||||
struct wfd_session *session)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(sink->session == session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(session) {
|
||||
r = ctl_wfd_add_session(ctl_wfd_get(), session);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if(sink->session) {
|
||||
ctl_wfd_remove_session_by_id(ctl_wfd_get(),
|
||||
wfd_session_get_id(sink->session),
|
||||
NULL);
|
||||
}
|
||||
|
||||
sink->session = session;
|
||||
wfd_fn_sink_properties_changed(sink, "Session");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wfd_sink_new(struct wfd_sink **out,
|
||||
struct ctl_peer *peer,
|
||||
union wfd_sube *sube)
|
||||
{
|
||||
struct wfd_sink *sink;
|
||||
|
||||
assert(out);
|
||||
assert(peer);
|
||||
assert(sube && wfd_sube_device_is_sink(sube));
|
||||
|
||||
sink = calloc(1, sizeof(struct wfd_sink));
|
||||
if(!sink) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sink->label = strdup(peer->label);
|
||||
if(!sink->label) {
|
||||
wfd_sink_free(sink);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sink->peer = peer;
|
||||
sink->dev_info = *sube;
|
||||
|
||||
*out = sink;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfd_sink_free(struct wfd_sink *sink)
|
||||
{
|
||||
struct wfd_session *s;
|
||||
|
||||
if(!sink) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(sink->session) {
|
||||
s = sink->session;
|
||||
wfd_sink_set_session(sink, NULL);
|
||||
wfd_session_free(s);
|
||||
}
|
||||
|
||||
if(sink->label) {
|
||||
free(sink->label);
|
||||
}
|
||||
|
||||
free(sink);
|
||||
}
|
||||
|
||||
const char * wfd_sink_get_label(struct wfd_sink *sink)
|
||||
{
|
||||
return sink->label;
|
||||
}
|
||||
|
||||
const union wfd_sube * wfd_sink_get_dev_info(struct wfd_sink *sink)
|
||||
{
|
||||
return &sink->dev_info;
|
||||
}
|
||||
|
||||
struct ctl_peer * wfd_sink_get_peer(struct wfd_sink *sink)
|
||||
{
|
||||
return sink->peer;
|
||||
}
|
||||
|
||||
int wfd_sink_start_session(struct wfd_sink *sink,
|
||||
struct wfd_session **out,
|
||||
const char *authority,
|
||||
const char *display,
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
uint16_t width,
|
||||
uint16_t height,
|
||||
const char *audio_dev)
|
||||
{
|
||||
int r;
|
||||
_wfd_session_free_ struct wfd_session *s = NULL;
|
||||
|
||||
assert(sink);
|
||||
assert(out);
|
||||
|
||||
if(wfd_sink_is_session_started(sink)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
r = wfd_out_session_new(&s,
|
||||
sink,
|
||||
authority,
|
||||
display,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
audio_dev);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = wfd_session_start(s, ctl_wfd_alloc_session_id(ctl_wfd_get()));
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = wfd_sink_set_session(sink, s);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
wfd_fn_sink_properties_changed(sink, "Session");
|
||||
|
||||
sink->session = s;
|
||||
*out = s;
|
||||
s = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wfd_fn_out_session_ended(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_out_session(s));
|
||||
|
||||
wfd_sink_set_session(wfd_out_session_get_sink(s), NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool wfd_sink_is_session_started(struct wfd_sink *sink)
|
||||
{
|
||||
return NULL != sink->session;
|
||||
}
|
||||
585
src/ctl/wfdctl.c
585
src/ctl/wfdctl.c
|
|
@ -1,585 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#define LOG_SUBSYSTEM "wfdctl"
|
||||
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include "ctl.h"
|
||||
#include "wfd.h"
|
||||
#include "wfd-dbus.h"
|
||||
#include "config.h"
|
||||
|
||||
static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus);
|
||||
static void ctl_wfd_free(struct ctl_wfd *wfd);
|
||||
|
||||
static struct ctl_wfd *wfd = NULL;
|
||||
static struct wfd_dbus *wfd_dbus = NULL;
|
||||
|
||||
struct wfd_dbus * wfd_dbus_get()
|
||||
{
|
||||
return wfd_dbus;
|
||||
}
|
||||
|
||||
struct ctl_wfd * ctl_wfd_get()
|
||||
{
|
||||
return wfd;
|
||||
}
|
||||
|
||||
int ctl_wfd_new(struct ctl_wfd **out, sd_event *loop, sd_bus *bus)
|
||||
{
|
||||
int r;
|
||||
struct ctl_wfd *wfd = calloc(1, sizeof(struct ctl_wfd));
|
||||
if(!wfd) {
|
||||
r = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
shl_htable_init_str(&wfd->sinks);
|
||||
shl_htable_init_uint(&wfd->sessions);
|
||||
wfd->loop = sd_event_ref(loop);
|
||||
|
||||
r = ctl_wfd_init(wfd, bus);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
*out = wfd;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
ctl_wfd_free(wfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ctl_wfd_free(struct ctl_wfd *wfd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!wfd) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctl_wifi_free(wfd->wifi);
|
||||
wfd->wifi = NULL;
|
||||
shl_htable_clear_str(&wfd->sinks, NULL, NULL);
|
||||
shl_htable_clear_uint(&wfd->sessions, NULL, NULL);
|
||||
|
||||
for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); ++ i) {
|
||||
if(wfd->signal_sources[i]) {
|
||||
sd_event_source_set_enabled(wfd->signal_sources[i], SD_EVENT_OFF);
|
||||
sd_event_source_unref(wfd->signal_sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(wfd->loop) {
|
||||
sd_event_unref(wfd->loop);
|
||||
}
|
||||
|
||||
free(wfd);
|
||||
}
|
||||
|
||||
int ctl_wfd_add_sink(struct ctl_wfd *wfd,
|
||||
struct ctl_peer *p,
|
||||
union wfd_sube *sube,
|
||||
struct wfd_sink **out)
|
||||
{
|
||||
_wfd_sink_free_ struct wfd_sink *s = NULL;
|
||||
int r = shl_htable_lookup_str(&wfd->sinks,
|
||||
p->label,
|
||||
NULL,
|
||||
NULL);
|
||||
if(r) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
r = wfd_sink_new(&s, p, sube);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = shl_htable_insert_str(&wfd->sinks,
|
||||
wfd_sink_to_htable(s),
|
||||
NULL);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
++wfd->n_sinks;
|
||||
*out = s;
|
||||
s = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctl_wfd_find_sink_by_label(struct ctl_wfd *wfd,
|
||||
const char *label,
|
||||
struct wfd_sink **out)
|
||||
{
|
||||
char **entry;
|
||||
int r = shl_htable_lookup_str(&wfd->sinks, label, NULL, &entry);
|
||||
if(r) {
|
||||
*out = wfd_sink_from_htable(entry);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ctl_wfd_remove_sink_by_label(struct ctl_wfd *wfd,
|
||||
const char *label,
|
||||
struct wfd_sink **out)
|
||||
{
|
||||
char **entry;
|
||||
int r = shl_htable_remove_str(&wfd->sinks, label, NULL, &entry);
|
||||
if(!r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
--wfd->n_sinks;
|
||||
|
||||
if(out) {
|
||||
*out = wfd_sink_from_htable(entry);
|
||||
}
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned int ctl_wfd_alloc_session_id(struct ctl_wfd *wfd)
|
||||
{
|
||||
return ++wfd->id_pool;
|
||||
}
|
||||
|
||||
int ctl_wfd_add_session(struct ctl_wfd *wfd, struct wfd_session *s)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(wfd);
|
||||
assert(s && wfd_session_get_id(s));
|
||||
assert(!ctl_wfd_find_session_by_id(wfd, wfd_session_get_id(s), NULL));
|
||||
|
||||
r = shl_htable_insert_uint(&wfd->sessions, wfd_session_to_htable(s));
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
++wfd->n_sessions;
|
||||
|
||||
wfd_fn_session_new(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ctl_wfd_find_session_by_id(struct ctl_wfd *wfd,
|
||||
unsigned int id,
|
||||
struct wfd_session **out)
|
||||
{
|
||||
unsigned int *entry;
|
||||
int r = shl_htable_lookup_uint(&wfd->sessions, id, &entry);
|
||||
if(r && out) {
|
||||
*out = wfd_session_from_htable(entry);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ctl_wfd_remove_session_by_id(struct ctl_wfd *wfd,
|
||||
unsigned int id,
|
||||
struct wfd_session **out)
|
||||
{
|
||||
unsigned int *entry;
|
||||
struct wfd_session *s;
|
||||
int r = shl_htable_remove_uint(&wfd->sessions, id, &entry);
|
||||
if(!r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
--wfd->n_sessions;
|
||||
|
||||
s = wfd_session_from_htable(entry);
|
||||
wfd_fn_session_free(s);
|
||||
if(out) {
|
||||
*out = s;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ctl_wfd_fetch_info(sd_event_source *s, void *userdata)
|
||||
{
|
||||
struct ctl_wfd *wfd = userdata;
|
||||
int r;
|
||||
|
||||
sd_event_source_unref(s);
|
||||
|
||||
r = ctl_wifi_fetch(wfd->wifi);
|
||||
if(0 > r) {
|
||||
log_warning("failed to fetch information about links and peers: %s",
|
||||
strerror(errno));
|
||||
sd_event_exit(wfd->loop, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ctl_wfd_handle_signal(sd_event_source *s,
|
||||
const struct signalfd_siginfo *si,
|
||||
void *userdata)
|
||||
{
|
||||
struct ctl_wfd *wfd = userdata;
|
||||
|
||||
sd_event_source_set_enabled(s, false);
|
||||
|
||||
return sd_event_exit(wfd->loop, 0);
|
||||
}
|
||||
|
||||
static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus)
|
||||
{
|
||||
int i, r;
|
||||
const int signals[SHL_ARRAY_LENGTH(wfd->signal_sources)] = {
|
||||
SIGINT, SIGHUP, SIGQUIT, SIGTERM
|
||||
};
|
||||
struct ctl_wifi *wifi;
|
||||
|
||||
for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); i ++) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signals[i]);
|
||||
r = sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
if(0 > r) {
|
||||
break;
|
||||
}
|
||||
|
||||
r = sd_event_add_signal(wfd->loop,
|
||||
&wfd->signal_sources[i],
|
||||
signals[i],
|
||||
ctl_wfd_handle_signal,
|
||||
wfd);
|
||||
if(0 > r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = ctl_wifi_new(&wifi, bus);
|
||||
if(0 > r) {
|
||||
r = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = sd_event_add_defer(wfd->loop, NULL, ctl_wfd_fetch_info, wfd);
|
||||
if(0 > r) {
|
||||
ctl_wifi_free(wifi);
|
||||
goto end;
|
||||
}
|
||||
|
||||
wfd->wifi = wifi;
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Callbacks from ctl-src */
|
||||
void wfd_fn_src_connected(struct wfd_src *s)
|
||||
{
|
||||
}
|
||||
|
||||
void wfd_fn_src_disconnected(struct wfd_src *s)
|
||||
{
|
||||
}
|
||||
|
||||
void wfd_fn_src_setup(struct wfd_src *s)
|
||||
{
|
||||
}
|
||||
|
||||
void wfd_fn_src_playing(struct wfd_src *s)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_peer_new(struct ctl_peer *p)
|
||||
{
|
||||
struct wfd_sink *s;
|
||||
union wfd_sube sube;
|
||||
int r;
|
||||
|
||||
log_debug("new peer %s (%s) shows up, wfd_subelems: '%s'",
|
||||
p->friendly_name,
|
||||
p->label,
|
||||
p->wfd_subelements);
|
||||
|
||||
r = wfd_sube_parse(p->wfd_subelements, &sube);
|
||||
if(0 > r) {
|
||||
log_debug("peer %s has invalid subelement", p->label);
|
||||
return;
|
||||
}
|
||||
|
||||
if(wfd_sube_device_is_sink(&sube)) {
|
||||
r = ctl_wfd_add_sink(ctl_wfd_get(), p, &sube, &s);
|
||||
if(0 > r) {
|
||||
log_warning("failed to add sink (%s, '%s'): %s",
|
||||
p->friendly_name,
|
||||
p->p2p_mac,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
r = wfd_fn_sink_new(s);
|
||||
if(0 > r) {
|
||||
log_warning("failed to publish newly added sink (%s): %s",
|
||||
wfd_sink_get_label(s),
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("sink %s added", s->label);
|
||||
}
|
||||
|
||||
if(wfd_sube_device_is_source(&sube)) {
|
||||
log_info("source %s ignired", p->label);
|
||||
}
|
||||
}
|
||||
|
||||
void ctl_fn_peer_free(struct ctl_peer *p)
|
||||
{
|
||||
struct wfd_sink *s;
|
||||
int r;
|
||||
|
||||
r = ctl_wfd_remove_sink_by_label(wfd, p->label, &s);
|
||||
if(r) {
|
||||
wfd_fn_sink_free(s);
|
||||
log_info("sink %s removed", s->label);
|
||||
wfd_sink_free(s);
|
||||
}
|
||||
|
||||
log_info("peer %s down", p->label);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_provision_discovery(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_peer_go_neg_request(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_peer_formation_failure(struct ctl_peer *p, const char *reason)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_peer_connected(struct ctl_peer *p)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_peer_disconnected(struct ctl_peer *p)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_link_new(struct ctl_link *l)
|
||||
{
|
||||
}
|
||||
|
||||
void ctl_fn_link_free(struct ctl_link *l)
|
||||
{
|
||||
}
|
||||
|
||||
void cli_fn_help()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* see: https://lists.freedesktop.org/archives/systemd-devel/2014-August/022329.html
|
||||
**/
|
||||
#define SD_SOURCE(p) ((SDSource *) (p))
|
||||
|
||||
typedef struct _SDSource SDSource;
|
||||
|
||||
struct _SDSource
|
||||
{
|
||||
GSource source;
|
||||
sd_event *event;
|
||||
GPollFD pollfd;
|
||||
};
|
||||
|
||||
static gboolean sd_source_prepare(GSource *source, gint *timeout)
|
||||
{
|
||||
return sd_event_prepare(SD_SOURCE(source)->event) > 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static gboolean sd_source_check(GSource *source)
|
||||
{
|
||||
return sd_event_wait(SD_SOURCE(source)->event, 0) > 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static gboolean sd_source_dispatch(GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer userdata)
|
||||
{
|
||||
return sd_event_dispatch(SD_SOURCE(source)->event) >= 0
|
||||
? G_SOURCE_CONTINUE
|
||||
: G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void sd_source_finalize(GSource *source)
|
||||
{
|
||||
sd_event_unref(SD_SOURCE(source)->event);
|
||||
}
|
||||
|
||||
static int sd_source_on_exit(sd_event_source *source, void *userdata)
|
||||
{
|
||||
g_main_loop_quit(userdata);
|
||||
|
||||
sd_event_source_set_enabled(source, false);
|
||||
sd_event_source_unref(source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_source_attach(GSource *source, GMainLoop *loop)
|
||||
{
|
||||
g_source_set_name(source, "sd-event");
|
||||
g_source_add_poll(source, &SD_SOURCE(source)->pollfd);
|
||||
g_source_attach(source, g_main_loop_get_context(loop));
|
||||
|
||||
return sd_event_add_exit(SD_SOURCE(source)->event,
|
||||
NULL,
|
||||
sd_source_on_exit,
|
||||
loop);
|
||||
}
|
||||
|
||||
GSource * sd_source_new(sd_event *event)
|
||||
{
|
||||
static GSourceFuncs funcs = {
|
||||
sd_source_prepare,
|
||||
sd_source_check,
|
||||
sd_source_dispatch,
|
||||
sd_source_finalize,
|
||||
};
|
||||
GSource *s = g_source_new(&funcs, sizeof(SDSource));
|
||||
if(s) {
|
||||
SD_SOURCE(s)->event = sd_event_ref(event);
|
||||
SD_SOURCE(s)->pollfd.fd = sd_event_get_fd(event);
|
||||
SD_SOURCE(s)->pollfd.events = G_IO_IN | G_IO_HUP;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
|
||||
GMainLoop *loop;
|
||||
GSource *source;
|
||||
sd_event *event;
|
||||
sd_bus *bus;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_TIME, "en_US.UTF-8");
|
||||
|
||||
if(getenv("LOG_LEVEL")) {
|
||||
log_max_sev = log_parse_arg(getenv("LOG_LEVEL"));
|
||||
}
|
||||
|
||||
gst_init(&argc, &argv);
|
||||
|
||||
loop = g_main_loop_new(NULL, FALSE);
|
||||
if(!loop) {
|
||||
r = -ENOMEM;
|
||||
goto deinit_gst;
|
||||
}
|
||||
|
||||
r = sd_event_default(&event);
|
||||
if(0 > r) {
|
||||
goto unref_loop;
|
||||
}
|
||||
|
||||
source = sd_source_new(event);
|
||||
if(!source) {
|
||||
r = -ENOMEM;
|
||||
goto unref_event;
|
||||
}
|
||||
|
||||
r = sd_source_attach(source, loop);
|
||||
if(0 > r) {
|
||||
goto unref_source;
|
||||
}
|
||||
|
||||
r = sd_bus_default_system(&bus);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to connect to system DBus: %s", strerror(errno));
|
||||
goto unref_source;
|
||||
}
|
||||
|
||||
r = sd_bus_attach_event(bus, event, 0);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to attache DBus event source to loop: %s",
|
||||
strerror(errno));
|
||||
goto unref_bus;
|
||||
}
|
||||
|
||||
r = ctl_wfd_new(&wfd, event, bus);
|
||||
if(0 > r) {
|
||||
goto bus_detach_event;;
|
||||
}
|
||||
|
||||
r = wfd_dbus_new(&wfd_dbus, event, bus);
|
||||
if(0 > r) {
|
||||
goto free_ctl_wfd;
|
||||
}
|
||||
|
||||
r = wfd_dbus_expose(wfd_dbus);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to publish WFD service: %s", strerror(errno));
|
||||
goto free_wfd_dbus;
|
||||
}
|
||||
|
||||
g_main_loop_run(loop);
|
||||
|
||||
free_wfd_dbus:
|
||||
wfd_dbus_free(wfd_dbus);
|
||||
wfd_dbus = NULL;
|
||||
free_ctl_wfd:
|
||||
ctl_wfd_free(wfd);
|
||||
wfd = NULL;
|
||||
bus_detach_event:
|
||||
sd_bus_detach_event(bus);
|
||||
unref_bus:
|
||||
sd_bus_flush_close_unref(bus);
|
||||
unref_source:
|
||||
g_source_ref(source);
|
||||
g_source_destroy(source);
|
||||
unref_event:
|
||||
sd_event_run(event, 0);
|
||||
sd_event_unref(event);
|
||||
unref_loop:
|
||||
g_main_loop_unref(loop);
|
||||
deinit_gst:
|
||||
gst_deinit();
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue