2012-01-30 13 views
5

espero que el título no es demasiado engañosa ... :)AudioServicesAddSystemSoundCompletion bajo el arco utilizando __bridge

que reproduzca un sonido sistema y añadir la SoundCompletion-Devolución de llamada a ella de este modo:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Mientras que « uno mismo »es una sencilla NSObject

En la devolución de llamada finalización trato de llamar a la rutina de juego nuevo:

he tenido que añadir la __bridge_transfer y el _ _bridge_retenido a los lanzamientos; de lo contrario, recibo errores, bloqueos u otro comportamiento inesperado.

Pero todo esto no funciona a pesar de todo eso.

Guardo los sonidos para tocar en un NSMutableArray, agarro la primera entrada de la matriz y la reproduzco, agrego la terminación del sonido y espero que suceda algo. Pero - con todo lo que retiene de transferencia de materia, el NSMutableArray está vacío en la segunda llamada ...

Aquí está el código:

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] - responder a mi propia pregunta:

Siempre es bueno descubrirlo por mi cuenta :)

Resulta que ya casi estaba allí.

La llamada para establecer la devolución de llamada es el siguiente:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Luego, en la devolución de llamada de funciones, hago esto:

myClass *theClass = (__bridge myClass *)myself; 
    CFRelease(myself); 
    [theClass playNextSound]; // The routine that plays the sounds 

y funciona ...

+0

Gracias por la respuesta, realmente me ayudó! Sin embargo, casi lo perdí, ya que la pregunta parece no contestada: ¿puedes agregar una respuesta a tu pregunta? ¿O puedo agregarlo apuntando a tus comentarios? Saludos v de todos modos;] – davidfrancis

Respuesta

8

No pude responder mi propia pregunta porque era demasiado rápido para StackOverflow, así que para completar esto, agregué la respuesta nuevamente :)

Resulta que ya casi estaba allí.

La llamada para establecer la devolución de llamada es el siguiente:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Luego, en la devolución de llamada de funciones, hago esto:

myClass *theClass = (__bridge myClass *)myself; 
CFRelease(myself); 
[theClass playNextSound]; // The routine that plays the sounds 

y funciona ...

+0

¿Hay alguna razón por la que no puedas usar __bridge? Obtengo bloqueos accediendo al objeto después con este método. –

+0

Funciona para mí. @AlastairStuart Creo que ese punto es cuando pasas el objeto a 'AudioServicesAddSystemSoundCompletion' que haces __bridge_retained que aumentará retainCount en 1. __bridge garantiza que no habrá transferencia de propiedad, por lo que el contador permanecerá igual en la devolución de llamada. CFRelease luego disminuirá retainCount en 1 y finalmente eliminará el objeto. – Andy

+0

¿No estaría CFRelease en 'theClass' en lugar de 'myself'? – shim

4

Para cualquiera que necesite un poco de ayuda extra ... Obtuve la respuesta de Swissdude para trabajar en un controlador de vista común como tal:

nota: (no se puede utilizar CFRelease (yo))

.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... 
Cuestiones relacionadas