2. The RubyCocoa Jukebox

To access this library from RubyCocoa, all that we need to do is define an Objective-C class to wrap the jukebox structure and provide messages to access the API.

Here’s the header file for our Objective-C wrapper. Since our class methods get looked up at runtime, we can leave them out of the header file (which may or may not be advisable, I’ll leave that decision to you).

Jukebox.h [Objective-C]
#import <Cocoa/Cocoa.h>
#import "cdjukebox.h"

@interface Jukebox : NSObject {
    CDJukebox *jukebox;
}

@end

Here’s the implementation of the Objective-C wrapper class. This is the hardest part of the whole process, and it’s not much of a challenge.

Jukebox.m [Objective-C]
#import "Jukebox.h"

@implementation Jukebox

- (Jukebox *) initWithUnit:(int) unit {
    jukebox = new_jukebox();
    assign_jukebox(jukebox, unit);
    return self;
}

- (void) seekDisc:(int)disc track:(int)track {
    jukebox_seek(jukebox, disc, track, 0);
}

- (double) seekTime {
    return get_avg_seek_time(jukebox);
}

- (void) dealloc {
    free_jukebox(jukebox);
    [super dealloc];
}

@end

// This initialization function gets called when we import the Ruby module.
// It doesn't need to do anything because the RubyCocoa bridge will do
// all the initialization work.
void Init_jukebox() { }

You can compile the example with the following command:

Compile command [shell]
% gcc -o jukebox.bundle -bundle -framework Foundation cdjukebox.c Jukebox.m

The extension is compiled into a file named jukebox.bundle. You can import it into ruby sessions that you start in the same working directory. To make it available from anywhere on your system, copy it to the appropriate site_ruby directory. If you’re running with the Apple-installed version of Ruby, this is probably /usr/lib/ruby/site_ruby/1.8. If you’ve built your own version from the Ruby sources, this is probably /usr/local/lib/ruby/site_ruby/1.8.

To test the extension, jump into irb and type the commands in the session log shown below:

Test session [irb]
% irb
irb(main):001:0> require 'osx/cocoa'
=> true
irb(main):002:0> require 'jukebox'
=> true
irb(main):003:0> OSX::ns_import :Jukebox
=> OSX::Jukebox
irb(main):004:0> j = OSX::Jukebox.alloc.initWithUnit(13)
allocating jukebox
assigning jukebox to unit 13
=> #<OSX::Jukebox:0x3ad11c class='Jukebox' id=0x1159620>
irb(main):005:0> j.seekDisc(3, :track, 16)
seeking disc 3 and track 16 for player 13
=> nil
irb(main):006:0> k = j
=> #<OSX::Jukebox:0x3ad11c class='Jukebox' id=0x1159620>
irb(main):007:0> k.seekDisc(3, :track, 16)
seeking disc 3 and track 16 for player 13
=> nil
irb(main):008:0> k.seekTime
getting seek time for unit 13
=> 54.321
irb(main):009:0> k = 0
=> 0
irb(main):010:0> j = 0
=> 0
irb(main):011:0> puts "the jukebox hasn't been freed yet"
the jukebox hasn't been freed yet
=> nil
irb(main):012:0> GC.start   # explicitly call the ruby garbage collector
disposing of jukebox with unit id 13
=> nil
irb(main):013:0> quit

Did you find an error? Is something missing? Post your comment or suggestion below!

Comments (0) post