I hope the title is not too misleading... :)
I play a system sound and add the SoundCompletion-Callback to it like so:
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self);
Whereas «self» is a simple NSObject
In the completion callback I try to call the playing routine again:
I had to add the __bridge_transfer and the __bridge_retained to the casts, otherwise I get errors, crashes, or other unexpected behaviour.
But the whole thing doesn't work despite all that.
I store the sounds to play in an NSMutableArray, grab the first entry of the array and play it, add the sound completion and hope stuff happens. But - with all that retained-transfer stuff, the NSMutableArray is empty on the second call...
Here's the code:
static void completionCallback (SystemSoundID  mySSID, void *myself) {
    NSLog(@"Audio callback");
    AudioServicesRemoveSystemSoundCompletion (mySSID);
    AudioServicesDisposeSystemSoundID(mySSID);
    [(__bridge_transfer Speaker *)myself speakCharacter];
    CFRelease(myself); // I heard I need this?
}
-(void)speakCharacter{
    if([sounds count] > 0){
        NSString *soundToPlay = [sounds objectAtIndex:0];
        [sounds removeObjectAtIndex:0];
        NSLog(@"TxtToSpeak %@", soundToPlay);
        CFURLRef        soundFileURLRef;
        NSURL *path = [[NSBundle mainBundle] URLForResource:[soundToPlay uppercaseString] withExtension:@"aif"];
        soundFileURLRef = (__bridge CFURLRef)path;
        SystemSoundID soundID;
        AudioServicesCreateSystemSoundID(soundFileURLRef, &soundID);
        AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self);
        AudioServicesPlaySystemSound (soundID);
    }
}
[EDIT] - ANSWERING MY OWN QUESTION:
Always nice to find it out myself :)
Turns out, I was almost there.
The call to set up the callback is as follows:
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self);
Then, in the callback-function, I do this:
myClass *theClass = (__bridge myClass *)myself;
    CFRelease(myself);
    [theClass playNextSound]; // The routine that plays the sounds
And it works...
I couldn't answer my own question since I was too fast for StackOverflow - so just to make this complete, I add the answer again :)
Turns out, I was almost there.
The call to set up the callback is as follows:
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self);
Then, in the callback-function, I do this:
myClass *theClass = (__bridge myClass *)myself;
CFRelease(myself);
[theClass playNextSound]; // The routine that plays the sounds
And it works...
For anybody that needs a little extra help... I got Swissdude's answer to work in a common view controller as such:
note: (you can't use CFRelease(myself))
.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
@interface MYVIEWCONTROLLERNAME : UIViewController
@property SystemSoundID mySentenceAudio;
@end
.m
 #import "MYVIEWCONTROLLERNAME.h"
 @interface MYVIEWCONTROLLERNAME ()
 {
     int myLetterCount;
     int myWordLength;
 }
 @end
 @implementation MYVIEWCONTROLLERNAME
 @synthesize mySentenceAudio;
  #pragma mark - Click Action
- (IBAction)SpellButtonPress:(UIButton *)sender {
    [self AudioDataAndPlayerLoader];
    myLetterCount = 0;
}
# pragma mark - Audio Data
-(void) AudioDataAndPlayerLoader {
    NSString*myWord = @"apple";
    myWordLength = myWord.length;
    NSArray*wordArray= [self stringToLetterArray:myWord];
    if (myWordLength > myLetterCount) {
        NSString* myLetter = [wordArray objectAtIndex:myLetterCount];
        [self playMySound:myLetter];
    }
}
- (NSArray*)stringToLetterArray:(NSString*)string {
    NSUInteger characterCount = [string length];
    NSMutableArray *temparray = [NSMutableArray arrayWithCapacity:[string length]];
    for (int i = 0; i<characterCount; i++)
    {
        [temparray addObject:[string substringWithRange:NSMakeRange (i,1)]];
    }
    return [temparray copy];
}
#pragma mark - Audio Loop
- (void) myAudioLoopCheck {
    myLetterCount++;
    NSLog(@"Audio Looped");
    if (myWordLength > myLetterCount) {
        [self performSelector:@selector(AudioDataAndPlayerLoader) withObject:nil afterDelay:.2];
    }
    else {
        NSLog(@"Done");
        myLetterCount = 0;
    }
}
#pragma mark - Audio Player
- (void) playMySound: (NSString*)soundTitle{
    NSString* SOUNDPATH = [[NSBundle mainBundle]
                           pathForResource:soundTitle
                           ofType:@"m4a"
                           inDirectory:@"audio/abc/"];
    if (SOUNDPATH != nil) {
        CFURLRef baseURL = (__bridge_retained CFURLRef)  [[NSURL alloc] initFileURLWithPath:SOUNDPATH];
        AudioServicesCreateSystemSoundID (baseURL, &mySentenceAudio);
        AudioServicesPlaySystemSound(mySentenceAudio);
        CFRelease(baseURL);
        AudioServicesAddSystemSoundCompletion (mySentenceAudio,NULL,NULL,theAudioServicesSystemSoundCompletionProc,(__bridge void*)self);
    }
    else {
    }
}
#pragma mark - Audio Player Callback
static void theAudioServicesSystemSoundCompletionProc (SystemSoundID  mySentenceAudio, void *myself) {
    NSLog(@"Audio callback");
    AudioServicesRemoveSystemSoundCompletion (mySentenceAudio);
    AudioServicesDisposeSystemSoundID(mySentenceAudio);
    MYVIEWCONTROLLERNAME *theClass = (__bridge MYVIEWCONTROLLERNAME *)myself;
    [theClass myAudioLoopCheck];
}
// life cycle code...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With