iOS开发之⾳频解析第三⽅框架介绍
最近在做iOS⾳频相关的App,在做之前选择了三种解决⽅案。第⼀种⽅案是使⽤苹果⾃带的⾳频解析类AVPlayer,虽然AVPlayer也可以播放⾳频。但是要做类似于QQ⾳乐这样的App,使⽤AVPlayer就显得⽆能为⼒了。第⼆种解决⽅案使⽤第三⽅⾳频解析框架AudioStreamer,这是⼀个⽼外写的⾳频解析框架。其中包括本地和⽹络的⾳频数据解析。核⼼⽂件 AudioPlayer.h 和 AudioPlayer.m。这套框架使⽤的是CFNetwork和CoreAudio封装的。其集成了进度拖动,断点续传等功能。使⽤这个框架做类似于QQ⾳乐,酷狗⾳乐等⾳频类App完全可以胜任。第三种解决⽅案使⽤第三⽅⾳频解析框架FreeStream,这个也是⽼外写的⼀个⾳频解析框架。对于这个框架⽽⾔,它是使⽤C++进⾏⾳频的解析。虽然是C++的Objc调⽤,却没有额外的性能消耗。这款⾳频解析框架主要特点是性能优越,内存占⽤⼩,是⼀个不错的选择。但由于这个框架要想做更多功能就要开发者⾃⼰去修改这个框架来满⾜⾃⼰的项⽬需求。下载地址:。
所以我综上对⽐选择了第⼆种解决⽅案,使⽤了AudioStreamer。AudioStreamer虽然作者⾃⼰把⽹络数据解析和本地数据解析封装好了,但我们实际上并不需要。我们可以根据⾃⼰的需求写⾃⼰的⽹络数据解析。关于AudioStream源码的分析,由于个⼈能⼒有限,并不能完全看懂。有兴趣的读者可以去研究⼀下源码。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. 播放器的播放状态
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;qq音乐不能播放
// 播放代理
@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)pr
ogress 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中的具体实现。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论