From 9dd805378edff72b9fb9fd15da079d8372ff9379 Mon Sep 17 00:00:00 2001 From: Derek Dai Date: Wed, 15 Feb 2017 18:19:16 +0800 Subject: [PATCH] miracle-wfdctl: finish migration of source side rtsp protocol --- src/ctl/ctl.h | 4 +- src/ctl/wfd-dbus.c | 12 +- src/ctl/wfd-out-session.c | 428 +++++++++++++++++++++++++------------- src/ctl/wfd-session.c | 149 +++++++++---- src/ctl/wfd-session.h | 35 +++- 5 files changed, 428 insertions(+), 200 deletions(-) diff --git a/src/ctl/ctl.h b/src/ctl/ctl.h index 94296fc..046457b 100644 --- a/src/ctl/ctl.h +++ b/src/ctl/ctl.h @@ -162,7 +162,7 @@ enum wfd_session_state { WFD_SESSION_STATE_NULL, WFD_SESSION_STATE_CONNECTING, - WFD_SESSION_STATE_CAPS_EXCHAING, + WFD_SESSION_STATE_CAPS_EXCHANGING, WFD_SESSION_STATE_ESTABLISHED, WFD_SESSION_STATE_SETING_UP, 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); enum wfd_session_dir wfd_session_get_dir(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); int wfd_session_is_started(struct wfd_session *s); void wfd_session_end(struct wfd_session *s); diff --git a/src/ctl/wfd-dbus.c b/src/ctl/wfd-dbus.c index 7734633..25975f2 100644 --- a/src/ctl/wfd-dbus.c +++ b/src/ctl/wfd-dbus.c @@ -489,7 +489,7 @@ static int wfd_dbus_session_get_sink(sd_bus *bus, 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 *interface, const char *property, @@ -498,10 +498,12 @@ static int wfd_dbus_session_get_url(sd_bus *bus, sd_bus_error *ret_error) { 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 *interface, const char *property, @@ -554,8 +556,8 @@ 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_PROPERTY("Url", "o", 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, }; diff --git a/src/ctl/wfd-out-session.c b/src/ctl/wfd-out-session.c index 09b3a4b..8b0cc1b 100644 --- a/src/ctl/wfd-out-session.c +++ b/src/ctl/wfd-out-session.c @@ -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); } -/*static int wfd_out_session_handle_get_parameter_reply(struct rtsp *bus,*/ - /*struct rtsp_message *m,*/ - /*void *userdata)*/ -/*{*/ - /*struct wfd_session *s = userdata;*/ +static int wfd_out_session_handle_get_parameter_reply(struct wfd_session *s, + struct rtsp_message *m, + enum wfd_session_state *new_state, + enum rtsp_message_id *next_request) +{ + 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",*/ - /*(char *) rtsp_message_get_raw(m));*/ - /*if(RTSP_CODE_OK != rtsp_message_get_code(m)) {*/ - /*wfd_session_end(wfd_session(userdata));*/ - /*return -EPROTO;*/ - /*}*/ + if(!rtsp_message_read(m, "{<&>}", "wfd_video_formats", &l)) { + r = wfd_video_formats_from_string(l, &vformats); + if(0 > r) { + return r; + } - /*return 0;*/ -/*}*/ + if(s->vformats) { + free(s->vformats); + } + s->vformats = vformats; + } -/*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;*/ - /*}*/ + if(!rtsp_message_read(m, "{<&>}", "wfd_audio_codecs", &l)) { + r = wfd_audio_codecs_from_string(l, &acodecs); + if(0 > r) { + return r; + } + + if(s->acodecs) { + free(s->acodecs); + } + s->acodecs = acodecs; + } - /*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;*/ - /*}*/ + if(!rtsp_message_read(m, "{<&>}", "wfd_client_rtp_ports", &l)) { + if(strncmp("RTP/AVP/UDP;unicast", l, 19)) { + return -EPROTO; + } - /*rtsp_message_seal(m);*/ + r = sscanf(l + 20, "%hd %hd %ms", + &rtp_ports[0], + &rtp_ports[1], + &t); + if(3 != r) { + return -EPROTO; + } - /*r = rtsp_call_async(s->rtsp,*/ - /*m,*/ - /*wfd_out_session_handle_get_parameter_reply,*/ - /*s,*/ - /*0,*/ - /*NULL);*/ - /*if (r < 0) {*/ - /*goto error;*/ - /*}*/ + if(strncmp("mode=play", t, 9)) { + return -EPROTO; + } - /*log_debug("Sending GET_PARAMETER (M3): %s\n",*/ - /*(char *) rtsp_message_get_raw(m));*/ + if(!rtp_ports[0] && !rtp_ports[1]) { + return -EPROTO; + } - /*return 0;*/ + s->rtp_ports[0] = rtp_ports[0]; + s->rtp_ports[1] = rtp_ports[1]; + } -/*error:*/ - /*wfd_session_end(s);*/ + *next_request = RTSP_M4_SET_PARAMETER; - /*return r;*/ -/*}*/ + 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) { @@ -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, 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; _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; rep = NULL; + *next_request = RTSP_M3_GET_PARAMETER; + return 0; } -static int wfd_out_session_check_options_reply(struct wfd_session *s, - struct rtsp_message *m) +static int wfd_out_session_handle_options_reply(struct wfd_session *s, + struct rtsp_message *m, + enum wfd_session_state *new_state, + enum rtsp_message_id *next_request) { int r; const char *public; @@ -356,102 +399,198 @@ static int wfd_out_session_request_options(struct wfd_session *s, return 0; } -/*static int wfd_out_session_handle_options_request(struct rtsp *bus,*/ - /*struct rtsp_message *request,*/ - /*struct wfd_session *s)*/ -/*{*/ -/*}*/ - -static int wfd_out_session_handle_play_reply(struct rtsp *bus, - struct rtsp_message *m, - void *userdata) +static int wfd_out_session_handle_play_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) { - /*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_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;*/ + _rtsp_message_unref_ struct rtsp_message *m = NULL; 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;*/ - /*}*/ + r = rtsp_message_new_reply_for(req, + &m, + RTSP_CODE_OK, + NULL); + if(0 > r) { + return r; + } + + r = rtsp_message_append(m, "", "Session", (uint32_t) s->id); + if(0 > r) { + return r; + } - /*snprintf(buf, sizeof(buf), tmp, s->url, s->sink.rtp_ports.profile,*/ - /*s->sink.rtp_ports.port0, s->sink.rtp_ports.port1);*/ + *out_rep = m; + m = NULL; - /*r = rtsp_message_append(req, "{&}", buf);*/ - /*if (r < 0) {*/ - /*cli_vERR(r);*/ - /*goto error;*/ - /*}*/ + *new_state = WFD_SESSION_STATE_PLAYING; - /*rtsp_message_seal(req);*/ - /*cli_debug("OUTGOING (M4): %s\n", rtsp_message_get_raw(req));*/ + return 0; +} - /*r = rtsp_call_async(s->rtsp, req, src_set_parameter_rep_fn, s, 0, NULL);*/ - /*if (r < 0) {*/ - /*cli_vERR(r);*/ - /*goto error;*/ - /*}*/ +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; - /*return 0;*/ + r = rtsp_message_read(req, "", "Transport", &l); + if(0 > r) { + return -EPROTO; + } -/*error:*/ - /*wfd_src_close(s);*/ - /*wfd_fn_src_disconnected(s);*/ + if(strncmp("RTP/AVP/UDP;unicast;", l, 20)) { + return -EPROTO; + } - return r; + 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, "{}", + "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[] = { @@ -467,20 +606,27 @@ const struct wfd_session_vtable session_vtables[] = { static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[] = { [RTSP_M1_REQUEST_SINK_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] = { .handle_request = wfd_out_session_handle_options_request }, [RTSP_M3_GET_PARAMETER] = { + .request = wfd_out_session_request_get_parameter, + .handle_reply = wfd_out_session_handle_get_parameter_reply }, [RTSP_M4_SET_PARAMETER] = { + .request = wfd_out_session_request_set_parameter, + .handle_reply = wfd_out_session_handle_set_parameter_reply }, [RTSP_M5_TRIGGER] = { + .request = wfd_out_session_request_trigger, }, [RTSP_M6_SETUP] = { + .handle_request = wfd_out_session_handle_setup_request, }, [RTSP_M7_PLAY] = { + .handle_request = wfd_out_session_handle_play_request, }, [RTSP_M8_TEARDOWN] = { }, diff --git a/src/ctl/wfd-session.c b/src/ctl/wfd-session.c index 6455db8..bad845e 100644 --- a/src/ctl/wfd-session.c +++ b/src/ctl/wfd-session.c @@ -18,14 +18,19 @@ */ #define LOG_SUBSYSTEM "wfd-session" +#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 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[]; @@ -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, enum rtsp_message_id id, 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)) { return -EINVAL; } 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, 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)) { return -EINVAL; } - assert(s->rtsp_disp_tbl[id].handle_reply); + + if(!s->rtsp_disp_tbl[id].handle_reply) { + return 0; + } - return (*s->rtsp_disp_tbl[id].handle_reply)(s, m); + return (*s->rtsp_disp_tbl[id].handle_reply)(s, m, new_state, next_request); } 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; } - if(s->url) { - free(s->url); - s->url = NULL; - } + wfd_video_formats_free(s->vformats); + s->vformats = 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); + s->rtp_ports[0] = 0; + s->rtp_ports[1] = 0; if(wfd_is_out_session(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; } -const char * wfd_session_get_url(struct wfd_session *s) -{ - return s->url; -} - uint64_t * wfd_session_to_htable(struct wfd_session *s) { 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); } -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; - 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) { - free(s->url); - s->url = url; + free(s->stream.url); + s->stream.url = url; + url = NULL; } 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; } - 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; } @@ -214,7 +245,7 @@ static enum rtsp_message_id wfd_session_message_to_id(struct wfd_session *s, return RTSP_M15_ENABLE_UIBC; } - if(!s->url) { + if(WFD_SESSION_STATE_CAPS_EXCHANGING == s->state) { 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; } -static int wfd_session_dispatch_request(struct rtsp *bus, +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; + enum rtsp_message_id id, next_request = RTSP_M_UNKNOWN; + enum wfd_session_state new_state = WFD_SESSION_STATE_NULL; int r; id = wfd_session_message_to_id(s, m); if(RTSP_M_UNKNOWN == id) { r = -EPROTO; - goto end; + 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); + r = wfd_session_do_handle_request(s, + id, + m, + &rep, + &new_state, + &next_request); if(0 > r) { - goto end; - } - - r = rtsp_message_set_cookie(rep, id); - if(0 > r) { - goto end; + goto error; } r = rtsp_message_seal(rep); if(0 > r) { - goto end; + goto error; } r = rtsp_send(bus, rep); if(0 > r) { - goto end; + goto error; } log_trace("sending %s (M%d) reply: %s", rtsp_message_id_to_string(id), id, (char *) rtsp_message_get_raw(rep)); -end: - if (0 > r) { - wfd_session_end(s); + 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; + +error: + wfd_session_end(s); + return r; } -static int wfd_session_dispatch_reply(struct rtsp *bus, +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; + enum wfd_session_state new_state = WFD_SESSION_STATE_NULL; + enum rtsp_message_id next_request = RTSP_M_UNKNOWN; if(!m) { goto error; @@ -322,18 +367,29 @@ static int wfd_session_dispatch_reply(struct rtsp *bus, goto error; } - id = (enum rtsp_message_id) rtsp_message_get_cookie(m); + 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); + r = wfd_session_do_handle_reply(s, id, m, &new_state, &next_request); if(0 > r) { 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; error: @@ -345,7 +401,6 @@ int wfd_session_request(struct wfd_session *s, enum rtsp_message_id id) { int r; _rtsp_message_unref_ struct rtsp_message *m = NULL; - uint64_t cookie = id; 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, m, - wfd_session_dispatch_reply, + wfd_session_handle_reply, s, 0, - &cookie); + 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, @@ -414,7 +471,7 @@ static int wfd_session_handle_io(sd_event_source *source, 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) { goto end; } @@ -422,7 +479,7 @@ static int wfd_session_handle_io(sd_event_source *source, s->rtsp = rtsp; 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); } diff --git a/src/ctl/wfd-session.h b/src/ctl/wfd-session.h index 9e97206..8834564 100644 --- a/src/ctl/wfd-session.h +++ b/src/ctl/wfd-session.h @@ -51,16 +51,26 @@ enum rtsp_message_id RTSP_M16_KEEPALIVE, }; +enum wfd_stream_id +{ + WFD_STREAM_ID_PRIMARY, + WFD_STREAM_ID_SECONDARY, +}; + struct rtsp_dispatch_entry { union { int (*request)(struct wfd_session *s, struct rtsp_message **out); int (*handle_request)(struct wfd_session *s, 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); - enum rtsp_message_id next_request; + int (*handle_reply)(struct wfd_session *s, + struct rtsp_message *m, + enum wfd_session_state *new_state, + enum rtsp_message_id *next_request); }; struct wfd_session_vtable @@ -76,16 +86,29 @@ struct wfd_session { enum wfd_session_dir dir; enum wfd_session_state state; - uint64_t id; - char *url; - struct rtsp *rtsp; + enum rtsp_message_id last_request; 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; }; const char * rtsp_message_id_to_string(enum rtsp_message_id id); 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_gen_stream_url(struct wfd_session *s, + const char *local_addr, + enum wfd_stream_id id); #endif /* MIRACLE_OUT_SESSION_H */