mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
miracle-wfdctl: now we can establish WFD session multiple times
in this revision, the source side RTSP protocol is not implemented completely, the focus is on stability, DBus interfaces.
This commit is contained in:
parent
fa9f4ab555
commit
81d735f7b9
8 changed files with 985 additions and 359 deletions
|
@ -137,10 +137,31 @@ bool ctl_sink_is_connected(struct ctl_sink *s);
|
|||
bool ctl_sink_is_closed(struct ctl_sink *s);
|
||||
|
||||
/* wfd session */
|
||||
#define wfd_session(s) (assert(s), (struct wfd_session *) (s))
|
||||
#define wfd_is_session(s) ( \
|
||||
(s) && \
|
||||
(WFD_SESSION_DIR_OUT == wfd_session(s)->dir || \
|
||||
WFD_SESSION_DIR_IN == wfd_session(s)->dir) \
|
||||
)
|
||||
#define wfd_is_out_session(s) (WFD_SESSION_DIR_OUT == wfd_session(s)->dir)
|
||||
#define wfd_is_in_session(s) (WFD_SESSION_DIR_IN == wfd_session(s)->dir)
|
||||
#define wfd_session_to_htable(s) (&(s)->id)
|
||||
#define wfd_session_from_htable(s) (shl_htable_entry(s, struct wfd_session, id))
|
||||
#define _wfd_session_free_ _shl_cleanup_(wfd_session_freep)
|
||||
|
||||
struct wfd_sink;
|
||||
struct wfd_out_session;
|
||||
|
||||
enum wfd_session_state
|
||||
{
|
||||
WFD_SESSION_STATE_NULL,
|
||||
WFD_SESSION_STATE_CONNECTING,
|
||||
WFD_SESSION_STATE_CAPS_EXCHAING,
|
||||
WFD_SESSION_STATE_SETING_UP,
|
||||
WFD_SESSION_STATE_PLAYING,
|
||||
WFD_SESSION_STATE_PAUSED,
|
||||
WFD_SESSION_STATE_TEARING_DOWN,
|
||||
};
|
||||
|
||||
enum wfd_session_dir
|
||||
{
|
||||
|
@ -151,22 +172,29 @@ enum wfd_session_dir
|
|||
struct wfd_session
|
||||
{
|
||||
enum wfd_session_dir dir;
|
||||
enum wfd_session_state state;
|
||||
uint64_t id;
|
||||
char *url;
|
||||
int fd;
|
||||
struct rtsp *rtsp;
|
||||
|
||||
bool connected : 1;
|
||||
bool hup: 1;
|
||||
};
|
||||
|
||||
int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink);
|
||||
int wfd_session_start(struct wfd_session *s);
|
||||
int wfd_session_start(struct wfd_session *s, uint64_t id);
|
||||
int wfd_session_is_started(struct wfd_session *s);
|
||||
void wfd_session_end(struct wfd_session *s);
|
||||
void wfd_session_free(struct wfd_session *s);
|
||||
uint64_t wfd_session_get_id(struct wfd_session *s);
|
||||
void wfd_session_set_id(struct wfd_session *s, uint64_t id);
|
||||
struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s);
|
||||
static inline void wfd_session_freep(struct wfd_session **s)
|
||||
{
|
||||
wfd_session_free(*s);
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
/* wfd sink */
|
||||
#define _wfd_sink_free_ _shl_cleanup_(wfd_sink_freep)
|
||||
#define wfd_sink_to_htable(s) (&(s)->label)
|
||||
#define wfd_sink_from_htable(s) shl_htable_entry(s, struct wfd_sink, label)
|
||||
|
||||
|
@ -188,11 +216,23 @@ const char * wfd_sink_get_label(struct wfd_sink *sink);
|
|||
const union wfd_sube * wfd_sink_get_dev_info(struct wfd_sink *sink);
|
||||
int wfd_sink_start_session(struct wfd_sink *sink,
|
||||
struct wfd_session **session);
|
||||
void wfd_sink_handle_session_ended(struct wfd_sink *sink);
|
||||
bool wfd_sink_is_session_started(struct wfd_sink *sink);
|
||||
static inline void wfd_sink_freep(struct wfd_sink **s)
|
||||
{
|
||||
wfd_sink_free(*s);
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
/* wfd handling */
|
||||
#define ctl_wfd_foreach_sink(_i, _w) \
|
||||
SHL_HTABLE_FOREACH_MACRO(_i, &(_w)->sinks, wfd_sink_from_htable)
|
||||
SHL_HTABLE_FOREACH_MACRO(_i, \
|
||||
&(_w)->sinks, \
|
||||
wfd_sink_from_htable)
|
||||
#define ctl_wfd_foreach_session(_i, _w) \
|
||||
SHL_HTABLE_FOREACH_MACRO(_i, \
|
||||
&(_w)->sessions, \
|
||||
wfd_session_from_htable)
|
||||
|
||||
struct ctl_wfd
|
||||
{
|
||||
|
@ -206,18 +246,21 @@ struct ctl_wfd
|
|||
};
|
||||
|
||||
struct ctl_wfd * ctl_wfd_get();
|
||||
int ctl_wfd_new(struct ctl_wfd **out, sd_event *loop, sd_bus *bus);
|
||||
void ctl_wfd_free(struct ctl_wfd *wfd);
|
||||
int ctl_wfd_find_sink_by_label(struct ctl_wfd *wfd,
|
||||
const char *label,
|
||||
struct wfd_sink **out);
|
||||
int ctl_wfd_add_session(struct ctl_wfd *wfd, struct wfd_session *s);
|
||||
int ctl_wfd_find_session_by_id(struct ctl_wfd *wfd,
|
||||
unsigned int id,
|
||||
uint64_t id,
|
||||
struct wfd_session **out);
|
||||
int ctl_wfd_remove_session_by_id(struct ctl_wfd *wfd,
|
||||
uint64_t id,
|
||||
struct wfd_session **out);
|
||||
uint64_t ctl_wfd_alloc_session_id(struct ctl_wfd *wfd);
|
||||
static inline struct sd_event * ctl_wfd_get_loop()
|
||||
{
|
||||
return ctl_wfd_get()->loop;
|
||||
}
|
||||
|
||||
/* CLI handling */
|
||||
|
||||
|
@ -351,5 +394,12 @@ void ctl_fn_sink_resolution_set(struct ctl_sink *s);
|
|||
|
||||
void cli_fn_help(void);
|
||||
|
||||
int wfd_fn_sink_new(struct wfd_sink *s);
|
||||
int wfd_fn_sink_free(struct wfd_sink *s);
|
||||
|
||||
int wfd_fn_session_new(struct wfd_session *s);
|
||||
int wfd_fn_session_free(struct wfd_session *s);
|
||||
int wfd_fn_out_session_ended(struct wfd_session *s);
|
||||
|
||||
#endif /* CTL_CTL_H */
|
||||
|
||||
|
|
|
@ -24,6 +24,21 @@
|
|||
#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;
|
||||
|
@ -43,6 +58,7 @@ int wfd_dbus_new(struct wfd_dbus **out, sd_event *loop, sd_bus *bus)
|
|||
wfd_dbus->loop = sd_event_ref(loop);
|
||||
|
||||
*out = wfd_dbus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -95,9 +111,9 @@ static int wfd_dbus_enum(sd_bus *bus,
|
|||
{
|
||||
int r = 0, i = 0;
|
||||
char **nodes, *node;
|
||||
struct wfd_dbus *wfd_dbus = userdata;
|
||||
struct ctl_wfd *wfd = ctl_wfd_get();
|
||||
struct wfd_sink *sink;
|
||||
struct wfd_session *session;
|
||||
struct ctl_wfd *wfd = ctl_wfd_get();
|
||||
|
||||
if(strcmp("/org/freedesktop/miracle/wfd", path)) {
|
||||
return 0;
|
||||
|
@ -107,7 +123,7 @@ static int wfd_dbus_enum(sd_bus *bus,
|
|||
return 0;
|
||||
}
|
||||
|
||||
nodes = malloc((wfd->n_sinks + 1) * sizeof(char *));
|
||||
nodes = malloc((wfd->n_sinks + wfd->n_sessions + 1) * sizeof(char *));
|
||||
if(!nodes) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -120,6 +136,14 @@ static int wfd_dbus_enum(sd_bus *bus,
|
|||
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;
|
||||
|
||||
|
@ -133,20 +157,69 @@ free_nodes:
|
|||
return r;
|
||||
}
|
||||
|
||||
int wfd_dbus_notify_new_sink(struct wfd_dbus *wfd_dbus, const char *p2p_mac)
|
||||
int _wfd_dbus_object_removed(struct wfd_dbus *wfd_dbus,
|
||||
const char *path,
|
||||
const char **ifaces,
|
||||
size_t n_ifaces)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
int i, r;
|
||||
_sd_bus_message_unref_ sd_bus_message *m;
|
||||
int r = sd_bus_message_new_signal(wfd_dbus->bus,
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_signal(wfd_dbus->bus,
|
||||
&m,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
"org.freedesktop.DBus.ObjectManager",
|
||||
"InterfaceAdded");
|
||||
"InterfaceRemoved");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink", p2p_mac, &path);
|
||||
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;
|
||||
|
||||
if(!wfd_dbus) {
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_signal(wfd_dbus->bus,
|
||||
&m,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
"org.freedesktop.DBus.ObjectManager",
|
||||
"InterfaceAdded");
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
@ -161,30 +234,66 @@ int wfd_dbus_notify_new_sink(struct wfd_dbus *wfd_dbus, const char *p2p_mac)
|
|||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.miracle.wfd.Sink", 0);
|
||||
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;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, 'e', "sa{sv}");
|
||||
return sd_bus_send(wfd_dbus->bus, m, NULL);
|
||||
}
|
||||
|
||||
int wfd_fn_sink_new(struct wfd_sink *s)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
int r = sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink",
|
||||
wfd_sink_get_label(s),
|
||||
&path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/*r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);*/
|
||||
/*if (r < 0)*/
|
||||
/*return r;*/
|
||||
/*r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);*/
|
||||
/*if (r < 0)*/
|
||||
/*return r;*/
|
||||
/*r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);*/
|
||||
/*if (r < 0)*/
|
||||
/*return r;*/
|
||||
/*r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);*/
|
||||
/*if (r < 0)*/
|
||||
/*return r;*/
|
||||
return wfd_dbus_object_added(path, "org.freedesktop.miracle.wfd.Sink");
|
||||
}
|
||||
|
||||
return 0;
|
||||
int wfd_fn_sink_free(struct wfd_sink *s)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
int r = sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink",
|
||||
wfd_sink_get_label(s),
|
||||
&path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return wfd_dbus_object_added(path, "org.freedesktop.miracle.wfd.Sink");
|
||||
}
|
||||
|
||||
int _wfd_fn_sink_properties_changed(struct wfd_sink *s, char **names)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
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,
|
||||
|
@ -195,7 +304,6 @@ static int wfd_dbus_find_sink(sd_bus *bus,
|
|||
sd_bus_error *ret_error)
|
||||
{
|
||||
_shl_free_ char *node = NULL;
|
||||
struct wfd_dbus *wfd_dbus = userdata;
|
||||
struct wfd_sink *sink;
|
||||
int r = sd_bus_path_decode(path,
|
||||
"/org/freedesktop/miracle/wfd/sink",
|
||||
|
@ -212,6 +320,29 @@ static int wfd_dbus_find_sink(sd_bus *bus,
|
|||
return r;
|
||||
}
|
||||
|
||||
int wfd_fn_session_new(struct wfd_session *s)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
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;
|
||||
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,
|
||||
|
@ -219,7 +350,23 @@ static int wfd_dbus_find_session(sd_bus *bus,
|
|||
void **ret_found,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
return 0;
|
||||
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,
|
||||
|
@ -227,7 +374,7 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
|
|||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_sink *sink = userdata;
|
||||
struct wfd_session *session;
|
||||
_wfd_session_free_ struct wfd_session *session = NULL;
|
||||
_shl_free_ char *path = NULL;
|
||||
int r = wfd_sink_start_session(sink, &session);
|
||||
if(0 > r) {
|
||||
|
@ -236,52 +383,46 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
|
|||
|
||||
r = wfd_dbus_get_session_path(session, &path);
|
||||
if(0 > r) {
|
||||
goto free_session;
|
||||
}
|
||||
|
||||
log_debug("path=%s", path);
|
||||
r = sd_bus_reply_method_return(m, "o", path);
|
||||
if(0 <= r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
free_session:
|
||||
wfd_session_free(session);
|
||||
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_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_peer(sd_bus *bus,
|
||||
const char *path,
|
||||
|
@ -291,25 +432,36 @@ static int wfd_dbus_sink_get_peer(sd_bus *bus,
|
|||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
return 0;
|
||||
struct wfd_sink *s = userdata;
|
||||
_shl_free_ char *peer_path;
|
||||
int r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/peer",
|
||||
s->label,
|
||||
&peer_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
return sd_bus_message_append(reply, "o", peer_path);
|
||||
}
|
||||
|
||||
//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_end(sd_bus_message *m,
|
||||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
return 0;
|
||||
wfd_session_end(userdata);
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_get_sink(sd_bus *bus,
|
||||
|
@ -320,9 +472,35 @@ static int wfd_dbus_session_get_sink(sd_bus *bus,
|
|||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
_shl_free_ char *sink_path;
|
||||
int r;
|
||||
|
||||
if(s->dir != WFD_SESSION_DIR_OUT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = wfd_dbus_get_sink_path(wfd_out_session_get_sink(s),
|
||||
&sink_path);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_append(reply, "o", sink_path);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_get_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;
|
||||
return sd_bus_message_append(reply, "s", s->url);
|
||||
}
|
||||
|
||||
static int wfd_dbus_session_get_state(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
|
@ -331,7 +509,29 @@ static int wfd_dbus_session_get_state(sd_bus *bus,
|
|||
void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
return 0;
|
||||
struct wfd_session *s = userdata;
|
||||
return sd_bus_message_append(reply, "i", s->state);
|
||||
}
|
||||
|
||||
int _wfd_fn_session_properties_changed(struct wfd_session *s, char **names)
|
||||
{
|
||||
_shl_free_ char *path;
|
||||
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[] = {
|
||||
|
@ -346,7 +546,7 @@ static const sd_bus_vtable wfd_dbus_sink_vtable[] = {
|
|||
/*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("Peer", "o", wfd_dbus_sink_get_peer, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/
|
||||
SD_BUS_PROPERTY("Peer", "o", wfd_dbus_sink_get_peer, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
|
@ -354,6 +554,7 @@ static const sd_bus_vtable wfd_dbus_session_vtable[] = {
|
|||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("End", NULL, NULL, wfd_dbus_session_end, 0),
|
||||
SD_BUS_PROPERTY("Sink", "o", wfd_dbus_session_get_sink, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Url", "o", wfd_dbus_session_get_url, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("State", "i", wfd_dbus_session_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
@ -367,7 +568,7 @@ int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
|
|||
wfd_dbus_vtable,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_fallback_vtable(wfd_dbus->bus,
|
||||
|
@ -378,19 +579,19 @@ int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
|
|||
wfd_dbus_find_sink,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
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) {*/
|
||||
/*goto end;*/
|
||||
/*}*/
|
||||
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,
|
||||
|
@ -398,12 +599,12 @@ int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
|
|||
wfd_dbus_enum,
|
||||
wfd_dbus);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_add_object_manager(wfd_dbus->bus, NULL, "/org/freedesktop/miracle/wfd");
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_request_name(wfd_dbus->bus, "org.freedesktop.miracle.wfd", 0);
|
||||
|
@ -411,7 +612,6 @@ int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
|
|||
wfd_dbus->exposed = true;
|
||||
}
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,25 @@
|
|||
#ifndef CTL_WFD_DBUS_H
|
||||
#define CTL_WFD_DBUS_H
|
||||
|
||||
struct wfd_dbus;
|
||||
#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_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_dbus_notify_new_sink(struct wfd_dbus *wfd_dbus, const char *p2p_mac);
|
||||
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
|
||||
|
||||
|
|
|
@ -16,25 +16,20 @@
|
|||
* 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 <arpa/inet.h>
|
||||
#include "ctl.h"
|
||||
#include "rtsp.h"
|
||||
#include "wfd-dbus.h"
|
||||
|
||||
#define wfd_session(s) ((struct wfd_session *) (s))
|
||||
#define wfd_is_session(s) (\
|
||||
(s) && \
|
||||
(WFD_SESSION_DIR_OUT == wfd_session(s)->dir || \
|
||||
WFD_SESSION_DIR_IN == wfd_session(s)->dir) \
|
||||
)
|
||||
#define wfd_out_session(s) ((struct wfd_out_session *) (s))
|
||||
#define wfd_is_out_session(s) (WFD_SESSION_DIR_OUT == wfd_session(s)->dir)
|
||||
#define wfd_in_session(s) ((struct wfd_in_session *) (s))
|
||||
#define wfd_is_in_session(s) (WFD_SESSION_DIR_IN == wfd_session(s)->dir)
|
||||
#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_vtable
|
||||
{
|
||||
int (*start)(struct wfd_session *s);
|
||||
int (*end)(struct wfd_session *s);
|
||||
void (*end)(struct wfd_session *s);
|
||||
void (*distruct)(struct wfd_session *s);
|
||||
};
|
||||
|
||||
|
@ -42,10 +37,18 @@ struct wfd_out_session
|
|||
{
|
||||
struct wfd_session parent;
|
||||
struct wfd_sink *sink;
|
||||
int fd;
|
||||
|
||||
bool sink_has_video: 1;
|
||||
bool sink_has_audio: 1;
|
||||
bool sink_has_pref_disp_mode: 1;
|
||||
bool sink_has_3d: 1;
|
||||
bool sink_has_uibc: 1;
|
||||
};
|
||||
|
||||
static void wfd_session_set_state(struct wfd_session *s, enum wfd_session_state state);
|
||||
static int wfd_out_session_start(struct wfd_session *s);
|
||||
static int wfd_out_session_end(struct wfd_session *s);
|
||||
static void wfd_out_session_end(struct wfd_session *s);
|
||||
static void wfd_out_session_distruct(struct wfd_session *s);
|
||||
|
||||
static const struct wfd_session_vtable session_vtables[] = {
|
||||
|
@ -58,26 +61,25 @@ static const struct wfd_session_vtable session_vtables[] = {
|
|||
|
||||
int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink)
|
||||
{
|
||||
int r;
|
||||
struct wfd_out_session *s = calloc(1, sizeof(struct wfd_out_session));
|
||||
if(!s) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wfd_session(s)->dir = WFD_SESSION_DIR_OUT;
|
||||
wfd_session(s)->fd = -1;
|
||||
wfd_session(s)->hup = true;
|
||||
s->fd = -1;
|
||||
s->sink = sink;
|
||||
|
||||
r = ctl_wfd_add_session(ctl_wfd_get(), wfd_session(s));
|
||||
if(0 > r) {
|
||||
wfd_session_free(wfd_session(s));
|
||||
}
|
||||
else {
|
||||
*out = wfd_session(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_out_session(s));
|
||||
|
||||
return wfd_out_session(s)->sink;
|
||||
}
|
||||
|
||||
uint64_t wfd_session_get_id(struct wfd_session *s)
|
||||
|
@ -85,35 +87,94 @@ uint64_t wfd_session_get_id(struct wfd_session *s)
|
|||
return s->id;
|
||||
}
|
||||
|
||||
void wfd_session_set_id(struct wfd_session *s, uint64_t id)
|
||||
static void wfd_session_set_state(struct wfd_session *s,
|
||||
enum wfd_session_state state)
|
||||
{
|
||||
assert(id);
|
||||
|
||||
s->id = id;
|
||||
if(state == s->state) {
|
||||
return;
|
||||
}
|
||||
|
||||
int wfd_session_start(struct wfd_session *s)
|
||||
s->state = state;
|
||||
|
||||
wfd_fn_session_properties_changed(s, "State");
|
||||
}
|
||||
|
||||
int wfd_session_start(struct wfd_session *s, uint64_t id)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(wfd_is_session(s));
|
||||
assert(id);
|
||||
|
||||
if(wfd_session_is_started(s)) {
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
r = (*session_vtables[s->dir].start)(s);
|
||||
if(0 <= r) {
|
||||
s->id = id;
|
||||
wfd_session_set_state(s, WFD_SESSION_STATE_CONNECTING);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int wfd_session_is_started(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
return (*session_vtables[s->dir].start)(s);
|
||||
return 0 != s->id;
|
||||
}
|
||||
|
||||
void wfd_session_end(struct wfd_session *s)
|
||||
{
|
||||
assert(wfd_is_session(s));
|
||||
|
||||
if(!wfd_session_is_started(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("session %lu ended", s->id);
|
||||
|
||||
(*session_vtables[s->dir].end)(s);
|
||||
|
||||
if(s->rtsp) {
|
||||
rtsp_unref(s->rtsp);
|
||||
s->rtsp = NULL;
|
||||
}
|
||||
|
||||
if(s->url) {
|
||||
free(s->url);
|
||||
s->url = NULL;
|
||||
}
|
||||
|
||||
s->hup = false;
|
||||
|
||||
wfd_session_set_state(s, WFD_SESSION_STATE_NULL);
|
||||
|
||||
if(wfd_is_out_session(s)) {
|
||||
wfd_fn_out_session_ended(s);
|
||||
}
|
||||
}
|
||||
|
||||
void wfd_session_free(struct wfd_session *s)
|
||||
{
|
||||
enum wfd_session_dir dir;
|
||||
|
||||
if(!wfd_is_session(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(s->id) {
|
||||
ctl_wfd_remove_session_by_id(ctl_wfd_get(), s->id, NULL);
|
||||
if(wfd_is_out_session(s)) {
|
||||
wfd_out_session(s)->sink = NULL;
|
||||
}
|
||||
|
||||
if(session_vtables[s->dir].distruct) {
|
||||
(*session_vtables[s->dir].distruct)(s);
|
||||
wfd_session_end(s);
|
||||
|
||||
if(session_vtables[dir].distruct) {
|
||||
(*session_vtables[dir].distruct)(s);
|
||||
}
|
||||
free(s->url);
|
||||
rtsp_unref(s->rtsp);
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
@ -122,6 +183,11 @@ enum wfd_session_dir wfd_session_get_dir(struct wfd_session *s)
|
|||
return s->dir;
|
||||
}
|
||||
|
||||
const char * wfd_session_get_url(struct wfd_session *s)
|
||||
{
|
||||
return s->url;
|
||||
}
|
||||
|
||||
static int wfd_session_gen_url(struct wfd_session *s, const char *addr)
|
||||
{
|
||||
char *url;
|
||||
|
@ -134,172 +200,334 @@ static int wfd_session_gen_url(struct wfd_session *s, const char *addr)
|
|||
return r;
|
||||
}
|
||||
|
||||
int wfd_out_session_handle_message(struct rtsp *rtsp,
|
||||
static int wfd_out_session_handle_get_parameter_reply(struct rtsp *bus,
|
||||
struct rtsp_message *m,
|
||||
void *userdata)
|
||||
{
|
||||
log_debug("Received GET_PARAMETER reply (M4): %s\n",
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
if(RTSP_CODE_OK == rtsp_message_get_code(m)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warning("Sink reply GET_PARAMETER (M4) with code: %d",
|
||||
rtsp_message_get_code(m));
|
||||
|
||||
wfd_session_end(wfd_session(userdata));
|
||||
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
static int wfd_out_session_send_get_parameter(sd_event_source *source,
|
||||
void *userdata)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
||||
int r = rtsp_message_new_request(s->rtsp,
|
||||
&m,
|
||||
"GET_PARAMETER",
|
||||
s->url);
|
||||
if (0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_message_append(m, "{&}",
|
||||
"wfd_video_formats\n"
|
||||
"wfd_audio_codecs\n"
|
||||
"wfd_client_rtp_ports"
|
||||
//"wfd_uibc_capability"
|
||||
);
|
||||
if (0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rtsp_message_seal(m);
|
||||
|
||||
r = rtsp_call_async(s->rtsp,
|
||||
m,
|
||||
wfd_out_session_handle_get_parameter_reply,
|
||||
s,
|
||||
0,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_debug("Sending GET_PARAMETER (M3): %s\n",
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
wfd_session_end(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_handle_options_reply(struct rtsp *bus,
|
||||
struct rtsp_message *m,
|
||||
void *userdata)
|
||||
{
|
||||
int r = 0;
|
||||
/*struct wfd_src *s = data;*/
|
||||
/*_rtsp_message_unref_ struct rtsp_message *req = NULL;*/
|
||||
int r = 0, i;
|
||||
struct wfd_session *s = userdata;
|
||||
char *public, *methods[3] = { NULL };
|
||||
|
||||
/*cli_debug("INCOMING (M1): %s\n", rtsp_message_get_raw(m));*/
|
||||
log_trace("received OPTIONS reply (M1): %s",
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
/*if(!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) {*/
|
||||
/*cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Failed to get OPTIONS from sink\n");*/
|
||||
/*goto error;*/
|
||||
/*}*/
|
||||
|
||||
/*r = rtsp_message_new_request(s->rtsp,*/
|
||||
/*&req,*/
|
||||
/*"GET_PARAMETER",*/
|
||||
/*s->url);*/
|
||||
/*if (r < 0) {*/
|
||||
/*cli_vERR(r);*/
|
||||
/*goto error;*/
|
||||
/*}*/
|
||||
|
||||
/*r = rtsp_message_append(req, "{&}",*/
|
||||
/*"wfd_video_formats\n"*/
|
||||
/*//"wfd_audio_codecs\n"*/
|
||||
/*"wfd_client_rtp_ports\n"*/
|
||||
/*//"wfd_uibc_capability"*/
|
||||
/*);*/
|
||||
/*if (r < 0) {*/
|
||||
/*cli_vERR(r);*/
|
||||
/*goto error;*/
|
||||
/*}*/
|
||||
|
||||
/*rtsp_message_seal(req);*/
|
||||
/*cli_debug("OUTGOING (M3): %s\n", rtsp_message_get_raw(req));*/
|
||||
|
||||
/*r = rtsp_call_async(s->rtsp, req, src_get_parameter_rep_fn, s, 0, NULL);*/
|
||||
/*if (r < 0) {*/
|
||||
/*cli_vERR(r);*/
|
||||
/*goto error;*/
|
||||
/*}*/
|
||||
|
||||
/*return 0;*/
|
||||
|
||||
/*error:*/
|
||||
/*wfd_src_close(s);*/
|
||||
/*wfd_fn_src_disconnected(s);*/
|
||||
|
||||
return r;
|
||||
if(!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) {
|
||||
r = -EPROTO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
static int wfd_out_session_send_options(struct wfd_session *s)
|
||||
r = rtsp_message_read(m, "<&>", "Public", &public);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sscanf(public, "%m[^,], %m[^,], %ms", &methods[0], &methods[1], &methods[2]);
|
||||
if(3 != r) {
|
||||
r = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for(i = 0; i < SHL_ARRAY_LENGTH(methods); i ++) {
|
||||
if(strcmp("org.wfa.wfd1.0", methods[i]) &&
|
||||
strcmp("SET_PARAMETER", methods[i]) &&
|
||||
strcmp("GET_PARAMETER", methods[i]))
|
||||
{
|
||||
_rtsp_message_unref_ struct rtsp_message *req = NULL;
|
||||
r = -EINVAL;
|
||||
log_info("Got invalid method from sink: %s", methods[i]);
|
||||
}
|
||||
|
||||
free(methods[i]);
|
||||
}
|
||||
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_add_defer(ctl_wfd_get_loop(),
|
||||
NULL,
|
||||
wfd_out_session_send_get_parameter,
|
||||
s);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
wfd_session_end(s);
|
||||
|
||||
log_info("error occured while handling reply of OPTIONS");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_send_options(sd_event_source *source,
|
||||
void *userdata)
|
||||
{
|
||||
struct wfd_session *s = userdata;
|
||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
||||
int r = rtsp_message_new_request(s->rtsp,
|
||||
&req,
|
||||
"OPTIONS",
|
||||
"*");
|
||||
&m,
|
||||
"OPTIONS", "*");
|
||||
if (0 > r) {
|
||||
return r;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_message_append(req, "<s>",
|
||||
"Require",
|
||||
"org.wfa.wfd1.0");
|
||||
r = rtsp_message_append(m,
|
||||
"<s>",
|
||||
"Require", "org.wfa.wfd1.0");
|
||||
if (0 > r) {
|
||||
return r;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_message_seal(req);
|
||||
r = rtsp_message_seal(m);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_call_async(s->rtsp,
|
||||
req,
|
||||
m,
|
||||
wfd_out_session_handle_options_reply,
|
||||
s,
|
||||
0,
|
||||
NULL);
|
||||
if (0 > r) {
|
||||
return r;
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_debug("Sending RTSP M1 message: %s",
|
||||
(char *) rtsp_message_get_raw(req));
|
||||
log_debug("sending OPTIONS (M1): %s", (char *) rtsp_message_get_raw(m));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
log_info("failed to send OPTIONS request: %s", strerror(errno));
|
||||
wfd_session_end(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_handle_incoming_conn(struct wfd_out_session *os)
|
||||
static int wfd_out_session_handle_options_request(struct rtsp *bus,
|
||||
struct rtsp_message *request,
|
||||
struct wfd_session *s)
|
||||
{
|
||||
int r, val;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
_shl_close_ int fd = -1;
|
||||
sd_event *loop;
|
||||
struct wfd_session *s = wfd_session(os);
|
||||
|
||||
log_debug("got connection request\n");
|
||||
|
||||
len = sizeof(addr);
|
||||
fd = accept4(s->fd, (struct sockaddr *) &addr, &len, SOCK_CLOEXEC);
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
if(0 > fd) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len);
|
||||
if (r < 0) {
|
||||
s->hup = true;
|
||||
return r;
|
||||
}
|
||||
else if (val) {
|
||||
s->hup = true;
|
||||
errno = val;
|
||||
return r;
|
||||
}
|
||||
|
||||
cli_debug("connection established");
|
||||
|
||||
r = rtsp_open(&s->rtsp, s->fd);
|
||||
const char *require;
|
||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
||||
int r = rtsp_message_read(request, "<s>", "Require", &require);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_default(&loop);
|
||||
if(strcmp("org.wfa.wfd1.0", require)) {
|
||||
r = rtsp_message_new_reply_for(request,
|
||||
&m,
|
||||
RTSP_CODE_OPTION_NOT_SUPPORTED,
|
||||
"Invalid specification");
|
||||
}
|
||||
else {
|
||||
r = rtsp_message_new_reply_for(request,
|
||||
&m,
|
||||
RTSP_CODE_OK,
|
||||
NULL);
|
||||
if(0 > r) {
|
||||
goto unref_rtsp;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_attach_event(s->rtsp, loop, 0);
|
||||
sd_event_unref(loop);
|
||||
if (0 > r) {
|
||||
goto unref_rtsp;
|
||||
r = rtsp_message_append(m,
|
||||
"<s>",
|
||||
"Public", "org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER");
|
||||
}
|
||||
|
||||
r = rtsp_add_match(s->rtsp, wfd_out_session_handle_message, s);
|
||||
if(0 > r) {
|
||||
goto unref_rtsp;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = wfd_out_session_send_options(s);
|
||||
r = rtsp_message_seal(m);
|
||||
if(0 > r) {
|
||||
goto unref_rtsp;
|
||||
goto error;
|
||||
}
|
||||
|
||||
s->fd = fd;
|
||||
fd = -1;
|
||||
s->connected = true;
|
||||
//wfd_fn_src_connected(s);
|
||||
r = rtsp_send(bus, m);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_debug("sending OPTIONS reply (M2): %s",
|
||||
(char *) rtsp_message_get_raw(m));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
s->hup = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_dispatch_request(struct rtsp *bus,
|
||||
struct rtsp_message *m,
|
||||
void *userdata)
|
||||
{
|
||||
const char *method;
|
||||
struct wfd_session *s = userdata;
|
||||
int r = 0;
|
||||
|
||||
if (!m) {
|
||||
s->hup = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
method = rtsp_message_get_method(m);
|
||||
if(!method) {
|
||||
log_info("unexpected message: %s", (char *) rtsp_message_get_raw(m));
|
||||
r = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(method, "OPTIONS")) {
|
||||
r = wfd_out_session_handle_options_request(bus, m, s);
|
||||
}
|
||||
/*else if (!strcmp(method, "GET_PARAMETER")) {*/
|
||||
/*wfd_out_session_handle_get_parameter_reply(s, m);*/
|
||||
/*}*/
|
||||
/*[>else if (!strcmp(method, "SETUP")) {<]*/
|
||||
/*[>wfd_out_session_handle_setup_reply(s, m);<]*/
|
||||
/*[>}<]*/
|
||||
/*[>else if (!strcmp(method, "PLAY")) {<]*/
|
||||
/*[>wfd_out_session_handle_play_reply(s, m);<]*/
|
||||
/*[>}<]*/
|
||||
/*[>else if (!strcmp(method, "PAUSE")) {<]*/
|
||||
/*[>wfd_out_session_handle_pause_reply(s, m);<]*/
|
||||
/*[>}<]*/
|
||||
/*[>else if (!strcmp(method, "TEARDOWN")) {<]*/
|
||||
/*[>wfd_out_session_handle_teardown_reply(s, m);<]*/
|
||||
/*[>}<]*/
|
||||
|
||||
end:
|
||||
if (s->hup) {
|
||||
wfd_session_end(s);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static int wfd_out_session_accept_connection(struct wfd_out_session *os)
|
||||
{
|
||||
int r;
|
||||
socklen_t len;
|
||||
struct sockaddr_storage addr;
|
||||
_shl_close_ int fd = -1;
|
||||
sd_event *loop = ctl_wfd_get_loop();
|
||||
struct wfd_session *s = wfd_session(os);
|
||||
_rtsp_unref_ struct rtsp *rtsp = NULL;
|
||||
|
||||
log_debug("accepting incoming RTSP connection\n");
|
||||
|
||||
len = sizeof(addr);
|
||||
fd = accept4(os->fd,
|
||||
(struct sockaddr *) &addr,
|
||||
&len,
|
||||
SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||
if(0 > fd) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
log_info("RTSP connection established");
|
||||
|
||||
r = rtsp_open(&rtsp, fd);
|
||||
if (0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
|
||||
r = rtsp_attach_event(rtsp, loop, 0);
|
||||
if (0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = rtsp_add_match(rtsp, wfd_out_session_dispatch_request, s);
|
||||
if (0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_add_defer(loop, NULL, wfd_out_session_send_options, s);
|
||||
if(0 > r) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
wfd_session_set_state(s, WFD_SESSION_STATE_CAPS_EXCHAING);
|
||||
|
||||
s->rtsp = rtsp;
|
||||
rtsp = NULL;
|
||||
|
||||
close(os->fd);
|
||||
os->fd = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
unref_rtsp:
|
||||
rtsp_unref(s->rtsp);
|
||||
error:
|
||||
s->hup = true;
|
||||
return r;
|
||||
|
@ -310,24 +538,33 @@ static int wfd_out_session_handle_io(sd_event_source *source,
|
|||
uint32_t mask,
|
||||
void *userdata)
|
||||
{
|
||||
sd_event_source_set_enabled(source, SD_EVENT_OFF);
|
||||
sd_event_source_unref(source);
|
||||
int r, val;
|
||||
socklen_t len;
|
||||
struct wfd_session *s = userdata;
|
||||
|
||||
if (mask & EPOLLIN) {
|
||||
return wfd_out_session_handle_incoming_conn(userdata);
|
||||
sd_event_source_set_enabled(source, SD_EVENT_OFF);
|
||||
|
||||
if (mask & EPOLLERR) {
|
||||
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len);
|
||||
s->hup = true;
|
||||
if(0 <= r) {
|
||||
r = -val;
|
||||
errno = val;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*if (mask & EPOLLERR) {*/
|
||||
/*cli_notice("ERR on socket");*/
|
||||
/*s->hup = true;*/
|
||||
/*}*/
|
||||
if (mask & EPOLLIN) {
|
||||
r = wfd_out_session_accept_connection(userdata);
|
||||
}
|
||||
|
||||
/*if (s->hup) {*/
|
||||
/*wfd_src_close(s);*/
|
||||
/*wfd_fn_src_disconnected(s);*/
|
||||
/*}*/
|
||||
end:
|
||||
if (s->hup) {
|
||||
log_info("failed to accept remote connection: %s", strerror(errno));
|
||||
wfd_session_end(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_start(struct wfd_session *s)
|
||||
|
@ -336,9 +573,8 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
union wfd_sube sube;
|
||||
struct sockaddr_in addr = {};
|
||||
struct ctl_peer *p = os->sink->peer;
|
||||
int enable;
|
||||
_shl_close_ int fd = -1;
|
||||
sd_event *loop;
|
||||
int enable;
|
||||
int r;
|
||||
|
||||
if(!os->sink->peer->connected) {
|
||||
|
@ -346,7 +582,9 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
r = wfd_sube_parse(p->l->wfd_subelements, &sube);
|
||||
r = wfd_sube_parse_with_id(WFD_SUBE_ID_DEVICE_INFO,
|
||||
p->l->wfd_subelements,
|
||||
&sube);
|
||||
if(0 > r) {
|
||||
log_warning("WfdSubelements property of link must be set before P2P scan");
|
||||
return -EINVAL;
|
||||
|
@ -355,6 +593,10 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
if(-1 != os->fd) {
|
||||
return EINPROGRESS;
|
||||
}
|
||||
|
||||
r = inet_pton(AF_INET, p->local_address, &addr.sin_addr);
|
||||
if (!r) {
|
||||
return -EAFNOSUPPORT;
|
||||
|
@ -380,7 +622,7 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
return r;
|
||||
}
|
||||
|
||||
r = listen(fd, 1);
|
||||
r = listen(fd, 10);
|
||||
if (0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
@ -389,15 +631,10 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
p->local_address,
|
||||
wfd_sube_device_get_rtsp_port(&sube));
|
||||
|
||||
r = sd_event_default(&loop);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(loop,
|
||||
r = sd_event_add_io(ctl_wfd_get_loop(),
|
||||
NULL,
|
||||
fd,
|
||||
EPOLLERR | EPOLLIN | EPOLLET,
|
||||
EPOLLIN,
|
||||
wfd_out_session_handle_io,
|
||||
s);
|
||||
if (r < 0) {
|
||||
|
@ -406,20 +643,27 @@ static int wfd_out_session_start(struct wfd_session *s)
|
|||
|
||||
r = wfd_session_gen_url(s, p->local_address);
|
||||
if(0 <= r) {
|
||||
s->fd = fd;
|
||||
os->fd = fd;
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int wfd_out_session_end(struct wfd_session *s)
|
||||
static void wfd_out_session_end(struct wfd_session *s)
|
||||
{
|
||||
return 0;
|
||||
struct wfd_out_session *os = wfd_out_session(s);
|
||||
if(os->fd) {
|
||||
close(os->fd);
|
||||
os->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void wfd_out_session_distruct(struct wfd_session *s)
|
||||
{
|
||||
|
||||
struct wfd_out_session *os = wfd_out_session(s);
|
||||
if(0 <= os->fd) {
|
||||
close(os->fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,15 +16,17 @@
|
|||
* 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 "ctl.h"
|
||||
#include "wfd-dbus.h"
|
||||
|
||||
int wfd_sink_new(struct wfd_sink **out,
|
||||
struct ctl_peer *peer,
|
||||
union wfd_sube *sube)
|
||||
{
|
||||
struct wfd_sink *sink;
|
||||
int r;
|
||||
|
||||
assert(out);
|
||||
assert(peer);
|
||||
|
@ -84,7 +86,7 @@ struct ctl_peer * wfd_sink_get_peer(struct wfd_sink *sink)
|
|||
int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out)
|
||||
{
|
||||
int r;
|
||||
struct wfd_session *session = NULL;
|
||||
_wfd_session_free_ struct wfd_session *s = NULL;
|
||||
|
||||
assert(sink);
|
||||
assert(out);
|
||||
|
@ -93,27 +95,45 @@ int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out)
|
|||
return -EALREADY;
|
||||
}
|
||||
|
||||
r = wfd_out_session_new(&session, sink);
|
||||
r = wfd_out_session_new(&s, sink);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = wfd_session_start(session);
|
||||
r = wfd_session_start(s, ctl_wfd_alloc_session_id(ctl_wfd_get()));
|
||||
if(0 > r) {
|
||||
goto free_session;
|
||||
return r;
|
||||
}
|
||||
|
||||
sink->session = session;
|
||||
*out = session;
|
||||
|
||||
goto end;
|
||||
|
||||
free_session:
|
||||
wfd_session_free(session);
|
||||
end:
|
||||
r = ctl_wfd_add_session(ctl_wfd_get(), 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));
|
||||
|
||||
struct wfd_sink *sink = wfd_out_session_get_sink(s);
|
||||
if(sink) {
|
||||
wfd_fn_sink_properties_changed(sink, "Session");
|
||||
ctl_wfd_remove_session_by_id(ctl_wfd_get(), s->id, NULL);
|
||||
sink->session = NULL;
|
||||
wfd_session_free(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool wfd_sink_is_session_started(struct wfd_sink *sink)
|
||||
{
|
||||
return NULL != sink->session;
|
||||
|
|
|
@ -305,16 +305,28 @@ static int wfd_sube_parse_ext_caps(const char *in, union wfd_sube *out)
|
|||
int wfd_sube_parse(const char *in, union wfd_sube *out)
|
||||
{
|
||||
uint8_t id;
|
||||
uint16_t len;
|
||||
const char *eoi = in + strlen(in);
|
||||
int r;
|
||||
|
||||
if((in + 6) >= eoi) {
|
||||
if((in + 2) >= eoi) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sscanf(in, "%2hhx%4hx", &id, &len);
|
||||
if(2 > r) {
|
||||
r = sscanf(in, "%2hhx", &id);
|
||||
if(1 > r) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return wfd_sube_parse_with_id(id, in + 2, out);
|
||||
}
|
||||
|
||||
int wfd_sube_parse_with_id(enum wfd_sube_id id,
|
||||
const char *in,
|
||||
union wfd_sube *out)
|
||||
{
|
||||
uint16_t len;
|
||||
int r = sscanf(in, "%4hx", &len);
|
||||
if(1 > r) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -326,7 +338,7 @@ int wfd_sube_parse(const char *in, union wfd_sube *out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = (*parse_func_tbl[id])(in + 6, out);
|
||||
r = (*parse_func_tbl[id])(in + 4, out);
|
||||
if(0 > r) {
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,9 @@ int vfd_get_cea_resolution(uint32_t mask, int *hres, int *vres);
|
|||
int vfd_get_vesa_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int vfd_get_hh_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int wfd_sube_parse(const char *in, union wfd_sube *out);
|
||||
int wfd_sube_parse_with_id(enum wfd_sube_id id,
|
||||
const char *in,
|
||||
union wfd_sube *out);
|
||||
|
||||
static inline int wfd_sube_device_get_type(const union wfd_sube *sube)
|
||||
{
|
||||
|
|
216
src/ctl/wfdctl.c
216
src/ctl/wfdctl.c
|
@ -41,7 +41,8 @@
|
|||
#include "shl_log.h"
|
||||
#include "config.h"
|
||||
|
||||
void ctl_wfd_free(struct ctl_wfd *wfd);
|
||||
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;
|
||||
|
@ -61,42 +62,51 @@ 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) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = ctl_wifi_new(&wfd->wifi, bus);
|
||||
if(0 > r) {
|
||||
ctl_wfd_free(wfd);
|
||||
return -ENOMEM;
|
||||
r = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
shl_htable_init_str(&wfd->sinks);
|
||||
shl_htable_init_u64(&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_clear_sink(char **elem, void *ctx)
|
||||
{
|
||||
if(*elem == ctx) {
|
||||
return;
|
||||
}
|
||||
wfd_sink_free(wfd_sink_from_htable(elem));
|
||||
}
|
||||
|
||||
static void ctl_wfd_clear_session(uint64_t *elem, void *ctx)
|
||||
static void ctl_wfd_destroy(struct ctl_wfd *wfd)
|
||||
{
|
||||
wfd_session_free(wfd_session_from_htable(elem));
|
||||
ctl_wifi_free(wfd->wifi);
|
||||
wfd->wifi = NULL;
|
||||
shl_htable_clear_str(&wfd->sinks, NULL, NULL);
|
||||
shl_htable_clear_u64(&wfd->sessions, NULL, NULL);
|
||||
}
|
||||
|
||||
void ctl_wfd_free(struct ctl_wfd *wfd)
|
||||
static void ctl_wfd_free(struct ctl_wfd *wfd)
|
||||
{
|
||||
if(!wfd) {
|
||||
return;
|
||||
}
|
||||
|
||||
shl_htable_clear_str(&wfd->sinks, ctl_wfd_clear_sink, NULL);
|
||||
shl_htable_clear_u64(&wfd->sessions, ctl_wfd_clear_session, NULL);
|
||||
ctl_wfd_destroy(wfd);
|
||||
|
||||
if(wfd->loop) {
|
||||
sd_event_unref(wfd->loop);
|
||||
|
@ -105,26 +115,39 @@ void ctl_wfd_free(struct ctl_wfd *wfd)
|
|||
free(wfd);
|
||||
}
|
||||
|
||||
static int ctl_wfd_add_sink(struct ctl_wfd *wfd, struct wfd_sink *sink)
|
||||
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;
|
||||
int r = shl_htable_lookup_str(&wfd->sinks,
|
||||
wfd_sink_get_label(sink),
|
||||
p->label,
|
||||
NULL,
|
||||
NULL);
|
||||
if(r) {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
r = shl_htable_insert_str(&wfd->sinks,
|
||||
wfd_sink_to_htable(sink),
|
||||
NULL);
|
||||
if(0 <= r) {
|
||||
++wfd->n_sinks;
|
||||
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)
|
||||
|
@ -138,16 +161,29 @@ int ctl_wfd_find_sink_by_label(struct ctl_wfd *wfd,
|
|||
return r;
|
||||
}
|
||||
|
||||
static int ctl_wfd_remove_sink_by_label(struct ctl_wfd *wfd, const char *label)
|
||||
static int ctl_wfd_remove_sink_by_label(struct ctl_wfd *wfd,
|
||||
const char *label,
|
||||
struct wfd_sink **out)
|
||||
{
|
||||
char **entry;
|
||||
if(!shl_htable_remove_str(&wfd->sinks, label, NULL, &entry)) {
|
||||
return 0;
|
||||
int r = shl_htable_remove_str(&wfd->sinks, label, NULL, &entry);
|
||||
if(!r) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
wfd_sink_free(wfd_sink_from_htable(entry));
|
||||
--wfd->n_sinks;
|
||||
|
||||
return 1;
|
||||
if(out) {
|
||||
*out = wfd_sink_from_htable(entry);
|
||||
}
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t 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)
|
||||
|
@ -155,9 +191,8 @@ int ctl_wfd_add_session(struct ctl_wfd *wfd, struct wfd_session *s)
|
|||
int r;
|
||||
|
||||
assert(wfd);
|
||||
assert(s && !s->id);
|
||||
|
||||
wfd_session_set_id(s, ++wfd->id_pool);
|
||||
assert(s && s->id);
|
||||
assert(!ctl_wfd_find_session_by_id(wfd, s->id, NULL));
|
||||
|
||||
r = shl_htable_insert_u64(&wfd->sessions, wfd_session_to_htable(s));
|
||||
if(0 > r) {
|
||||
|
@ -166,11 +201,13 @@ int ctl_wfd_add_session(struct ctl_wfd *wfd, struct wfd_session *s)
|
|||
|
||||
++wfd->n_sessions;
|
||||
|
||||
wfd_fn_session_new(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ctl_wfd_find_session_by_id(struct ctl_wfd *wfd,
|
||||
unsigned int id,
|
||||
uint64_t id,
|
||||
struct wfd_session **out)
|
||||
{
|
||||
uint64_t *entry;
|
||||
|
@ -187,9 +224,31 @@ int ctl_wfd_remove_session_by_id(struct ctl_wfd *wfd,
|
|||
struct wfd_session **out)
|
||||
{
|
||||
uint64_t *entry;
|
||||
struct wfd_session *s;
|
||||
int r = shl_htable_remove_u64(&wfd->sessions, id, &entry);
|
||||
if(r && out) {
|
||||
*out = wfd_session_from_htable(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 = 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;
|
||||
|
@ -199,20 +258,23 @@ static int ctl_wfd_handle_signal(sd_event_source *s,
|
|||
const struct signalfd_siginfo *si,
|
||||
void *userdata)
|
||||
{
|
||||
int r;
|
||||
sd_event_source *exit_source;
|
||||
struct ctl_wfd *wfd = userdata;
|
||||
ctl_wfd_destroy(wfd);
|
||||
|
||||
sd_event_exit(wfd->loop, 0);
|
||||
|
||||
sd_event_source_unref(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctl_wfd_init(struct ctl_wfd *wfd)
|
||||
static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus)
|
||||
{
|
||||
int i;
|
||||
int i, r;
|
||||
const int signals[] = { SIGINT, SIGHUP, SIGQUIT, SIGTERM };
|
||||
int r = ctl_wifi_fetch(wfd->wifi);
|
||||
if(0 > r) {
|
||||
goto end;
|
||||
}
|
||||
struct ctl_wifi *wifi;
|
||||
|
||||
for(i = 0; i < SHL_ARRAY_LENGTH(signals); i ++) {
|
||||
sigset_t mask;
|
||||
|
@ -233,6 +295,20 @@ int ctl_wfd_init(struct ctl_wfd *wfd)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -261,52 +337,59 @@ 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 = wfd_sube_parse(p->wfd_subelements, &sube);
|
||||
int r = wfd_sube_parse_with_id(WFD_SUBE_ID_DEVICE_INFO,
|
||||
p->wfd_subelements,
|
||||
&sube);
|
||||
if(0 > r) {
|
||||
log_debug("invalid subelement: '%s'", p->wfd_subelements);
|
||||
return;
|
||||
}
|
||||
|
||||
if(wfd_sube_device_is_sink(&sube)) {
|
||||
struct wfd_sink *sink;
|
||||
if(0 > wfd_sink_new(&sink, p, &sube)) {
|
||||
log_warning("failed to create sink (%s): %s",
|
||||
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;
|
||||
}
|
||||
if(0 > ctl_wfd_add_sink(wfd, sink)) {
|
||||
wfd_sink_free(sink);
|
||||
log_warning("failed to add sink (%s): %s",
|
||||
p->p2p_mac,
|
||||
|
||||
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;
|
||||
}
|
||||
/*if(0 > wfd_dbus_notify_new_sink(wfd_dbus, p->p2p_mac)) {*/
|
||||
/*log_warning("failed to notify about newly added sink (%s): %s",*/
|
||||
/*p->p2p_mac,*/
|
||||
/*strerror(errno));*/
|
||||
/*return;*/
|
||||
/*}*/
|
||||
log_debug("sink added: %s (%s)",
|
||||
wfd_sink_get_label(sink),
|
||||
p->friendly_name);
|
||||
|
||||
log_info("sink %s added", s->label);
|
||||
}
|
||||
}
|
||||
|
||||
void ctl_fn_peer_free(struct ctl_peer *p)
|
||||
{
|
||||
union wfd_sube sube;
|
||||
int r = wfd_sube_parse(p->wfd_subelements, &sube);
|
||||
if(0 > r) {
|
||||
log_debug("invalid subelement: %s", p->wfd_subelements);
|
||||
struct wfd_sink *s;
|
||||
_shl_free_ char *label;
|
||||
int r = ctl_wfd_remove_sink_by_label(wfd, p->label, &s);
|
||||
if(!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(wfd_sube_device_is_sink(&sube)) {
|
||||
ctl_wfd_remove_sink_by_label(wfd, p->label);
|
||||
label = strdup(s->label);
|
||||
|
||||
r = wfd_fn_sink_free(s);
|
||||
if(0 > r) {
|
||||
log_warning("failed to unpublish removed sink (%s): %s",
|
||||
wfd_sink_get_label(s),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
wfd_sink_free(s);
|
||||
|
||||
log_info("sink %s removed", label);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_provision_discovery(struct ctl_peer *p,
|
||||
|
@ -364,11 +447,14 @@ int main(int argc, char **argv)
|
|||
|
||||
r = sd_bus_default_system(&bus);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to connect to system DBus: %s", strerror(errno));
|
||||
goto unref_loop;
|
||||
}
|
||||
|
||||
r = sd_bus_attach_event(bus, loop, 0);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to attache DBus event source to loop: %s",
|
||||
strerror(errno));
|
||||
goto unref_bus;
|
||||
}
|
||||
|
||||
|
@ -377,11 +463,6 @@ int main(int argc, char **argv)
|
|||
goto bus_detach_event;;
|
||||
}
|
||||
|
||||
r = ctl_wfd_init(wfd);
|
||||
if(0 > r) {
|
||||
goto free_ctl_wfd;
|
||||
}
|
||||
|
||||
r = wfd_dbus_new(&wfd_dbus, loop, bus);
|
||||
if(0 > r) {
|
||||
goto free_ctl_wfd;
|
||||
|
@ -389,18 +470,21 @@ int main(int argc, char **argv)
|
|||
|
||||
r = wfd_dbus_expose(wfd_dbus);
|
||||
if(0 > r) {
|
||||
log_warning("unabled to publish WFD service: %s", strerror(errno));
|
||||
goto free_ctl_wfd;
|
||||
}
|
||||
|
||||
r = ctl_wfd_run(wfd);
|
||||
if(0 > r) {
|
||||
log_warning("%s\n", strerror(errno));
|
||||
log_warning("unabled to keep WFD service running: %s", strerror(errno));
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue