ARC下使用__bridge的AudioServicesAddSystemSoundCompletion

发布于 2024-12-29 21:24:36 字数 1964 浏览 3 评论 0原文

我希望标题不会太误导...:)

我播放系统声音并向其中添加 SoundCompletion-Callback,如下所示:

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

而“self”是一个简单的 NSObject

在完成回调中我尝试调用播放例程再次:

我必须将 __bridge_transfer 和 __bridge_retained 添加到强制转换中,否则我会遇到错误、崩溃或其他意外行为。

但尽管如此,整件事还是行不通。

我将要播放的声音存储在 NSMutableArray 中,抓取数组的第一个条目并播放它,添加声音完成并希望事情发生。 但是 - 有了所有保留传输的东西, NSMutableArray 在第二次调用时是空的......

这是代码:

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);
    }
}

[编辑] - 回答我自己的问题:

总是很高兴自己找到它:)

结果,我就快到了。

设置回调的调用如下:

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

然后,在回调函数中,我执行以下操作:

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

它有效......

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

帅冕 2025-01-05 21:24:36

我无法回答我自己的问题,因为我对 StackOverflow 来说太快了 - 所以为了完成这个任务,我再次添加了答案:)

事实证明,我就快到了。

设置回调的调用如下:

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

然后,在回调函数中,我执行以下操作:

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

它有效......

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

爱*していゐ 2025-01-05 21:24:36

对于任何需要一点额外帮助的人......
我得到了 Swissdude 在通用视图控制器中工作的答案,如下所示:

注意:(你不能使用 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...

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...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文