1
0
Fork 0
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:
Derek Dai 2017-03-19 13:39:22 +08:00
parent 5532bf14d1
commit b21aa0d039
No known key found for this signature in database
GPG key ID: E109CC97553EF009
16 changed files with 44 additions and 47 deletions

View file

@ -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:

View file

@ -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);
}
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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)",
};

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}