1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-02-15 04:42:06 +00:00

miracle-dispd: stablizing and removing memory leak

This commit is contained in:
Derek Dai 2017-04-11 17:02:09 +08:00
parent aa5d6c0468
commit e117704d4e
9 changed files with 438 additions and 453 deletions

View file

@ -41,6 +41,7 @@ errordomain WfdCtlError
TIMEOUT, TIMEOUT,
MONITOR_GONE, MONITOR_GONE,
FORMATION_ERROR, FORMATION_ERROR,
NO_P2P_SUPPORT,
} }
private void print(string format, ...) private void print(string format, ...)
@ -335,17 +336,20 @@ private class WfdCtl : GLib.Application
opt_iface); opt_iface);
} }
if(!l.managed) { if(l.managed) {
info("wifid is acquiring ownership of %s...", opt_iface); info("wifid is releasing ownership of %s...", opt_iface);
l.unmanage();
l.manage();
yield wait_prop_changed(l, "Managed"); yield wait_prop_changed(l, "Managed");
} }
info("wifid is acquiring ownership of %s...", opt_iface);
l.manage();
yield wait_prop_changed(l, "Managed");
} }
private async void start_p2p_scan() throws Error private async void start_p2p_scan() throws Error
{ {
Link l = find_link_by_name(opt_iface); Link? l = find_link_by_name(opt_iface);
if(l.wfd_subelements != opt_wfd_subelems) { if(l.wfd_subelements != opt_wfd_subelems) {
info("update wfd_subelems to broadcast what kind of device we are"); info("update wfd_subelems to broadcast what kind of device we are");
@ -354,7 +358,7 @@ private class WfdCtl : GLib.Application
} }
if(-1 == l.p2p_state) { if(-1 == l.p2p_state) {
error("link %s has no P2P supporting", l.interface_name); throw new WfdCtlError.NO_P2P_SUPPORT("link %s has no P2P supporting", l.interface_name);
} }
else if(0 == l.p2p_state) { else if(0 == l.p2p_state) {
info("wait for P2P supporting status..."); info("wait for P2P supporting status...");
@ -568,24 +572,23 @@ private class WfdCtl : GLib.Application
yield form_p2p_group(); yield form_p2p_group();
yield establish_session(); yield establish_session();
yield wait_for_session_ending(); yield wait_for_session_ending();
yield release_wnic_ownership();
quit();
} }
public void stop_wireless_display() public void stop_wireless_display()
{ {
info("tearing down wireless display...");
if(null != curr_session) { if(null != curr_session) {
info("tearing down wireless display...");
try { try {
curr_session.teardown(); curr_session.teardown();
} }
catch(Error e) { catch(Error e) {
warning("failed to tearing down normally: %s", e.message); warning("failed to tearing down normally: %s", e.message);
quit();
} }
wait_prop_changed.begin(curr_sink, "Session", 3, () => {
release_wnic_ownership.begin(quit);
});
} }
else { else {
release_wnic_ownership.begin(quit); release_wnic_ownership.begin(quit);
@ -598,44 +601,27 @@ private class WfdCtl : GLib.Application
print("please specify a peer MAC with -p option"); print("please specify a peer MAC with -p option");
return false; return false;
} }
print("peer-mac=%s", opt_peer_mac);
if(null == opt_display) { if(null == opt_display) {
opt_display = Environment.get_variable("DISPLAY"); opt_display = Environment.get_variable("DISPLAY");
if(null == opt_display) {
print("no video source found. play specify one by DISPLAY " +
"environment or -d option");
return false;
}
else {
print("no display name specified by -d, " +
"use DISPLAY environment variable instead");
}
} }
print("display=%s", opt_display);
if(null == opt_authority) { if(null == opt_authority) {
opt_authority = Environment.get_variable("XAUTHORITY"); opt_authority = Environment.get_variable("XAUTHORITY");
if(null == opt_authority) {
print("no display authority found. play specify one by XAUTHORITY " +
"environment or -x option");
return false;
}
else {
print("no display authority specified by -x, " +
"use XAUTHORITY environment variable instead");
}
} }
print("authority=%s", opt_authority);
if(null == opt_iface) { if(null == opt_iface) {
opt_iface = "wlan0"; opt_iface = "wlan0";
print("no wireless adapter specified by -i, use '%s' instead",
opt_iface);
} }
print("interface=%s", opt_iface);
if(null == opt_wfd_subelems) { if(null == opt_wfd_subelems) {
opt_wfd_subelems = "000600111c4400c8"; opt_wfd_subelems = "000600111c4400c8";
print("no wfd_subelems specified by -w, use '%s' instead",
opt_wfd_subelems);
} }
print("wfd_subelemens=%s", opt_wfd_subelems);
display = Gdk.Display.open(opt_display); display = Gdk.Display.open(opt_display);
if(null == display) { if(null == display) {
@ -653,6 +639,7 @@ private class WfdCtl : GLib.Application
print("invalid screen number option: %d", opt_monitor_num); print("invalid screen number option: %d", opt_monitor_num);
return false; return false;
} }
print("monitor-num=%d", opt_monitor_num);
return true; return true;
} }
@ -671,6 +658,16 @@ private class WfdCtl : GLib.Application
print("failed to cast to wireless display: %s", e.message); print("failed to cast to wireless display: %s", e.message);
release(); release();
} }
release_wnic_ownership.begin((o, r) => {
try {
release_wnic_ownership.end(r);
}
catch(Error e) {
}
quit();
});
}); });
hold(); hold();

View file

