mirror of
https://github.com/gpac/gpac.git
synced 2026-01-12 00:05:22 +08:00
rmtws: for js move on_new_client cb from filter session to core sys object
This commit is contained in:
@@ -159,8 +159,8 @@ unsigned long long get_utc(DOMString date);
|
||||
Fraction get_ntp();
|
||||
|
||||
|
||||
/*! shifts an NTP 64-bit timestamp by the given number of microseconds
|
||||
\param ntp source NTP
|
||||
/*! shifts an NTP 64-bit timestamp by the given number of microseconds
|
||||
\param ntp source NTP
|
||||
\param microseconds number of microseconds to add (positive) or remove (negative)
|
||||
\return adjusted NTP 64 bit timestamp as fraction, 'n' continaing seconds, 'd' containing fractional part
|
||||
*/
|
||||
@@ -400,6 +400,18 @@ Rect rect_union(Rect r1, Rect r2);
|
||||
Rect rect_intersect(Rect r1, Rect r2);
|
||||
|
||||
|
||||
/*! enables websocket monitoring server - see \ref gf_sys_enable_rmtws
|
||||
*
|
||||
* define the \ref rmt_on_new_client attribute to set callbacks
|
||||
* \param enable (default: true) will enable the server if true, stop it if false
|
||||
*/
|
||||
void enable_rmtws(bool enable);
|
||||
|
||||
/*! set the callback function when new clients connect to the websocket server
|
||||
* the function shall take one parameter of type \ref JS_RMTClient
|
||||
*/
|
||||
optional attribute function rmt_on_new_client;
|
||||
|
||||
/*! number of cores */
|
||||
attribute readonly unsigned long nb_cores;
|
||||
|
||||
@@ -526,7 +538,7 @@ attribute readonly unsigned long h;
|
||||
/*! object used for file enumeration - cannot be created through constructor*/
|
||||
interface FileInformation {
|
||||
/*! file name*/
|
||||
DOMString name;
|
||||
DOMString name;
|
||||
/*! file path*/
|
||||
DOMString path;
|
||||
/*! true if directory*/
|
||||
@@ -942,7 +954,32 @@ attribute readonly FileIO parent;
|
||||
|
||||
};
|
||||
|
||||
/*! Object representing a monitoring websocket client
|
||||
*
|
||||
* will be passed to the session \ref rmt_on_new_client callback
|
||||
*/
|
||||
interface JS_RMTClient {
|
||||
|
||||
/*! a callback called when the client receives data
|
||||
*
|
||||
* the function shall be of type function(data)
|
||||
* where data will be either of type string (for utf8 data) or arraybuffer (for binary data)
|
||||
*/
|
||||
optional attribute function on_data;
|
||||
|
||||
/*! a callback called when the client disconnects or is deleted */
|
||||
optional attribute function on_close;
|
||||
|
||||
/*! a string of format ip:port representing the client */
|
||||
readonly attribute string peer_address;
|
||||
|
||||
/*! sends data to the client on the websocket
|
||||
\param data the data to send, can be either of type string (for utf8 data) or arraybuffer (for binary data)
|
||||
*/
|
||||
void send(data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
@@ -83,19 +83,6 @@ JSFSFilter get_filter(unsigned long index);
|
||||
*/
|
||||
JSFSFilter get_filter(DOMString iname);
|
||||
|
||||
|
||||
/*! enables websocket monitoring server - see \ref gf_sys_enable_rmtws
|
||||
*
|
||||
* define the \ref rmt_on_new_client attribute to set callbacks
|
||||
* \param enable (default: true) will enable the server if true, stop it if false
|
||||
*/
|
||||
void enable_rmtws(bool enable);
|
||||
|
||||
/*! set the callback function when new clients connect to the websocket server
|
||||
* the function shall take one parameter of type \ref JSFS_RMTClient
|
||||
*/
|
||||
optional attribute function rmt_on_new_client;
|
||||
|
||||
/*! inserts a filter in graph
|
||||
|
||||
\param filter_to_add string describin the filter to add, can be in the form "src=" for sources, "dst=" for sinks or regular string for filters.
|
||||
@@ -448,34 +435,5 @@ optional attribute DOMString hint;
|
||||
|
||||
};
|
||||
|
||||
/*! Object representing a monitoring websocket client
|
||||
*
|
||||
* will be passed to the session \ref rmt_on_new_client callback
|
||||
*/
|
||||
interface JSFS_RMTClient {
|
||||
|
||||
/*! a callback called when the client receives data
|
||||
*
|
||||
* the function shall be of type function(data)
|
||||
* where data will be either of type string (for utf8 data) or arraybuffer (for binary data)
|
||||
*/
|
||||
optional attribute function on_data;
|
||||
|
||||
/*! a callback called when the client disconnects or is deleted */
|
||||
optional attribute function on_close;
|
||||
|
||||
/*! a string of format ip:port representing the client */
|
||||
readonly attribute string peer_address;
|
||||
|
||||
/*! sends data to the client on the websocket
|
||||
\param data the data to send, can be either of type string (for utf8 data) or arraybuffer (for binary data)
|
||||
*/
|
||||
void send(data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
@@ -240,7 +240,9 @@ function JSClient(id, client) {
|
||||
|
||||
}
|
||||
|
||||
session.rmt_on_new_client = function(client) {
|
||||
sys.enable_rmtws();
|
||||
|
||||
sys.rmt_on_new_client = function(client) {
|
||||
console.log("rmt on client");
|
||||
print(typeof(client));
|
||||
|
||||
|
||||
@@ -61,13 +61,6 @@ static void jsfs_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
|
||||
JS_MarkValue(rt, task->_obj2, mark_func);
|
||||
}
|
||||
}
|
||||
{
|
||||
JSFS_Task* task = (JSFS_Task*) rmt_get_on_new_client_task();
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_MarkValue(rt, task->fun, mark_func);
|
||||
JS_MarkValue(rt, task->_obj, mark_func);
|
||||
}
|
||||
}
|
||||
|
||||
gf_fs_lock_filters(fs, GF_TRUE);
|
||||
count = gf_list_count(fs->filters);
|
||||
@@ -113,7 +106,6 @@ enum
|
||||
JSFS_LAST_PROCESS_ERR,
|
||||
JSFS_LAST_CONNECT_ERR,
|
||||
JSFS_PATH,
|
||||
JSFS_RMT_ON_NEW_CLIENT
|
||||
};
|
||||
|
||||
GF_Filter *jsff_get_filter(JSContext *c, JSValue this_val)
|
||||
@@ -160,278 +152,6 @@ static void jsfs_exec_task_custom(JSFS_Task *task, const char *text, GF_Filter *
|
||||
gf_js_lock(task->ctx, GF_FALSE);
|
||||
}
|
||||
|
||||
//// RMTClient js class ////
|
||||
|
||||
static JSClassID jsfs_rmt_client_class_id;
|
||||
|
||||
static void jsfs_rmt_client_finalizer(JSRuntime *rt, JSValue val) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(val, jsfs_rmt_client_class_id);
|
||||
if (!client) return;
|
||||
|
||||
JSFS_Task* task = rmt_client_get_on_data_task(client);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d jsfs_rmt_client_finalizer client %p task %p\n", __FILE__, __LINE__, client, task));
|
||||
rmt_client_set_on_data_cbk(client, NULL, NULL);
|
||||
|
||||
JSFS_Task* deltask = rmt_client_get_on_del_task(client);
|
||||
rmt_client_set_on_del_cbk(client, NULL, NULL);
|
||||
|
||||
JS_SetOpaque(val, NULL);
|
||||
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(task->ctx, task->fun);
|
||||
JS_FreeValue(task->ctx, task->_obj);
|
||||
gf_free(task);
|
||||
}
|
||||
|
||||
if (deltask && deltask->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(deltask->ctx, deltask->fun);
|
||||
JS_FreeValue(deltask->ctx, deltask->_obj);
|
||||
gf_free(deltask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void jsfs_rmt_client_gc_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(val, jsfs_rmt_client_class_id);
|
||||
if (!client) return;
|
||||
|
||||
JSFS_Task* task = rmt_client_get_on_data_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_MarkValue(rt, task->fun, mark_func);
|
||||
JS_MarkValue(rt, task->_obj, mark_func);
|
||||
}
|
||||
|
||||
task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_MarkValue(rt, task->fun, mark_func);
|
||||
JS_MarkValue(rt, task->_obj, mark_func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static JSClassDef jsfs_rmt_client_class = {
|
||||
"RMTClient",
|
||||
.finalizer = jsfs_rmt_client_finalizer,
|
||||
.gc_mark = jsfs_rmt_client_gc_mark
|
||||
};
|
||||
|
||||
enum {
|
||||
JSFS_RMT_CLIENT_ON_DATA,
|
||||
JSFS_RMT_CLIENT_ON_CLOSE,
|
||||
JSFS_RMT_CLIENT_PEER_ADDRESS
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void jsfs_rmt_run_task(JSFS_Task* task, JSValue arg) {
|
||||
|
||||
if (!task || task->type != RMT_CALLBACK_JS )
|
||||
return;
|
||||
|
||||
int argc = JS_IsUndefined(arg) ? 0 : 1;
|
||||
|
||||
gf_js_lock(task->ctx, GF_TRUE);
|
||||
|
||||
JSValue ret = JS_Call(task->ctx, task->fun, task->_obj, argc, &arg);
|
||||
|
||||
if (JS_IsException(ret)) {
|
||||
js_dump_error(task->ctx);
|
||||
}
|
||||
JS_FreeValue(task->ctx, ret);
|
||||
JS_FreeValue(task->ctx, arg);
|
||||
js_std_loop(task->ctx);
|
||||
gf_js_lock(task->ctx, GF_FALSE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void jsfs_rmt_on_del_client(void *udta) {
|
||||
if (udta) {
|
||||
JSFS_Task *task = udta;
|
||||
if (task->type == RMT_CALLBACK_JS && task->ctx && !JS_IsUndefined(task->_obj)) {
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d deleting opaque obj from task %p\n", __FILE__, __LINE__,task));
|
||||
|
||||
if (JS_IsFunction(task->ctx, task->fun))
|
||||
jsfs_rmt_run_task(task, JS_UNDEFINED);
|
||||
|
||||
jsfs_rmt_client_finalizer(NULL, task->_obj);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void jsfs_rmt_client_on_data(void *udta, const u8* payload, u64 size, Bool is_binary) {
|
||||
JSFS_Task *task = udta;
|
||||
if (!task || task->type != RMT_CALLBACK_JS) return;
|
||||
|
||||
JSValue arg;
|
||||
if (is_binary) {
|
||||
arg = JS_NewArrayBufferCopy(task->ctx, payload, size);
|
||||
} else {
|
||||
arg = JS_NewStringLen(task->ctx, payload, size);
|
||||
}
|
||||
|
||||
jsfs_rmt_run_task(task, arg);
|
||||
|
||||
}
|
||||
|
||||
static JSValue jsfs_rmt_client_prop_get(JSContext *ctx, JSValueConst this_val, int magic) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, jsfs_rmt_client_class_id);
|
||||
if (!client)
|
||||
return JS_UNDEFINED;
|
||||
|
||||
switch (magic) {
|
||||
case JSFS_RMT_CLIENT_PEER_ADDRESS:;
|
||||
const char* peer_address = rmt_get_peer_address(client);
|
||||
if (peer_address) {
|
||||
return JS_NewString(ctx, peer_address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue jsfs_rmt_client_prop_set(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, jsfs_rmt_client_class_id);
|
||||
if (!client)
|
||||
return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
switch (magic) {
|
||||
case JSFS_RMT_CLIENT_ON_DATA:;
|
||||
|
||||
JSFS_Task* oldtask = (JSFS_Task*) rmt_client_get_on_data_task(client);
|
||||
if (oldtask && oldtask->type == RMT_CALLBACK_JS) {
|
||||
rmt_client_set_on_data_cbk(client, NULL, NULL);
|
||||
JS_FreeValue(ctx, oldtask->fun);
|
||||
JS_FreeValue(ctx, oldtask->_obj);
|
||||
gf_free(oldtask);
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JSFS_Task *task;
|
||||
GF_SAFEALLOC(task, JSFS_Task);
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_client_set_on_data_cbk(client, task, jsfs_rmt_client_on_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case JSFS_RMT_CLIENT_ON_CLOSE:
|
||||
|
||||
if (JS_IsUndefined(value) || JS_IsNull(value)) {
|
||||
|
||||
JSFS_Task *task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
// reset the js function but keep the ref to the client for on_delete
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
task->fun = JS_UNDEFINED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JSFS_Task *task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
JS_FreeValue(ctx, task->_obj);
|
||||
}
|
||||
else
|
||||
GF_SAFEALLOC(task, JSFS_Task);
|
||||
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_client_set_on_del_cbk(client, task, jsfs_rmt_on_del_client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue jsfs_rmt_client_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, jsfs_rmt_client_class_id);
|
||||
if (!client)
|
||||
return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
if (!argc)
|
||||
return JS_UNDEFINED;
|
||||
|
||||
if (JS_IsString(argv[0])) {
|
||||
const char *msg = JS_ToCString(ctx, argv[0]);
|
||||
GF_Err e = rmt_client_send_to_ws(client, msg, strlen(msg), GF_FALSE);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d sent msg <%s> to client <%p> returned <%d>\n", __FILE__, __LINE__, msg, client, e));
|
||||
JS_FreeCString(ctx, msg);
|
||||
}
|
||||
else if (JS_IsArrayBuffer(ctx, argv[0])) {
|
||||
u32 bufsize=0;
|
||||
u8* buf = JS_GetArrayBuffer(ctx, (size_t*)&bufsize, argv[0]);
|
||||
if (buf && bufsize) {
|
||||
GF_Err e = rmt_client_send_to_ws(client, buf, bufsize, GF_TRUE);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d sent binary msg <%.*s> to client <%p> returned <%d>\n", __FILE__, __LINE__, bufsize, buf, client, e));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry jsfs_rmt_client_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF("on_data", NULL, jsfs_rmt_client_prop_set, JSFS_RMT_CLIENT_ON_DATA),
|
||||
JS_CGETSET_MAGIC_DEF("on_close", NULL, jsfs_rmt_client_prop_set, JSFS_RMT_CLIENT_ON_CLOSE),
|
||||
|
||||
JS_CGETSET_MAGIC_DEF("peer_address", jsfs_rmt_client_prop_get, NULL, JSFS_RMT_CLIENT_PEER_ADDRESS),
|
||||
|
||||
JS_CFUNC_DEF("send", 1, jsfs_rmt_client_send)
|
||||
};
|
||||
|
||||
|
||||
static void jsfs_rmt_on_new_client(void *udta, void* new_client) {
|
||||
JSFS_Task *task = udta;
|
||||
if (!task) return;
|
||||
|
||||
JSValue obj = JS_NewObjectClass(task->ctx, jsfs_rmt_client_class_id);
|
||||
if (JS_IsException(obj)) {
|
||||
GF_LOG(GF_LOG_WARNING, GF_LOG_RMTWS, ("%s:%d obj JS_IsException\n", __FILE__, __LINE__));
|
||||
}
|
||||
JS_SetOpaque(obj, new_client);
|
||||
|
||||
JSFS_Task *deltask;
|
||||
GF_SAFEALLOC(deltask, JSFS_Task);
|
||||
deltask->type = RMT_CALLBACK_JS;
|
||||
deltask->ctx = task->ctx;
|
||||
deltask->_obj = JS_DupValue(task->ctx, obj);
|
||||
|
||||
rmt_client_set_on_del_cbk((RMT_ClientCtx*)new_client, (void*)deltask, jsfs_rmt_on_del_client);
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d jsfs_rmt_on_new_client calling task %p with opaque %p\n", __FILE__, __LINE__, task, new_client));
|
||||
|
||||
jsfs_rmt_run_task(task, obj);
|
||||
}
|
||||
|
||||
|
||||
static JSValue jsfs_prop_get(JSContext *ctx, JSValueConst this_val, int magic)
|
||||
{
|
||||
GF_FilterSession *fs = JS_GetOpaque(this_val, fs_class_id);
|
||||
@@ -485,38 +205,6 @@ static JSValue jsfs_prop_set(JSContext *ctx, JSValueConst this_val, JSValueConst
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case JSFS_RMT_ON_NEW_CLIENT:
|
||||
|
||||
if (JS_IsUndefined(value) || JS_IsNull(value)) {
|
||||
|
||||
JSFS_Task* task = (JSFS_Task*) rmt_get_on_new_client_task();
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
rmt_set_on_new_client_cbk(NULL, NULL);
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
JS_FreeValue(ctx, task->_obj);
|
||||
gf_free(task);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JSFS_Task *task;
|
||||
GF_SAFEALLOC(task, JSFS_Task);
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
//gf_list_add(fs->jstasks, task);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_set_on_new_client_cbk(task, jsfs_rmt_on_new_client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
@@ -616,16 +304,6 @@ static JSValue jsfs_lock_filters(JSContext *ctx, JSValueConst this_val, int argc
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue jsfs_enable_rmtws(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
Bool enable = GF_TRUE;
|
||||
GF_FilterSession *fs = JS_GetOpaque(this_val, fs_class_id);
|
||||
if (!fs) return GF_JS_EXCEPTION(ctx);
|
||||
if (argc > 0 && JS_IsBool(argv[0])) enable = JS_ToBool(ctx, argv[0]);
|
||||
gf_sys_enable_rmtws(enable);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
void jsfs_on_filter_created(GF_Filter *new_filter)
|
||||
{
|
||||
if (!new_filter->session->new_f_task) return;
|
||||
@@ -2264,7 +1942,6 @@ static const JSCFunctionListEntry fs_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF_ENUM("nb_filters", jsfs_prop_get, NULL, JSFS_NB_FILTERS),
|
||||
JS_CGETSET_MAGIC_DEF_ENUM("last_task", jsfs_prop_get, NULL, JSFS_LAST_TASK),
|
||||
JS_CGETSET_MAGIC_DEF("http_max_bitrate", jsfs_prop_get, jsfs_prop_set, JSFS_HTTP_MAX_RATE),
|
||||
JS_CGETSET_MAGIC_DEF("rmt_on_new_client", NULL, jsfs_prop_set, JSFS_RMT_ON_NEW_CLIENT),
|
||||
JS_CGETSET_MAGIC_DEF("http_bitrate", jsfs_prop_get, NULL, JSFS_HTTP_RATE),
|
||||
JS_CGETSET_MAGIC_DEF("connected", jsfs_prop_get, NULL, JSFS_CONNECTED),
|
||||
JS_CGETSET_MAGIC_DEF("last_process_error", jsfs_prop_get, NULL, JSFS_LAST_PROCESS_ERR),
|
||||
@@ -2275,7 +1952,6 @@ static const JSCFunctionListEntry fs_funcs[] = {
|
||||
JS_CFUNC_DEF("abort", 0, jsfs_abort),
|
||||
JS_CFUNC_DEF("get_filter", 0, jsfs_get_filter),
|
||||
JS_CFUNC_DEF("lock_filters", 0, jsfs_lock_filters),
|
||||
JS_CFUNC_DEF("enable_rmtws", 0, jsfs_enable_rmtws),
|
||||
JS_CFUNC_DEF("set_new_filter_fun", 0, jsfs_set_new_filter_fun),
|
||||
JS_CFUNC_DEF("set_del_filter_fun", 0, jsfs_set_del_filter_fun),
|
||||
JS_CFUNC_DEF("set_event_fun", 0, jsfs_set_event_fun),
|
||||
@@ -2400,13 +2076,6 @@ GF_Err gf_fs_load_js_api(JSContext *c, GF_FilterSession *fs)
|
||||
JS_SetPropertyFunctionList(c, proto, jsf_auth_funcs, countof(jsf_auth_funcs));
|
||||
JS_SetClassProto(c, jsf_auth_class_id, proto);
|
||||
|
||||
JS_NewClassID(&jsfs_rmt_client_class_id);
|
||||
JS_NewClass(rt, jsfs_rmt_client_class_id, &jsfs_rmt_client_class);
|
||||
proto = JS_NewObjectClass(c, jsfs_rmt_client_class_id);
|
||||
JS_SetPropertyFunctionList(c, proto, jsfs_rmt_client_funcs, countof(jsfs_rmt_client_funcs));
|
||||
JS_SetClassProto(c, jsfs_rmt_client_class_id, proto);
|
||||
|
||||
|
||||
fs_obj = JS_NewObjectClass(c, fs_class_id);
|
||||
JS_SetPropertyFunctionList(c, fs_obj, fs_funcs, countof(fs_funcs));
|
||||
JS_SetOpaque(fs_obj, fs);
|
||||
@@ -2541,17 +2210,6 @@ void gf_fs_unload_script(GF_FilterSession *fs, void *js_ctx)
|
||||
i--;
|
||||
count--;
|
||||
}
|
||||
{
|
||||
JSFS_Task* task = (JSFS_Task*) rmt_get_on_new_client_task();
|
||||
if (fs->js_ctx && task && task->type == RMT_CALLBACK_JS) {
|
||||
rmt_set_on_new_client_cbk(NULL, NULL);
|
||||
|
||||
JS_FreeValue(task->ctx, task->fun);
|
||||
JS_FreeValue(task->ctx, task->_obj);
|
||||
|
||||
gf_free(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (fs->js_ctx || js_ctx) {
|
||||
JSContext *c = fs->js_ctx ? fs->js_ctx : js_ctx;
|
||||
|
||||
@@ -54,6 +54,14 @@ typedef struct
|
||||
GF_List *allocated_contexts;
|
||||
} GF_JSRuntime;
|
||||
|
||||
typedef struct __js_sys_task {
|
||||
JSValue fun;
|
||||
JSValue _obj;
|
||||
|
||||
u32 type;
|
||||
JSContext *ctx;
|
||||
} JS_Sys_Task;
|
||||
|
||||
static GF_JSRuntime *js_rt = NULL;
|
||||
|
||||
JSContext *gf_js_create_context()
|
||||
@@ -95,6 +103,15 @@ void gf_js_delete_context(JSContext *ctx)
|
||||
|
||||
gf_js_call_gc(ctx);
|
||||
|
||||
|
||||
JS_Sys_Task* task = (JS_Sys_Task*) rmt_get_on_new_client_task();
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
rmt_set_on_new_client_cbk(NULL, NULL);
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
JS_FreeValue(ctx, task->_obj);
|
||||
gf_free(task);
|
||||
}
|
||||
|
||||
gf_mx_p(js_rt->mx);
|
||||
gf_list_del_item(js_rt->allocated_contexts, ctx);
|
||||
JS_FreeContext(ctx);
|
||||
@@ -916,6 +933,285 @@ static JSValue bitstream_constructor(JSContext *ctx, JSValueConst new_target, in
|
||||
return anobj;
|
||||
}
|
||||
|
||||
//// RMTClient js class ////
|
||||
|
||||
static JSClassID js_sys_rmt_client_class_id;
|
||||
|
||||
|
||||
static JSValue js_sys_enable_rmtws(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
Bool enable = GF_TRUE;
|
||||
if (argc > 0 && JS_IsBool(argv[0])) enable = JS_ToBool(ctx, argv[0]);
|
||||
gf_sys_enable_rmtws(enable);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static void js_sys_rmt_client_finalizer(JSRuntime *rt, JSValue val) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(val, js_sys_rmt_client_class_id);
|
||||
if (!client) return;
|
||||
|
||||
JS_Sys_Task* task = rmt_client_get_on_data_task(client);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d js_sys_rmt_client_finalizer client %p task %p\n", __FILE__, __LINE__, client, task));
|
||||
rmt_client_set_on_data_cbk(client, NULL, NULL);
|
||||
|
||||
JS_Sys_Task* deltask = rmt_client_get_on_del_task(client);
|
||||
rmt_client_set_on_del_cbk(client, NULL, NULL);
|
||||
|
||||
JS_SetOpaque(val, NULL);
|
||||
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(task->ctx, task->fun);
|
||||
JS_FreeValue(task->ctx, task->_obj);
|
||||
gf_free(task);
|
||||
}
|
||||
|
||||
if (deltask && deltask->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(deltask->ctx, deltask->fun);
|
||||
JS_FreeValue(deltask->ctx, deltask->_obj);
|
||||
gf_free(deltask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void js_sys_rmt_client_gc_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(val, js_sys_rmt_client_class_id);
|
||||
if (!client) return;
|
||||
|
||||
JS_Sys_Task* task = rmt_client_get_on_data_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_MarkValue(rt, task->fun, mark_func);
|
||||
JS_MarkValue(rt, task->_obj, mark_func);
|
||||
}
|
||||
|
||||
task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_MarkValue(rt, task->fun, mark_func);
|
||||
JS_MarkValue(rt, task->_obj, mark_func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static JSClassDef js_sys_rmt_client_class = {
|
||||
"RMTClient",
|
||||
.finalizer = js_sys_rmt_client_finalizer,
|
||||
.gc_mark = js_sys_rmt_client_gc_mark
|
||||
};
|
||||
|
||||
enum {
|
||||
JS_SYS_RMT_CLIENT_ON_DATA,
|
||||
JS_SYS_RMT_CLIENT_ON_CLOSE,
|
||||
JS_SYS_RMT_CLIENT_PEER_ADDRESS
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void js_sys_rmt_run_task(JS_Sys_Task* task, JSValue arg) {
|
||||
|
||||
if (!task || task->type != RMT_CALLBACK_JS )
|
||||
return;
|
||||
|
||||
int argc = JS_IsUndefined(arg) ? 0 : 1;
|
||||
|
||||
gf_js_lock(task->ctx, GF_TRUE);
|
||||
|
||||
JSValue ret = JS_Call(task->ctx, task->fun, task->_obj, argc, &arg);
|
||||
|
||||
if (JS_IsException(ret)) {
|
||||
js_dump_error(task->ctx);
|
||||
}
|
||||
JS_FreeValue(task->ctx, ret);
|
||||
JS_FreeValue(task->ctx, arg);
|
||||
js_std_loop(task->ctx);
|
||||
gf_js_lock(task->ctx, GF_FALSE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void js_sys_rmt_on_del_client(void *udta) {
|
||||
if (udta) {
|
||||
JS_Sys_Task *task = udta;
|
||||
if (task->type == RMT_CALLBACK_JS && task->ctx && !JS_IsUndefined(task->_obj)) {
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d deleting opaque obj from task %p\n", __FILE__, __LINE__,task));
|
||||
|
||||
if (JS_IsFunction(task->ctx, task->fun))
|
||||
js_sys_rmt_run_task(task, JS_UNDEFINED);
|
||||
|
||||
js_sys_rmt_client_finalizer(NULL, task->_obj);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void js_sys_rmt_client_on_data(void *udta, const u8* payload, u64 size, Bool is_binary) {
|
||||
JS_Sys_Task *task = udta;
|
||||
if (!task || task->type != RMT_CALLBACK_JS) return;
|
||||
|
||||
JSValue arg;
|
||||
if (is_binary) {
|
||||
arg = JS_NewArrayBufferCopy(task->ctx, payload, size);
|
||||
} else {
|
||||
arg = JS_NewStringLen(task->ctx, payload, size);
|
||||
}
|
||||
|
||||
js_sys_rmt_run_task(task, arg);
|
||||
|
||||
}
|
||||
|
||||
static JSValue js_sys_rmt_client_prop_get(JSContext *ctx, JSValueConst this_val, int magic) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, js_sys_rmt_client_class_id);
|
||||
if (!client)
|
||||
return JS_UNDEFINED;
|
||||
|
||||
switch (magic) {
|
||||
case JS_SYS_RMT_CLIENT_PEER_ADDRESS:;
|
||||
const char* peer_address = rmt_get_peer_address(client);
|
||||
if (peer_address) {
|
||||
return JS_NewString(ctx, peer_address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_sys_rmt_client_prop_set(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, js_sys_rmt_client_class_id);
|
||||
if (!client)
|
||||
return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
switch (magic) {
|
||||
case JS_SYS_RMT_CLIENT_ON_DATA:;
|
||||
|
||||
JS_Sys_Task* oldtask = (JS_Sys_Task*) rmt_client_get_on_data_task(client);
|
||||
if (oldtask && oldtask->type == RMT_CALLBACK_JS) {
|
||||
rmt_client_set_on_data_cbk(client, NULL, NULL);
|
||||
JS_FreeValue(ctx, oldtask->fun);
|
||||
JS_FreeValue(ctx, oldtask->_obj);
|
||||
gf_free(oldtask);
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JS_Sys_Task *task;
|
||||
GF_SAFEALLOC(task, JS_Sys_Task);
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_client_set_on_data_cbk(client, task, js_sys_rmt_client_on_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case JS_SYS_RMT_CLIENT_ON_CLOSE:
|
||||
|
||||
if (JS_IsUndefined(value) || JS_IsNull(value)) {
|
||||
|
||||
JS_Sys_Task *task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
// reset the js function but keep the ref to the client for on_delete
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
task->fun = JS_UNDEFINED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JS_Sys_Task *task = rmt_client_get_on_del_task(client);
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
JS_FreeValue(ctx, task->_obj);
|
||||
}
|
||||
else
|
||||
GF_SAFEALLOC(task, JS_Sys_Task);
|
||||
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_client_set_on_del_cbk(client, task, js_sys_rmt_on_del_client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_sys_rmt_client_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||||
|
||||
RMT_ClientCtx* client = JS_GetOpaque(this_val, js_sys_rmt_client_class_id);
|
||||
if (!client)
|
||||
return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
if (!argc)
|
||||
return JS_UNDEFINED;
|
||||
|
||||
if (JS_IsString(argv[0])) {
|
||||
const char *msg = JS_ToCString(ctx, argv[0]);
|
||||
GF_Err e = rmt_client_send_to_ws(client, msg, strlen(msg), GF_FALSE);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d sent msg <%s> to client <%p> returned <%d>\n", __FILE__, __LINE__, msg, client, e));
|
||||
JS_FreeCString(ctx, msg);
|
||||
}
|
||||
else if (JS_IsArrayBuffer(ctx, argv[0])) {
|
||||
u32 bufsize=0;
|
||||
u8* buf = JS_GetArrayBuffer(ctx, (size_t*)&bufsize, argv[0]);
|
||||
if (buf && bufsize) {
|
||||
GF_Err e = rmt_client_send_to_ws(client, buf, bufsize, GF_TRUE);
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d sent binary msg <%.*s> to client <%p> returned <%d>\n", __FILE__, __LINE__, bufsize, buf, client, e));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_sys_rmt_client_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF("on_data", NULL, js_sys_rmt_client_prop_set, JS_SYS_RMT_CLIENT_ON_DATA),
|
||||
JS_CGETSET_MAGIC_DEF("on_close", NULL, js_sys_rmt_client_prop_set, JS_SYS_RMT_CLIENT_ON_CLOSE),
|
||||
|
||||
JS_CGETSET_MAGIC_DEF("peer_address", js_sys_rmt_client_prop_get, NULL, JS_SYS_RMT_CLIENT_PEER_ADDRESS),
|
||||
|
||||
JS_CFUNC_DEF("send", 1, js_sys_rmt_client_send)
|
||||
};
|
||||
|
||||
static void js_sys_rmt_on_new_client(void *udta, void* new_client) {
|
||||
JS_Sys_Task *task = udta;
|
||||
if (!task) return;
|
||||
|
||||
JSValue obj = JS_NewObjectClass(task->ctx, js_sys_rmt_client_class_id);
|
||||
if (JS_IsException(obj)) {
|
||||
GF_LOG(GF_LOG_WARNING, GF_LOG_RMTWS, ("%s:%d obj JS_IsException\n", __FILE__, __LINE__));
|
||||
}
|
||||
JS_SetOpaque(obj, new_client);
|
||||
|
||||
JS_Sys_Task *deltask;
|
||||
GF_SAFEALLOC(deltask, JS_Sys_Task);
|
||||
deltask->type = RMT_CALLBACK_JS;
|
||||
deltask->ctx = task->ctx;
|
||||
deltask->_obj = JS_DupValue(task->ctx, obj);
|
||||
|
||||
rmt_client_set_on_del_cbk((RMT_ClientCtx*)new_client, (void*)deltask, js_sys_rmt_on_del_client);
|
||||
|
||||
GF_LOG(GF_LOG_DEBUG, GF_LOG_RMTWS, ("%s:%d js_sys_rmt_on_new_client calling task %p with opaque %p\n", __FILE__, __LINE__, task, new_client));
|
||||
|
||||
js_sys_rmt_run_task(task, obj);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
JS_SYS_NB_CORES = 1,
|
||||
@@ -956,8 +1252,11 @@ enum
|
||||
JS_SYS_V_MAJOR,
|
||||
JS_SYS_V_MINOR,
|
||||
JS_SYS_V_MICRO,
|
||||
JS_SYS_RMT_ON_NEW_CLIENT,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define RTI_REFRESH_MS 200
|
||||
static JSValue js_sys_prop_get(JSContext *ctx, JSValueConst this_val, int magic)
|
||||
{
|
||||
@@ -1120,6 +1419,34 @@ static JSValue js_sys_prop_set(JSContext *ctx, JSValueConst this_val, JSValueCon
|
||||
gf_opts_set_key("core", "last-dir", prop_val);
|
||||
JS_FreeCString(ctx, prop_val);
|
||||
break;
|
||||
case JS_SYS_RMT_ON_NEW_CLIENT:
|
||||
|
||||
if (JS_IsUndefined(value) || JS_IsNull(value)) {
|
||||
|
||||
JS_Sys_Task* task = (JS_Sys_Task*) rmt_get_on_new_client_task();
|
||||
if (task && task->type == RMT_CALLBACK_JS) {
|
||||
rmt_set_on_new_client_cbk(NULL, NULL);
|
||||
JS_FreeValue(ctx, task->fun);
|
||||
JS_FreeValue(ctx, task->_obj);
|
||||
gf_free(task);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (JS_IsFunction(ctx, value)) {
|
||||
|
||||
JS_Sys_Task *task;
|
||||
GF_SAFEALLOC(task, JS_Sys_Task);
|
||||
if (!task) return GF_JS_EXCEPTION(ctx);
|
||||
|
||||
task->type = RMT_CALLBACK_JS;
|
||||
task->ctx = ctx;
|
||||
task->fun = JS_DupValue(ctx, value);
|
||||
task->_obj = JS_DupValue(ctx, this_val);
|
||||
|
||||
rmt_set_on_new_client_cbk(task, js_sys_rmt_on_new_client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
@@ -2847,6 +3174,8 @@ static const JSCFunctionListEntry sys_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF_ENUM("version_minor", js_sys_prop_get, NULL, JS_SYS_V_MINOR),
|
||||
JS_CGETSET_MAGIC_DEF_ENUM("version_micro", js_sys_prop_get, NULL, JS_SYS_V_MICRO),
|
||||
|
||||
JS_CGETSET_MAGIC_DEF_ENUM("rmt_on_new_client", NULL, js_sys_prop_set, JS_SYS_RMT_ON_NEW_CLIENT),
|
||||
|
||||
JS_CFUNC_DEF("set_arg_used", 0, js_sys_set_arg_used),
|
||||
JS_CFUNC_DEF("error_string", 0, js_sys_error_string),
|
||||
JS_CFUNC_DEF("prompt_input", 0, js_sys_prompt_input),
|
||||
@@ -2916,6 +3245,8 @@ static const JSCFunctionListEntry sys_funcs[] = {
|
||||
JS_CFUNC_DEF("mpd_parse", 0, js_sys_mpd_parse),
|
||||
|
||||
JS_CFUNC_DEF("_avmix_audio", 0, js_audio_mix),
|
||||
|
||||
JS_CFUNC_DEF("enable_rmtws", 0, js_sys_enable_rmtws),
|
||||
};
|
||||
|
||||
|
||||
@@ -3827,6 +4158,13 @@ static int js_gpaccore_init(JSContext *ctx, JSModuleDef *m)
|
||||
ctor = JS_NewCFunction2(ctx, fileio_constructor, "FileIO", 1, JS_CFUNC_constructor, 0);
|
||||
JS_SetModuleExport(ctx, m, "FileIO", ctor);
|
||||
|
||||
//RMTClient constructor
|
||||
JS_NewClassID(&js_sys_rmt_client_class_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), js_sys_rmt_client_class_id, &js_sys_rmt_client_class);
|
||||
proto = JS_NewObjectClass(ctx, js_sys_rmt_client_class_id);
|
||||
JS_SetPropertyFunctionList(ctx, proto, js_sys_rmt_client_funcs, countof(js_sys_rmt_client_funcs));
|
||||
JS_SetClassProto(ctx, js_sys_rmt_client_class_id, proto);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Submodule testsuite updated: dab7ca663c...244b917926
Reference in New Issue
Block a user