diff options
author | Janos Kovacs <janos.f.kovacs@nokia.com> | 2010-02-05 05:53:51 +0200 |
---|---|---|
committer | Janos Kovacs <janos.f.kovacs@nokia.com> | 2010-02-05 05:53:51 +0200 |
commit | 1120e7ec07197225043e3e718c4c5ef867beec25 (patch) | |
tree | cd840feb33c7fa16a9a35eaa30b721aa79460570 /src | |
parent | 56af9beb47bdb9f4b8958863c4001506a54db9ff (diff) |
- high level C API with glib bindings
- example fmradio
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 18 | ||||
-rw-r--r-- | src/res-msg.h | 37 | ||||
-rw-r--r-- | src/res-types.h | 61 | ||||
-rw-r--r-- | src/resource-glib-glue.c | 37 | ||||
-rw-r--r-- | src/resource-glue.h | 20 | ||||
-rw-r--r-- | src/resource.c | 759 | ||||
-rw-r--r-- | src/resource.h | 49 |
7 files changed, 957 insertions, 24 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 64896ad..13cfd28 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,7 @@ libdir = ${src_dir} -lib_LTLIBRARIES = libresource.la +lib_LTLIBRARIES = libresource.la libresource-glib.la -libresource_la_SOURCES = resource.c \ - res-msg.c res-conn.c res-proto.c res-set.c \ +libresource_la_SOURCES = res-msg.c res-conn.c res-proto.c res-set.c \ dbus-proto.c dbus-msg.c \ internal-proto.c internal-msg.c libresource_la_CFLAGS = @DBUS_CFLAGS@ -I$(top_srcdir) -fvisibility=hidden @@ -12,8 +11,19 @@ endif libresource_la_LDFLAGS = /usr/lib -version-info $(subst .,:,$(VERSION)) libresource_la_LIBADD = @DBUS_LIBS@ +libresource_glib_la_SOURCES = resource.c resource-glib-glue.c +libresource_glib_la_CFLAGS = @DBUS_CFLAGS@ -I$(top_srcdir)/src \ + -fvisibility=hidden +if DEBUG +libresource_glib_la_CFLAGS += -D__DEBUG__ +endif +libresource_glib_la_LDFLAGS = /usr/lib -version-info $(subst .,:,$(VERSION)) +libresource_glib_la_LIBADD = $(top_builddir)/src/libresource.la @DBUS_LIBS@ + + pkgincludedir = $(includedir)/resource -pkginclude_HEADERS = resource.h res-conn.h res-proto.h res-set.h res-msg.h +pkginclude_HEADERS = resource.h res-types.h res-conn.h res-proto.h res-set.h \ + res-msg.h libdir = /usr/lib MAINTAINERCLEANFILES = Makefile.in diff --git a/src/res-msg.h b/src/res-msg.h index 8c10028..16e3d56 100644 --- a/src/res-msg.h +++ b/src/res-msg.h @@ -3,28 +3,29 @@ #include <stdint.h> +#include <res-types.h> + #ifdef __cplusplus extern "C" { #endif - -#define RESMSG_BIT(n) (((uint32_t)1) << (n)) - -#define RESMSG_AUDIO_PLAYBACK RESMSG_BIT(0) -#define RESMSG_VIDEO_PLAYBACK RESMSG_BIT(1) -#define RESMSG_AUDIO_RECORDING RESMSG_BIT(2) -#define RESMSG_VIDEO_RECORDING RESMSG_BIT(3) -#define RESMSG_VIBRA RESMSG_BIT(4) -#define RESMSG_LEDS RESMSG_BIT(5) -#define RESMSG_BACKLIGHT RESMSG_BIT(6) -#define RESMSG_SYSTEM_BUTTON RESMSG_BIT(8) -#define RESMSG_LOCK_BUTTON RESMSG_BIT(9) -#define RESMSG_SCALE_BUTTON RESMSG_BIT(10) -#define RESMSG_SNAP_BUTTON RESMSG_BIT(11) -#define RESMSG_LENS_COVER RESMSG_BIT(12) - -#define RESMSG_MODE_AUTO_RELEASE RESMSG_BIT(0) -#define RESMSG_MODE_ALWAYS_REPLY RESMSG_BIT(1) +#define RESMSG_BIT(b) (((uint32_t)1) << (b)) + +#define RESMSG_AUDIO_PLAYBACK RESOURCE_AUDIO_PLAYBACK +#define RESMSG_VIDEO_PLAYBACK RESOURCE_VIDEO_PLAYBACK +#define RESMSG_AUDIO_RECORDING RESOURCE_AUDIO_RECORDING +#define RESMSG_VIDEO_RECORDING RESOURCE_VIDEO_RECORDING +#define RESMSG_VIBRA RESOURCE_VIBRA +#define RESMSG_LEDS RESOURCE_LEDS +#define RESMSG_BACKLIGHT RESOURCE_BACKLIGHT +#define RESMSG_SYSTEM_BUTTON RESOURCE_SYSTEM_BUTTON +#define RESMSG_LOCK_BUTTON RESOURCE_LOCK_BUTTON +#define RESMSG_SCALE_BUTTON RESOURCE_SCALE_BUTTON +#define RESMSG_SNAP_BUTTON RESOURCE_SNAP_BUTTON +#define RESMSG_LENS_COVER RESOURCE_LENS_COVER + +#define RESMSG_MODE_AUTO_RELEASE RESOURCE_AUTO_RELEASE +#define RESMSG_MODE_ALWAYS_REPLY RESOURCE_ALWAYS_REPLY typedef enum resmsg_type_e { RESMSG_INVALID = -1, diff --git a/src/res-types.h b/src/res-types.h new file mode 100644 index 0000000..ebcd9c8 --- /dev/null +++ b/src/res-types.h @@ -0,0 +1,61 @@ +#ifndef __RES_TYPES_H__ +#define __RES_TYPES_H__ + +#define RESOURCE_BIT(b) (((uint32_t)1) << (b)) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + resource_audio_playback = 0, + resource_video_playback = 1, + resource_audio_recording = 2, + resource_video_recording = 3, + resource_vibra = 4, + resource_leds = 5, + resource_backlight = 6, + resource_system_button = 8, + resource_lock_button = 9, + resource_scale_button = 10, + resource_snap_button = 11, + resource_lens_cover = 12, +} resource_type_t; + + +#define RESOURCE_AUDIO_PLAYBACK RESOURCE_BIT( resource_audio_playback ) +#define RESOURCE_VIDEO_PLAYBACK RESOURCE_BIT( resource_video_playback ) +#define RESOURCE_AUDIO_RECORDING RESOURCE_BIT( resource_audio_recording ) +#define RESOURCE_VIDEO_RECORDING RESOURCE_BIT( resource_video_recording ) +#define RESOURCE_VIBRA RESOURCE_BIT( resource_vibra ) +#define RESOURCE_LEDS RESOURCE_BIT( resource_leds ) +#define RESOURCE_BACKLIGHT RESOURCE_BIT( resource_backlight ) +#define RESOURCE_SYSTEM_BUTTON RESOURCE_BIT( resource_system_button ) +#define RESOURCE_LOCK_BUTTON RESOURCE_BIT( resource_lock_button ) +#define RESOURCE_SCALE_BUTTON RESOURCE_BIT( resource_scale_button ) +#define RESOURCE_SNAP_BUTTON RESOURCE_BIT( resource_snap_button ) +#define RESOURCE_LENS_COVER RESOURCE_BIT( resource_lens_cover ) + +typedef enum { + resource_auto_release = 0, + resource_always_reply = 1, +} resource_mode_t; + +#define RESOURCE_AUTO_RELEASE RESOURCE_BIT( resource_auto_release ) +#define RESOURCE_ALWAYS_REPLY RESOURCE_BIT( resource_always_reply ) + + +#ifdef __cplusplus +}; +#endif + + +#endif /* __RES_TYPES_H__ */ + +/* + * Local Variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim:set expandtab shiftwidth=4: + */ diff --git a/src/resource-glib-glue.c b/src/resource-glib-glue.c new file mode 100644 index 0000000..b1ca72d --- /dev/null +++ b/src/resource-glib-glue.c @@ -0,0 +1,37 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "resource-glue.h" +#include "visibility.h" + +DBusConnection *resource_get_dbus_bus(DBusBusType type, DBusError *err) +{ + DBusConnection *conn = NULL; + + if ((conn = dbus_bus_get(type, err)) != NULL) { + dbus_connection_setup_with_g_main(conn, NULL); + } + + return conn; +} + +void *resource_timer_add(uint32_t delay, resconn_timercb_t cbfunc,void *cbdata) +{ + return NULL; +} + +void resource_timer_del(void *timer) +{ +} + +/* + * Local Variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim:set expandtab shiftwidth=4: + */ diff --git a/src/resource-glue.h b/src/resource-glue.h new file mode 100644 index 0000000..4e668c2 --- /dev/null +++ b/src/resource-glue.h @@ -0,0 +1,20 @@ +#ifndef __LIB_RESOURCE_GLUE_H__ +#define __LIB_RESOURCE_GLUE_H__ + +#include <stdint.h> + +#include <res-conn.h> + +DBusConnection *resource_get_dbus_bus(DBusBusType, DBusError *); +void *resource_timer_add(uint32_t, resconn_timercb_t,void *); +void resource_timer_del(void *); + +#endif /* __LIB_RESOURCE_GLUE_H__ */ + +/* + * Local Variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim:set expandtab shiftwidth=4: + */ diff --git a/src/resource.c b/src/resource.c index 08a6bbd..ac74a28 100644 --- a/src/resource.c +++ b/src/resource.c @@ -1,9 +1,766 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <res-conn.h> + #include "resource.h" +#include "resource-glue.h" +#include "visibility.h" + +#include <res-conn.h> + + +typedef enum { + client_created = 0, + client_connecting, + client_ready +} client_state_t; + +typedef void (*request_complete_t)(resource_set_t *, uint32_t, void *, + int32_t, const char *); + +typedef struct request_s { + struct request_s *next; + resmsg_type_t msgtyp; + uint32_t reqno; + int busy; + struct { + request_complete_t function; + void *data; + } cb; +} request_t; + + +#define RESOURCE_CONFIG_COMMON \ + union resource_config_u *next; \ + uint32_t mask + +typedef struct { + RESOURCE_CONFIG_COMMON; +} any_config_t; + +typedef struct { + RESOURCE_CONFIG_COMMON; + char *group; /* audio group */ + pid_t pid; /* PID of the streaming component */ + char *stream; /* pulseaudio stream name */ +} audio_config_t; + +typedef union resource_config_u { + any_config_t any; + audio_config_t audio; +} resource_config_t; + +typedef struct { + resource_callback_t function; + void *data; +} callback_t; + +struct resource_set_s { + struct resource_set_s *next; + DBusConnection *dbus; /* D-Bus connection */ + char *klass; /* resource class */ + uint32_t id; /* resource id */ + uint32_t mode; + resconn_t *resconn; + struct { + uint32_t all; + uint32_t opt; + } resources; /* libresource resources */ + client_state_t client; /* resource client state */ + int acquire; + callback_t grantcb; + callback_t advicecb; + resource_config_t *configs; + resset_t *resset; + request_t *reqlist; +}; + +static resource_set_t *rslist; +static uint32_t rsid; +static uint32_t reqno; + +static DBusConnection *get_dbus(void); +static resconn_t *get_manager(DBusConnection *); +static void manager_is_up(resconn_t *); +static void connect_to_manager(resconn_t *, resource_set_t *); +static void disconnect_from_manager(resmsg_t *, resset_t *,void *); +static void receive_grant_message(resmsg_t *, resset_t *, void *); +static void receive_advice_message(resmsg_t *, resset_t *, void *); +static int send_reqister_message(resource_set_t *, uint32_t); +static int send_update_message(resource_set_t *, uint32_t); +static int send_audio_message(resource_set_t *, uint32_t); +static int send_acquire_message(resource_set_t *, uint32_t); +static int send_release_message(resource_set_t *, uint32_t); +static void connect_complete_cb(resource_set_t *, uint32_t, void *, + int32_t, const char *); +static void request_complete_cb(resource_set_t *, uint32_t, + void *, int32_t, const char *); +static void status_cb(resset_t *, resmsg_t *); +static void send_request(resource_set_t *); +static int audio_config_create(resource_set_t *, const char *, + pid_t pid, const char *); +static int audio_config_update(resource_config_t *, const char *, + pid_t, const char *); +static uint32_t push_request(resource_set_t *, resmsg_type_t, + request_complete_t, void *); +static request_t *peek_request(resource_set_t *); +static request_t *pop_request(resource_set_t *, uint32_t); +static void resource_log(const char *, ...); + + +EXPORT resource_set_t *resource_set_create(const char *klass, + uint32_t mandatory, + uint32_t optional, + uint32_t mode, + resource_callback_t grantcb, + void *grantdata) +{ + DBusConnection *dbus = get_dbus(); + resconn_t *resconn = get_manager(dbus); + resource_set_t *rs = NULL; + char mbuf[256]; + char obuf[256]; + + if (klass && (mandatory || optional) && grantcb) { + + optional = optional & ~mandatory; + + if ((rs = malloc(sizeof(resource_set_t))) != NULL) { + + memset(rs, 0, sizeof(resource_set_t)); + rs->next = rslist; + rs->dbus = dbus; + rs->klass = strdup(klass); + rs->id = rsid++; + rs->mode = mode; + rs->resconn = resconn; + rs->client = client_created; + rs->resources.all = mandatory | optional; + rs->resources.opt = optional; + rs->grantcb.function = grantcb; + rs->grantcb.data = grantdata; + + rslist = rs; + + resource_log("created resource set %u (klass '%s', " + "mandatory %s, optional %s)", rs->id, rs->klass, + resmsg_res_str(mandatory, mbuf, sizeof(mbuf)), + resmsg_res_str(optional , obuf, sizeof(obuf))); + + connect_to_manager(resconn, rs); + } + } + + return rs; +} + +EXPORT void resource_set_destroy(resource_set_t *rs) +{ +} + + +EXPORT int resource_set_configure_advice_callback(resource_set_t *rs, + resource_callback_t *advcb, + void *advdata) +{ + if (rs != NULL) { + rs->advicecb.function = advcb; + rs->advicecb.data = advdata; + } +} + + +EXPORT int resource_set_configure_resources(resource_set_t *rs, + uint32_t mandatory, + uint32_t optional) +{ + int success = FALSE; + uint32_t all; + uint32_t rn; + char mbuf[256]; + char obuf[256]; + + if (rs != NULL) { + + optional = optional & ~mandatory; + all = mandatory | optional; + + resource_log("updating resource set %u (klass '%s', " + "mandatory %s, optional %s)", rs->id, rs->klass, + resmsg_res_str(mandatory, mbuf, sizeof(mbuf)), + resmsg_res_str(optional , obuf, sizeof(obuf))); + + if (rs->resources.all != all || rs->resources.opt != optional) { + + rs->resources.all = mandatory | optional; + rs->resources.opt = optional; + + rn = push_request(rs, RESMSG_UPDATE, NULL,NULL); + + success = rn ? TRUE : FALSE; + } + } + + return success; +} + + +EXPORT int resource_set_configure_audio(resource_set_t *rs, + const char *group, + pid_t pid, + const char *stream) +{ + resource_config_t *prev; + resource_config_t *cfg; + int need_update; + + if (!(rs->resources.all & RESOURCE_AUDIO_PLAYBACK)) + return FALSE; + + for (prev = (resource_config_t *)&rs->configs; + (cfg = prev->any.next) != NULL; + prev = prev->any.next) + { + if (cfg->any.mask == RESOURCE_AUDIO_PLAYBACK) { + need_update = audio_config_update(cfg, group, pid,stream); + break; + } + } + + if (cfg == NULL) + need_update = audio_config_create(rs, group, pid,stream); + + if (need_update) + push_request(rs, RESMSG_AUDIO, NULL,NULL); + + return TRUE; +} + +EXPORT int resource_set_acquire(resource_set_t *rs) +{ + if (rs && !rs->acquire) { + rs->acquire = TRUE; + push_request(rs, RESMSG_ACQUIRE, NULL,NULL); + } + + return TRUE; +} + +EXPORT int resource_set_release(resource_set_t *rs) +{ + if (rs && rs->acquire) { + rs->acquire = FALSE; + push_request(rs, RESMSG_RELEASE, NULL,NULL); + } + + return TRUE; +} -void foo(void) + + +static DBusConnection *get_dbus(void) { + static DBusConnection *dbus = NULL; + + DBusError err; + + if (dbus == NULL) { + dbus_error_init(&err); + + dbus = resource_get_dbus_bus(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + /* TODO: some more distinctive errno setting would not harm :) */ + errno = EIO; + dbus_error_free(&err); + } + } + + return dbus; } +static resconn_t *get_manager(DBusConnection *dbus) +{ + static resconn_t *mgr = NULL; + + if (mgr == NULL && dbus != NULL) { + mgr = resproto_init(RESPROTO_ROLE_CLIENT, RESPROTO_TRANSPORT_DBUS, + manager_is_up, dbus); + + resproto_set_handler(mgr, RESMSG_UNREGISTER, disconnect_from_manager); + resproto_set_handler(mgr, RESMSG_GRANT , receive_grant_message ); + resproto_set_handler(mgr, RESMSG_ADVICE , receive_advice_message ); + } + + return mgr; +} + +static void manager_is_up(resconn_t *resconn) +{ + resource_set_t *rs; + + for (rs = rslist; rs != NULL; rs = rs->next) { + if (rs->resconn == resconn && rs->client == client_created) + connect_to_manager(resconn, rs); + } +} + +static void connect_to_manager(resconn_t *resconn, resource_set_t *rs) +{ + resource_config_t *cfg; + + if (rs != NULL) { + rs->client = client_connecting; + + push_request(rs, RESMSG_REGISTER, connect_complete_cb, NULL); + + for (cfg = rs->configs; cfg != NULL; cfg = cfg->any.next) { + switch (cfg->any.mask) { + case RESMSG_AUDIO_PLAYBACK: + push_request(rs, RESMSG_AUDIO, NULL,NULL); + default: + break; + } + } + + if (rs->acquire) + push_request(rs, RESMSG_ACQUIRE, NULL,NULL); + } +} + +static void disconnect_from_manager(resmsg_t *msg, resset_t *resset,void *data) +{ + resource_set_t *rs = resset->userdata; + + (void)data; + + if (rs != NULL && resset == rs->resset) { + rs->client = client_created; + } +} + + +static void receive_grant_message(resmsg_t *msg, resset_t *resset, void *data) +{ + resource_set_t *rs = resset->userdata; + uint32_t rn = msg->notify.reqno; + uint32_t gr = msg->notify.resrc; + + (void)data; + + if (rs != NULL && resset == rs->resset) { + resource_log("recived grant %u (resources 0x%x)", rn, gr); + + rs->grantcb.function(rs, gr, rs->grantcb.data); + } +} + +static void receive_advice_message(resmsg_t *msg, resset_t *resset, void *data) +{ + resource_set_t *rs = resset->userdata; + uint32_t adv = msg->notify.resrc; + + (void)data; + + if (rs != NULL && resset == rs->resset) { + if (rs->advicecb.function) { + rs->advicecb.function(rs, adv, rs->advicecb.data); + } + } +} + +static int send_reqister_message(resource_set_t *rs, uint32_t rn) +{ + resset_t *resset; + resmsg_t msg; + + if (rs->resconn != NULL) { + resource_log("sending register message"); + + memset(&msg, 0, sizeof(msg)); + msg.record.type = RESMSG_REGISTER; + msg.record.id = rs->id; + msg.record.reqno = rn; + msg.record.rset.all = rs->resources.all; + msg.record.rset.opt = rs->resources.opt; + msg.record.klass = rs->klass; + msg.record.mode = rs->mode; + + resset = resconn_connect(rs->resconn, &msg, status_cb); + + if (resset != NULL) { + rs->resset = resset; + resset->userdata = rs; + } + } + + return rs->resset ? TRUE : FALSE; +} + +static int send_update_message(resource_set_t *rs, uint32_t rn) +{ + resset_t *resset = rs->resset; + int success = FALSE; + resmsg_t msg; + + if (resset != NULL && (void *)rs == resset->userdata) { + resource_log("sending update message"); + + memset(&msg, 0, sizeof(msg)); + msg.record.type = RESMSG_UPDATE; + msg.record.id = rs->id; + msg.record.reqno = rn; + msg.record.rset.all = rs->resources.all; + msg.record.rset.opt = rs->resources.opt; + msg.record.klass = rs->klass; + msg.record.mode = rs->mode; + + success = resproto_send_message(resset, &msg, status_cb); + } + + return success; +} + +static int send_audio_message(resource_set_t *rs, uint32_t rn) +{ + resset_t *resset = rs->resset; + int success = FALSE; + resource_config_t *cfg; + resmsg_t msg; + char *stream; + + if (resset != NULL && (void *)rs == resset->userdata) { + for (cfg = rs->configs; cfg != NULL; cfg = cfg->any.next) { + if (cfg->any.mask == RESOURCE_AUDIO_PLAYBACK) { + + stream = cfg->audio.stream ? cfg->audio.stream : (char *)""; + + resource_log("sending audio message"); + + memset(&msg, 0, sizeof(msg)); + msg.audio.type = RESMSG_AUDIO; + msg.audio.id = rs->id; + msg.audio.reqno = rn; + msg.audio.group = cfg->audio.group; + msg.audio.pid = cfg->audio.pid; + msg.audio.property.name = (char*)"media.name"; + msg.audio.property.match.method = resmsg_method_equals; + msg.audio.property.match.pattern = stream; + + success = resproto_send_message(resset, &msg, status_cb); + + break; + } + } /* for */ + } + + return success; +} + + +static int send_acquire_message(resource_set_t *rs, uint32_t rn) +{ + resset_t *resset = rs->resset; + int success = FALSE; + resmsg_t msg; + + if (resset != NULL && (void *)rs == resset->userdata) { + resource_log("sending acquire message"); + + memset(&msg, 0, sizeof(msg)); + msg.possess.type = RESMSG_ACQUIRE; + msg.possess.id = rs->id; + msg.possess.reqno = rn; + + success = resproto_send_message(resset, &msg, status_cb); + } + + return success; +} + +static int send_release_message(resource_set_t *rs, uint32_t rn) +{ + resset_t *resset = rs->resset; + int success = FALSE; + resmsg_t msg; + + if (resset != NULL && (void *)rs == resset->userdata) { + resource_log("sending release message"); + + memset(&msg, 0, sizeof(msg)); + msg.possess.type = RESMSG_RELEASE; + msg.possess.id = rs->id; + msg.possess.reqno = rn; + + success = resproto_send_message(resset, &msg, status_cb); + } + + return success; +} + +static void connect_complete_cb(resource_set_t *rs, uint32_t rn, void *data, + int32_t errcod, const char *errmsg) +{ + if (errcod != 0) { + resource_log("failed to connect resource manager: %d %s", + errcod, errmsg); + rs->client = client_created; + } + else { + resource_log("resource set %u is ready", rs->id); + rs->client = client_ready; + } +} + +static void request_complete_cb(resource_set_t *rs, uint32_t rn, void *data, + int32_t errcod, const char *errmsg) +{ + resource_log("request %u completed. status %d %s", rn, errcod, errmsg); + + if (errcod != 0) { + rs->grantcb.function(rs, 0, rs->grantcb.data); + } +} + +static void status_cb(resset_t *resset, resmsg_t *msg) +{ + resource_set_t *rs = resset->userdata; + resmsg_status_t *st = &msg->status; + request_t *rq; + + if (rs != NULL && rs->resset == resset) { + + resource_log("%s(%u) status: %d '%s'", __FUNCTION__, + st->reqno, st->errcod, st->errmsg); + + if ((rq = pop_request(rs, msg->status.reqno)) != NULL) { + + if (rq->cb.function != NULL) { + rq->cb.function(rs, msg->any.reqno, rq->cb.data, + st->errcod, st->errmsg); + } + + send_request(rs); + } + } +} + +static void send_request(resource_set_t *rs) +{ + request_t *rq; + uint32_t rn; + int success; + + while ((rq = peek_request(rs)) != NULL) { + + if (rq == NULL || rq->busy) + break; + + if (rs->client == client_created) + continue; + + rn = rq->reqno; + + switch (rq->msgtyp) { + case RESMSG_REGISTER: success = send_reqister_message(rs, rn); break; + case RESMSG_UPDATE: success = send_update_message(rs, rn); break; + case RESMSG_AUDIO: success = send_audio_message(rs, rn); break; + case RESMSG_ACQUIRE: success = send_acquire_message(rs, rn); break; + case RESMSG_RELEASE: success = send_release_message(rs, rn); break; + default: success = FALSE; break; + } + + if (success) { + rq->busy = TRUE; + break; + } + + if (rq->msgtyp == RESMSG_REGISTER) + rs->client = client_created; + + resource_log("failed to send %s message", resmsg_type_str(rq->msgtyp)); + + pop_request(rs, rn); + + } /* while */ +} + +static int audio_config_create(resource_set_t *rs, + const char *group, + pid_t pid, + const char *stream) +{ + resource_config_t *cfg; + int need_update = FALSE; + + if (group || !pid || stream) { + if ((cfg = malloc(sizeof(resource_config_t))) != NULL) { + memset(cfg, 0, sizeof(resource_config_t)); + cfg->audio.next = rs->configs; + cfg->audio.mask = RESOURCE_AUDIO_PLAYBACK; + cfg->audio.group = group ? strdup(group) : NULL; + cfg->audio.pid = pid; + cfg->audio.stream = stream ? strdup(stream) : NULL; + + rs->configs = cfg; + + need_update = TRUE; + } + } + + return need_update; +} + +static int audio_config_update(resource_config_t *cfg, + const char *group, + pid_t pid, + const char *stream) +{ + char *oldstr; + pid_t oldpid; + int need_update = FALSE; + + + if (group) { + oldstr = cfg->audio.group; + + if (!oldstr || (oldstr && strcmp(oldstr, group))) { + need_update = TRUE; + free(oldstr); + cfg->audio.group = strdup(group); + } + } + + if (pid) { + oldpid = cfg->audio.pid; + + if (!oldpid || (oldpid && (oldpid != pid))) { + need_update = TRUE; + cfg->audio.pid = pid; + } + } + + if (stream) { + oldstr = cfg->audio.stream; + + if (!oldstr || (oldstr && strcmp(oldstr, stream))) { + need_update = TRUE; + free(oldstr); + cfg->audio.stream = strdup(stream); + } + } + + return need_update; +} + +static uint32_t push_request(resource_set_t *rs, + resmsg_type_t msgtyp, + request_complete_t callback, + void *data) +{ + request_t *last; + request_t *rq; + uint32_t rn; + + if (rs->client == client_created) + rn = 0; + else { + + for (last = (void*)&rs->reqlist; last->next; last = last->next) + ; + + if ((rq = malloc(sizeof(request_t))) == NULL) + rn = 0; + else { + rn = ++reqno; + + memset(rq, 0, sizeof(request_t)); + rq->msgtyp = msgtyp; + rq->reqno = rn; + rq->cb.function = callback; + rq->cb.data = data; + + last->next = rq; + + resource_log("pushed %u %s request", rq->reqno, + resmsg_type_str(msgtyp)); + + send_request(rs); + } + } + + return rn; +} + +static request_t *peek_request(resource_set_t *rs) +{ + return rs->reqlist; +} + + + +static request_t *pop_request(resource_set_t *rs, uint32_t rn) +{ + request_t *prev; + request_t *rq; + + for (prev = (void*)&rs->reqlist; (rq = prev->next); prev = prev->next) { + if (rq->reqno == rn) { + + resource_log("popping message %u (%s message)", + rn, resmsg_type_str(rq->msgtyp)); + + prev->next = rq->next; + rq->next = NULL; + + break; + } + } + + return rq; +} + + + +static void resource_log(const char *fmt, ...) +{ + static int got_env; + static int printit; + + va_list ap; + char *envstr; + char *end; + char buf[1024]; + + if (!got_env) { + if ((envstr = getenv("LIBRESOURCE_DEBUG")) != NULL) { + printit = strtol(envstr, &end, 10); + + if (printit < 0 || !envstr[0] || *end) + printit = 0; + + got_env = TRUE; + + if (printit) + printf("resource: logging turned on\n"); + } + } + + if (printit) { + snprintf(buf, sizeof(buf), "resource: %s\n", fmt); + + va_start(ap, fmt); + + vprintf(buf, ap); + + va_end(ap); + } +} + + /* * Local Variables: diff --git a/src/resource.h b/src/resource.h index 9dc9049..fa9bab8 100644 --- a/src/resource.h +++ b/src/resource.h @@ -1,7 +1,54 @@ #ifndef __LIB_RESOURCE_H__ #define __LIB_RESOURCE_H__ -#include <res-conn.h> +#include <stdint.h> +#include <sys/types.h> +#include <res-types.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct resource_set_s resource_set_t; + + +typedef void (*resource_callback_t)(resource_set_t *resource_set, + uint32_t resources, + void *userdata); + + +resource_set_t *resource_set_create(const char *klass, + uint32_t mandatory, + uint32_t optional, + uint32_t mode, + resource_callback_t grantcb, + void *grantdata); + +void resource_set_destroy(resource_set_t *resource_set); + +int resource_set_configure_advice_callback(resource_set_t *resource_set, + resource_callback_t *advicecb, + void *advicedata); + +int resource_set_configure_resources(resource_set_t *resource_set, + uint32_t mandatory, + uint32_t optional); + +int resource_set_configure_audio(resource_set_t *resource_set, + const char *audio_group, + pid_t pid_of_renderer, + const char *pulseaudio_stream_name); + +int resource_set_acquire(resource_set_t *resource_set); +int resource_set_release(resource_set_t *resource_set); + + + + +#ifdef __cplusplus +}; +#endif #endif /* __LIB_RESOURCE_H__ */ |