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中的具体实现。
目录
相关文章
|
26天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
57 1
|
2天前
|
SQL 存储 关系型数据库
数据库开发之图形化工具以及表操作的详细解析
数据库开发之图形化工具以及表操作的详细解析
18 0
|
2天前
|
SQL 存储 关系型数据库
数据库开发之mysql前言以及详细解析
数据库开发之mysql前言以及详细解析
11 0
|
11天前
|
SQL API 数据库
Python中的SQLAlchemy框架:深度解析与实战应用
【4月更文挑战第13天】在Python的众多ORM(对象关系映射)框架中,SQLAlchemy以其功能强大、灵活性和易扩展性脱颖而出,成为许多开发者首选的数据库操作工具。本文将深入探讨SQLAlchemy的核心概念、功能特点以及实战应用,帮助读者更好地理解和使用这一框架。
|
12天前
|
机器学习/深度学习 分布式计算 BI
Flink实时流处理框架原理与应用:面试经验与必备知识点解析
【4月更文挑战第9天】本文详尽探讨了Flink实时流处理框架的原理,包括运行时架构、数据流模型、状态管理和容错机制、资源调度与优化以及与外部系统的集成。此外,还介绍了Flink在实时数据管道、分析、数仓与BI、机器学习等领域的应用实践。同时,文章提供了面试经验与常见问题解析,如Flink与其他系统的对比、实际项目挑战及解决方案,并展望了Flink的未来发展趋势。附带Java DataStream API代码样例,为学习和面试准备提供了实用素材。
34 0
|
13天前
|
监控 测试技术 Android开发
移动应用与系统:开发与操作系统的深度解析
【4月更文挑战第11天】在这篇文章中,我们将深入探讨移动应用的开发过程,以及移动操作系统如何影响这些应用的性能和功能。我们将详细分析移动应用开发的关键步骤,包括需求分析、设计、编码、测试和维护。同时,我们也将探讨移动操作系统,如Android和iOS,如何为应用开发提供支持,并影响其性能。
|
iOS开发
iOS开发拓展篇—音频处理(音乐播放器6)
iOS开发拓展篇—音频处理(音乐播放器6) 一、图片处理   说明: Aspect表示按照原来的宽高比进行缩放。 Aspectfit表示按照原来的宽高比缩放,要求看到全部图片,后果是不能完全覆盖窗口,会留有空白。
756 0
|
iOS开发
iOS开发拓展篇—音频处理(音乐播放器4)
iOS开发拓展篇—音频处理(音乐播放器4) 说明:该文主要介绍音乐播放器实现过程中的一些细节控制。 实现的效果:    一、完整的代码 YYPlayingViewController.m文件 1 // 2 // YYPlayingViewController.
632 0
|
1月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
85 3
|
3月前
|
存储 iOS开发
iOS 开发,如何进行应用的本地化(Localization)?
iOS 开发,如何进行应用的本地化(Localization)?
122 2

推荐镜像

更多