@ -34,7 +34,7 @@
#define wfd_session_has_id(s) (0 < wfd_session_get_id(s)) #define wfd_session_has_id(s) (0 < wfd_session_get_id(s))
#define wfd_is_out_session(s) (WFD_SESSION_DIR_OUT == wfd_session_get_dir(s)) #define wfd_is_out_session(s) (WFD_SESSION_DIR_OUT == wfd_session_get_dir(s))
#define wfd_is_in_session(s) (WFD_SESSION_DIR_IN == wfd_session_get_dir(s)) #define wfd_is_in_session(s) (WFD_SESSION_DIR_IN == wfd_session_get_dir(s))
#define _wfd_session_free_ _shl_cleanup_(wfd_session_free_p) #define _wfd_session_unref_ _shl_cleanup_(wfd_session_unrefp)
struct wfd_sink; struct wfd_sink;
struct wfd_session; struct wfd_session;
@ -76,10 +76,11 @@ int wfd_session_is_established(struct wfd_session *s);
int wfd_session_resume(struct wfd_session *s); int wfd_session_resume(struct wfd_session *s);
int wfd_session_pause(struct wfd_session *s); int wfd_session_pause(struct wfd_session *s);
int wfd_session_teardown(struct wfd_session *s); int wfd_session_teardown(struct wfd_session *s);
void wfd_session_free(struct wfd_session *s); struct wfd_session * wfd_session_ref(struct wfd_session *s);
void wfd_session_unref(struct wfd_session *s);
uint64_t wfd_session_get_id(struct wfd_session *s); uint64_t wfd_session_get_id(struct wfd_session *s);
struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s); struct wfd_sink * wfd_out_session_get_sink(struct wfd_session *s);
void wfd_session_free_p(struct wfd_session **s); void wfd_session_unrefp(struct wfd_session **s);
unsigned int * wfd_session_to_htable(struct wfd_session *s); unsigned int * wfd_session_to_htable(struct wfd_session *s);
struct wfd_session * wfd_session_from_htable(unsigned int *e); struct wfd_session * wfd_session_from_htable(unsigned int *e);

View file

@ -25,8 +25,6 @@
#include <time.h> #include <time.h>
#include <systemd/sd-event.h> #include <systemd/sd-event.h>
#include <systemd/sd-daemon.h> #include <systemd/sd-daemon.h>
#include <glib.h>
#include <gst/gst.h>
#include "ctl.h" #include "ctl.h"
#include "disp.h" #include "disp.h"
#include "wfd.h" #include "wfd.h"
@ -103,6 +101,43 @@ static void ctl_wfd_free(struct ctl_wfd *wfd)
free(wfd); free(wfd);
} }
static int ctl_wfd_handle_shutdown(sd_event_source *s,
uint64_t usec,
void *userdata)
{
struct ctl_wfd *wfd = userdata;
sd_event_source_set_enabled(s, false);
sd_event_source_unref(s);
sd_event_exit(wfd->loop, 0);
return 0;
}
void ctl_wfd_shutdown(struct ctl_wfd *wfd)
{
uint64_t now;
int r = sd_event_now(ctl_wfd_get_loop(), CLOCK_MONOTONIC, &now);
if(0 > r) {
goto error;
}
r = sd_event_add_time(ctl_wfd_get_loop(),
NULL,
CLOCK_MONOTONIC,
now + 100 * 1000,
0,
ctl_wfd_handle_shutdown,
wfd);
if(0 <= r) {
return;
}
error:
sd_event_exit(wfd->loop, 0);
}
int ctl_wfd_add_sink(struct ctl_wfd *wfd, int ctl_wfd_add_sink(struct ctl_wfd *wfd,
struct ctl_peer *p, struct ctl_peer *p,
union wfd_sube *sube, union wfd_sube *sube,
@ -407,90 +442,9 @@ void cli_fn_help()
{ {
} }
/*
* see: https://lists.freedesktop.org/archives/systemd-devel/2014-August/022329.html
**/
#define SD_SOURCE(p) ((SDSource *) (p))
typedef struct _SDSource SDSource;
struct _SDSource
{
GSource source;
sd_event *event;
GPollFD pollfd;
};
static gboolean sd_source_prepare(GSource *source, gint *timeout)
{
return sd_event_prepare(SD_SOURCE(source)->event) > 0 ? TRUE : FALSE;
}
static gboolean sd_source_check(GSource *source)
{
return sd_event_wait(SD_SOURCE(source)->event, 0) > 0 ? TRUE : FALSE;
}
static gboolean sd_source_dispatch(GSource *source,
GSourceFunc callback,
gpointer userdata)
{
return sd_event_dispatch(SD_SOURCE(source)->event) >= 0
? G_SOURCE_CONTINUE
: G_SOURCE_REMOVE;
}
static void sd_source_finalize(GSource *source)
{
sd_event_unref(SD_SOURCE(source)->event);
}
static int sd_source_on_exit(sd_event_source *source, void *userdata)
{
g_main_loop_quit(userdata);
sd_event_source_set_enabled(source, false);
sd_event_source_unref(source);
return 0;
}
static int sd_source_attach(GSource *source, GMainLoop *loop)
{
g_source_set_name(source, "sd-event");
g_source_add_poll(source, &SD_SOURCE(source)->pollfd);
g_source_attach(source, g_main_loop_get_context(loop));
return sd_event_add_exit(SD_SOURCE(source)->event,
NULL,
sd_source_on_exit,
loop);
}
GSource * sd_source_new(sd_event *event)
{
static GSourceFuncs funcs = {
sd_source_prepare,
sd_source_check,
sd_source_dispatch,
sd_source_finalize,
};
GSource *s = g_source_new(&funcs, sizeof(SDSource));
if(s) {
SD_SOURCE(s)->event = sd_event_ref(event);
SD_SOURCE(s)->pollfd.fd = sd_event_get_fd(event);
SD_SOURCE(s)->pollfd.events = G_IO_IN | G_IO_HUP;
}
return s;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int r; int r;
GMainLoop *loop;
GSource *source;
sd_event *event; sd_event *event;
sd_bus *bus; sd_bus *bus;
@ -501,17 +455,10 @@ int main(int argc, char **argv)
log_max_sev = log_parse_arg(getenv("LOG_LEVEL")); log_max_sev = log_parse_arg(getenv("LOG_LEVEL"));
} }
gst_init(&argc, &argv);
loop = g_main_loop_new(NULL, FALSE);
if(!loop) {
r = -ENOMEM;
goto deinit_gst;
}
r = sd_event_default(&event); r = sd_event_default(&event);
if(0 > r) { if(0 > r) {
goto unref_loop; log_warning("can't create default event loop");
goto end;
} }
r = sd_event_set_watchdog(event, true); r = sd_event_set_watchdog(event, true);
@ -520,33 +467,20 @@ int main(int argc, char **argv)
goto unref_event; goto unref_event;
} }
source = sd_source_new(event);
if(!source) {
r = -ENOMEM;
goto unref_event;
}
r = sd_source_attach(source, loop);
if(0 > r) {
goto unref_source;
}
r = sd_bus_default_system(&bus); r = sd_bus_default_system(&bus);
if(0 > r) { if(0 > r) {
log_warning("unable to connect to system DBus: %s", strerror(errno)); log_warning("unable to connect to system DBus: %s", strerror(errno));
goto unref_source; goto disable_watchdog;
} }
r = sd_bus_attach_event(bus, event, 0); r = sd_bus_attach_event(bus, event, 0);
if(0 > r) { if(0 > r) {
log_warning("unable to attache DBus event source to loop: %s",
strerror(errno));
goto unref_bus; goto unref_bus;
} }
r = ctl_wfd_new(&wfd, event, bus); r = ctl_wfd_new(&wfd, event, bus);
if(0 > r) { if(0 > r) {
goto bus_detach_event;; goto bus_detach_event;
} }
r = wfd_dbus_new(&wfd_dbus, event, bus); r = wfd_dbus_new(&wfd_dbus, event, bus);
@ -567,31 +501,23 @@ int main(int argc, char **argv)
goto free_wfd_dbus; goto free_wfd_dbus;
} }
g_main_loop_run(loop); sd_event_loop(event);
sd_notify(false, "STATUS=Exiting.."); sd_notify(false, "STATUS=Exiting..");
free_wfd_dbus: free_wfd_dbus:
wfd_dbus_free(wfd_dbus); wfd_dbus_free(wfd_dbus);
wfd_dbus = NULL;
free_ctl_wfd: free_ctl_wfd:
ctl_wfd_free(wfd); ctl_wfd_free(wfd);
wfd = NULL;
bus_detach_event: bus_detach_event:
sd_bus_detach_event(bus); sd_bus_detach_event(bus);
unref_bus: unref_bus:
sd_bus_flush_close_unref(bus); sd_bus_flush_close_unref(bus);
unref_source: disable_watchdog:
g_source_ref(source);
g_source_destroy(source);
unref_event:
sd_event_run(event, 0);
sd_event_unref(event);
unref_loop:
g_main_loop_unref(loop);
deinit_gst:
gst_deinit();
sd_event_set_watchdog(event, false); sd_event_set_watchdog(event, false);
unref_event:
sd_event_unref(event);
end:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
} }

