iPhone: AVAudioPlayer不支持的文件类型

27
我的应用程序从服务器下载一个mp3文件并播放给用户听。该文件的比特率为64 kbps(如果我理解正确,这个比特率在iPhone上是可以接受的范围内)。我已经查阅了数十个网站,它们都建议我按照以下步骤执行:
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://.../file.mp3"]];
NSError *e = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error&e];
[player setDelegate:self];

当我运行代码时,播放器返回空值并出现以下错误:
2011-02-04 10:44:46.176 MyApp[6052:207] Error loading audio: Error Domain=NSOSStatusErrorDomain Code=1954115647 "The operation couldn’t be completed. (OSStatus error 1954115647.)"
2011-02-04 10:44:49.647 MyApp[6052:207] unsupported file type

我已检查了该文件并知道它可以正常工作。在Windows Media Player和Mac上的Quicktime中播放没有问题。 我还将文件上传到iPhone模拟器中,完全没有问题就能播放。这个文件没问题,但由于某种原因AVAudioPlayer不喜欢它。
是否有什么需要改变的?NSData是否有某种设置指定文件类型?有人有任何想法吗?
4个回答

32

我终于找到了解决这个问题的方法!不是使用NSData对象来初始化音频播放器,而是将文件保存到Documents文件夹中,然后使用文件URL来初始化播放器。

//download file and play from disk
NSData *audioData = [NSData dataWithContentsOfURL:someURL];
NSString *docDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:@"%@/%@.mp3", docDirPath , fileName];
[audioData writeToFile:filePath atomically:YES];

NSError *error;
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
if (player == nil) {
    NSLog(@"AudioPlayer did not load properly: %@", [error description]);
} else {
    [player play];
}

当应用程序完成对文件的操作后,可以将其删除。希望这不仅能帮到我!


14

我们也遇到了类似的问题 - 我们必须先将文件写入磁盘。最终我发现下载的数据在开头有一些额外的空字节。当使用 initWithContentsOfURL 从磁盘读取时,AVAudioPlayer 知道如何处理这个问题,但当使用 initWithData 从 NSData 加载时,它就不知道该怎么处理。修剪这些字节后问题得到解决。


哦,那很有趣。也许应该将其作为错误提交给苹果?最终我还是选择了保存的文件,因为它更符合我们试图做的事情。谢谢你的提示! - mtmurdock
2
你是如何确定要修剪哪些字节的?你是怎么做到的? - typeoneerror
3
@typeoneerror说:“我拿了一个特定的文件,在十六进制编辑器中查看它,并阅读mp3规范,以了解头部是如何定义的。这时我注意到了矛盾之处。虽然不是很通用,但你可以以编程方式查看NSData的前几个字节,并跳过其中任何为0的字节。” - Don
@Don,我在编辑器中查看并注意到大多数的第一个字节都是0,但不是全部。我如何知道什么时候可以安全地跳过? - user592419
@user592419 看一下http://www.datavoyage.com/mpgscript/mpeghdr.htm,它描述了mp3帧,第一个帧应该有前11个字节设置。我不是音频专家,而且已经有一段时间没有看过这个了,但也许可以尝试查找第一个帧并忽略它之前的所有内容。我想知道这是否有效。 - Don
@Don,我进一步研究了这个问题,实际上比我想象的更加复杂。你能否看一下https://dev59.com/3XHYa4cB1Zd3GeqPLGqg? - user592419

11

iOS 7起AVAudioPlayer有了新的初始化方法。

NSError *error;
[[AVAudioPlayer alloc] initWithData:soundData fileTypeHint:AVFileTypeMPEGLayer3 error:&error]

支持的UTI

NSString *const AVFileType3GPP;
NSString *const AVFileType3GPP2;
NSString *const AVFileTypeAIFC;
NSString *const AVFileTypeAIFF;
NSString *const AVFileTypeAMR;
NSString *const AVFileTypeAC3;
NSString *const AVFileTypeMPEGLayer3;
NSString *const AVFileTypeSunAU;
NSString *const AVFileTypeCoreAudioFormat;
NSString *const AVFileTypeAppleM4V;
NSString *const AVFileTypeMPEG4;
NSString *const AVFileTypeAppleM4A;
NSString *const AVFileTypeQuickTimeMovie;
NSString *const AVFileTypeWAVE;

谢谢您,您的答复非常帮助我! - Alexander Khitev
非常棒的答案,谢谢!在某些方面似乎是iOS 9的救援解决方案... - Resty

1
如果您的产品名称包含空格,则会收到错误消息。
我的项目产品名称是:Panorama 1453 TR。由于initWithContentsOfURL方法无法获取文件路径,因此它无法工作。您可以在NSURL *fileURL =处设置断点。一步一步进行,您可以查看fileURL中的数据。
我将其更改为Panorama1453TR,然后它可以工作。

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