# Pulseaudio c extension callback function

**URL:** <https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273>\
**Category:** Ruby\
**Created:** [November 5, 2007, 6:25pm UTC](https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273 "2007-11-05T18:25:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![blackedder](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/c57346/32.png) [@blackedder](https://www.ruby-forum.com/u/blackedder)\
**Post date:** [November 5, 2007, 6:25pm UTC](https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273/1 "2007-11-05T18:25:30Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![blackedder](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/c57346/32.png) [@blackedder](https://www.ruby-forum.com/u/blackedder)\
**Post date:** [November 5, 2007, 8:25pm UTC](https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273/2 "2007-11-05T20:25:46Z")

</div>

On Tue, Nov 06, 2007 at 02:25:29AM +0900, Edwin Van leeuwen wrote:

> {  
> 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;

```

> 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

---

<div class="post-metadata">

**Author:** ![blackedder](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/c57346/32.png) [@blackedder](https://www.ruby-forum.com/u/blackedder)\
**Post date:** [November 5, 2007, 9:27pm UTC](https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273/3 "2007-11-05T21:27:20Z")

</div>

On Tue, Nov 06, 2007 at 05:08:17AM +0900, Edwin Van leeuwen wrote:

> 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

---

<div class="post-metadata">

**Author:** ![blackedder](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/c57346/32.png) [@blackedder](https://www.ruby-forum.com/u/blackedder)\
**Post date:** [November 5, 2007, 9:08pm UTC](https://www.ruby-forum.com/t/pulseaudio-c-extension-callback-function/119273/4 "2007-11-05T21:08:19Z")

</div>

Paul B. wrote:

> 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