View file

@ -1,8 +1,5 @@
gstreamer = dependency('gstreamer-1.0')
gstreamer_base = dependency('gstreamer-base-1.0')
inc = include_directories('../..', '../ctl',) inc = include_directories('../..', '../ctl',)
deps = [libsystemd, gstreamer, gstreamer_base, libmiracle_shared_dep] deps = [libsystemd, libmiracle_shared_dep]
if readline.found() if readline.found()
deps += [readline] deps += [readline]
endif endif

View file

@ -22,6 +22,7 @@
#include <systemd/sd-bus.h> #include <systemd/sd-bus.h>
#include "disp.h" #include "disp.h"
#include "util.h" #include "util.h"
#include "shl_log.h"
#include "wfd-dbus.h" #include "wfd-dbus.h"
#define wfd_dbus_object_added(o, argv...) ({ \ #define wfd_dbus_object_added(o, argv...) ({ \
@ -370,7 +371,7 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m,
sd_bus_error *ret_error) sd_bus_error *ret_error)
{ {
struct wfd_sink *sink = userdata; struct wfd_sink *sink = userdata;
_wfd_session_free_ struct wfd_session *session = NULL; _wfd_session_unref_ struct wfd_session *session = NULL;
_shl_free_ char *path = NULL; _shl_free_ char *path = NULL;
const char *authority; const char *authority;
const char *display; const char *display;
@ -649,8 +650,18 @@ int _wfd_fn_session_properties_changed(struct wfd_session *s, char **names)
names); names);
} }
static int wfd_dbus_shutdown(sd_bus_message *m,
void *userdata,
sd_bus_error *ret_error)
{
ctl_wfd_shutdown(ctl_wfd_get());
return sd_bus_reply_method_return(m, NULL);
}
static const sd_bus_vtable wfd_dbus_vtable[] = { static const sd_bus_vtable wfd_dbus_vtable[] = {
SD_BUS_VTABLE_START(0), SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Shutdown", NULL, NULL, wfd_dbus_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END, SD_BUS_VTABLE_END,
}; };
@ -682,7 +693,7 @@ int wfd_dbus_expose(struct wfd_dbus *wfd_dbus)
int r = sd_bus_add_object_vtable(wfd_dbus->bus, int r = sd_bus_add_object_vtable(wfd_dbus->bus,
NULL, NULL,
"/org/freedesktop/miracle/wfd", "/org/freedesktop/miracle/wfd",
"org.freedesktop.miracle.wfd.Display", "org.freedesktop.miracle.wfd",
wfd_dbus_vtable, wfd_dbus_vtable,
wfd_dbus); wfd_dbus);
if(0 > r) { if(0 > r) {

View file

@ -24,8 +24,6 @@
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
#include <gst/gst.h>
#include <gst/base/base.h>
#include "wfd-session.h" #include "wfd-session.h"
#include "shl_log.h" #include "shl_log.h"
#include "rtsp.h" #include "rtsp.h"
@ -61,8 +59,8 @@ struct wfd_out_session
uint32_t mask; uint32_t mask;
char *audio_dev; char *audio_dev;
GstElement *pipeline; /*GstElement *pipeline;*/
GstBus *bus; /*GstBus *bus;*/
}; };
static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[]; static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[];
@ -80,7 +78,7 @@ int wfd_out_session_new(struct wfd_session **out,
_shl_free_ char *display_schema = NULL; _shl_free_ char *display_schema = NULL;
_shl_free_ char *display_name = NULL; _shl_free_ char *display_name = NULL;
char *display_param; char *display_param;
_wfd_session_free_ struct wfd_session *s; _wfd_session_unref_ struct wfd_session *s;
struct wfd_out_session *os; struct wfd_out_session *os;
enum wfd_display_type display_type; enum wfd_display_type display_type;
enum wfd_resolution_standard std; enum wfd_resolution_standard std;
@ -133,8 +131,7 @@ int wfd_out_session_new(struct wfd_session **out,
return -ENOMEM; return -ENOMEM;
} }
s->dir = WFD_SESSION_DIR_OUT; wfd_session_init(s, WFD_SESSION_DIR_OUT, out_session_rtsp_disp_tbl);
s->rtsp_disp_tbl = out_session_rtsp_disp_tbl;
os->fd = -1; os->fd = -1;
os->sink = sink; os->sink = sink;
os->display_type = display_type; os->display_type = display_type;
@ -303,10 +300,10 @@ void wfd_out_session_destroy(struct wfd_session *s)
os->fd = -1; os->fd = -1;
} }
if(os->gst_launch_source) { /*if(os->gst_launch_source) {*/
sd_event_source_unref(os->gst_launch_source); /*sd_event_source_unref(os->gst_launch_source);*/
os->gst_launch_source = NULL; /*os->gst_launch_source = NULL;*/
} /*}*/
if(os->audio_dev) { if(os->audio_dev) {
free(os->audio_dev); free(os->audio_dev);
@ -323,17 +320,17 @@ void wfd_out_session_destroy(struct wfd_session *s)
os->authority = NULL; os->authority = NULL;
} }
if(os->bus) { /*if(os->bus) {*/
gst_bus_remove_watch(os->bus); /*gst_bus_remove_watch(os->bus);*/
g_object_unref(os->bus); /*g_object_unref(os->bus);*/
os->bus = NULL; /*os->bus = NULL;*/
} /*}*/
if(os->pipeline) { /*if(os->pipeline) {*/
gst_element_set_state(os->pipeline, GST_STATE_NULL); /*gst_element_set_state(os->pipeline, GST_STATE_NULL);*/
g_object_unref(os->pipeline); /*g_object_unref(os->pipeline);*/
os->pipeline = NULL; /*os->pipeline = NULL;*/
} /*}*/
} }
int wfd_out_session_initiate_request(struct wfd_session *s) int wfd_out_session_initiate_request(struct wfd_session *s)
@ -547,43 +544,43 @@ static int wfd_out_session_request_options(struct wfd_session *s,
return 0; return 0;
} }
static gboolean wfd_out_session_handle_gst_message(GstBus *bus, //static gboolean wfd_out_session_handle_gst_message(GstBus *bus,
GstMessage *m, // GstMessage *m,
gpointer userdata) // gpointer userdata)
{ //{
struct wfd_session *s = userdata; // struct wfd_session *s = userdata;
struct wfd_out_session *os = userdata; // struct wfd_out_session *os = userdata;
GstState old_state, new_state; // GstState old_state, new_state;
//
switch(GST_MESSAGE_TYPE(m)) { // switch(GST_MESSAGE_TYPE(m)) {
case GST_MESSAGE_STATE_CHANGED: // case GST_MESSAGE_STATE_CHANGED:
if(os->pipeline != (void *) GST_MESSAGE_SRC(m)) { // if(os->pipeline != (void *) GST_MESSAGE_SRC(m)) {
break; // break;
} // }
//
gst_message_parse_state_changed(m, &old_state, &new_state, NULL); // gst_message_parse_state_changed(m, &old_state, &new_state, NULL);
if(GST_STATE_PLAYING == new_state) { // if(GST_STATE_PLAYING == new_state) {
log_info("stream is playing"); // log_info("stream is playing");
wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING); // wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
} // }
else if(GST_STATE_PLAYING == old_state && // else if(GST_STATE_PLAYING == old_state &&
GST_STATE_PAUSED == new_state) { // GST_STATE_PAUSED == new_state) {
log_info("stream is paused"); // log_info("stream is paused");
wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED); // wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED);
} // }
break; // break;
case GST_MESSAGE_EOS: // case GST_MESSAGE_EOS:
case GST_MESSAGE_ERROR: // case GST_MESSAGE_ERROR:
log_warning("%s encounter unexpected error or EOS", // log_warning("%s encounter unexpected error or EOS",
GST_MESSAGE_SRC_NAME(m)); // GST_MESSAGE_SRC_NAME(m));
wfd_session_teardown(s); // wfd_session_teardown(s);
break; // break;
default: // default:
break; // break;
} // }
//
return TRUE; // return TRUE;
} //}
inline static char * uint16_to_str(uint16_t i, char *buf, size_t len) inline static char * uint16_to_str(uint16_t i, char *buf, size_t len)
{ {
@ -599,188 +596,188 @@ inline static char * quote_str(const char *s, char *d, size_t len)
return d; return d;
} }
static int wfd_out_session_create_pipeline(struct wfd_session *s) //static int wfd_out_session_create_pipeline(struct wfd_session *s)
{ //{
char rrtp_port[16], rrtcp_port[16], lrtcp_port[16]; // char rrtp_port[16], rrtcp_port[16], lrtcp_port[16];
char audio_dev[256]; // char audio_dev[256];
char vsrc_param1[16] = "", vsrc_param2[16] = ""; // char vsrc_param1[16] = "", vsrc_param2[16] = "";
char vsrc_param3[16] = "", vsrc_param4[16] = ""; // char vsrc_param3[16] = "", vsrc_param4[16] = "";
struct wfd_out_session *os = wfd_out_session(s); // struct wfd_out_session *os = wfd_out_session(s);
GstElement *pipeline; // GstElement *pipeline;
GstElement *vsrc; // GstElement *vsrc;
GstBus *bus; // GstBus *bus;
GError *error = NULL; // GError *error = NULL;
const char **tmp; // const char **tmp;
int r; // int r;
const char *pipeline_desc[128] = { // const char *pipeline_desc[128] = {
"ximagesrc", // "ximagesrc",
"name=vsrc", // "name=vsrc",
"use-damage=false", // "use-damage=false",
"show-pointer=false", // "show-pointer=false",
vsrc_param1, // vsrc_param1,
vsrc_param2, // vsrc_param2,
vsrc_param3, // vsrc_param3,
vsrc_param4, // vsrc_param4,
"!", "video/x-raw,", // "!", "video/x-raw,",
"framerate=30/1", // "framerate=30/1",
//"!", "vaapipostproc", // //"!", "vaapipostproc",
// "scale-method=2", /* high quality scaling mode */ // // "scale-method=2", /* high quality scaling mode */
// "format=3", /* yv12" */ // // "format=3", /* yv12" */
//"!", "vaapih264enc", // //"!", "vaapih264enc",
// "rate-control=1", // // "rate-control=1",
// "num-slices=1", /* in WFD spec, one slice per frame */ // // "num-slices=1", /* in WFD spec, one slice per frame */
// "max-bframes=0", /* in H264 CHP, no bframe supporting */ // // "max-bframes=0", /* in H264 CHP, no bframe supporting */
// "cabac=true", /* in H264 CHP, CABAC entropy codeing is supported, but need more processing to decode */ // // "cabac=true", /* in H264 CHP, CABAC entropy codeing is supported, but need more processing to decode */
// "dct8x8=true", /* in H264 CHP, DTC is supported */ // // "dct8x8=true", /* in H264 CHP, DTC is supported */
// "cpb-length=50", /* shortent buffer in order to decrease latency */ // // "cpb-length=50", /* shortent buffer in order to decrease latency */
// "keyframe-period=30", // // "keyframe-period=30",
// /* "bitrate=62500", */ /* the max bitrate of H264 level 4.2, crashing my dongle, let codec decide */ // // /* "bitrate=62500", */ /* the max bitrate of H264 level 4.2, crashing my dongle, let codec decide */
"!", "videoscale", // "!", "videoscale",
"method=0", // "method=0",
"!", "video/x-raw,", // "!", "video/x-raw,",
"width=1920,", // "width=1920,",
"height=1080", // "height=1080",
"!", "videoconvert", // "!", "videoconvert",
"dither=0", // "dither=0",
"!", "video/x-raw,", // "!", "video/x-raw,",
"format=YV12" // "format=YV12"
"!", "x264enc", // "!", "x264enc",
"pass=4", /* constant quantizer */ // "pass=4", /* constant quantizer */
"b-adapt=false", /* no bframe suppport in CHP */ // "b-adapt=false", /* no bframe suppport in CHP */
"key-int-max=30", /* send IDR pictures per second */ // "key-int-max=30", /* send IDR pictures per second */
"speed-preset=4", /* faster */ // "speed-preset=4", /* faster */
"tune=4", /* zero latency */ // "tune=4", /* zero latency */
"!", "h264parse", // "!", "h264parse",
"!", "video/x-h264,", // "!", "video/x-h264,",
"alignment=nal,", // "alignment=nal,",
"stream-format=byte-stream" // "stream-format=byte-stream"
"!", "queue", // "!", "queue",
"max-size-buffers=0", // "max-size-buffers=0",
"max-size-bytes=0", // "max-size-bytes=0",
"!", "mpegtsmux", // "!", "mpegtsmux",
"name=muxer", // "name=muxer",
"!", "rtpmp2tpay", // "!", "rtpmp2tpay",
"!", ".send_rtp_sink_0", "rtpbin", // "!", ".send_rtp_sink_0", "rtpbin",
"name=session", // "name=session",
"do-retransmission=true", // "do-retransmission=true",
"do-sync-event=true", // "do-sync-event=true",
"do-lost=true", // "do-lost=true",
"ntp-time-source=3", // "ntp-time-source=3",
"buffer-mode=0", // "buffer-mode=0",
"latency=20", // "latency=20",
"max-misorder-time=30", // "max-misorder-time=30",
"!", "application/x-rtp", // "!", "application/x-rtp",
"!", "udpsink", // "!", "udpsink",
"sync=false", // "sync=false",
"async=false", // "async=false",
"host=", wfd_out_session_get_sink(s)->peer->remote_address, // "host=", wfd_out_session_get_sink(s)->peer->remote_address,
"port=", uint16_to_str(s->stream.rtp_port, rrtp_port,sizeof(rrtp_port)), // "port=", uint16_to_str(s->stream.rtp_port, rrtp_port,sizeof(rrtp_port)),
"udpsrc", // "udpsrc",
"address=", wfd_out_session_get_sink(s)->peer->local_address, // "address=", wfd_out_session_get_sink(s)->peer->local_address,
"port=", uint16_to_str(LOCAL_RTCP_PORT, lrtcp_port,sizeof(lrtcp_port)), // "port=", uint16_to_str(LOCAL_RTCP_PORT, lrtcp_port,sizeof(lrtcp_port)),
"reuse=true", // "reuse=true",
"!", "session.recv_rtcp_sink_0", // "!", "session.recv_rtcp_sink_0",
NULL // NULL
}; // };
//
if(s->stream.rtcp_port) { // if(s->stream.rtcp_port) {
for(tmp = pipeline_desc; *tmp; ++tmp); // for(tmp = pipeline_desc; *tmp; ++tmp);
*tmp ++ = "session.send_rtcp_src_0"; // *tmp ++ = "session.send_rtcp_src_0";
*tmp ++ = "!"; // *tmp ++ = "!";
*tmp ++ = "udpsink"; // *tmp ++ = "udpsink";
*tmp ++ = "host="; // *tmp ++ = "host=";
*tmp ++ = wfd_out_session_get_sink(s)->peer->remote_address; // *tmp ++ = wfd_out_session_get_sink(s)->peer->remote_address;
*tmp ++ = "port="; // *tmp ++ = "port=";
*tmp ++ = uint16_to_str(s->stream.rtcp_port, rrtcp_port,sizeof(rrtcp_port)); // *tmp ++ = uint16_to_str(s->stream.rtcp_port, rrtcp_port,sizeof(rrtcp_port));
*tmp ++ = "sync=false"; // *tmp ++ = "sync=false";
*tmp ++ = "async=false"; // *tmp ++ = "async=false";
*tmp ++ = NULL; // *tmp ++ = NULL;
} // }
//
if(*os->audio_dev) { // if(*os->audio_dev) {
for(tmp = pipeline_desc; *tmp; ++tmp); // for(tmp = pipeline_desc; *tmp; ++tmp);
*tmp ++ = "pulsesrc"; // *tmp ++ = "pulsesrc";
*tmp ++ = "do-timestamp=true"; // *tmp ++ = "do-timestamp=true";
*tmp ++ = "client-name=miraclecast"; // *tmp ++ = "client-name=miraclecast";
*tmp ++ = "device="; // *tmp ++ = "device=";
*tmp ++ = quote_str(os->audio_dev, audio_dev, sizeof(audio_dev)); // *tmp ++ = quote_str(os->audio_dev, audio_dev, sizeof(audio_dev));
*tmp ++ = "!"; // *tmp ++ = "!";
*tmp ++ = "voaacenc"; // *tmp ++ = "voaacenc";
*tmp ++ = "mark-granule=true"; // *tmp ++ = "mark-granule=true";
*tmp ++ = "hard-resync=true"; // *tmp ++ = "hard-resync=true";
*tmp ++ = "tolerance=40"; // *tmp ++ = "tolerance=40";
*tmp ++ = "!"; // *tmp ++ = "!";
*tmp ++ = "audio/mpeg,"; // *tmp ++ = "audio/mpeg,";
*tmp ++ = "rate=48000,"; // *tmp ++ = "rate=48000,";
*tmp ++ = "channels=2,"; // *tmp ++ = "channels=2,";
*tmp ++ = "stream-format=adts,"; // *tmp ++ = "stream-format=adts,";
*tmp ++ = "base-profile=lc"; // *tmp ++ = "base-profile=lc";
*tmp ++ = "!"; // *tmp ++ = "!";
*tmp ++ = "queue"; // *tmp ++ = "queue";
*tmp ++ = "max-size-buffers=0"; // *tmp ++ = "max-size-buffers=0";
*tmp ++ = "max-size-bytes=0"; // *tmp ++ = "max-size-bytes=0";
*tmp ++ = "max-size-time=0"; // *tmp ++ = "max-size-time=0";
*tmp ++ = "!"; // *tmp ++ = "!";
*tmp ++ = "muxer."; // *tmp ++ = "muxer.";
*tmp ++ = NULL; // *tmp ++ = NULL;
} // }
//
/* bad pratice, but since we are in the same process, // /* bad pratice, but since we are in the same process,
I think this is the only way to do it */ // I think this is the only way to do it */
if(WFD_DISPLAY_TYPE_X == os->display_type) { // if(WFD_DISPLAY_TYPE_X == os->display_type) {
r = setenv("XAUTHORITY", os->authority, 1); // r = setenv("XAUTHORITY", os->authority, 1);
if(0 > r) { // if(0 > r) {
return r; // return r;
} // }
//
r = setenv("DISPLAY", os->display_name, 1); // r = setenv("DISPLAY", os->display_name, 1);
if(0 > r) { // if(0 > r) {
return r; // return r;
} // }
//
if(!os->display_param_name) { // if(!os->display_param_name) {
snprintf(vsrc_param1, sizeof(vsrc_param1), "startx=%hu", os->x); // snprintf(vsrc_param1, sizeof(vsrc_param1), "startx=%hu", os->x);
snprintf(vsrc_param2, sizeof(vsrc_param2), "starty=%hu", os->y); // snprintf(vsrc_param2, sizeof(vsrc_param2), "starty=%hu", os->y);
snprintf(vsrc_param3, sizeof(vsrc_param3), "endx=%d", os->x + os->width - 1); // snprintf(vsrc_param3, sizeof(vsrc_param3), "endx=%d", os->x + os->width - 1);
snprintf(vsrc_param4, sizeof(vsrc_param4), "endy=%d", os->y + os->height - 1); // snprintf(vsrc_param4, sizeof(vsrc_param4), "endy=%d", os->y + os->height - 1);
} // }
else if(!strcmp("xid", os->display_param_name) || // else if(!strcmp("xid", os->display_param_name) ||
!strcmp("xname", os->display_param_name)) { // !strcmp("xname", os->display_param_name)) {
snprintf(vsrc_param1, sizeof(vsrc_param1), // snprintf(vsrc_param1, sizeof(vsrc_param1),
"%s=\"%s\"", // "%s=\"%s\"",
os->display_param_name, // os->display_param_name,
os->display_param_value); // os->display_param_value);
} // }
} // }
//
pipeline = gst_parse_launchv(pipeline_desc, &error); // pipeline = gst_parse_launchv(pipeline_desc, &error);
if(!pipeline) { // if(!pipeline) {
if(error) { // if(error) {
log_error("failed to create pipeline: %s", error->message); // log_error("failed to create pipeline: %s", error->message);
g_error_free(error); // g_error_free(error);
} // }
return -1; // return -1;
} // }
//
vsrc = gst_bin_get_by_name(GST_BIN(pipeline), "vsrc"); // vsrc = gst_bin_get_by_name(GST_BIN(pipeline), "vsrc");
gst_base_src_set_live(GST_BASE_SRC(vsrc), true); // gst_base_src_set_live(GST_BASE_SRC(vsrc), true);
g_object_unref(vsrc); // g_object_unref(vsrc);
vsrc = NULL; // vsrc = NULL;
//
r = gst_element_set_state(pipeline, GST_STATE_PAUSED); // r = gst_element_set_state(pipeline, GST_STATE_PAUSED);
if(GST_STATE_CHANGE_FAILURE == r) { // if(GST_STATE_CHANGE_FAILURE == r) {
g_object_unref(pipeline); // g_object_unref(pipeline);
return -1; // return -1;
} // }
//
bus = gst_element_get_bus(pipeline); // bus = gst_element_get_bus(pipeline);
gst_bus_add_watch(bus, wfd_out_session_handle_gst_message, s); // gst_bus_add_watch(bus, wfd_out_session_handle_gst_message, s);
//
os->pipeline = pipeline; // os->pipeline = pipeline;
os->bus = bus; // os->bus = bus;
//
return 0; // return 0;
} //}
static int wfd_out_session_handle_pause_request(struct wfd_session *s, static int wfd_out_session_handle_pause_request(struct wfd_session *s,
struct rtsp_message *req, struct rtsp_message *req,
@ -789,10 +786,10 @@ static int wfd_out_session_handle_pause_request(struct wfd_session *s,
_rtsp_message_unref_ struct rtsp_message *m = NULL; _rtsp_message_unref_ struct rtsp_message *m = NULL;
int r; int r;
r = gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_READY); // r = gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_READY);
if(GST_STATE_CHANGE_FAILURE == r) { // if(GST_STATE_CHANGE_FAILURE == r) {
return -1; // return -1;
} // }
r = rtsp_message_new_reply_for(req, r = rtsp_message_new_reply_for(req,
&m, &m,
@ -815,18 +812,19 @@ static int wfd_out_session_handle_teardown_request(struct wfd_session *s,
_rtsp_message_unref_ struct rtsp_message *m = NULL; _rtsp_message_unref_ struct rtsp_message *m = NULL;
int r; int r;
gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_NULL); wfd_session_set_state(s, WFD_SESSION_STATE_TEARING_DOWN);
/*gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_NULL);*/
r = rtsp_message_new_reply_for(req, /*r = rtsp_message_new_reply_for(req,*/
&m, /*&m,*/
RTSP_CODE_OK, /*RTSP_CODE_OK,*/
NULL); /*NULL);*/
if(0 > r) { /*if(0 > r) {*/
return r; /*return r;*/
} /*}*/
*out_rep = m; /**out_rep = m;*/
m = NULL; /*m = NULL;*/
return 0; return 0;
} }
@ -836,17 +834,19 @@ static int wfd_out_session_post_handle_play(sd_event_source *source,
void *userdata) void *userdata)
{ {
struct wfd_session *s = userdata; struct wfd_session *s = userdata;
GstStateChangeReturn r; //GstStateChangeReturn r;
sd_event_source_unref(source); sd_event_source_unref(source);
wfd_out_session(s)->gst_launch_source = NULL; wfd_out_session(s)->gst_launch_source = NULL;
r = gst_element_set_state(wfd_out_session(s)->pipeline, /*r = gst_element_set_state(wfd_out_session(s)->pipeline,*/
GST_STATE_PLAYING); /*GST_STATE_PLAYING);*/
if(GST_STATE_CHANGE_FAILURE == r) { /*if(GST_STATE_CHANGE_FAILURE == r) {*/
wfd_session_teardown(s); /*wfd_session_teardown(s);*/
return -1; /*return -1;*/
} /*}*/
wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
return 0; return 0;
} }
@ -972,10 +972,10 @@ static int wfd_out_session_handle_setup_request(struct wfd_session *s,
return r; return r;
} }
r = wfd_out_session_create_pipeline(s); /*r = wfd_out_session_create_pipeline(s);*/
if(0 > r) { /*if(0 > r) {*/
return r; /*return r;*/
} /*}*/
*out_rep = m; *out_rep = m;
m = NULL; m = NULL;

