iOS开发之音频解析第三方框架介绍

简介:
最近在做iOS音频相关的App,在做之前选择了三种解决方案。第一种方案是使用苹果自带的音频解析类AVPlayer,虽然AVPlayer也可以播放音频。但是要做类似于QQ音乐这样的App,使用AVPlayer就显得无能为力了。第二种解决方案使用第三方音频解析框架AudioStreamer,这是一个老外写的音频解析框架。其中包括本地和网络的音频数据解析。核心文件 AudioPlayer.h 和 AudioPlayer.m。这套框架使用的是CFNetwork和CoreAudio封装的。其集成了进度拖动,断点续传等功能。使用这个框架做类似于QQ音乐,酷狗音乐等音频类App完全可以胜任。第三种解决方案使用第三方音频解析框架FreeStream,这个也是老外写的一个音频解析框架。对于这个框架而言,它是使用C++进行音频的解析。虽然是C++的Objc调用,却没有额外的性能消耗。这款音频解析框架主要特点是性能优越,内存占用小,是一个不错的选择。但由于这个框架要想做更多功能就要开发者自己去修改这个框架来满足自己的项目需求。下载地址: http://code4app.com/ios/FreeStreamer/52afca18cb7e84eb788b4690
    所以我综上对比选择了第二种解决方案,使用了AudioStreamer。AudioStreamer虽然作者自己把网络数据解析和本地数据解析封装好了,但我们实际上并不需要。我们可以根据自己的需求写自己的网络数据解析。关于AudioStream源码的分析,由于个人能力有限,并不能完全看懂。有兴趣的读者可以去研究一下源码。AudioStreamer下载地址: http://code4app.com/ios/Audjusta ... c55cb7e8450688b5158
    下面根据我自己的经验说一下这个框架在项目中该如何使用。也许我们并非一开始就去研究框架源码。这样是不明智的,就这个框架来说,它涉及到了CoreAudio的知识。首先你要非常了解苹果的音频队列服务,对CFNetwork也要很了解。
    一般来说我们使用第三方框架都会看.h中给我们所提供的接口。能满足需求就无需修改,不能满足则在进行扩展。下面我们一起看看AudioPlayer.h中给我们提供了哪些接口。
AudioPlayer.h
1.缓冲设置
缓冲数据的大小设置  此处设置的是2M,在iPhone4上测试会发出内存溢出的警告, 故这个值不宜设置的太大,一般是1 * 1024 或者 2 * 1024。设置这个缓冲大小,可以实现音频的断点续传的功能。

#define AudioPlayerDefaultNumberOfAudioQueueBuffers (2 * 1024)


2.播放网络状态
typedef enum
{
    AudioPlayerInternalStateInitialised = 0, 
    AudioPlayerInternalStateRunning = 1, 
    AudioPlayerInternalStatePlaying = (1 << 1) | AudioPlayerInternalStateRunning, // 数据加载成功,进入音频播放状态
    AudioPlayerInternalStateStartingThread = (1 << 2) | AudioPlayerInternalStateRunning,   // 开始进行音频的播放
    AudioPlayerInternalStateWaitingForData = (1 << 3) | AudioPlayerInternalStateRunning, // 等待数据的加载,缓冲数据中
    AudioPlayerInternalStateWaitingForQueueToStart = (1 << 4) | AudioPlayerInternalStateRunning, // 等待音频队列开始播放
    AudioPlayerInternalStatePaused = (1 << 5) | AudioPlayerInternalStateRunning, //  暂停音频的播放,数据停止加载
    AudioPlayerInternalStateRebuffering = (1 << 6) | AudioPlayerInternalStateRunning, // 开始数据的重新加载
    AudioPlayerInternalStateStopping = (1 << 7), // 一个音频数据加载完毕,停止播放。
    AudioPlayerInternalStateStopped = (1 << 8), // 数据加载完成,播放状态为停止状态
    AudioPlayerInternalStateDisposed = (1 << 9), // 数据加载失败,一般是无效数据
    AudioPlayerInternalStateError = (1 << 10)    //   数据加载出错,一般是网络错误。
}
AudioPlayerInternalState;

3. 播放器的播放状态
typedef enum
{
    AudioPlayerStateReady, // 播放器已经准备好
    AudioPlayerStateRunning = 1, // 播放器正在运行中
    AudioPlayerStatePlaying = (1 << 1) | AudioPlayerStateRunning, // 播放器开始播放音频
    AudioPlayerStatePaused = (1 << 2) | AudioPlayerStateRunning,
    AudioPlayerStateStopped = (1 << 3), // 暂停播放和停止播放
    AudioPlayerStateError = (1 << 4), // 播放音频错误,一般是网络数据错误
    AudioPlayerStateDisposed = (1 << 5) // 播放错误,一般是由无效数据导致的错误
}
AudioPlayerState;

4. 监听播放器播放停止的原因
typedef enum
{
    AudioPlayerStopReasonNoStop = 0, // 未知原因停止
    AudioPlayerStopReasonEof, // 播放到文件末尾导致的停止
    AudioPlayerStopReasonUserAction,// 用户操作导致的停止
    AudioPlayerStopReasonUserActionFlushStop // 用户刷新播放导致的停止
}
AudioPlayerStopReason;

