1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00

miracle-wfdctl: finish migration of source side rtsp protocol

This commit is contained in:
Derek Dai 2017-02-15 18:19:16 +08:00
parent 3bcb8f51f6
commit 9dd805378e
No known key found for this signature in database
GPG key ID: E109CC97553EF009
5 changed files with 428 additions and 200 deletions

View file

@ -162,7 +162,7 @@ enum wfd_session_state
{ {
WFD_SESSION_STATE_NULL, WFD_SESSION_STATE_NULL,
WFD_SESSION_STATE_CONNECTING, WFD_SESSION_STATE_CONNECTING,
WFD_SESSION_STATE_CAPS_EXCHAING, WFD_SESSION_STATE_CAPS_EXCHANGING,
WFD_SESSION_STATE_ESTABLISHED, WFD_SESSION_STATE_ESTABLISHED,
WFD_SESSION_STATE_SETING_UP, WFD_SESSION_STATE_SETING_UP,
WFD_SESSION_STATE_PLAYING, WFD_SESSION_STATE_PLAYING,
@ -174,7 +174,7 @@ int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink);
int wfd_session_start(struct wfd_session *s, uint64_t id); int wfd_session_start(struct wfd_session *s, uint64_t id);
enum wfd_session_dir wfd_session_get_dir(struct wfd_session *s); enum wfd_session_dir wfd_session_get_dir(struct wfd_session *s);
uint64_t wfd_session_get_id(struct wfd_session *s); uint64_t wfd_session_get_id(struct wfd_session *s);
const char * wfd_session_get_url(struct wfd_session *s); const char * wfd_session_get_stream_url(struct wfd_session *s);
enum wfd_session_state wfd_session_get_state(struct wfd_session *s); enum wfd_session_state wfd_session_get_state(struct wfd_session *s);
int wfd_session_is_started(struct wfd_session *s); int wfd_session_is_started(struct wfd_session *s);
void wfd_session_end(struct wfd_session *s); void wfd_session_end(struct wfd_session *s);

View file

@ -489,7 +489,7 @@ static int wfd_dbus_session_get_sink(sd_bus *bus,
return sd_bus_message_append(reply, "o", sink_path); return sd_bus_message_append(reply, "o", sink_path);
} }
static int wfd_dbus_session_get_url(sd_bus *bus, static int wfd_dbus_get_session_presentation_url(sd_bus *bus,
const char *path, const char *path,
const char *interface, const char *interface,
const char *property, const char *property,
@ -498,10 +498,12 @@ static int wfd_dbus_session_get_url(sd_bus *bus,
sd_bus_error *ret_error) sd_bus_error *ret_error)
{ {
struct wfd_session *s = userdata; struct wfd_session *s = userdata;
return sd_bus_message_append(reply, "s", wfd_session_get_url(s)); return sd_bus_message_append(reply,
"s",
wfd_session_get_stream_url(s));
} }
static int wfd_dbus_session_get_state(sd_bus *bus, static int wfd_dbus_get_session_state(sd_bus *bus,
const char *path, const char *path,
const char *interface, const char *interface,
const char *property, const char *property,
@ -554,8 +556,8 @@ static const sd_bus_vtable wfd_dbus_session_vtable[] = {
SD_BUS_VTABLE_START(0), SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("End", NULL, NULL, wfd_dbus_session_end, 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("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("Url", "o", wfd_dbus_get_session_presentation_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_PROPERTY("State", "i", wfd_dbus_get_session_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_VTABLE_END, SD_BUS_VTABLE_END,
}; };

View file

@ -186,67 +186,104 @@ static int wfd_out_session_initiate_request(struct wfd_session *s)
return wfd_session_request(s, RTSP_M1_REQUEST_SINK_OPTIONS); return wfd_session_request(s, RTSP_M1_REQUEST_SINK_OPTIONS);
} }
/*static int wfd_out_session_handle_get_parameter_reply(struct rtsp *bus,*/ static int wfd_out_session_handle_get_parameter_reply(struct wfd_session *s,
/*struct rtsp_message *m,*/ struct rtsp_message *m,
/*void *userdata)*/ enum wfd_session_state *new_state,
/*{*/ enum rtsp_message_id *next_request)
/*struct wfd_session *s = userdata;*/ {
struct wfd_video_formats *vformats;
struct wfd_audio_codecs *acodecs;
uint16_t rtp_ports[2];
_shl_free_ char *t = NULL;
const char *l;
int r;
/*log_debug("received GET_PARAMETER reply (M3): %s\n",*/ if(!rtsp_message_read(m, "{<&>}", "wfd_video_formats", &l)) {
/*(char *) rtsp_message_get_raw(m));*/ r = wfd_video_formats_from_string(l, &vformats);
/*if(RTSP_CODE_OK != rtsp_message_get_code(m)) {*/ if(0 > r) {
/*wfd_session_end(wfd_session(userdata));*/ return r;
/*return -EPROTO;*/ }
/*}*/
/*return 0;*/ if(s->vformats) {
/*}*/ free(s->vformats);
}
s->vformats = vformats;
}
/*static int wfd_out_session_send_get_parameter(sd_event_source *source,*/ if(!rtsp_message_read(m, "{<&>}", "wfd_audio_codecs", &l)) {
/*void *userdata)*/ r = wfd_audio_codecs_from_string(l, &acodecs);
/*{*/ if(0 > r) {
/*struct wfd_session *s = userdata;*/ return r;
/*_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, "{&}",*/ if(s->acodecs) {
/*"wfd_video_formats\n"*/ free(s->acodecs);
/*"wfd_audio_codecs\n"*/ }
/*"wfd_client_rtp_ports"*/ s->acodecs = acodecs;
/*//"wfd_uibc_capability"*/ }
/*);*/
/*if (0 > r) {*/
/*goto error;*/
/*}*/
/*rtsp_message_seal(m);*/ if(!rtsp_message_read(m, "{<&>}", "wfd_client_rtp_ports", &l)) {
if(strncmp("RTP/AVP/UDP;unicast", l, 19)) {
return -EPROTO;
}
/*r = rtsp_call_async(s->rtsp,*/ r = sscanf(l + 20, "%hd %hd %ms",
/*m,*/ &rtp_ports[0],
/*wfd_out_session_handle_get_parameter_reply,*/ &rtp_ports[1],
/*s,*/ &t);
/*0,*/ if(3 != r) {
/*NULL);*/ return -EPROTO;
/*if (r < 0) {*/ }
/*goto error;*/
/*}*/
/*log_debug("Sending GET_PARAMETER (M3): %s\n",*/ if(strncmp("mode=play", t, 9)) {
/*(char *) rtsp_message_get_raw(m));*/ return -EPROTO;
}
/*return 0;*/ if(!rtp_ports[0] && !rtp_ports[1]) {
return -EPROTO;
}
/*error:*/ s->rtp_ports[0] = rtp_ports[0];
/*wfd_session_end(s);*/ s->rtp_ports[1] = rtp_ports[1];
}
/*return r;*/ *next_request = RTSP_M4_SET_PARAMETER;
/*}*/
return 0;
}
static int wfd_out_session_request_get_parameter(struct wfd_session *s,
struct rtsp_message **out)
{
_rtsp_message_unref_ struct rtsp_message *m = NULL;
int r = rtsp_message_new_request(s->rtsp,
&m,
"GET_PARAMETER",
"rtsp://localhost/wfd1.0");
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;
}
*out = m;
m = NULL;
return 0;
error:
wfd_session_end(s);
return r;
}
static bool find_strv(const char *str, char **strv) static bool find_strv(const char *str, char **strv)
{ {
@ -262,7 +299,9 @@ static bool find_strv(const char *str, char **strv)
static int wfd_out_session_handle_options_request(struct wfd_session *s, static int wfd_out_session_handle_options_request(struct wfd_session *s,
struct rtsp_message *req, struct rtsp_message *req,
struct rtsp_message **out_rep) struct rtsp_message **out_rep,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{ {
const char *require; const char *require;
_rtsp_message_unref_ struct rtsp_message *rep = NULL; _rtsp_message_unref_ struct rtsp_message *rep = NULL;
@ -298,11 +337,15 @@ static int wfd_out_session_handle_options_request(struct wfd_session *s,
*out_rep = rep; *out_rep = rep;
rep = NULL; rep = NULL;
*next_request = RTSP_M3_GET_PARAMETER;
return 0; return 0;
} }
static int wfd_out_session_check_options_reply(struct wfd_session *s, static int wfd_out_session_handle_options_reply(struct wfd_session *s,
struct rtsp_message *m) struct rtsp_message *m,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{ {
int r; int r;
const char *public; const char *public;
@ -356,104 +399,200 @@ static int wfd_out_session_request_options(struct wfd_session *s,
return 0; return 0;
} }
/*static int wfd_out_session_handle_options_request(struct rtsp *bus,*/ static int wfd_out_session_handle_play_request(struct wfd_session *s,
/*struct rtsp_message *request,*/ struct rtsp_message *req,
/*struct wfd_session *s)*/ struct rtsp_message **out_rep,
/*{*/ enum wfd_session_state *new_state,
/*}*/ enum rtsp_message_id *next_request)
static int wfd_out_session_handle_play_reply(struct rtsp *bus,
struct rtsp_message *m,
void *userdata)
{ {
/*struct wfd_session *s = userdata;*/ _rtsp_message_unref_ struct rtsp_message *m = NULL;
/*log_trace("received SETUP (M5) reply: %s",*/
/*(char *) rtsp_message_get_raw(m));*/
/*wfd_out_session_send_play(s);*/
return 0;
}
static int wfd_out_session_send_play(struct wfd_session *s)
{
return 0;
}
static int wfd_out_session_handle_setup_reply(struct rtsp *bus,
struct rtsp_message *m,
void *userdata)
{
/*struct wfd_session *s = userdata;*/
/*log_trace("received SETUP (M5) reply: %s",*/
/*(char *) rtsp_message_get_raw(m));*/
/*wfd_out_session_send_play(s);*/
return 0;
}
static int wfd_out_session_handle_set_parameter_reply(struct rtsp *bus,
struct rtsp_message *m,
void *userdata)
{
/*struct wfd_session *s = userdata;*/
/*log_trace("received SET_PARAMETER (M4) reply: %s",*/
/*(char *) rtsp_message_get_raw(m));*/
/*wfd_out_session_send_setup(s);*/
return 0;
}
static int wfd_out_session_send_set_parameter_request(struct wfd_session *s)
{
/*_rtsp_message_unref_ struct rtsp_message *req;*/
int r; int r;
/*const static char tmp[] =*/
/*"wfd_video_formats: 38 00 02 10 00000080 00000000 00000000 00 0000 0000 11 none none\n"*/
/*//"wfd_audio_codecs: AAC 00000001 00\n"*/
/*//"wfd_uibc_capability: input_category_list=GENERIC\n;generic_cap_list=SingleTouch;hidc_cap_list=none;port=5100\n"*/
/*//"wfd_uibc_setting: disable\n"*/
/*"wfd_presentation_URL: %s/streamid=0 none\n"*/
/*"wfd_client_rtp_ports: %s %d %d mode=play";*/
/*r = rtsp_message_new_request(s->rtsp,*/
/*&req,*/
/*"SET_PARAMETER",*/
/*s->url);*/
/*if (r < 0) {*/
/*cli_vERR(r);*/
/*goto error;*/
/*}*/
/*snprintf(buf, sizeof(buf), tmp, s->url, s->sink.rtp_ports.profile,*/
/*s->sink.rtp_ports.port0, s->sink.rtp_ports.port1);*/
/*r = rtsp_message_append(req, "{&}", buf);*/
/*if (r < 0) {*/
/*cli_vERR(r);*/
/*goto error;*/
/*}*/
/*rtsp_message_seal(req);*/
/*cli_debug("OUTGOING (M4): %s\n", rtsp_message_get_raw(req));*/
/*r = rtsp_call_async(s->rtsp, req, src_set_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);*/
r = rtsp_message_new_reply_for(req,
&m,
RTSP_CODE_OK,
NULL);
if(0 > r) {
return r; return r;
} }
r = rtsp_message_append(m, "<u>", "Session", (uint32_t) s->id);
if(0 > r) {
return r;
}
*out_rep = m;
m = NULL;
*new_state = WFD_SESSION_STATE_PLAYING;
return 0;
}
static int wfd_out_session_handle_setup_request(struct wfd_session *s,
struct rtsp_message *req,
struct rtsp_message **out_rep,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{
int r;
const char *l;
_rtsp_message_unref_ struct rtsp_message *m = NULL;
_shl_free_ char *sess = NULL, *trans = NULL;
r = rtsp_message_read(req, "<s>", "Transport", &l);
if(0 > r) {
return -EPROTO;
}
if(strncmp("RTP/AVP/UDP;unicast;", l, 20)) {
return -EPROTO;
}
l += 20;
if(strncmp("client_port=", l, 12)) {
return -EPROTO;
}
l += 12;
errno = 0;
s->stream.rtp_port = strtoul(l, NULL, 10);
if(errno) {
return -errno;
}
r = rtsp_message_new_reply_for(req,
&m,
RTSP_CODE_OK,
NULL);
if(0 > r) {
return r;
}
r = asprintf(&sess, "%" PRIu64 ";timeout=30", s->id);
if(0 > r) {
return r;
}
r = rtsp_message_append(m, "<&>", "Session", sess);
if(0 > r) {
return r;
}
r = asprintf(&trans, "RTP/AVP/UDP;unicast;client_port=%hd",
s->stream.rtp_port);
if(0 > r) {
return r;
}
r = rtsp_message_append(m, "<&>", "Transport", trans);
if(0 > r) {
return r;
}
*out_rep = m;
m = NULL;
return 0;
}
static int wfd_out_session_request_trigger(struct wfd_session *s,
struct rtsp_message **out)
{
_rtsp_message_unref_ struct rtsp_message *m = NULL;
int r;
switch(wfd_session_get_state(s)) {
case WFD_SESSION_STATE_ESTABLISHED:
r = rtsp_message_new_request(s->rtsp,
&m,
"SET_PARAMETER",
wfd_session_get_stream_url(s));
if(0 > r) {
return r;
}
r = rtsp_message_append(m, "{<s>}",
"wfd_trigger_method",
"SETUP");
if(0 > r) {
return r;
}
break;
default:
break;
}
if(m) {
*out = m;
m = NULL;
}
return 0;
}
static int wfd_out_session_handle_set_parameter_reply(struct wfd_session *s,
struct rtsp_message *m,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{
*new_state = WFD_SESSION_STATE_ESTABLISHED;
*next_request = RTSP_M5_TRIGGER;
return 0;
}
static int wfd_out_session_request_set_parameter(struct wfd_session *s,
struct rtsp_message **out)
{
_rtsp_message_unref_ struct rtsp_message *m;
_shl_free_ char *body = NULL;
int r;
r = wfd_session_gen_stream_url(s,
wfd_out_session(s)->sink->peer->local_address,
WFD_STREAM_ID_PRIMARY);
if(0 > r) {
return r;
}
s->stream.id = WFD_STREAM_ID_PRIMARY;
r = asprintf(&body,
"wfd_video_formats: 38 00 02 10 00000080 00000000 00000000 00 0000 0000 11 none none\n"
"wfd_audio_codecs: AAC 00000001 00\n"
"wfd_presentation_URL: %s none\n"
"wfd_client_rtp_ports: %u %u mode=play",
//"wfd_uibc_capability: input_category_list=GENERIC\n;generic_cap_list=SingleTouch;hidc_cap_list=none;port=5100\n"
//"wfd_uibc_setting: disable\n",
wfd_session_get_stream_url(s),
s->rtp_ports[0],
s->rtp_ports[1]);
if(0 > r) {
return r;
}
r = rtsp_message_new_request(s->rtsp,
&m,
"SET_PARAMETER",
"rtsp://localhost/wfd1.0");
if (0 > r) {
return r;
}
r = rtsp_message_append(m, "{&}", body);
if (0 > r) {
return r;
}
*out = m;
m = NULL;
return 0;
}
const struct wfd_session_vtable session_vtables[] = { const struct wfd_session_vtable session_vtables[] = {
[WFD_SESSION_DIR_OUT] = { [WFD_SESSION_DIR_OUT] = {
.initiate_io = wfd_out_session_initiate_io, .initiate_io = wfd_out_session_initiate_io,
@ -467,20 +606,27 @@ const struct wfd_session_vtable session_vtables[] = {
static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[] = { static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[] = {
[RTSP_M1_REQUEST_SINK_OPTIONS] = { [RTSP_M1_REQUEST_SINK_OPTIONS] = {
.request = wfd_out_session_request_options, .request = wfd_out_session_request_options,
.handle_reply = wfd_out_session_check_options_reply .handle_reply = wfd_out_session_handle_options_reply
}, },
[RTSP_M2_REQUEST_SRC_OPTIONS] = { [RTSP_M2_REQUEST_SRC_OPTIONS] = {
.handle_request = wfd_out_session_handle_options_request .handle_request = wfd_out_session_handle_options_request
}, },
[RTSP_M3_GET_PARAMETER] = { [RTSP_M3_GET_PARAMETER] = {
.request = wfd_out_session_request_get_parameter,
.handle_reply = wfd_out_session_handle_get_parameter_reply
}, },
[RTSP_M4_SET_PARAMETER] = { [RTSP_M4_SET_PARAMETER] = {
.request = wfd_out_session_request_set_parameter,
.handle_reply = wfd_out_session_handle_set_parameter_reply
}, },
[RTSP_M5_TRIGGER] = { [RTSP_M5_TRIGGER] = {
.request = wfd_out_session_request_trigger,
}, },
[RTSP_M6_SETUP] = { [RTSP_M6_SETUP] = {
.handle_request = wfd_out_session_handle_setup_request,
}, },
[RTSP_M7_PLAY] = { [RTSP_M7_PLAY] = {
.handle_request = wfd_out_session_handle_play_request,
}, },
[RTSP_M8_TEARDOWN] = { [RTSP_M8_TEARDOWN] = {
}, },

View file

@ -18,14 +18,19 @@
*/ */
#define LOG_SUBSYSTEM "wfd-session" #define LOG_SUBSYSTEM "wfd-session"
#include "ctl.h"
#include "rtsp.h" #include "rtsp.h"
#include "wfd-dbus.h" #include "wfd-dbus.h"
#include "wfd-session.h" #include "wfd-session.h"
#include "shl_macro.h" #include "shl_macro.h"
#define rtsp_message_id_is_valid(id) ( \ #define rtsp_message_id_is_valid(_id) ( \
(id) >= RTSP_M1_REQUEST_SINK_OPTIONS && \ (_id) >= RTSP_M1_REQUEST_SINK_OPTIONS && \
(id) <= RTSP_M16_KEEPALIVE \ (_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[]; static const char *rtsp_message_names[];
@ -47,26 +52,37 @@ static inline int wfd_session_do_request(struct wfd_session *s,
static inline int wfd_session_do_handle_request(struct wfd_session *s, static inline int wfd_session_do_handle_request(struct wfd_session *s,
enum rtsp_message_id id, enum rtsp_message_id id,
struct rtsp_message *req, struct rtsp_message *req,
struct rtsp_message **out_rep) struct rtsp_message **out_rep,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{ {
if(!rtsp_message_id_is_valid(id)) { if(!rtsp_message_id_is_valid(id)) {
return -EINVAL; return -EINVAL;
} }
assert(s->rtsp_disp_tbl[id].handle_request); assert(s->rtsp_disp_tbl[id].handle_request);
return (*s->rtsp_disp_tbl[id].handle_request)(s, req, out_rep); return (*s->rtsp_disp_tbl[id].handle_request)(s,
req,
out_rep,
new_state,
next_request);
} }
static inline int wfd_session_do_handle_reply(struct wfd_session *s, static inline int wfd_session_do_handle_reply(struct wfd_session *s,
enum rtsp_message_id id, enum rtsp_message_id id,
struct rtsp_message *m) struct rtsp_message *m,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request)
{ {
if(!rtsp_message_id_is_valid(id)) { if(!rtsp_message_id_is_valid(id)) {
return -EINVAL; return -EINVAL;
} }
assert(s->rtsp_disp_tbl[id].handle_reply);
return (*s->rtsp_disp_tbl[id].handle_reply)(s, m); if(!s->rtsp_disp_tbl[id].handle_reply) {
return 0;
}
return (*s->rtsp_disp_tbl[id].handle_reply)(s, m, new_state, next_request);
} }
uint64_t wfd_session_get_id(struct wfd_session *s) uint64_t wfd_session_get_id(struct wfd_session *s)
@ -115,12 +131,18 @@ void wfd_session_end(struct wfd_session *s)
s->rtsp = NULL; s->rtsp = NULL;
} }
if(s->url) { wfd_video_formats_free(s->vformats);
free(s->url); s->vformats = NULL;
s->url = NULL; wfd_audio_codecs_free(s->acodecs);
} s->acodecs = NULL;
free(s->stream.url);
s->stream.url = NULL;
s->last_request = RTSP_M_UNKNOWN;
wfd_session_set_state(s, WFD_SESSION_STATE_NULL); wfd_session_set_state(s, WFD_SESSION_STATE_NULL);
s->rtp_ports[0] = 0;
s->rtp_ports[1] = 0;
if(wfd_is_out_session(s)) { if(wfd_is_out_session(s)) {
wfd_fn_out_session_ended(s); wfd_fn_out_session_ended(s);
@ -149,11 +171,6 @@ enum wfd_session_dir wfd_session_get_dir(struct wfd_session *s)
return s->dir; return s->dir;
} }
const char * wfd_session_get_url(struct wfd_session *s)
{
return s->url;
}
uint64_t * wfd_session_to_htable(struct wfd_session *s) uint64_t * wfd_session_to_htable(struct wfd_session *s)
{ {
return &s->id; return &s->id;
@ -164,13 +181,27 @@ struct wfd_session * wfd_session_from_htable(uint64_t *e)
return shl_htable_entry(e, struct wfd_session, id); return shl_htable_entry(e, struct wfd_session, id);
} }
static int wfd_session_set_url(struct wfd_session *s, const char *addr) 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; char *url;
int r = asprintf(&url, "rtsp://%s/wfd1.0", addr); 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) { if(0 <= r) {
free(s->url); free(s->stream.url);
s->url = url; s->stream.url = url;
url = NULL;
} }
return r; return r;
@ -206,7 +237,7 @@ static enum rtsp_message_id wfd_session_message_to_id(struct wfd_session *s,
return RTSP_M13_REQUEST_IDR; return RTSP_M13_REQUEST_IDR;
} }
if(0 >= rtsp_message_read(m, "{<>}", "wfd_uibc_capability") && s->url) { if(0 >= rtsp_message_read(m, "{<>}", "wfd_uibc_capability")) { // && s->url) {
return RTSP_M14_ESTABLISH_UIBC; return RTSP_M14_ESTABLISH_UIBC;
} }
@ -214,7 +245,7 @@ static enum rtsp_message_id wfd_session_message_to_id(struct wfd_session *s,
return RTSP_M15_ENABLE_UIBC; return RTSP_M15_ENABLE_UIBC;
} }
if(!s->url) { if(WFD_SESSION_STATE_CAPS_EXCHANGING == s->state) {
return RTSP_M4_SET_PARAMETER; return RTSP_M4_SET_PARAMETER;
} }
@ -253,65 +284,79 @@ static enum rtsp_message_id wfd_session_message_to_id(struct wfd_session *s,
return RTSP_M_UNKNOWN; return RTSP_M_UNKNOWN;
} }
static int wfd_session_dispatch_request(struct rtsp *bus, static int wfd_session_handle_request(struct rtsp *bus,
struct rtsp_message *m, struct rtsp_message *m,
void *userdata) void *userdata)
{ {
_rtsp_message_unref_ struct rtsp_message *rep = NULL; _rtsp_message_unref_ struct rtsp_message *rep = NULL;
struct wfd_session *s = userdata; struct wfd_session *s = userdata;
enum rtsp_message_id id; enum rtsp_message_id id, next_request = RTSP_M_UNKNOWN;
enum wfd_session_state new_state = WFD_SESSION_STATE_NULL;
int r; int r;
id = wfd_session_message_to_id(s, m); id = wfd_session_message_to_id(s, m);
if(RTSP_M_UNKNOWN == id) { if(RTSP_M_UNKNOWN == id) {
r = -EPROTO; r = -EPROTO;
goto end; goto error;
} }
log_trace("received %s (M%d) request: %s", rtsp_message_id_to_string(id), log_trace("received %s (M%d) request: %s", rtsp_message_id_to_string(id),
id, id,
(char *) rtsp_message_get_raw(m)); (char *) rtsp_message_get_raw(m));
r = wfd_session_do_handle_request(s, id, m, &rep); r = wfd_session_do_handle_request(s,
id,
m,
&rep,
&new_state,
&next_request);
if(0 > r) { if(0 > r) {
goto end; goto error;
}
r = rtsp_message_set_cookie(rep, id);
if(0 > r) {
goto end;
} }
r = rtsp_message_seal(rep); r = rtsp_message_seal(rep);
if(0 > r) { if(0 > r) {
goto end; goto error;
} }
r = rtsp_send(bus, rep); r = rtsp_send(bus, rep);
if(0 > r) { if(0 > r) {
goto end; goto error;
} }
log_trace("sending %s (M%d) reply: %s", rtsp_message_id_to_string(id), log_trace("sending %s (M%d) reply: %s", rtsp_message_id_to_string(id),
id, id,
(char *) rtsp_message_get_raw(rep)); (char *) rtsp_message_get_raw(rep));
end: if(WFD_SESSION_STATE_NULL != new_state) {
if (0 > r) { wfd_session_set_state(s, new_state);
wfd_session_end(s);
} }
if(rtsp_message_id_is_valid(next_request)) {
r = wfd_session_request(s, next_request);
if(0 > r) {
goto error;
}
}
return 0;
error:
wfd_session_end(s);
return r; return r;
} }
static int wfd_session_dispatch_reply(struct rtsp *bus, static int wfd_session_handle_reply(struct rtsp *bus,
struct rtsp_message *m, struct rtsp_message *m,
void *userdata) void *userdata)
{ {
int r; int r;
enum rtsp_message_id id; enum rtsp_message_id id;
struct wfd_session *s = userdata; struct wfd_session *s = userdata;
enum wfd_session_state new_state = WFD_SESSION_STATE_NULL;
enum rtsp_message_id next_request = RTSP_M_UNKNOWN;
if(!m) { if(!m) {
goto error; goto error;
@ -322,18 +367,29 @@ static int wfd_session_dispatch_reply(struct rtsp *bus,
goto error; goto error;
} }
id = (enum rtsp_message_id) rtsp_message_get_cookie(m); id = s->last_request;
log_trace("received %s (M%d) reply: %s", log_trace("received %s (M%d) reply: %s",
rtsp_message_id_to_string(id), rtsp_message_id_to_string(id),
id, id,
(char *) rtsp_message_get_raw(m)); (char *) rtsp_message_get_raw(m));
r = wfd_session_do_handle_reply(s, id, m); r = wfd_session_do_handle_reply(s, id, m, &new_state, &next_request);
if(0 > r) { if(0 > r) {
goto error; goto error;
} }
if(WFD_SESSION_STATE_NULL != new_state) {
wfd_session_set_state(s, new_state);
}
if(rtsp_message_id_is_valid(next_request)) {
r = wfd_session_request(s, next_request);
if(0 > r) {
goto error;
}
}
return 0; return 0;
error: error:
@ -345,7 +401,6 @@ int wfd_session_request(struct wfd_session *s, enum rtsp_message_id id)
{ {
int r; int r;
_rtsp_message_unref_ struct rtsp_message *m = NULL; _rtsp_message_unref_ struct rtsp_message *m = NULL;
uint64_t cookie = id;
assert(s); assert(s);
@ -361,14 +416,16 @@ int wfd_session_request(struct wfd_session *s, enum rtsp_message_id id)
r = rtsp_call_async(s->rtsp, r = rtsp_call_async(s->rtsp,
m, m,
wfd_session_dispatch_reply, wfd_session_handle_reply,
s, s,
0, 0,
&cookie); NULL);
if(0 > r) { if(0 > r) {
return r; return r;
} }
s->last_request = id;
log_trace("sending %s (M%d) request: %s", log_trace("sending %s (M%d) request: %s",
rtsp_message_id_to_string(id), rtsp_message_id_to_string(id),
id, id,
@ -414,7 +471,7 @@ static int wfd_session_handle_io(sd_event_source *source,
goto end; goto end;
} }
r = rtsp_add_match(rtsp, wfd_session_dispatch_request, s); r = rtsp_add_match(rtsp, wfd_session_handle_request, s);
if (0 > r) { if (0 > r) {
goto end; goto end;
} }
@ -422,7 +479,7 @@ static int wfd_session_handle_io(sd_event_source *source,
s->rtsp = rtsp; s->rtsp = rtsp;
rtsp = NULL; rtsp = NULL;
wfd_session_set_state(s, WFD_SESSION_STATE_CAPS_EXCHAING); wfd_session_set_state(s, WFD_SESSION_STATE_CAPS_EXCHANGING);
r = (*session_vtables[s->dir].initiate_request)(s); r = (*session_vtables[s->dir].initiate_request)(s);
} }

View file

@ -51,16 +51,26 @@ enum rtsp_message_id
RTSP_M16_KEEPALIVE, RTSP_M16_KEEPALIVE,
}; };
enum wfd_stream_id
{
WFD_STREAM_ID_PRIMARY,
WFD_STREAM_ID_SECONDARY,
};
struct rtsp_dispatch_entry struct rtsp_dispatch_entry
{ {
union { union {
int (*request)(struct wfd_session *s, struct rtsp_message **out); int (*request)(struct wfd_session *s, struct rtsp_message **out);
int (*handle_request)(struct wfd_session *s, int (*handle_request)(struct wfd_session *s,
struct rtsp_message *req, struct rtsp_message *req,
struct rtsp_message **out_rep); struct rtsp_message **out_rep,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request);
}; };
int (*handle_reply)(struct wfd_session *s, struct rtsp_message *m); int (*handle_reply)(struct wfd_session *s,
enum rtsp_message_id next_request; struct rtsp_message *m,
enum wfd_session_state *new_state,
enum rtsp_message_id *next_request);
}; };
struct wfd_session_vtable struct wfd_session_vtable
@ -76,16 +86,29 @@ struct wfd_session
{ {
enum wfd_session_dir dir; enum wfd_session_dir dir;
enum wfd_session_state state; enum wfd_session_state state;
uint64_t id; enum rtsp_message_id last_request;
char *url;
struct rtsp *rtsp;
const struct rtsp_dispatch_entry *rtsp_disp_tbl; const struct rtsp_dispatch_entry *rtsp_disp_tbl;
uint64_t 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;
} stream;
bool destructed: 1; bool destructed: 1;
}; };
const char * rtsp_message_id_to_string(enum rtsp_message_id id); const char * rtsp_message_id_to_string(enum rtsp_message_id id);
struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s); struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s);
int wfd_session_request(struct wfd_session *s, enum rtsp_message_id id); int wfd_session_request(struct wfd_session *s, enum rtsp_message_id id);
int wfd_session_gen_stream_url(struct wfd_session *s,
const char *local_addr,
enum wfd_stream_id id);
#endif /* MIRACLE_OUT_SESSION_H */ #endif /* MIRACLE_OUT_SESSION_H */