【问题标题】:Unable to play mp3 file in iPhone game无法在 iPhone 游戏中播放 mp3 文件
【发布时间】:2013-08-27 10:49:08
【问题描述】:

我想在我的游戏中播放背景音乐(理想情况下我希望它淡入/淡出,但我希望它先播放)

我查看了关于 SO 的各种答案,我的代码看起来似乎正确,但由于某种原因文件没有播放,实际上它在 AVAudioPlayer *player 行上崩溃(没有有用的输出)。如果我继续,它会在[player play] 行再次崩溃,但error0

再次更新...

GameViewController.h

@property (nonatomic, retain) AVAudioPlayer *player;

GameViewController.m

@synthesize player; // the player object

ViewDidLoad:

NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"bgtrack" ofType: @"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error: nil]; // breaks here
[player prepareToPlay];

我包括

#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

更新:

根据 cmets,我尝试直接从 Apple 开发中心复制/粘贴代码。我正在使用最新的 XCode 4 和 iOS 6.1 模拟器。

当它崩溃时,我没有得到任何信息栏表明它遇到了断点。该文件包含在包中

【问题讨论】:

  • 您是否在捆绑包中包含了音频文件?
  • 是的,但仍然没有快乐? ://
  • 详细说明问题:什么设备?还是模拟器? ios版?在 github 上分享资源?您尝试过 Apple 的示例代码吗?
  • 已更新。尝试了你所有的建议,但仍然没有进一步:/
  • 所以只是模拟器不玩了?你在真机上试过吗?原因是模拟器不播放声音存在已知问题。 stackoverflow.com/questions/302399/…

标签: iphone ios objective-c avaudioplayer


【解决方案1】:

您需要存储对 player 的强引用(可能在您的视图控制器的 ivar 或其他东西中)。如果您只是将该代码放入-viewDidLoad 方法或其他东西中而没有对其进行强引用,则会发生的情况是播放器将在有机会开始播放之前被释放。例如:

@interface MyViewController : UIViewController

@end

@implementation MyViewController
{
    AVAudioPlayer* player;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"YourMP3FileName" ofType:@"mp3"];
    NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
    NSError *error;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:&error];
    player.numberOfLoops = -1; //infinite
    player.currentTime = 139;// 2:19;

    [player play];
}

@end

这对我来说很好,但如果 player 不是视图控制器的 ivar,我就听不到声音。

另外,我创建了以下类,它将作为“一次性”AVAudioPlayer 工作。对于numberOfLoops 为-1(无限)的情况,这显然会出现问题,因为这意味着它永远不会停止播放或消失,但在您想要播放一次然后消失的情况下,它可能会使事情变得稍微容易一些无需保留对它的引用。

OneShotAVAudioPlayer.h

#import <AVFoundation/AVFoundation.h>

@interface OneShotAVAudioPlayer : AVAudioPlayer
@end

OneShotAVAudioPlayer.m

#import "OneShotAVAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import <objc/runtime.h>

@interface OneShotAVAudioPlayer () <AVAudioPlayerDelegate>
@property(weak) id<AVAudioPlayerDelegate> p_exogenousDelegate;
@end

@implementation OneShotAVAudioPlayer

static void * const OneShotAVAudioPlayerKey = (void*)&OneShotAVAudioPlayerKey;

- (id)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError
{
    if (self = [super initWithContentsOfURL:url error:outError])
    {
        // Retain ourself
        objc_setAssociatedObject(self, OneShotAVAudioPlayerKey, self, OBJC_ASSOCIATION_RETAIN);
        [super setDelegate: self];
    }
    return self;
}

- (id)initWithData:(NSData *)data error:(NSError **)outError;
{
    if (self = [super initWithData:data error:outError])
    {
                    // Retain ourself
        objc_setAssociatedObject(self, OneShotAVAudioPlayerKey, self, OBJC_ASSOCIATION_RETAIN);
        [super setDelegate: self];
    }
    return self;
}

- (void)setDelegate:(id<AVAudioPlayerDelegate>)delegate
{
    self.p_exogenousDelegate = delegate;
}

- (id<AVAudioPlayerDelegate>)delegate
{
    return self.p_exogenousDelegate;
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    @try
    {
        if ([self.p_exogenousDelegate respondsToSelector: _cmd])
            [self.p_exogenousDelegate audioPlayerDidFinishPlaying:player successfully:flag];
    }
    @finally
    {
        // Make a strong ref so we stay alive through the scope of this function
        typeof(self) keepAlive = self;
        // Give up the self retain
        objc_setAssociatedObject(keepAlive, OneShotAVAudioPlayerKey, nil, OBJC_ASSOCIATION_RETAIN);
        // Push in the "real" (outside) delegate, cause our job is done here.
        [super setDelegate: self.p_exogenousDelegate];
    }
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
    @try
    {
        if ([self.p_exogenousDelegate respondsToSelector: _cmd])
            [self.p_exogenousDelegate audioPlayerDecodeErrorDidOccur:player error:error];
    }
    @finally
    {
        // Make a strong ref so we stay alive through the scope of this function
        typeof(self) keepAlive = self;
        // Give up the self retain
        objc_setAssociatedObject(keepAlive, OneShotAVAudioPlayerKey, nil, OBJC_ASSOCIATION_RETAIN);
        // Push in the "real" (outside) delegate, cause our job is done here.
        [super setDelegate: self.p_exogenousDelegate];
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    BOOL retVal = [super respondsToSelector: aSelector];
    if (!retVal)
    {
        struct objc_method_description method = protocol_getMethodDescription(@protocol(AVAudioPlayerDelegate), aSelector, YES, YES);
        if (method.name)
        {
            retVal = [self.p_exogenousDelegate respondsToSelector: aSelector];
        }
    }
    return retVal;
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    id retVal = [super forwardingTargetForSelector:aSelector];
    if (!retVal)
    {
        struct objc_method_description method = protocol_getMethodDescription(@protocol(AVAudioPlayerDelegate), aSelector, YES, YES);
        if (method.name && [self.p_exogenousDelegate respondsToSelector: aSelector])
        {
            retVal = self.p_exogenousDelegate;
        }
    }
    return retVal;
}

- (void)setNumberOfLoops:(NSInteger)numberOfLoops
{
    if (numberOfLoops < 0)
    {
        NSLog(@"Warning! You have set an infinite loop count for an instance of %@ (%p). This means the instance will effectively be leaked.", NSStringFromClass([self class]), self);
    }
    [super setNumberOfLoops: numberOfLoops];
}

@end

发帖here as a gist

【讨论】:

  • 谢谢,这是一个很好的建议,但是当我执行您的建议时它仍然崩溃。我似乎没有得到任何输出或它发生的原因?
  • 异常/崩溃的回溯是什么? (只需编辑问题——不可能在 SO 评论中阅读回溯)
  • 我没有得到奇怪的异常信息,它只是停止执行,没有更多信息。
【解决方案2】:

将玩家 ivar 提升为强属性,如果玩家为零,则记录 [error description]

如果它崩溃了,那肯定是错误的。是否添加了异常断点?

【讨论】:

  • 我目前已经在@interface 中定义了它,就像@property (strong, nonatomic) AVAudioPlayer *BackgroundMusicPlayer; 一样,但仍然不起作用。没有错误信息:/
  • 我已经为所有异常设置了一个断点,但我没有得到任何关于实际发生的信息:/
  • 正如我在上面评论的那样,发布您的代码,尝试示例代码,更改 mp3,检查音量,做一些功课。
猜你喜欢
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多