View file

@ -46,6 +46,11 @@ extern int wfd_out_session_teardown(struct wfd_session *);
extern void wfd_out_session_end(struct wfd_session *); extern void wfd_out_session_end(struct wfd_session *);
extern void wfd_out_session_destroy(struct wfd_session *); extern void wfd_out_session_destroy(struct wfd_session *);
static const char * rtsp_message_id_to_string(enum rtsp_message_id id); static const char * rtsp_message_id_to_string(enum rtsp_message_id id);
static int wfd_session_handle_request(struct rtsp *bus,
struct rtsp_message *m,
void *userdata);
static bool wfd_session_is_hup(struct wfd_session *s);
static void wfd_session_hup(struct wfd_session *s);
const struct wfd_session_vtable session_vtbl[] = { const struct wfd_session_vtable session_vtbl[] = {
[WFD_SESSION_DIR_OUT] = { [WFD_SESSION_DIR_OUT] = {
@ -177,11 +182,9 @@ int wfd_session_pause(struct wfd_session *s)
int wfd_session_teardown(struct wfd_session *s) int wfd_session_teardown(struct wfd_session *s)
{ {
log_info("wfd_session_teardown(%p)", s);
assert(wfd_is_session(s)); assert(wfd_is_session(s));
/* notify and detach from sink */
wfd_fn_out_session_ended(s);
if(wfd_session_is_established(s)) { if(wfd_session_is_established(s)) {
if(!session_vtbl[s->dir].teardown) { if(!session_vtbl[s->dir].teardown) {
return 0; return 0;
@ -189,18 +192,36 @@ int wfd_session_teardown(struct wfd_session *s)
return session_vtbl[s->dir].teardown(s);; return session_vtbl[s->dir].teardown(s);;
} }
else {
//wfd_session_free(s); /* notify and detach from sink */
wfd_fn_out_session_ended(s);
}
return 0; return 0;
} }
void wfd_session_free(struct wfd_session *s) struct wfd_session * wfd_session_ref(struct wfd_session *s)
{
if(s) {
++ s->ref_count;
}
return s;
}
void wfd_session_unref(struct wfd_session *s)
{ {
if(!s) { if(!s) {
return; return;
} }
assert(1 <= s->ref_count);
-- s->ref_count;
if(s->ref_count) {
return;
}
if(session_vtbl[s->dir].destroy) { if(session_vtbl[s->dir].destroy) {
(*session_vtbl[s->dir].destroy)(s); (*session_vtbl[s->dir].destroy)(s);
} }
@ -220,11 +241,7 @@ void wfd_session_free(struct wfd_session *s)
s->stream.url = NULL; s->stream.url = NULL;
} }
if(s->rtsp) { wfd_session_hup(s);
rtsp_detach_event(s->rtsp);
rtsp_unref(s->rtsp);
s->rtsp = NULL;
}
s->rtp_ports[0] = 0; s->rtp_ports[0] = 0;
s->rtp_ports[1] = 0; s->rtp_ports[1] = 0;
@ -400,7 +417,7 @@ static int wfd_session_handle_request(struct rtsp *bus,
_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;
char date[128]; char date[64];
uint64_t usec; uint64_t usec;
time_t sec; time_t sec;
int r; int r;
@ -427,6 +444,11 @@ static int wfd_session_handle_request(struct rtsp *bus,
goto error; goto error;
} }
if(WFD_SESSION_STATE_TEARING_DOWN == wfd_session_get_state(s)) {
wfd_session_hup(s);
return 0;
}
r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec); r = sd_event_now(ctl_wfd_get_loop(), CLOCK_REALTIME, &usec);
if(0 > r) { if(0 > r) {
goto error; goto error;
@ -437,7 +459,7 @@ static int wfd_session_handle_request(struct rtsp *bus,
"%a, %d %b %Y %T %z", "%a, %d %b %Y %T %z",
gmtime(&sec)); gmtime(&sec));
r = rtsp_message_append(rep, "<s>", "Date", date); r = rtsp_message_append(rep, "<&>", "Date", date);
if(0 > r) { if(0 > r) {
goto error; goto error;
} }
@ -515,6 +537,17 @@ error:
return r; return r;
} }
int wfd_session_init(struct wfd_session *s,
enum wfd_session_dir dir,
const struct rtsp_dispatch_entry *disp_tbl)
{
s->ref_count = 1;
s->dir = dir;
s->rtsp_disp_tbl = disp_tbl;
return 0;
}
int wfd_session_request(struct wfd_session *s, int wfd_session_request(struct wfd_session *s,
enum rtsp_message_id id, enum rtsp_message_id id,
const struct wfd_arg_list *args) const struct wfd_arg_list *args)
@ -589,6 +622,8 @@ static int wfd_session_handle_io(sd_event_source *source,
goto end; goto end;
} }
log_trace("rtsp->ref = %ld", *(unsigned long *) rtsp);
conn = -1; conn = -1;
r = rtsp_attach_event(rtsp, ctl_wfd_get_loop(), 0); r = rtsp_attach_event(rtsp, ctl_wfd_get_loop(), 0);
@ -622,6 +657,23 @@ end:
return r; return r;
} }
static bool wfd_session_is_hup(struct wfd_session *s)
{
return NULL == s->rtsp;
}
static void wfd_session_hup(struct wfd_session *s)
{
if(!s || !s->rtsp) {
return;
}
rtsp_remove_match(s->rtsp, wfd_session_handle_request, s);
rtsp_detach_event(s->rtsp);
rtsp_unref(s->rtsp);
s->rtsp = NULL;
}
int wfd_session_start(struct wfd_session *s, uint64_t id) int wfd_session_start(struct wfd_session *s, uint64_t id)
{ {
int r; int r;
@ -658,9 +710,11 @@ int wfd_session_start(struct wfd_session *s, uint64_t id)
return 0; return 0;
} }
void wfd_session_free_p(struct wfd_session **s) void wfd_session_unrefp(struct wfd_session **s)
{ {
wfd_session_free(*s); if(s) {
wfd_session_unref(*s);
}
} }
static const char * rtsp_message_id_to_string(enum rtsp_message_id id) static const char * rtsp_message_id_to_string(enum rtsp_message_id id)

View file

@ -93,6 +93,7 @@ struct wfd_session_vtable
struct wfd_session struct wfd_session
{ {
int ref_count;
enum wfd_session_dir dir; enum wfd_session_dir dir;
enum wfd_session_state state; enum wfd_session_state state;
enum rtsp_message_id last_request; enum rtsp_message_id last_request;
@ -112,7 +113,9 @@ struct wfd_session
} stream; } stream;
}; };
int wfd_session_init(struct wfd_session *s); int wfd_session_init(struct wfd_session *s,
enum wfd_session_dir dir,
const struct rtsp_dispatch_entry *disp_tbl);
int wfd_session_gen_stream_url(struct wfd_session *s, int wfd_session_gen_stream_url(struct wfd_session *s,
const char *local_addr, const char *local_addr,
enum wfd_stream_id id); enum wfd_stream_id id);

