1
Fork 0

Compare commits

..

No commits in common. "aca076f51b0957e8640a9f8b2cec4a16d702a1c0" and "3838b9f52a031d921610d49138261d8269e546e8" have entirely different histories.

6 changed files with 62 additions and 80 deletions

View file

@ -43,8 +43,6 @@ OBJS = $(shell find src -type f -iname '*.c' | sed 's/\(.*\)\.c$$/$(BUILD_DIR)\/
TARGET = $(BUILD_DIR)/$(PROJECT).so TARGET = $(BUILD_DIR)/$(PROJECT).so
LUA_CPATH = $(shell echo "$${PWD}/$(BUILD_DIR)/?.so;$${LUA_CPATH}")
ifdef CI ifdef CI
CHECK_ARGS ?= --formatter TAP CHECK_ARGS ?= --formatter TAP
TEST_ARGS ?= --output=TAP TEST_ARGS ?= --output=TAP
@ -52,11 +50,6 @@ TEST_ARGS ?= --output=TAP
CCFLAGS += -Werror CCFLAGS += -Werror
endif endif
bold := $(shell tput bold)
orange := $(shell tput setaf 7)
title := $(bold)$(orange)
reset := $(shell tput sgr0)
.PHONY: all clean doc doc-content doc-styles install uninstall test check rock .PHONY: all clean doc doc-content doc-styles install uninstall test check rock
all: build doc all: build doc
@ -65,23 +58,23 @@ build: $(TARGET)
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)/%.o: %.c
@mkdir -p $(shell dirname "$@") @mkdir -p $(shell dirname "$@")
@echo "$(title)$(CC) $< -o $@$(reset)" @echo "\033[1;97m$(CC) $< -o $@\033[0m"
@$(CC) -c $(CCFLAGS) $< -o $@ @$(CC) -c $(CCFLAGS) $< -o $@
$(TARGET): $(OBJS) $(TARGET): $(OBJS)
@echo "$(title)$(CC) -o $@$(reset)" @echo "\033[1;97m$(CC) -o $@\033[0m"
@$(CC) $(LIBFLAG) -o $@ $(OBJS) $(LIBS) @$(CC) $(LIBFLAG) -o $@ $(OBJS) $(LIBS)
$(BUILD_DIR)/doc/index.html: $(BUILD_DIR)/doc/index.html:
@mkdir -p "$(BUILD_DIR)/doc" "$(BUILD_DIR)/src" @mkdir -p "$(BUILD_DIR)/doc" "$(BUILD_DIR)/src"
@echo "$(title)Preprocess sources$(reset)" @echo "\033[1;97mPreprocess sources\033[0m"
sh tools/process_docs.sh "$(BUILD_DIR)" sh tools/process_docs.sh "$(BUILD_DIR)"
@echo "$(title)Generate documentation$(reset)" @echo "\033[1;97mGenerate documentation\033[0m"
ldoc --config=doc/config.ld --dir "$(BUILD_DIR)/doc" --project $(PROJECT) "$(BUILD_DIR)/src" ldoc --config=doc/config.ld --dir "$(BUILD_DIR)/doc" --project $(PROJECT) "$(BUILD_DIR)/src"
$(BUILD_DIR)/doc/ldoc.css: doc/ldoc.scss $(BUILD_DIR)/doc/ldoc.css: doc/ldoc.scss
@mkdir -p "$(BUILD_DIR)/doc" @mkdir -p "$(BUILD_DIR)/doc"
@echo "$(title)Generate stylesheet$(reset)" @echo "\033[1;97mGenerate stylesheet\033[0m"
sass doc/ldoc.scss $(BUILD_DIR)/doc/ldoc.css sass doc/ldoc.scss $(BUILD_DIR)/doc/ldoc.css
doc-styles: $(BUILD_DIR)/doc/ldoc.css doc-styles: $(BUILD_DIR)/doc/ldoc.css
@ -94,10 +87,10 @@ clean:
rm -r out/ rm -r out/
install: build doc install: build doc
@echo "$(title)Install C library\033[0m" @echo "\033[1;97mInstall C library\033[0m"
install -vDm 644 -t $(INSTALL_LIBDIR) $(TARGET) install -vDm 644 -t $(INSTALL_LIBDIR) $(TARGET)
@echo "$(title)Install documentation\033[0m" @echo "\033[1;97mInstall documentation\033[0m"
install -vd $(INSTALL_DOCDIR) install -vd $(INSTALL_DOCDIR)
cp -vr $(BUILD_DIR)/doc/* $(INSTALL_DOCDIR) cp -vr $(BUILD_DIR)/doc/* $(INSTALL_DOCDIR)
@ -108,11 +101,8 @@ uninstall:
check: check:
@echo "Nothing to do" @echo "Nothing to do"
spec: build test:
busted --config-file=.busted.lua --lua=$(LUA) $(TEST_ARGS) busted --config-file=.busted.lua --lua=$(LUA) $(TEST_ARGS)
test: build
$(LUA) test.lua
rock: rock:
luarocks --local --lua-version $(LUA_VERSION) make rocks/lua-libpulse-glib-scm-1.rockspec luarocks --local --lua-version $(LUA_VERSION) make rocks/lua-libpulse-glib-scm-1.rockspec

View file

@ -1,4 +1,6 @@
#pragma once #ifndef callback_h_INCLUDED
#define callback_h_INCLUDED
#include <lua.h> #include <lua.h>
#include <pulse/context.h> #include <pulse/context.h>
@ -38,3 +40,6 @@ void free_lua_callback(simple_callback_data*);
// Simple implementation of `pa_context_success_cb_t` that calls a provided Lua function. // Simple implementation of `pa_context_success_cb_t` that calls a provided Lua function.
void success_callback(pa_context*, int, void*); void success_callback(pa_context*, int, void*);
#endif // callback_h_INCLUDED

View file

@ -1,7 +1,7 @@
#include "context.h" #include "context.h"
#include "lua_util.h"
#include "pulseaudio.h" #include "pulseaudio.h"
#include "lua_util.h"
#include <pulse/context.h> #include <pulse/context.h>
#include <pulse/error.h> #include <pulse/error.h>
@ -33,29 +33,18 @@ void context_event_callback(pa_context* c, pa_subscription_event_type_t event_ty
simple_callback_data* data = (simple_callback_data*) userdata; simple_callback_data* data = (simple_callback_data*) userdata;
lua_State* L = data->L; lua_State* L = data->L;
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TFUNCTION);
luaL_checkudata(L, 2, LUA_PA_CONTEXT); luaL_checkudata(L, 2, LUA_PA_CONTEXT);
// Iterate over the list of subscription callbacks and call each one // `lua_call` will pop the function and arguments from the stack, but this callback will likely be called
lua_pushnil(L); // multiple times.
while (lua_next(L, 1) != 0) { // To preseve the values for future calls, we need to duplicate them.
// TODO: Once we do have the "nothing here" value, we need to check for that here. lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_pushinteger(L, event_type);
lua_pushinteger(L, index);
// Copy the `self` parameter lua_call(L, 3, 0);
lua_pushvalue(L, 2);
lua_pushinteger(L, event_type);
lua_pushinteger(L, index);
lua_call(L, 3, 0);
}
}
void context_subscribe_success_callback(pa_context* _c, int success, void* userdata) {
simple_callback_data* data = (simple_callback_data*) userdata;
if (!success) {
luaL_error(data->L, "Failed to subscribe to events");
}
} }
@ -73,7 +62,6 @@ int context_new(lua_State* L, pa_mainloop_api* pa_api) {
} }
lgi_ctx->context = ctx; lgi_ctx->context = ctx;
lgi_ctx->connected = FALSE; lgi_ctx->connected = FALSE;
lgi_ctx->subscribed = FALSE;
lgi_ctx->state_callback_data = prepare_lua_callback(L, 0); lgi_ctx->state_callback_data = prepare_lua_callback(L, 0);
lgi_ctx->event_callback_data = prepare_lua_callback(L, 0); lgi_ctx->event_callback_data = prepare_lua_callback(L, 0);
@ -83,10 +71,6 @@ int context_new(lua_State* L, pa_mainloop_api* pa_api) {
luaL_getmetatable(L, LUA_PA_CONTEXT); luaL_getmetatable(L, LUA_PA_CONTEXT);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
// Copy the `context` value to the event callback
lua_pushvalue(L, -1);
lua_xmove(L, lgi_ctx->event_callback_data->L, 1);
return 1; return 1;
} }
@ -213,19 +197,8 @@ int context_subscribe(lua_State* L) {
lua_pa_context* ctx = luaL_checkudata(L, 1, LUA_PA_CONTEXT); lua_pa_context* ctx = luaL_checkudata(L, 1, LUA_PA_CONTEXT);
luaL_checktype(L, 2, LUA_TFUNCTION); luaL_checktype(L, 2, LUA_TFUNCTION);
// This call is only effective when the connection state is "ready".
// So we have to do it here, rather than during `context_connect`,
// but we also need to make sure it's only called once.
if (!ctx->subscribed) {
pa_context_subscribe(ctx->context,
PA_SUBSCRIPTION_MASK_ALL,
context_subscribe_success_callback,
ctx->event_callback_data);
}
size_t pos = lua_rawlen(ctx->event_callback_data->L, 1) + 1; size_t pos = lua_rawlen(ctx->event_callback_data->L, 1) + 1;
// Duplicate the callback function, so we can move it over to the other thread // Duplicate the callback function, so we can move it over to the other thread
// TODO: Do we actually need to duplicate?
lua_pushvalue(L, 2); lua_pushvalue(L, 2);
lua_xmove(L, ctx->event_callback_data->L, 1); lua_xmove(L, ctx->event_callback_data->L, 1);
lua_rawseti(ctx->event_callback_data->L, 1, pos); lua_rawseti(ctx->event_callback_data->L, 1, pos);
@ -245,14 +218,6 @@ int context_unsubscribe(lua_State* L) {
return 0; return 0;
} }
// TODO: Handle calling this twice on the same index.
// Given that we use an array to track things, and Lua's way of counting in arrays
// doesn't like `nil`s, we probably need a special "nothing here" value that's not `nil`,
// and signifies an index that has already been unsubscribed.
// TODO: Simplify things. Supporting just the index is enough.
// Comparing by function is convenient, but also confusing to inexperienced devs.
switch (lua_type(L, 2)) { switch (lua_type(L, 2)) {
case LUA_TNUMBER: { case LUA_TNUMBER: {
pos = lua_tointeger(L, 2); pos = lua_tointeger(L, 2);
@ -292,8 +257,6 @@ int context_unsubscribe(lua_State* L) {
} }
} }
// TODO: As explained above, we need to handle calling unsubscribe twice better.
// Indices should not be re-used but replaced by a special "nothing here" value.
for (; pos < len; ++pos) { for (; pos < len; ++pos) {
lua_rawgeti(thread_L, 1, pos + 1); lua_rawgeti(thread_L, 1, pos + 1);
lua_rawseti(thread_L, 1, pos); lua_rawseti(thread_L, 1, pos);

View file

@ -24,7 +24,6 @@
typedef struct lua_pa_context { typedef struct lua_pa_context {
pa_context* context; pa_context* context;
bool connected; bool connected;
bool subscribed;
simple_callback_data* state_callback_data; simple_callback_data* state_callback_data;
simple_callback_data* event_callback_data; simple_callback_data* event_callback_data;
} lua_pa_context; } lua_pa_context;
@ -96,9 +95,6 @@ int context_get_state(lua_State*);
* Any number of callbacks may be registered at the same time, and can be unscubscribed with * Any number of callbacks may be registered at the same time, and can be unscubscribed with
* @{Context:unsubscribe}, using the returned subscription ID. * @{Context:unsubscribe}, using the returned subscription ID.
* *
* This must called after the connection state changed to "ready" (index `4`). Otherwise
* it will have no effect.
*
* @function Context:subscribe * @function Context:subscribe
* @tparam function cb * @tparam function cb
* @treturn number The subscription ID. * @treturn number The subscription ID.

View file

@ -1,4 +1,5 @@
#pragma once #ifndef lua_util_h_INCLUDED
#define lua_util_h_INCLUDED
#include <lauxlib.h> #include <lauxlib.h>
#include <lua.h> #include <lua.h>
@ -7,9 +8,6 @@
#if LUA_VERSION_NUM <= 501 #if LUA_VERSION_NUM <= 501
#define lua_rawlen lua_objlen #define lua_rawlen lua_objlen
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
#define luaL_newlibtable(L, l) (lua_createtable(L, 0, sizeof(l) / sizeof(l[0])))
#endif #endif
#if LUA_VERSION_NUM > 501 #if LUA_VERSION_NUM > 501
@ -20,3 +18,6 @@ typedef struct luaU_enumfield {
const char* name; const char* name;
const char* value; const char* value;
} luaU_enumfield; } luaU_enumfield;
#endif // lua_util_h_INCLUDED

View file

@ -10,8 +10,10 @@
#include <lualib.h> #include <lualib.h>
#include <pulse/glib-mainloop.h> #include <pulse/glib-mainloop.h>
#if LUA_VERSION_NUM <= 501 #if LUA_VERSION_NUM <= 501
// Shamelessly copied from Lua 5.3 source. // Shamelessly copied from Lua 5.3 source.
// TODO: What's the official way to do this in 5.1?
void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) { void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) {
luaL_checkstack(L, nup, "too many upvalues"); luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */ for (; l->name != NULL; l++) { /* fill the table with given functions */
@ -27,8 +29,12 @@ void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) {
} }
lua_pop(L, nup); /* remove upvalues */ lua_pop(L, nup); /* remove upvalues */
} }
#define luaL_newlib(L, l) (luaL_register(L, LUA_PULSEAUDIO, l))
#endif #endif
int pulseaudio_new(lua_State* L) { int pulseaudio_new(lua_State* L) {
GMainContext* ctx = g_main_context_default(); GMainContext* ctx = g_main_context_default();
if (ctx == NULL) { if (ctx == NULL) {
@ -80,13 +86,17 @@ int pulseaudio_new_context(lua_State* L) {
void createlib_volume(lua_State* L) { void createlib_volume(lua_State* L) {
luaL_newmetatable(L, LUA_PA_VOLUME); luaL_newmetatable(L, LUA_PA_VOLUME);
luaL_newlib(L, volume_f); lua_createtable(L, 0, sizeof volume_f / sizeof volume_f[0]);
luaL_setfuncs(L, volume_f, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_setfuncs(L, volume_mt, 0); luaL_setfuncs(L, volume_mt, 0);
#if LUA_VERSION_NUM <= 501
luaL_register(L, LUA_PA_VOLUME, volume_lib);
#else
luaL_newlib(L, volume_lib); luaL_newlib(L, volume_lib);
#endif
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} }
@ -94,12 +104,17 @@ void createlib_volume(lua_State* L) {
void createlib_proplist(lua_State* L) { void createlib_proplist(lua_State* L) {
luaL_newmetatable(L, LUA_PA_PROPLIST); luaL_newmetatable(L, LUA_PA_PROPLIST);
luaL_newlib(L, proplist_f); lua_createtable(L, 0, sizeof proplist_f / sizeof proplist_f[0]);
luaL_setfuncs(L, proplist_f, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_setfuncs(L, proplist_mt, 0); luaL_setfuncs(L, proplist_mt, 0);
#if LUA_VERSION_NUM <= 501
luaL_register(L, LUA_PA_PROPLIST, proplist_lib);
#else
luaL_newlib(L, proplist_lib); luaL_newlib(L, proplist_lib);
#endif
// Create a metatable with an `__index` table for read-only enum fields. // Create a metatable with an `__index` table for read-only enum fields.
lua_createtable(L, 0, 1); lua_createtable(L, 0, 1);
@ -118,7 +133,8 @@ void createlib_proplist(lua_State* L) {
void createlib_context(lua_State* L) { void createlib_context(lua_State* L) {
luaL_newmetatable(L, LUA_PA_CONTEXT); luaL_newmetatable(L, LUA_PA_CONTEXT);
luaL_newlib(L, context_f); lua_createtable(L, 0, sizeof context_f / sizeof context_f[0]);
luaL_setfuncs(L, context_f, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_setfuncs(L, context_mt, 0); luaL_setfuncs(L, context_mt, 0);
@ -128,12 +144,17 @@ void createlib_context(lua_State* L) {
void createlib_pulseaudio(lua_State* L) { void createlib_pulseaudio(lua_State* L) {
luaL_newmetatable(L, LUA_PULSEAUDIO); luaL_newmetatable(L, LUA_PULSEAUDIO);
luaL_newlib(L, pulseaudio_f); lua_createtable(L, 0, sizeof pulseaudio_f / sizeof pulseaudio_f[0]);
luaL_setfuncs(L, pulseaudio_f, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_setfuncs(L, pulseaudio_mt, 0); luaL_setfuncs(L, pulseaudio_mt, 0);
#if LUA_VERSION_NUM <= 501
luaL_register(L, LUA_PULSEAUDIO, pulseaudio_lib);
#else
luaL_newlib(L, pulseaudio_lib); luaL_newlib(L, pulseaudio_lib);
#endif
} }
@ -156,11 +177,17 @@ LUA_MOD_EXPORT int luaopen_lua_libpulse_glib(lua_State* L) {
LUA_MOD_EXPORT int luaopen_lua_libpulse_glib_volume(lua_State* L) { LUA_MOD_EXPORT int luaopen_lua_libpulse_glib_volume(lua_State* L) {
luaL_newmetatable(L, LUA_PA_VOLUME); luaL_newmetatable(L, LUA_PA_VOLUME);
luaL_newlib(L, volume_f); lua_createtable(L, 0, sizeof volume_f / sizeof volume_f[0]);
luaL_setfuncs(L, volume_f, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_setfuncs(L, volume_mt, 0); luaL_setfuncs(L, volume_mt, 0);
#if LUA_VERSION_NUM <= 501
luaL_register(L, LUA_PA_VOLUME, volume_lib);
#else
luaL_newlib(L, volume_lib); luaL_newlib(L, volume_lib);
#endif
return 1; return 1;
} }