Pulseaudio c extension callback function

E

edder

Hi all,

I started working on a ruby wrapper for pulseaudio. I am a bit out of my
depth here, because my c experience is very limited and very rusty and I
am kinda stuck. The library is basically event driven. You attach some
callback function, start the mainloop and wait for events. In c you
would basically the following:

static void
callback( pa_context *c, void *userdata )
{
}

pa_mainloop *m = pa_mainloop_new();
pa_mainloop_api *api = pa_mainloop_get_api( m );
pa_context *context = pa_context_new(api, "name");
/* Here the callback function is attached */
pa_context_set_state_callback( context, callback, userdata );
pa_context_connect( connect, NULL, 0, NULL);

The interesting part is the callback function, which is defined as
follows:

static void
callback( pa_context *c, void *userdata )
{
}

I now want to define my own callback function and have it change the
status of my context object. Then I can define listeners in ruby on the
status method and will be home free. The problem is to somehow pass the
current context object to the c based callback function. My context
class is just a wrapper around pa_context, so ideally I could use
pa_context *c to "find" my object again, but if I use Data_Wrap_Struct
it will create a new context object won't it? The closest I came was:

static void
callback( pa_context *c, void *klass )
{
VALUE obj;
obj = * (VALUE *) klass;
rb_funcall( obj, rb_intern( "status=" ), 1, INT2NUM(2) );
}

static VALUE
cContext_connect( VALUE klass )
{
pa_context_set_state_callback( DATA_PTR( klass ), callback, &klass );
pa_context_connect(DATA_PTR( klass ), NULL, 0, NULL);
return klass;
}

but then I got the following error:
NoMethodError: undefined method `status=' for
PulseAudio::Mainloop:0xb79ac9ac>
(I have no clue where this mainloop object comes from, except that it is
ofcourse the mainloop that will call the callback function)

Also I have the feeling this could introduce problems with the GC
cleaning up my context object, because officialy it's not referenced
anymore (but I'm reasonably clueless about memory management and
pointers etc).

Does anyone have any pointers for me :) ?

Cheers,

Edwin
 
P

pbrannan

static void
callback( pa_context *c, void *klass )
{
VALUE obj;
obj = * (VALUE *) klass;
rb_funcall( obj, rb_intern( "status=" ), 1, INT2NUM(2) );
}

static VALUE
cContext_connect( VALUE klass )
{
pa_context_set_state_callback( DATA_PTR( klass ), callback, &klass );

klass is a temporary variable; you probably don't want to take its
address. Instead you can cast klass to a pointer:

pa_context_set_state_callback( DATA_PTR( klass ), callback, (void *)klass );

then in your callback function, write:

VALUE obj = (VALUE *) klass;
pa_context_connect(DATA_PTR( klass ), NULL, 0, NULL);
return klass;
}

but then I got the following error:
NoMethodError: undefined method `status=' for
PulseAudio::Mainloop:0xb79ac9ac>
(I have no clue where this mainloop object comes from, except that it is
ofcourse the mainloop that will call the callback function)

Also I have the feeling this could introduce problems with the GC
cleaning up my context object, because officialy it's not referenced
anymore (but I'm reasonably clueless about memory management and
pointers etc).

If I understand your question, when the context object is destroyed, you
need to unregister the callback. That will ensure that the library
doesn't keep a reference to the freed object. You can do this by
passing a `free' function to Data_Wrap_Struct.
Does anyone have any pointers for me :) ?

Other than the pointers to object you've already created? :)

Paul
 
E

edder

Paul said:
klass is a temporary variable; you probably don't want to take its
address. Instead you can cast klass to a pointer:

pa_context_set_state_callback( DATA_PTR( klass ), callback, (void
*)klass );

then in your callback function, write:

VALUE obj = (VALUE *) klass;

Thanks, it worked when I changed it to:

VALUE obj = (VALUE) klass;

Otherwise I got a compile error. I really should refresh my c, because
clearly my approach of changing the code until it stops segvaulting is
not the best :) Although it seems to give me decent progress :)
If I understand your question, when the context object is destroyed, you
need to unregister the callback. That will ensure that the library
doesn't keep a reference to the freed object. You can do this by
passing a `free' function to Data_Wrap_Struct.

Yes, I am already using the unref function for the context itself. I am
not sure if that also unregisters the callback. I guess I should be
testing that later.

Edwin
 
P

pbrannan

Thanks, it worked when I changed it to:

VALUE obj = (VALUE) klass;

Oops, typo. :)
Yes, I am already using the unref function for the context itself. I am
not sure if that also unregisters the callback. I guess I should be
testing that later.

That's the behavior I would expect, but I've never used pulseaudio.

Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top