View file

@ -45,9 +45,10 @@ static int wfd_sink_set_session(struct wfd_sink *sink,
ctl_wfd_remove_session_by_id(ctl_wfd_get(), ctl_wfd_remove_session_by_id(ctl_wfd_get(),
wfd_session_get_id(sink->session), wfd_session_get_id(sink->session),
NULL); NULL);
wfd_session_unref(sink->session);
} }
sink->session = session; sink->session = session ? wfd_session_ref(session) : NULL;
wfd_fn_sink_properties_changed(sink, "Session"); wfd_fn_sink_properties_changed(sink, "Session");
return 0; return 0;
@ -90,11 +91,7 @@ void wfd_sink_free(struct wfd_sink *sink)
return; return;
} }
if(sink->session) { wfd_sink_set_session(sink, NULL);
s = sink->session;
wfd_sink_set_session(sink, NULL);
wfd_session_free(s);
}
if(sink->label) { if(sink->label) {
free(sink->label); free(sink->label);
@ -129,7 +126,7 @@ int wfd_sink_start_session(struct wfd_sink *sink,
const char *audio_dev) const char *audio_dev)
{ {
int r; int r;
_wfd_session_free_ struct wfd_session *s = NULL; _wfd_session_unref_ struct wfd_session *s = NULL;
assert(sink); assert(sink);
assert(out); assert(out);
@ -165,7 +162,6 @@ int wfd_sink_start_session(struct wfd_sink *sink,
sink->session = s; sink->session = s;
*out = s; *out = s;
s = NULL;
return 0; return 0;
} }