views:

2038

answers:

2

On the iPhone I need to get the path for the resource. OK, done that, but when it comes to CFURLCreateFromFileSystemRepresentation thing, I just don't know how to solve this. Why does this error occur? Any solution or workaround would be highly appreciated. Thank you in advance.

I have taken a look at the following examples in order to play audio using AudioQueue on the iPhone: SpeakHere, AudioQueueTools (from the SimpleSDK directory) and AudioQueueTest. I tried do this and that, trying to put the puzzles together. Right now, I am stuck at this. The program crashed because of the exception thrown from the sndFile above.

I am using AVAudioPlayer to play every sound on my iPhone games. On the real iPhone device, it turned out to be very laggy when a sound is to be played, so I decided I need to use AudioQueue.

- (id) initWithFile: (NSString*) argv{

    if (self = [super init]){
        NSString *soundFilePath = [[NSBundle mainBundle]
                                    pathForResource:argv
                                             ofType:@"mp3"];
        int len = [soundFilePath length];
        char* fpath = new char[len];

        //this is for changing NSString into char* to match
        //CFURLCreateFromFileSystemRepresentation function's requirement.
        for (int i = 0; i < [soundFilePath length]; i++){
            fpath[i] = [soundFilePath characterAtIndex:i];
        }

        CFURLRef sndFile = CFURLCreateFromFileSystemRepresentation
                           (NULL, (const UInt8 *)fpath, strlen(fpath), false);
        if (!sndFile) {
            NSLog(@"sndFile error");
            XThrowIfError (!sndFile, "can't parse file path");
        }
}
A: 

I'm not sure if this will get rid of your exception, but there is a simpler way to convert an NSString to an array of char. Here is how I would write this method:

- (id) initWithFile:(NSString*) argv
{
    if ((self = [super init]) == nil) { return nil; }

    NSString * soundFilePath = [[NSBundle mainBundle]
                                 pathForResource:argv
                                          ofType:@"mp3"];
    CFURLRef sndFile = CFURLCreateFromFileSystemRepresentation
                       (NULL, [soundFilePath UTF8String],
                        [soundFilePath length], NO);

    if (!sndFile) { NSLog(@"sndFile error"); }
    XThrowIfError (!sndFile, "can't parse file path");

    ...
}

Or, since CFURL is "toll-free bridged" with NSURL, you can simply do:

- (id) initWithFile:(NSString*) argv
{
    if ((self = [super init]) == nil) { return nil; }

    NSString * soundFilePath = [[NSBundle mainBundle]
                                 pathForResource:argv
                                          ofType:@"mp3"];
    NSURL * sndFile = [NSURL URLWithString:[soundFilePath
                       stringByAddingPercentEscapesUsingEncoding:
                         NSUTF8StringEncoding]];
    if (!sndFile) { NSLog(@"sndFile error"); }
    XThrowIfError (!sndFile, "can't parse file path");

    ...
}
e.James
+2  A: 

Why do you need a CFURL?

If you have a method elsewhere that requires a CFURL, you can simply use an NSURL thanks to toll-free bridging. So to create the NSURL, you'd just do:

  NSString * soundFilePath = [[NSBundle mainBundle]
                                 pathForResource:argv
                                          ofType:@"mp3"];

  NSURL *soundURL = [NSURL fileURLWithPath:soundFilePath];

In general, if you find yourself using CF objects you are probably doing something wrong.

Kendall Helmstetter Gelner
What does CF stand for? I feel silly for asking, but there's too many possibilities.
Sneakyness
Core Foundation, the NS calls are based on top of these lower level calls - usually there's a cleaner, easier way to use an NS method than a CF method.
Kendall Helmstetter Gelner