I'm using libusb-1.0 to pair a BLE dongle to an RCU.
For this, I write a pairing request to the dongle interface succesfully.
To listen to the dongle response I'm using the function libusb_fill_interrupt_transfer and I pass a callback, which will be executed when receiving the response.
This function accepts a parameter, as mentionned in the documentation (void *user_data), that can be used in the callback. But when I try to use this parameter, I get a compilation error.
undeclared (first use in this function)
Following the call of the previous function and the declaration of my callback :
libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
sizeof(pairing->buffer), cb_aknowledgement, pairing, 0);
static void cb_aknowledgement(struct libusb_transfer *transfer)
{
if (pairing->transfer->status != LIBUSB_TRANSFER_COMPLETED) {
printf( "img transfer status %d?\n", pairing->transfer->status);
libusb_free_transfer(pairing->transfer);
pairing->transfer = NULL;
return;
}
if(pairing->buffer[0]!=0x05 || pairing->buffer[1]!=0x21)
{
printf( "wrong command recieved\n");
libusb_free_transfer(pairing->transfer);
pairing->transfer = NULL;
return;
}
printf("I've read data \n");
printf("USB Report Id = 0x%x \n",pairing->buffer[0]);
printf("Command = 0x%x \n",pairing->buffer[1]);
printf("Acknowledgement type = 0x%x \n",pairing->buffer[2]);
return ;
}
The question is: How can I use the user_data I passed as a parameter to the callback?
Use transfer->user_data. From libusb_transfer structure doc :
Data Fields
void * user_data
User context data to pass to the callback function.
I don't know what is the type of pairing but it would look like this:
int main() {
...
struct pairing_type_s *pairing = pairing_init();
...
libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
sizeof(pairing->buffer), cb_aknowledgement, pairing, 0);
...
}
// Then later:
static void cb_aknowledgement(struct libusb_transfer *transfer)
{
assert(transfer != NULL);
struct pairing_type_s *pairing = transfer->user_data;
assert(pairing != NULL);
// use pairing like a pro
...
}
But you can also be more pro, if you ensure that you always call libusb_fill_interrupt_transfer with pairing->transfer with cb_aknowledgement and use container_of macro:
int main() {
...
struct pairing_type_s *pairing = pairing_init();
...
libusb_fill_interrupt_transfer(pairing->transfer, dctx->devh, 0x84, pairing->buffer,
sizeof(pairing->buffer), cb_aknowledgement, NULL, 0);
...
}
// Then later:
static void cb_aknowledgement(struct libusb_transfer *transfer)
{
assert(transfer != NULL);
struct pairing_type_s *pairing = container_of(transfer, struct pairing_type_s, transfer);
assert(pairing != NULL);
// use pairing like a pro
...
}
But I would prefer the first method in this case, as it's more readable and more errorless.
Related
First off, I am not a programmer, I do electrical engineering. I have done some programming, but would never say that I am a good programmer. This question will probably be downvoted, but that is ok because I have been trying to do this for two months now.
I no nothing about event.h, but I have an existing code that works and uses this. It goes like this (I changed some things to hide information, but the code works):
struct event_base *base;
struct event *read_event;
struct event *signal_event;
typedef struct sample_ctx {
sens_handle_t *sens_handler;
sens_data_t data;
} sample_ctx_t;
// signal handler to break the event loop
void
signal_handler(evutil_socket_t sock, short event, void *user_data)
{
event_base_loopbreak(base);
}
// receive callback
void
sens_recv_cb(evutil_socket_t sock, short event, void *user_data)
{
static int i = 0;
int timeout = 0;
static struct timeval timestamp;
struct timeval timestamp2;
struct timeval diff;
sens_status_t status;
sample_ctx_t *ctx;
ctx = (sample_ctx_t *)user_data;
if (i == 0) {
gettimeofday(×tamp, NULL);
i = 1;
}
status = sens_read(&ctx->data, ctx->sens_handler);
if ((status == SENS_SUCCESS) &&
!isnan(ctx->data.info1) &&
!isnan(ctx->data.info2) &&
!isnan(ctx->data.info3) &&
!isnan(ctx->data.info4)) {
fprintf(stderr, "%lf %lf %lf %lf\n",
ctx->data.info1,
ctx->data.info2,
ctx->data.info3,
ctx->data.info4);
gettimeofday(×tamp, NULL);
} else {
gettimeofday(×tamp2, NULL);
timersub(×tamp2, ×tamp, &diff);
timeout = diff.tv_sec + (diff.tv_usec / 1000000);
}
}
int main()
{
int fd;
status_t status;
sample_ctx_t ctx;
memset(&ctx, 0, sizeof(ctx));
status = sensor_open(&fd, &ctx.gps_handler);
if (status != V2X_SUCCESS) {
fprintf(stderr, "Open failed ... sensor might not be running\n");
goto deinit_4;
}
base = event_base_new();
if (!base) {
fprintf(stderr, "Failed to create event base\n");
goto deinit_3;
}
// register for the read events
read_event = event_new(base, fd, EV_PERSIST|EV_READ, sens_recv_cb, &ctx);
if (!read_event) {
fprintf(stderr, "Failed to create read event\n");
goto deinit_2;
}
// register for the SIGINT signal on ctrl + c key combo
signal_event = evsignal_new(base, SIGINT, signal_handler, NULL);
if (!signal_event) {
fprintf(stderr, "Failed to create signal event\n");
goto deinit_1;
}
event_add(read_event, NULL);
evsignal_add(signal_event, NULL);
event_base_dispatch(base);
evsignal_del(signal_event);
deinit_1:
event_free(read_event);
deinit_2:
event_base_free(base);
deinit_3:
sensor_close(ctx.sens_handler);
deinit_4:
return 0;
}
This code retrieves data from a sensor and prints it to the screen. It's purpose is pretty simple, but the way it has to be done is what is complicated; for me at least.
Ok, so in the sens_recv_cb function, the ctx->data is printed to the screen, but I need to access that in the main function. The only time this function is called is in the event_new function in main. Is there a way get that data in main? Like lets say I just want to print ctx->data.info1 in main while still printing out everything from before in the sens_recv_cb function.
Is what I want to do possible without changing the entire code?
Because main and sens_recv_cb are asynchronous, you'll need a way to signal between them and a way for the call-back to store the data. You can combine both with a linked list:
struct node {
sample_ctx_t data;
struct node *next;
struct node *previous;
}
struct node *head = NULL;
struct node *tail = NULL;
The event handler adds to the head of the list and the main function removes them from the tail. It's a FIFO. You'll need to use atomic operations when reading/writing data to the list. The links provide what you need to know, and if you search, you'll find lots of example code around here and at other sites. You can probably find an open source, thread-safe linked list implementation on GitHub.
Basically, when the list is empty, there's nothing for main to consume.
I have a proto message defined as:
message SimpleMessage {
repeated int32 number = 1;}
now, after compiling, the field is of pb_callback_t and I suppose to write that function. (without .options file)
now, where and what should the function contain? where does the data itself being stored and how can I access it/ assign new data to it?
* EDIT *
according to #Groo 's answer, this is the code I tried:
typedef struct {
int numbers_decoded;
} DecodingState;
bool read_single_number(pb_istream_t *istream, const pb_field_t *field, void **arg)
{
// get the pointer to the custom state
DecodingState *state = (DecodingState*)(*arg);
int32_t value;
if (!pb_decode_varint32(istream, &value))
{
const char * error = PB_GET_ERROR(istream);
printf("Protobuf error: %s", error);
return false;
}
printf("Decoded successfully: %d", value);
state->numbers_decoded++;
return true;
}
int main(void) {
int32_t arr[3] = {10, 22, 342};
uint8_t buffer[128];
size_t message_length;
bool status;
SimpleMessage simple = SimpleMessage_init_zero;
printf("\nbefore : arr[0] = %d\n",arr[0]);
// set the argument and the callback fn
simple.number.arg = &arr;
simple.number.funcs.decode = read_single_number;
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
status = pb_encode(&ostream, SimpleMessage_fields, &simple);
message_length = ostream.bytes_written;
SimpleMessage simple1 = SimpleMessage_init_zero;
simple = simple1;
arr[0] = 0;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
// this function will call read_single_number several times
status = pb_decode(&istream, SimpleMessage_fields, &simple);
printf("\nafter : arr[0] = %d\n",arr[0]);
return EXIT_SUCCESS;
}
and the output is:
before : arr[0] = 10
Decoded successfully: 17
after : arr[0] = 0
what do I do wrong?
You can use some nanopb-specific proto flags to force nanopb to generate structs with statically allocated arrays.
However, the default behavior of nanopb's protogen is to generate a callback function which is called by nanopb during encoding (once for the entire list) and decoding (once for each item in the list). This is sometimes preferred in low-memory embedded systems, because you don't need to allocate more than one item at a time.
So, for your .proto file:
message SimpleMessage {
repeated int32 number = 1;
}
You might get something like:
typedef struct _SimpleMessage {
pb_callback_t number;
} SimpleMessage;
Meaning you will have to create your own callback function which will be called for each item in succession.
So for simplicity, let's say you have a simple "variable length" list like this:
#define MAX_NUMBERS 32
typedef struct
{
int32_t numbers[MAX_NUMBERS];
int32_t numbers_count;
}
IntList;
// add a number to the int list
void IntList_add_number(IntList * list, int32_t number)
{
if (list->numbers_count < MAX_NUMBERS)
{
list->numbers[list->numbers_count] = number;
list->numbers_count++;
}
}
Obviously, for such an example, using callbacks wouldn't make any sense, but it makes the example simple.
Encoding callback must iterate through the list, and write the protobuf tag and the value for each item in the list:
bool SimpleMessage_encode_numbers(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg)
{
IntList * source = (IntList*)(*arg);
// encode all numbers
for (int i = 0; i < source->numbers_count; i++)
{
if (!pb_encode_tag_for_field(ostream, field))
{
const char * error = PB_GET_ERROR(ostream);
printf("SimpleMessage_encode_numbers error: %s", error);
return false;
}
if (!pb_encode_svarint(ostream, source->numbers[i]))
{
const char * error = PB_GET_ERROR(ostream);
printf("SimpleMessage_encode_numbers error: %s", error);
return false;
}
}
return true;
}
Decoding callback is called once for each item, and "appends" to the list:
bool SimpleMessage_decode_single_number(pb_istream_t *istream, const pb_field_t *field, void **arg)
{
IntList * dest = (IntList*)(*arg);
// decode single number
int64_t number;
if (!pb_decode_svarint(istream, &number))
{
const char * error = PB_GET_ERROR(istream);
printf("SimpleMessage_decode_single_number error: %s", error);
return false;
}
// add to destination list
IntList_add_number(dest, (int32_t)number);
return true;
}
With these two in place, you must be careful to assign the right callback to the right function:
uint8_t buffer[128];
size_t total_bytes_encoded = 0;
// encoding
{
// prepare the actual "variable" array
IntList actualData = { 0 };
IntList_add_number(&actualData, 123);
IntList_add_number(&actualData, 456);
IntList_add_number(&actualData, 789);
// prepare the nanopb ENCODING callback
SimpleMessage msg = SimpleMessage_init_zero;
msg.number.arg = &actualData;
msg.number.funcs.encode = SimpleMessage_encode_numbers;
// call nanopb
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (!pb_encode(&ostream, SimpleMessage_fields, &msg))
{
const char * error = PB_GET_ERROR(&ostream);
printf("pb_encode error: %s", error);
return;
}
total_bytes_encoded = ostream.bytes_written;
printf("Encoded size: %d", total_bytes_encoded);
}
And similar for decoding:
// decoding
{
// empty array for decoding
IntList decodedData = { 0 };
// prepare the nanopb DECODING callback
SimpleMessage msg = SimpleMessage_init_zero;
msg.number.arg = &decodedData;
msg.number.funcs.decode = SimpleMessage_decode_single_number;
// call nanopb
pb_istream_t istream = pb_istream_from_buffer(buffer, total_bytes_encoded);
if (!pb_decode(&istream, SimpleMessage_fields, &msg))
{
const char * error = PB_GET_ERROR(&istream);
printf("pb_decode error: %s", error);
return;
}
printf("Bytes decoded: %d", total_bytes_encoded - istream.bytes_left);
}
If you have a repeated struct inside your message, your callback will not use
nanopb primitive functions (like pb_decode_varint32 above), but again pb_decode for each concrete message type. Your callback can also attach new callbacks to those nested structs, if needed.
To complement Groo's answer, here are answers to your specific questions.
1. Now, where and what should the function contain?
Groo provided good explanation of the callback functions. The network_server example in nanopb repository also uses callbacks and can be a useful reference: network_server/server.c network_server/client.c
2. Where does the data itself being stored?
Wherever you want! The whole point of nanopb's callbacks is that it gives you full flexibility in deciding how to store your data. In some cases you may want to even process the data on the fly, not storing it anywhere.
For example, the network_server example above gets the filenames from filesystem and sends them to the network directly - this way it can handle any amount of files without requiring much memory.
3. How can I access it/ assign new data to it?
Now this is the downside of callbacks - you'll have to implement your own access and allocation functions for whatever storage you use. That's why for the most common cases, either static allocation (with fixed maximum size) or dynamic allocation (which malloc()s required amount of memory) are more convenient.
mon_param is allocated memory by the main process invoking the thread function.
This function will be invoked by multiple threads.So, can I safely assume that it is thread safe as I am using only the variables on the stack?
struct table* get_row_of_machine(int row_num,struct mon_agent *mon_param)
{
struct table *table_row = mon_param->s_table_rows;
if(row_num < mon_param->total_states)
{
table_row = table_row + row_num;
}
return table_row;
}
//in the main function code goes like this ....
int main()
{
int msg_type,ret;
while(!s_interrupted)
{
inter_thread_pair = zsock_new(ZMQ_PAIR);
if(inter_thread_pair != NULL)
zsock_bind (inter_thread_pair, "inproc://zmq_main_pair");
int ret_val = zmq_poll(&socket_items[0], 1, 0); // Do not POLL indefinitely.
if(socket_items[0].revents & ZMQ_POLLIN)
{
char *msg = zstr_recv (inter_thread_pair); //
if(msg != NULL)
{
struct mon_agent *mon_params;
//This is where mon_params is getting its memory
mon_params = (struct mon_agent*)malloc(sizeof(struct mon_agent));
msg_type = get_msg_type(msg);
if(msg_type == /*will check for some message type here*/)
{
struct thread_sock_params *thd_sock = create_connect_pair_socket(thread_count);
// copy the contents of thread_sock_params and also the mon_params to this struct
struct thread_parameters parameters;
parameters.sock_params = thd_sock;
parameters.params = mon_params; //mon_params getting copid here.
//Every time I receive a particular message, I create a new thread and pass on the parameters.
//So, each thread gets its own mon_params memory allocated.
ret = pthread_create(&thread,NULL,monitoring_thread,(void*)¶meters);
and then it goes on like this.
}
}
}
and the code continues..... there is a breakpoint somewhere down..
}
}
void* mon_thread(void *data)
{
// First time data is sent as a function parameter and later will be received as messages.
struct thread_parameters *th_param = (struct thread_parameters *)data;
struct mon_agent *mon_params = th_param->params;
zsock_t* thread_pair_client = zsock_new(ZMQ_PAIR);
//printf("Value of socket is %s: \n",th_param->socket_ep);
rc = zsock_connect(thread_pair_client,th_param->sock_params->socket_ep);
if(rc == -1)
{
printf("zmq_connect failed in monitoring thread.\n");
}
while(!s_interrupted)
{
int row;
//logic to maintain the curent row.
//also receive other messages from thread_pair_client czmq socket.
run_machine(row,mon_params);
}
}
void run_machine(int row_num, struct mon_agent *mon_params)
{
struct table* table_row = get_row_of_state_machine(row_num,mon_param);
}
In short, no.
The way to make parameters thread safe is by design.
There is no fool proof way to do this or a rule of thumb. If you know your codes design well enough and you know no other thread will access the same struct then it's possibly thread safe.
If you do know some other thread might try to access the struct you can use all sorts of synchronization primitives like mutexes, critical sections, semaphores or more generally locks.
I stuck to send a stasis_message for a self made module to the ARI.
I try to use the code example from the documentation :
https://wiki.asterisk.org/wiki/display/AST/Stasis+Message+Bus
I use asterisk 13 instead example (who use the 12), and some signature are changed.
Here is the initialisation :
struct stasis_topic *foo_topic;
static int load_module(void)
{
// Register to stasis.
stasis_app_register(app, callback_stasis, 0);
// Create a bridge on witch ARI can conenct.
stasis_app_bridge_create("mixing", app, "11000");
// Create the topic
foo_topic = stasis_topic_create(app);
return ast_register_application_xml(app, exec);
}
And the code method who is calling when phone arrive :
static int exec()
{
publish_foo();
}
static void publish_foo()
{
printf("Trace 1\n");
char* test = "dataToSend";
RAII_VAR(struct stasis_message_type*, foo_type, NULL, ao2_cleanup);
stasis_message_type_create(app, NULL, &foo_type);
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
printf("Trace 3\n");
msg = stasis_message_create(type, test);
if (!msg)
return;
stasis_publish(foo_topic, msg);
printf("PASSING MESSAGE 4\n");
}
I always get message like :
bad magic number 0x332065 for object 0x7f2ea5ab8ec5
And this error appends in the method stasis_create_message().
[Edit]
I do not understand the error and the cause any help is appreciated.
As suggest by arheops, there is the function who are created problem. Apparently my object cannot be convert to an Asterisk object. Probably the structure I need to send to the create_message_function must be on a astobj2 type.
static struct astobj2 *INTERNAL_OBJ(void *user_data)
{
struct astobj2 *p;
if (!user_data) {
ast_log(LOG_ERROR, "user_data is NULL\n");
return NULL;
}
p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
if (AO2_MAGIC != p->priv_data.magic) {
if (p->priv_data.magic) {
ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
p->priv_data.magic, user_data);
} else {
ast_log(LOG_ERROR,
"bad magic number for object %p. Object is likely destroyed.\n",
user_data);
}
ast_assert(0);
return NULL;
}
return p;
}
And the struct of astobj2 definition :
struct astobj2
{
struct __priv_data priv_data;
void *user_data[0];
};
I tried to create a a2object like describe here, and I get an error :
*** Error in `asterisk': free(): invalid pointer:
Thanks
To send a stasis message, you need to create an a2object, normally you can perform this part with the macro :
RAII_VAR
But I cannot get a working example with this, so I create my-self the object with the following methods :
typedef struct ast_foo
{
int n;
} ast_foo;
// Destructor is automatically called when the message is not referenced anymore.
static void foo_dtor(void *obj)
{
struct foo *obj_foo = obj;
// Free all resources you have reserve here.
}
/**
* #return a ast_foo struct, with destructor setted.
*/
static struct ast_foo* make_me_a_foo(void)
{
struct ast_foo *obj_foo;
obj_foo = ao2_alloc(sizeof(ast_foo), foo_dtor);
// if char* do malloc for them.
if (!obj_foo) {
ast_log(LOG_NOTICE, "make foo failed... 2\n");
return NULL;
}
return obj_foo;
}
There is a full example for send and subscribe a stasis message :
static const char app[] = "StasisTest";
struct stasis_topic *foo_topic;
typedef struct ast_foo
{
int n;
} ast_foo;
// Destructor automatically call when message is not referenced anymore.
static void foo_dtor(void *obj)
{
struct foo *obj_foo = obj;
// Free all resources you have reserve here.
}
/**
* #return a ast_foo struct, with destructor setted.
*/
static struct ast_foo* make_me_a_foo(void)
{
struct ast_foo *obj_foo;
obj_foo = ao2_alloc(sizeof(ast_foo), foo_dtor);
// if char* do malloc for them.
if (!obj_foo) {
ast_log(LOG_NOTICE, "make foo failed... 2\n");
return NULL;
}
return obj_foo;
}
/**
* Send a stasis message, with the long way...
*/
static void publish_foo()
{
ast_log(LOG_NOTICE, "Enter publish message\n");
RAII_VAR(struct stasis_message_type*, foo_type, NULL, ao2_cleanup);
ast_log(LOG_NOTICE, "Create data to send\n");
ast_foo* foo_data = make_me_a_foo();
foo_data->n = 12;
ast_log(LOG_NOTICE, "Create the message to send.\n");
stasis_message_type_create(app, NULL, &foo_type);
if (!foo_type)
{
ast_log(LOG_NOTICE, "Oh no my type is NULL \n");
}
else
{
ast_log(LOG_NOTICE, "Ok foo type \n");
}
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
msg = stasis_message_create(foo_type, foo_data);
if (!msg)
{
ast_log(LOG_NOTICE, "Fail to send message\n");
sleep(1);
return;
}
stasis_publish(foo_topic, msg);
}
static int exec()
{
// First method.
publish_foo();
return 0;
}
static int unload_module(void) {
stasis_app_unregister(app);
ao2_cleanup(foo_topic);
foo_topic = NULL;
return ast_unregister_application(app);
}
void bar_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
{
ast_log(LOG_NOTICE, "Test stasis received a message from topic\n");
}
static int load_module(void) {
stasis_init();
// Register.
ast_foo* foo_data2 = make_me_a_foo();
foo_topic = stasis_topic_create("StasisTest");
stasis_subscribe(foo_topic, bar_callback, foo_data2);
return ast_register_application_xml(app, exec);
}
But there is a really more simpler way with the send of json object tought
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/stasis.h"
#include "asterisk/json.h"
#include "asterisk/stasis_app.h"
#include "StasisTest.h"
#define AST_MODULE "stasis_test"
static const char app[] = "StasisTest";
static int exec()
{
// Second simpler method.
struct ast_json* inte = ast_json_integer_create(51);
int result = stasis_app_send("StasisTest", inte);
ast_log(LOG_NOTICE, "Stasis send %d\n", result);
return 0;
}
static int unload_module(void)
{
stasis_app_unregister(app);
return ast_unregister_application(app);
}
//Test stasis
void callback_stasis(void* data, const char* app_name, struct ast_json* message)
{
ast_log(LOG_NOTICE, "Receive a stasis message from json\n");
int json_res = ast_json_integer_get(message);
ast_log(LOG_NOTICE, "Integer get : %d\n", json_res);
}
static int load_module(void) {
stasis_init();
// Register for the short way.
stasis_app_register(app, callback_stasis, 0);
return ast_register_application_xml(app, exec);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "The wonders of foo", .load = load_module, .unload = unload_module);
I'm currently building a program which needs to interface with the d-bus. I'm using the glib dbus library. I have a method that returns a dbus dictionary type, like this:
array [
dict entry(
string "Metadata"
variant array [
dict entry(
string "mpris:artUrl"
variant string "http://open.spotify.com/thumb/05e9ad92c22953e6c778536613605b67faa5a095"
)
dict entry(
string "mpris:length"
variant uint64 238000000
)
My question is, how on earth do I get this in my C program? I've tried the usual `dbus_g_proxy_connect_signal´ with a registered marshaller without much luck!
Edit: I've added some sample code (Which is not working, but does compile)
#include <string.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#define DBUS_SERVICE "com.spotify.qt"
#define DBUS_PATH "/"
#define DBUS_INTERFACE "org.freedesktop.MediaPlayer2"
#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
//Global bus connection
DBusGConnection *bus;
DBusGProxy *proxy;
//Main gloop
GMainLoop *loop = NULL;
//Callback function.
static void callbackfunc(DBusGProxy *player_proxy, GHashTable *table){
GValue *value;
/* fetch values from hash table */
value = (GValue *) g_hash_table_lookup(table, "artist");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nArtist: %s\n",g_value_get_string(value));
}
value = (GValue *) g_hash_table_lookup(table, "album");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nAlbum: %s\n",g_value_get_string(value));
}
value = (GValue *) g_hash_table_lookup(table, "title");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nTitle: %s\n",g_value_get_string(value));
}
}
int main (int argc, char **argv){
GError *error = NULL;
g_type_init ();
/* Get (on) the bus :p */
bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
if (bus == NULL) {
g_printerr("Failed to open connection to bus: %s", error->message);
g_error_free(error);
return -1;
}
/* Create a proxy object for the bus driver */
proxy = dbus_g_proxy_new_for_name (bus,
DBUS_SERVICE,
DBUS_PATH,
DBUS_INTERFACE);
if (!proxy) {
g_printerr("Couldn't connect: %s", error->message);
g_error_free(error);
return -1;
}
/* Create the main loop instance */
loop = g_main_loop_new (NULL, FALSE);
dbus_g_proxy_add_signal(proxy, "GetMetadata",
DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy, "GetMetadata",
G_CALLBACK(callbackfunc), NULL, NULL);
g_print("Going into main function\n");
/* Main loop */
g_main_loop_run (loop);
return 0;
}
I'm going to port my code to use GIO rather than glib-dbus, I did how ever manage to get it working with glib-dbus using this:
if (dbus_g_proxy_call(p_proxy_md, "GetMetadata", NULL, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VALUE_HASHTABLE, &table, G_TYPE_INVALID)) {
value = (GValue *) g_hash_table_lookup(table, "xesam:title");
sprintf(currentTrack.trackname,"%s",g_value_get_string(value));
value = (GValue *) g_hash_table_lookup(table, "xesam:album");
sprintf(currentTrack.album,"%s",g_value_get_string(value));
tmp = g_hash_table_lookup(table, "xesam:artist");
if (tmp != NULL)
{
GStrv strv = g_value_get_boxed(g_hash_table_lookup(table, "xesam:artist"));
sprintf(currentTrack.artist,"%s",*strv);
}
}
sprintf(notifybody,"By %s on %s",currentTrack.artist,currentTrack.album);
music_noti = notify_notification_new(currentTrack.trackname,notifybody, NULL);
notify_notification_set_timeout(music_noti,1500);
notify_notification_set_icon_from_pixbuf(music_noti, notifyicon);
notify_notification_show(music_noti, NULL);
notify_uninit();
}
Without using GLIB or any external library, the best way I've found is outlined in this post.
It requires knowing the structure of the datatype ahead of time, which is a bit annoying. However, you can use dbus-monitor to see what DBUS is sending first. Then you have to make an iterator for each level of the array. See the DBUS message documentation for how to use the iterators.