Pulseaudio c extension callback function

Discussion in 'Ruby' started by edder@tkwsping.nl, Nov 5, 2007.

  1. Guest

    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
    --
    Posted via http://www.ruby-forum.com/.
    , Nov 5, 2007
    #1
    1. Advertising

  2. Guest

    On Tue, Nov 06, 2007 at 02:25:29AM +0900, Edwin Van leeuwen wrote:
    > 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
    , Nov 5, 2007
    #2
    1. Advertising

  3. Guest

    Paul Brannan 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
    --
    Posted via http://www.ruby-forum.com/.
    , Nov 5, 2007
    #3
  4. Guest

    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
    , Nov 5, 2007
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. prettysmurfed
    Replies:
    6
    Views:
    681
    prettysmurfed
    Jul 22, 2003
  2. pvdm
    Replies:
    1
    Views:
    668
    tom_usenet
    Sep 9, 2003
  3. Diez B. Roggisch

    passing callback function to c-extension

    Diez B. Roggisch, Jan 14, 2004, in forum: Python
    Replies:
    4
    Views:
    331
    Diez B. Roggisch
    Jan 14, 2004
  4. JDT
    Replies:
    6
    Views:
    525
    James Kanze
    Mar 29, 2007
  5. Angus
    Replies:
    32
    Views:
    790
    Richard
    Apr 15, 2008
Loading...

Share This Page