天天看点

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

最近在做iOS音频相关的App,在做之前选择了三种解决方案。第一种方案是使用苹果自带的音频解析类AVPlayer,虽然AVPlayer也可以播放音频。但是要做类似于QQ音乐这样的App,使用AVPlayer就显得无能为力了。第二种解决方案使用第三方音频解析框架AudioStreamer,这是一个老外写的音频解析框架。其中包括本地和网络的音频数据解析。核心文件

    下面根据我自己的经验说一下这个框架在项目中该如何使用。也许我们并非一开始就去研究框架源码。这样是不明智的,就这个框架来说,它涉及到了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. 播放器的播放状态

    AudioPlayerStateReady, // 播放器已经准备好

    AudioPlayerStateRunning = 1, // 播放器正在运行中

    AudioPlayerStatePlaying = (1 << 1) | AudioPlayerStateRunning, // 播放器开始播放音频

    AudioPlayerStatePaused = (1 << 2) | AudioPlayerStateRunning,

    AudioPlayerStateStopped = (1 << 3), // 暂停播放和停止播放

    AudioPlayerStateError = (1 << 4), // 播放音频错误,一般是网络数据错误

    AudioPlayerStateDisposed = (1 << 5) // 播放错误,一般是由无效数据导致的错误

AudioPlayerState;

4. 监听播放器播放停止的原因

    AudioPlayerStopReasonNoStop = 0, // 未知原因停止

    AudioPlayerStopReasonEof, // 播放到文件末尾导致的停止

    AudioPlayerStopReasonUserAction,// 用户操作导致的停止

    AudioPlayerStopReasonUserActionFlushStop // 用户刷新播放导致的停止

AudioPlayerStopReason;

5. 播放状态码

    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;

今天先写到这,以后有时间可以研究一下AudioPlayer.m中的具体实现。