diff --git a/res/miracle-wfdctl-demo b/res/miracle-wfdctl-demo index 630dc3e..e494416 100755 --- a/res/miracle-wfdctl-demo +++ b/res/miracle-wfdctl-demo @@ -199,6 +199,6 @@ invoke org.freedesktop.miracle.wfd \ /org/freedesktop/miracle/wfd/sink/$peer_id \ org.freedesktop.miracle.wfd.Sink \ Peer /org/freedesktop/miracle/wifi/peer/$peer_id \ - StartSession + StartSession sqqqq 'x://:0.0' 0 0 1920 1080 wait diff --git a/src/ctl/ctl.h b/src/ctl/ctl.h index 6b0fd37..3d5c709 100644 --- a/src/ctl/ctl.h +++ b/src/ctl/ctl.h @@ -170,7 +170,13 @@ enum wfd_session_state WFD_SESSION_STATE_TEARING_DOWN, }; -int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink); +int wfd_out_session_new(struct wfd_session **out, + struct wfd_sink *sink, + const char *display, + uint16_t x, + uint16_t y, + uint16_t width, + uint16_t height); 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); @@ -211,7 +217,12 @@ void wfd_sink_free(struct wfd_sink *sink); 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); + struct wfd_session **out, + const char *display, + uint16_t x, + uint16_t y, + uint16_t width, + uint16_t height); 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) diff --git a/src/ctl/wfd-dbus.c b/src/ctl/wfd-dbus.c index 5feccc2..49e9470 100644 --- a/src/ctl/wfd-dbus.c +++ b/src/ctl/wfd-dbus.c @@ -376,7 +376,19 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m, struct wfd_sink *sink = userdata; _wfd_session_free_ struct wfd_session *session = NULL; _shl_free_ char *path = NULL; - int r = wfd_sink_start_session(sink, &session); + char *display = NULL; + uint16_t x, y, width, height; + int r; + + r = sd_bus_message_read(m, "sqqqq", &display, &x, &y, &width, &height); + if(0 > r) { + return r; + } + + r = wfd_sink_start_session(sink, + &session, + display, + x, y, width, height); if(0 > r) { return r; } @@ -610,7 +622,7 @@ static const sd_bus_vtable wfd_dbus_vtable[] = { static const sd_bus_vtable wfd_dbus_sink_vtable[] = { SD_BUS_VTABLE_START(0), - SD_BUS_METHOD("StartSession", NULL, "o", wfd_dbus_sink_start_session, 0), + SD_BUS_METHOD("StartSession", "sqqqq", "o", wfd_dbus_sink_start_session, 0), /*SD_BUS_PROPERTY("AudioFormats", "a{sv}", wfd_dbus_sink_get_audio_formats, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ /*SD_BUS_PROPERTY("VideoFormats", "a{sv}", wfd_dbus_sink_get_video_formats, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ /*SD_BUS_PROPERTY("HasAudio", "b", wfd_dbus_sink_has_audio, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ diff --git a/src/ctl/wfd-out-session.c b/src/ctl/wfd-out-session.c index 9e10781..a21527a 100644 --- a/src/ctl/wfd-out-session.c +++ b/src/ctl/wfd-out-session.c @@ -21,11 +21,18 @@ #include #include #include +#include #include #include "wfd-session.h" #include "shl_log.h" #include "rtsp.h" +enum wfd_display_type +{ + WFD_DISPLAY_TYPE_UNKNOWN, + WFD_DISPLAY_TYPE_X, +}; + struct wfd_out_session { struct wfd_session parent; @@ -33,15 +40,59 @@ struct wfd_out_session int fd; sd_event_source *gst_launch_source; sd_event_source *gst_term_source; + + enum wfd_display_type display_type; + char *display_name; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + enum wfd_resolution_standard std; + uint32_t mask; }; static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[]; -#include - -int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink) +int wfd_out_session_new(struct wfd_session **out, + struct wfd_sink *sink, + const char *display, + uint16_t x, + uint16_t y, + uint16_t width, + uint16_t height) { - struct wfd_out_session *s = calloc(1, sizeof(struct wfd_out_session)); + _shl_free_ char *display_schema = NULL; + _shl_free_ char *display_name = NULL; + enum wfd_display_type display_type; + struct wfd_out_session *s; + enum wfd_resolution_standard std; + uint32_t mask; + int r; + + r = sscanf(display, "%m[^:]://%ms", + &display_schema, + &display_name); + if(r != 2) { + return -EINVAL; + } + + if(!strcmp("x", display_schema)) { + display_type = WFD_DISPLAY_TYPE_X; + } + else { + return -EINVAL; + } + + if(!width || !height) { + return -EINVAL; + } + + r = vfd_get_mask_from_resolution(width, height, &std, &mask); + if(0 > r) { + return -EINVAL; + } + + s = calloc(1, sizeof(struct wfd_out_session)); if(!s) { return -ENOMEM; } @@ -50,6 +101,15 @@ int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink) wfd_session(s)->rtsp_disp_tbl = out_session_rtsp_disp_tbl; s->fd = -1; s->sink = sink; + s->display_type = display_type; + s->display_name = display_name; + display_name = NULL; + s->x = x; + s->y = y; + s->width = width; + s->height = height; + s->mask = mask; + s->std = std; *out = wfd_session(s); @@ -215,6 +275,11 @@ void wfd_out_session_destroy(struct wfd_session *s) os->gst_launch_source = NULL; } + if(os->display_name) { + free(os->display_name); + os->display_name = NULL; + } + wfd_out_session_kill_gst(s); } @@ -429,19 +494,27 @@ static int wfd_out_session_request_options(struct wfd_session *s, return 0; } +inline static char * uint16_to_str(uint16_t i, char *buf, size_t len) +{ + snprintf(buf, len, "%u", i); + + return buf; +} + static int wfd_out_session_launch_gst(struct wfd_session *s, pid_t *out) { sigset_t sigset; - char port[10]; + char x[16], y[16], width[16], height[16], port[16]; + struct wfd_out_session *os = wfd_out_session(s); char * args[] = { "gst-launch-1.0", "ximagesrc", "use-damage=false", "show-pointer=false", - "startx=0", - "starty=0", - "endx=1279", - "endy=719", + "startx=", uint16_to_str(os->x, x, sizeof(x)), + "starty=", uint16_to_str(os->x, y, sizeof(y)), + "endx=", uint16_to_str(os->width - 1, width, sizeof(width)), + "endy=", uint16_to_str(os->height - 1, height, sizeof(height)), "!", "vaapipostproc", "!", "video/x-raw,", "format=YV12", @@ -454,12 +527,10 @@ static int wfd_out_session_launch_gst(struct wfd_session *s, pid_t *out) "!", "rtpmp2tpay", "!", "udpsink", "host=", wfd_out_session_get_sink(s)->peer->remote_address, - "port=", port, + "port=", uint16_to_str(s->stream.rtp_port, port, sizeof(port)), NULL }; - snprintf(port, sizeof(port), "%hu", s->stream.rtp_port); - pid_t p = fork(); if(0 > p) { return p; @@ -748,6 +819,7 @@ static int wfd_out_session_request_set_parameter(struct wfd_session *s, const struct wfd_arg_list *args, struct rtsp_message **out) { + struct wfd_out_session *os = wfd_out_session(s); _rtsp_message_unref_ struct rtsp_message *m = NULL; _shl_free_ char *body = NULL; int r; @@ -762,12 +834,15 @@ static int wfd_out_session_request_set_parameter(struct wfd_session *s, s->stream.id = WFD_STREAM_ID_PRIMARY; r = asprintf(&body, - "wfd_video_formats: 00 00 02 10 00001401 00000000 00000000 00 0000 0000 00 none none\n" + "wfd_video_formats: 00 00 02 10 %08X %08X %08X 00 0000 0000 00 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_RESOLUTION_STANDARD_CEA == os->std ? os->mask : 0, + WFD_RESOLUTION_STANDARD_VESA == os->std ? os->mask: 0, + WFD_RESOLUTION_STANDARD_HH == os->std ? os->mask : 0, wfd_session_get_stream_url(s), s->rtp_ports[0], s->rtp_ports[1]); diff --git a/src/ctl/wfd-sink.c b/src/ctl/wfd-sink.c index 9d8436a..b61d441 100644 --- a/src/ctl/wfd-sink.c +++ b/src/ctl/wfd-sink.c @@ -117,7 +117,13 @@ struct ctl_peer * wfd_sink_get_peer(struct wfd_sink *sink) return sink->peer; } -int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out) +int wfd_sink_start_session(struct wfd_sink *sink, + struct wfd_session **out, + const char *display, + uint16_t x, + uint16_t y, + uint16_t width, + uint16_t height) { int r; _wfd_session_free_ struct wfd_session *s = NULL; @@ -129,7 +135,7 @@ int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out) return -EALREADY; } - r = wfd_out_session_new(&s, sink); + r = wfd_out_session_new(&s, sink, display, x, y, width, height); if(0 > r) { return r; } diff --git a/src/ctl/wfd.c b/src/ctl/wfd.c index 5ba7124..46b9a4c 100644 --- a/src/ctl/wfd.c +++ b/src/ctl/wfd.c @@ -262,6 +262,55 @@ int vfd_get_hh_resolution(uint32_t mask, int *hres, int *vres) return -EINVAL; } +int vfd_get_mask_from_resolution(int hres, + int vres, + enum wfd_resolution_standard *out_std, + uint32_t *out_mask) +{ + struct { + const struct wfd_resolution *entries; + size_t n_entries; + } tbls[] = { + [WFD_RESOLUTION_STANDARD_CEA] = { + resolutions_cea, + SHL_ARRAY_LENGTH(resolutions_cea) + }, + [WFD_RESOLUTION_STANDARD_VESA] = { + resolutions_vesa, + SHL_ARRAY_LENGTH(resolutions_vesa) + }, + [WFD_RESOLUTION_STANDARD_HH] = { + resolutions_hh, + SHL_ARRAY_LENGTH(resolutions_hh) + }, + }; + enum wfd_resolution_standard std = WFD_RESOLUTION_STANDARD_CEA; + uint32_t mask = 0; + size_t n; + + for(; std <= WFD_RESOLUTION_STANDARD_HH; ++ std) { + for(n = 0; n < tbls[std].n_entries; ++ n) { + if(hres == tbls[std].entries[n].hres && + vres == tbls[std].entries[n].vres) { + mask |= 1 << n; + } + } + + if(mask) { + if(out_mask) { + *out_mask = mask; + } + if(out_std) { + *out_std = std; + } + + return 0; + } + } + + return -ENOENT; +} + static int wfd_sube_parse_device_info(const char *in, union wfd_sube *out) { int r = sscanf(in, "%4hx%4hx%4hx", diff --git a/src/ctl/wfd.h b/src/ctl/wfd.h index 4a46dda..02a8432 100644 --- a/src/ctl/wfd.h +++ b/src/ctl/wfd.h @@ -152,6 +152,10 @@ int wfd_get_resolutions(enum wfd_resolution_standard std, 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 vfd_get_mask_from_resolution(int hres, + int vres, + enum wfd_resolution_standard *out_std, + uint32_t *out_mask); 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,