1
Fork 0

fix(context): Fix callback functions

The stack setup for callback threads was all over the place, and pretty
messed up.
This commit is contained in:
Lucas Schwiderski 2022-05-23 14:52:55 +02:00
parent 188c8a7666
commit e0aaa99cb1
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8
5 changed files with 64 additions and 46 deletions

View file

@ -3,7 +3,7 @@
#include "pulseaudio.h"
simple_callback_data* prepare_lua_callback(lua_State* L) {
simple_callback_data* prepare_lua_callback(lua_State* L, int callback_index) {
// Prepare a new thread to run the callback with
lua_pushstring(L, LUA_PULSEAUDIO);
lua_rawget(L, LUA_REGISTRYINDEX);
@ -12,15 +12,21 @@ simple_callback_data* prepare_lua_callback(lua_State* L) {
lua_State* thread = lua_newthread(L);
int thread_ref = luaL_ref(L, -2);
if (callback_index != 0) {
// Copy the callback function to the thread's stack
lua_pushvalue(L, 2);
luaL_checktype(L, callback_index, LUA_TFUNCTION);
lua_pushvalue(L, callback_index);
lua_xmove(L, thread, 1);
}
simple_callback_data* data = malloc(sizeof(struct simple_callback_data));
data->L = thread;
data->thread_ref = thread_ref;
data->is_list = false;
// Clean up the intermediate data from creating the thread
lua_pop(L, 2);
return data;
}

View file

@ -27,16 +27,19 @@ typedef struct simple_callback_data {
//
// The returned callback data needs to be `free()`d at the end of the callback. `free_lua_callback`
// handles both `free()` and `luaL_unref()`.
simple_callback_data* prepare_lua_callback(lua_State* L);
//
// The first `int` is the index to a function on the stack. If this is non-zero, that value will
// be copied to the thread's stack.
simple_callback_data* prepare_lua_callback(lua_State*, int);
// Removes the thread reference, to allow the thread to be garbage collected, and `free`s
// the callback data.
void free_lua_callback(simple_callback_data* data);
void free_lua_callback(simple_callback_data*);
// Simple implementation of `pa_context_success_cb_t` that calls a provided Lua function.
void success_callback(pa_context* c, int success, void* userdata);
void success_callback(pa_context*, int, void*);
#endif // callback_h_INCLUDED

View file

@ -12,12 +12,12 @@
void context_state_callback(pa_context* c, void* userdata) {
simple_callback_data* data = (simple_callback_data*) userdata;
luaL_checktype(data->L, 1, LUA_TFUNCTION);
luaL_checkudata(data->L, 2, LUA_PA_CONTEXT);
// `lua_call` will pop the function and arguments from the stack, but this callback will likely be called
// multiple times.
// To preseve the values for future calls, we need to duplicate them.
lua_pushvalue(data->L, 1);
lua_pushvalue(data->L, 2);
// This can't really fail, but for consistency, we keep the error value.
lua_pushnil(data->L);
pa_context_state_t state = pa_context_get_state(c);
lua_pushinteger(data->L, state);
@ -61,8 +61,11 @@ int context_new(lua_State* L, pa_mainloop_api* pa_api) {
}
lgi_ctx->context = ctx;
lgi_ctx->connected = FALSE;
lgi_ctx->state_callback_data = prepare_lua_callback(L);
lgi_ctx->event_callback_data = prepare_lua_callback(L);
lgi_ctx->state_callback_data = prepare_lua_callback(L, 0);
lgi_ctx->event_callback_data = prepare_lua_callback(L, 0);
// Create the table used to store the subscription callbacks.
lua_newtable(lgi_ctx->event_callback_data->L);
luaL_getmetatable(L, LUA_PA_CONTEXT);
lua_setmetatable(L, -2);
@ -118,6 +121,11 @@ int context_connect(lua_State* L) {
if (nargs > 3)
flags = luaL_checkinteger(L, 4);
// Make sure the callback function is at a known position in the thread's stack
lua_settop(ctx->state_callback_data->L, 0);
lua_pushvalue(L, 3);
lua_xmove(L, ctx->state_callback_data->L, 1);
pa_context_set_state_callback(ctx->context, context_state_callback, ctx->state_callback_data);
pa_context_set_subscribe_callback(ctx->context, context_event_callback, ctx->event_callback_data);
@ -150,7 +158,7 @@ int context_set_default_sink(lua_State* L) {
lua_pa_context* ctx = luaL_checkudata(L, 1, LUA_PA_CONTEXT);
const char* name = luaL_checkstring(L, 2);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_set_default_sink(ctx->context, name, success_callback, data);
if (op == NULL) {
@ -169,7 +177,7 @@ int context_set_default_source(lua_State* L) {
lua_pa_context* ctx = luaL_checkudata(L, 1, LUA_PA_CONTEXT);
const char* name = luaL_checkstring(L, 2);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_set_default_source(ctx->context, name, success_callback, data);
if (op == NULL) {

View file

@ -34,7 +34,7 @@ int context_get_server_info(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
pa_operation* op = pa_context_get_server_info(ctx->context, server_info_callback, data);
if (op == NULL) {
@ -94,7 +94,7 @@ int context_get_sink_info_list(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
data->is_list = true;
// Create the list to store infos in
lua_newtable(data->L);
@ -123,7 +123,7 @@ int context_get_sink_info_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
pa_operation* op = pa_context_get_sink_info_by_name(ctx->context, name, sink_info_callback, data);
if (op == NULL) {
@ -152,7 +152,7 @@ int context_get_sink_info_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_get_sink_info_by_index(ctx->context, (uint32_t) index - 1, sink_info_callback, data);
if (op == NULL) {
@ -193,7 +193,7 @@ int context_set_sink_volume_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
const char* name = luaL_checkstring(L, 2);
pa_cvolume* volume = volume_from_lua(L, 3);
@ -228,7 +228,7 @@ int context_set_sink_volume_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_cvolume* volume = volume_from_lua(L, 3);
pa_operation* op =
@ -277,7 +277,7 @@ int context_set_sink_mute_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_set_sink_mute_by_name(ctx->context, name, mute, success_callback, data);
if (op == NULL) {
@ -307,7 +307,7 @@ int context_set_sink_mute_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_set_sink_mute_by_index(ctx->context, (uint32_t) index - 1, mute, success_callback, data);
@ -351,7 +351,7 @@ int context_set_sink_suspended_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_suspend_sink_by_name(ctx->context, name, suspended, success_callback, data);
if (op == NULL) {
@ -381,7 +381,7 @@ int context_set_sink_suspended_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_suspend_sink_by_index(ctx->context, (uint32_t) index - 1, suspended, success_callback, data);
@ -467,7 +467,7 @@ int context_get_source_info_list(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
data->is_list = true;
// Create the list to store infos in
lua_newtable(data->L);
@ -496,7 +496,7 @@ int context_get_source_info_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_get_source_info_by_name(ctx->context, name, source_info_callback, data);
if (op == NULL) {
@ -525,7 +525,7 @@ int context_get_source_info_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op =
pa_context_get_source_info_by_index(ctx->context, (uint32_t) index - 1, source_info_callback, data);
@ -567,7 +567,7 @@ int context_set_source_volume_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
const char* name = luaL_checkstring(L, 2);
pa_cvolume* volume = volume_from_lua(L, 3);
@ -602,7 +602,7 @@ int context_set_source_volume_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_cvolume* volume = volume_from_lua(L, 3);
pa_operation* op =
@ -651,7 +651,7 @@ int context_set_source_mute_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_set_source_mute_by_name(ctx->context, name, mute, success_callback, data);
if (op == NULL) {
@ -681,7 +681,7 @@ int context_set_source_mute_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_set_source_mute_by_index(ctx->context, (uint32_t) index - 1, mute, success_callback, data);
@ -725,7 +725,7 @@ int context_set_source_suspended_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_suspend_source_by_name(ctx->context, name, suspended, success_callback, data);
if (op == NULL) {
@ -755,7 +755,7 @@ int context_set_source_suspended_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_suspend_source_by_index(ctx->context, (uint32_t) index - 1, suspended, success_callback, data);
@ -832,7 +832,7 @@ int context_get_sink_input_info_list(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
data->is_list = true;
// Create the list to store infos in
lua_newtable(data->L);
@ -864,7 +864,7 @@ int context_get_sink_input_info(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op =
pa_context_get_sink_input_info(ctx->context, (uint32_t) index - 1, sink_input_info_callback, data);
@ -915,7 +915,7 @@ int context_move_sink_input_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_move_sink_input_by_index(ctx->context,
(uint32_t) sink_input_index - 1,
@ -954,7 +954,7 @@ int context_move_sink_input_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_move_sink_input_by_name(ctx->context,
(uint32_t) sink_input_index - 1,
@ -985,7 +985,7 @@ int context_set_sink_input_volume(lua_State* L) {
}
pa_cvolume* volume = volume_from_lua(L, 3);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_set_sink_input_volume(ctx->context, (uint32_t) index - 1, volume, success_callback, data);
@ -1009,7 +1009,7 @@ int context_set_sink_input_mute(lua_State* L) {
}
bool mute = lua_toboolean(L, 3);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_set_sink_input_mute(ctx->context, (uint32_t) index - 1, mute, success_callback, data);
if (op == NULL) {
@ -1032,7 +1032,7 @@ int context_kill_sink_input(lua_State* L) {
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_kill_sink_input(ctx->context, (uint32_t) index - 1, success_callback, data);
if (op == NULL) {
@ -1092,7 +1092,7 @@ int context_get_source_output_info_list(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 2);
data->is_list = true;
// Create the list to store infos in
lua_newtable(data->L);
@ -1124,7 +1124,7 @@ int context_get_source_output_info(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op =
pa_context_get_source_output_info(ctx->context, (uint32_t) index - 1, source_output_info_callback, data);
@ -1175,7 +1175,7 @@ int context_move_source_output_by_index(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_move_source_output_by_index(ctx->context,
(uint32_t) source_output_index - 1,
@ -1214,7 +1214,7 @@ int context_move_source_output_by_name(lua_State* L) {
return 0;
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op = pa_context_move_source_output_by_name(ctx->context,
(uint32_t) source_output_index - 1,
@ -1245,7 +1245,7 @@ int context_set_source_output_volume(lua_State* L) {
}
pa_cvolume* volume = volume_from_lua(L, 3);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_set_source_output_volume(ctx->context, (uint32_t) index - 1, volume, success_callback, data);
@ -1269,7 +1269,7 @@ int context_set_source_output_mute(lua_State* L) {
}
bool mute = lua_toboolean(L, 3);
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 4);
pa_operation* op =
pa_context_set_source_output_mute(ctx->context, (uint32_t) index - 1, mute, success_callback, data);
@ -1293,7 +1293,7 @@ int context_kill_source_output(lua_State* L) {
}
simple_callback_data* data = prepare_lua_callback(L);
simple_callback_data* data = prepare_lua_callback(L, 3);
pa_operation* op = pa_context_kill_source_output(ctx->context, (uint32_t) index - 1, success_callback, data);
if (op == NULL) {

View file

@ -12,4 +12,5 @@ typedef struct luaU_enumfield {
const char* value;
} luaU_enumfield;
#endif // lua_util_h_INCLUDED