5. 播放状态码
typedef enum
{
    AudioPlayerErrorNone = 0, // 一般错误
    AudioPlayerErrorDataSource, // 数据错误
    AudioPlayerErrorStreamParseBytesFailed, // 解析数据流失败
    AudioPlayerErrorDataNotFound, // 数据没有找到
    AudioPlayerErrorQueueStartFailed, // 音频队列准备失败
    AudioPlayerErrorQueuePauseFailed, // 音频队列暂停失败
    AudioPlayerErrorUnknownBuffer,    // 不知名的数据缓冲
    AudioPlayerErrorQueueStopFailed,  // 音频队列停止失败
    AudioPlayerErrorOther       // 其他错误
}
AudioPlayerErrorCode;

@class AudioPlayer;

// 播放代理
@protocol AudioPlayerDelegate <NSObject>
// 播放状态f发生变化的调用
-(void) audioPlayer:(AudioPlayer*)audioPlayer stateChanged:(AudioPlayerState)state;
// 播放出错的调用
-(void) audioPlayer:(AudioPlayer*)audioPlayer didEncounterError:(AudioPlayerErrorCode)errorCode;
// 开始播放 得到itemId
-(void) audioPlayer:(AudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId;
// 缓冲完成的调用
-(void) audioPlayer:(AudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId;
// 已经播放结束的回调
-(void) audioPlayer:(AudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(AudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration;

@optional

-(void) audioPlayer:(AudioPlayer*)audioPlayer logInfo:(NSString*)line;
// 播放网络变化的回调
-(void) audioPlayer:(AudioPlayer*)audioPlayer internalStateChanged:(AudioPlayerInternalState)state;

// 取消播放
-(void) audioPlayer:(AudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems;
@end

@class QueueEntry;

typedef struct
{
    AudioQueueBufferRef ref; // 音频队列缓冲引用
    int bufferIndex;
}
AudioQueueBufferRefLookupEntry;

@interface AudioPlayer : NSObject<DataSourceDelegate>
{
@private
    UInt8* readBuffer;
    int readBufferSize;
    
    NSOperationQueue* fastApiQueue;
    
    QueueEntry* currentlyPlayingEntry;
    QueueEntry* currentlyReadingEntry;
    
    NSMutableArray* upcomingQueue;
    NSMutableArray* bufferingQueue;
    
    AudioQueueBufferRef* audioQueueBuffer;
    AudioQueueBufferRefLookupEntry* audioQueueBufferLookup;
    unsigned int audioQueueBufferRefLookupCount;
    unsigned int audioQueueBufferCount;
    AudioStreamPacketDescription* packetDescs;
    bool* bufferUsed;
    int numberOfBuffersUsed;
    
    AudioQueueRef audioQueue;
    AudioStreamBasicDescription currentAudioStreamBasicDescription;
    
    NSThread* playbackThread;
    NSRunLoop* playbackThreadRunLoop;
    NSConditionLock* threadFinishedCondLock;
    
    AudioFileStreamID audioFileStream;
    
    BOOL discontinuous;
    
    int bytesFilled;
    int packetsFilled;
    
    int fillBufferIndex;
    
    UIBackgroundTaskIdentifier backgroundTaskId;
    
    AudioPlayerErrorCode errorCode;
    AudioPlayerStopReason stopReason;
    
    int currentlyPlayingLock;
    pthread_mutex_t playerMutex;
    pthread_mutex_t queueBuffersMutex;
    pthread_cond_t queueBufferReadyCondition;
    
    volatile BOOL waiting;
    volatile BOOL disposeWasRequested;
    volatile BOOL seekToTimeWasRequested;
    volatile BOOL newFileToPlay;
    volatile double requestedSeekTime;
    volatile BOOL audioQueueFlushing;
    volatile SInt64 audioPacketsReadCount;
    volatile SInt64 audioPacketsPlayedCount;
    
    BOOL meteringEnabled;
    AudioQueueLevelMeterState* levelMeterState;
    NSInteger numberOfChannels;
}

// 音频的总时间  这个时间是由播放器自己计算出来的。
@property (readonly) double duration;
// 音频当前播放的进度
@property (readonly) double progress;
// 播放器的状态
@property (readwrite) AudioPlayerState state;
// 停止播放时的原因
@property (readonly) AudioPlayerStopReason stopReason;
@property (readwrite, unsafe_unretained) id<AudioPlayerDelegate> delegate;
@property (readwrite) BOOL meteringEnabled;

// 对外接口
-(id) init;

-(id) initWithNumberOfAudioQueueBuffers:(int)numberOfAudioQueueBuffers andReadBufferSize:(int)readBufferSizeIn;

// 从URL地址获取数据源
-(DataSource*) dataSourceFromURL:(NSURL*)url;

// 播放指定URL的资源
-(void) play:(NSURL*)url;

-(void) queueDataSource:(DataSource*)dataSource withQueueItemId:(NSObject*)queueItemId;
// 设置数据源
-(void) setDataSource:(DataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId;
// 设置播放进度
-(void) seekToTime:(double)value;

// 暂停播放
-(void) pause;
// 唤醒播放
-(void) resume;
// 停止播放
-(void) stop;
// 刷新停止
-(void) flushStop;

-(void) mute;
-(void) unmute;
-(void) dispose;
// 得到当前播放id
-(NSObject*) currentlyPlayingQueueItemId;
// 刷新
-(void) updateMeters;
-(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber;
-(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber;

@end

今天先写到这,以后有时间可以研究一下AudioPlayer.m中的具体实现。
目录
相关文章
|
7天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
7天前
|
存储 Swift iOS开发
使用Swift开发一个简单的iOS应用的详细步骤。
使用Swift开发iOS应用的步骤包括:创建Xcode项目,设计界面(Storyboard或代码),定义数据模型,实现业务逻辑,连接界面和逻辑,处理数据存储(如Core Data),添加网络请求(必要时),调试与测试,根据测试结果优化改进,最后提交至App Store或其它平台发布。
21 0
|
7天前
|
安全 Swift iOS开发
【Swift 开发专栏】Swift 与 UIKit:构建 iOS 应用界面
【4月更文挑战第30天】本文探讨了Swift和UIKit在构建iOS应用界面的关键技术和实践方法。Swift的简洁语法、类型安全和高效编程模型,加上与UIKit的紧密集成,使开发者能便捷地创建用户界面。UIKit提供视图、控制器、布局、动画和事件处理等功能,支持灵活的界面设计。实践中,遵循设计原则,合理组织视图层次,运用布局和动画,以及实现响应式设计,能提升界面质量和用户体验。文章通过登录、列表和详情界面的实际案例展示了Swift与UIKit的结合应用。
|
7天前
|
存储 安全 Swift
【Swift 开发专栏】使用 Swift 开发一个简单的 iOS 应用
【4月更文挑战第30天】本文介绍了使用 Swift 开发简单 iOS 待办事项应用的步骤。首先,阐述了 iOS 开发的吸引力及 Swift 语言的优势。接着,详细说明了应用的需求和设计,包括添加、查看和删除待办事项的功能。开发步骤包括创建项目、界面搭建、数据存储、功能实现,并提供了相关代码示例。最后,强调了实际开发中需注意的细节和优化,旨在帮助初学者掌握 Swift 和 iOS 开发基础。
|
15天前
|
iOS开发 开发者 UED
利用SwiftUI构建动态列表:iOS开发的新范式
【4月更文挑战第22天】在本文中,我们将深入探讨如何使用SwiftUI来创建动态列表。SwiftUI是苹果最新推出的用户界面工具集,它允许开发者以声明式的方式描述用户界面,从而简化了代码的复杂性。我们将通过具体的代码实例,展示如何利用SwiftUI的List和ForEach视图来创建动态列表,并讨论其在实际开发中的应用。
15 2
|
17天前
|
设计模式 监控 前端开发
深入解析iOS中的并发编程模式
【4月更文挑战第20天】 在当今移动应用开发中,提升程序的响应性和性能是至关重要的。特别是在iOS平台上,合理利用多线程和并发编程技术可以显著改善用户体验。本文旨在探讨几种在iOS开发中广泛使用的并发编程模式,包括线程、GCD(Grand Central Dispatch)、Operation Queues以及异步设计模式等。通过对这些技术的深入分析与比较,我们不仅将揭示各自的优势和潜在缺陷,还会展示如何结合它们以解决实际开发中遇到的并发挑战。
|
19天前
|
API 定位技术 iOS开发
IOS开发基础知识:什么是 Cocoa Touch?它在 iOS 开发中的作用是什么?
【4月更文挑战第18天】**Cocoa Touch** 是iOS和Mac OS X应用的核心框架,包含面向对象库、运行时系统和触摸优化工具。它提供Mac验证的开发模式,强调触控接口和性能,涵盖3D图形、音频、网络及设备访问API,如相机和GPS。是构建高效iOS应用的基础,对开发者至关重要。
19 0
|
27天前
|
搜索推荐 iOS开发 开发者
利用SwiftUI构建动态用户界面:iOS开发新篇章
【4月更文挑战第10天】在移动应用的世界中,流畅的用户体验和引人注目的界面设计是至关重要的。随着SwiftUI的推出,iOS开发者被赋予了创造高度动态且响应式界面的能力。本文将深入探讨如何利用SwiftUI的强大特性来实现一个动态用户界面,包括其声明性语法、状态绑定以及视图更新机制。我们将通过一个天气应用案例,了解如何有效地运用这些工具来提升应用的交互性和视觉吸引力。
|
20小时前
|
分布式计算 Java API
Java8 Lambda实现源码解析
Java8的lambda应该大家都比较熟悉了,本文主要从源码层面探讨一下lambda的设计和实现。
|
1天前
|
算法 Java Go
ArrayList源码解析
ArrayList源码解析
7 1

推荐镜像

更多