iosobjective-cdelegatesavaudioplayertrigger.io

Using a class as an AVAudioPlayerDelegate for a static AVAudioPlayer


I can't maintain an instance in a TriggerIO plugin, so I need a static way of responding to my AVAudioPlayer's events. However, I can't set the player.delegate to audio_API, so I'm a bit stuck.

audio_API.h:

@interface audio_API : NSObject<AVAudioPlayerDelegate>

audio_API.m:

static AVAudioPlayer* player = nil;


@implementation audio_API


+ (void)play:(ForgeTask*)task {

    // parse the file url from the file object
    ForgeFile* file = [[ForgeFile alloc] initWithFile:[task.params objectForKey:@"file"]];
    NSString* fileURL = [file url];

    NSLog(@"Playing file at %@", fileURL);

    NSURL* url = [NSURL URLWithString:fileURL];


    // TESTING
    url = [[NSBundle mainBundle] URLForResource:@"seconds.m4a" withExtension:nil];
    // END TESTING

    NSAssert(url, @"URL is invalid.");

    // create the player
    NSError* error = nil;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if(!player)
    {
        NSLog(@"Error creating player: %@", error);
    };

//    player.delegate = audio_API;

    [player play];

    [task success:nil];
}


+ (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    if (flag) {
        [ForgeLog d:@"Audio finished playing successfully."];
    } else {
        [ForgeLog d:@"Audio did not finish playing successfully."];
    }

    // call the audio.finishedPlaying event
    [[ForgeApp sharedApp] event:@"audio.finishedPlaying" withParam:nil];
}

+ (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
    [ForgeLog d:@"Audio had error decoding."];
    [ForgeLog e:error];

    // call the audio.decodeErrorOccurred event
    [[ForgeApp sharedApp] event:@"audio.decodeErrorOccurred" withParam:nil];
}

@end

Any idea of how to make this work?

Thanks.


Solution

  • The delegate has to be an object, but audio_API is type name. However, you can simply assign the delegate to be the class object of audio_API:

    player.delegate = (id<AVAudioPlayerDelegate>)[audio_API class];
    

    Note: If you don't cast the class object the compiler will complain, because [audio_API class] returns a Class, not a Class<AVAudioPlayerDelegate>, even if you specify the delegate on the interface for audio_API