AVAudioPlayer无法播放任何声音。

63

我正在开发一个需要使用AVFoundation框架播放一些声音的iOS应用程序。Xcode 4中的工作区结构包含两个项目:

  • 工作区
    • 应用程序本身(主要项目)
    • 一个实用库

在构建实用库后,它会生成一个静态库,该库将作为框架在主应用程序中使用。

因此,当尝试使用下面的代码在主应用程序中播放声音时,它按预期工作。

NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *path = [NSString stringWithFormat:@"%@/sound.mp3", resourcePath];

NSURL *url = [NSURL fileURLWithPath:path];
NSError *error = nil;

AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url
                                                                    error:&error];
[audioPlayer play];
与之相反的是,当尝试使用与上述相同的代码在实用程序库中播放完全相同的声音(或任何其他声音)时,根本不会播放任何声音,尽管错误为 nil 并且 audioPlayer 属性值是正确的(通道数,持续时间)。
我已经确保AVFoundation框架在两个项目中都存在。
此外,我的类使用AVAudioPlayerDelegate协议并实现了这两个方法:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error;

尝试播放声音后,没有调用这些方法之一。

如果我使用 AudioToolbox 框架,那么它会播放声音。但是出于几个原因,我希望使用 AVFoundation

有什么想法吗?我是否遗漏了 AVFoundation 的某些东西?这可能与从静态库中使用 AVAudioPlayer 有关吗?

提前感谢。


你能告诉我们错误变量输出了什么吗?就是这里的 AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; 中的那个。 - Jesse Black
@Maudicus,就像我说的那样,在播放声音后错误为nil。我找到了解决方案,它与我没有提及和考虑到的某些事情有关:我正在使用ARC编译。ARC插入了一个释放调用到音频播放器中,因此在离开创建它的方法后立即被释放,如这里所解释的那样。 - msoler
很抱歉我复制了你的代码并且它运行成功了。我没有注意到你关于错误为nil的声明。我很高兴问题已经解决了。 - Jesse Black
10个回答

170

我找到了解决方案,与我之前没有提及和考虑的内容有关:我正在使用自动引用计数(ARC)进行编译。

ARC向音频播放器插入一个释放调用,因此它在离开创建它的方法后立即被释放。这与 AVAudioPlayer 无关,而是与 ARC 有关。

为了解决这个问题,我只需为处理声音的类创建一个 AVAudioPlayer 属性,以便它不再被 ARC 释放。嗯,至少,在该类的实例被释放之前它不会被释放。

有关 ARC 的更多信息,请参阅自动引用计数:零弱引用,其中详细介绍了我遇到此问题的原因。


1
这种情况之前曾经发生过,当时与 AVAudioPlayer 没有任何关系,甚至在遇到 AVAudioPlayer 不可思议地无法播放声音的问题时,我也忘记了这个解决方案。好在我们要记住 ARC! - Tim Arnold
我知道这是一个老话题,但与其创建一个新问题询问同样的事情,您能否请像我五岁一样向我解释这意味着什么?我制作了一个iOS应用程序,我有一个提交按钮,当计算完成时,它会播放声音。我首先制作了一个简化版本作为OS X应用程序,它运行良好,但作为iOS应用程序,使用AVAudioPlayer而不是NSSound或其他东西,它不起作用,并且50%的时间会导致应用程序崩溃。 - Jonathan Weinraub
@JonathanWeinraub 抱歉,没有看到任何代码很难判断。你的崩溃和AVAudioPlayer问题可能与多种原因有关。 - msoler
非常感谢。我也遇到了同样的问题。 - deltaaruna
我需要多个玩家,所以与其使用多个属性,我创建了一个NSMutableDictionary,并将玩家与key作为lastPathComponent存储。 - Scott Fister
这是正确的。因为它异步播放声音,所以在声音播放之前,您的AVAudioPlayer对象已经丢失了。 - Aggressor

39

是的,绝对没错;这也是我的代码出现问题的原因。

我引入了一个属性:

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

这让一切都顺利地解决了。


1
你还在使用alloc initWithContentsOfUrl吗? - Ethan Parker

31

使用这个,它肯定会起作用...

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];

NSURL *url = [NSURL fileURLWithPath:@"path of the sound file :)"];
_player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[_player setDelegate:self];
[_player prepareToPlay];
[_player play];

3
AVAudioSession 对我非常有效。如果没有它,我只能在模拟器中播放声音而不能在设备上播放。 - Bojan Dimovski
1
感谢您调用 prepareToPlay - Alexmelyon
这对我帮助很大! - Tom Kincaid

20

你是否配置了AVAudioSession?

我曾经遇到过类似的问题,通过以下方式解决:

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:NULL];
或者
[audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];

希望能对你有所帮助。


我已经回答了Madicus关于这个问题,但我没有直接将其发布为我的问题的答案,因为我无法这样做(可能是因为StackOverflow在最初的几个小时/天不允许自动回答)。现在官方答案已经在这里了。 :) 无论如何,还是谢谢! - msoler
将其添加到您的viewDidLoad方法中。在录制后但播放之前设置会话不起作用。此外,如果没有设置会话,则在模拟器上可以工作但在设备上无法工作。 - Chase Roberts

6

即使在类范围内声音播放器变量已声明,它也不能播放。

至少在iOS 10 iPhone 5c物理设备上是这样的。

play() 的结果为 true,因此似乎没有发生错误。

必须添加以下内容(Swift 3、4),现在才能正确播放声音。

let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSessionCategoryPlayback)

1

0

我曾经遇到过同样的问题。我通过在.h文件中添加以下行来解决它:

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

在 .m 文件中:

NSError *error;
NSString *soundFilePath = [NSString stringWithFormat:@"%@/dancepechance.mp3",
                               [[NSBundle mainBundle] resourcePath]];
    NSURL *url = [NSURL fileURLWithPath:soundFilePath];
    self.audioPlayer = [[AVAudioPlayer alloc]
                                  initWithContentsOfURL:url
                                  error:&error];
    NSLog(@"Error %@",error);
    [self.audioPlayer prepareToPlay];
    [self.audioPlayer play];

0

您可以使用来自 AVKitAVPlayerViewController 来处理音频和视频。这里提供了 Swift 和 Objective-C 代码 链接


0

对我来说,这个做了它的工作。

do {
     try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
    } catch {
        assertionFailure("Failed to configure `AVAAudioSession`: \(error.localizedDescription)")
    }

-1
请在页面上停留一段时间,我曾经遇到过同样的问题,并使用 sleep 函数解决了它。
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
                                             pathForResource:@"sounds-1027-are-you-kidding"
                                             ofType:@"mp3"]];
        AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc]
                                      initWithContentsOfURL:url
                                      error:nil];
        [audioPlayer play];
        sleep(2);


3
尽量避免使用sleepdispatch_after是更好的替代方案。 - Bojan Dimovski
这段代码将使audioPlayer实例保持活动状态2秒钟。 这使得代码依赖于音频文件的长度,并且对于任何音频文件都无法工作。此外,它将挂起调用线程2秒钟,在大多数情况下,这不是期望的行为。 - msoler
这是一个粗糙但富有创意的解决方案,它有其优缺点。在我的情况下,我正在尝试向用户提示新信息。在播放警报声时将应用程序中所有活动冻结一秒钟实际上是引起用户注意的好方法。因此,这实际上符合我的需求。它不应该被投票否定。 - Joe C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接