久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 8255|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

iOS開(kāi)發(fā)之音頻解析第三方框架介紹

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:85764 發(fā)表于 2015-7-18 00:36 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
    最近在做iOS音頻相關(guān)的App,在做之前選擇了三種解決方案。第一種方案是使用蘋(píng)果自帶的音頻解析類AVPlayer,雖然AVPlayer也可以播放音頻。但是要做類似于QQ音樂(lè)這樣的App,使用AVPlayer就顯得無(wú)能為力了。第二種解決方案使用第三方音頻解析框架AudioStreamer,這是一個(gè)老外寫(xiě)的音頻解析框架。其中包括本地和網(wǎng)絡(luò)的音頻數(shù)據(jù)解析。核心文件 AudioPlayer.h 和 AudioPlayer.m。這套框架使用的是CFNetwork和CoreAudio封裝的。其集成了進(jìn)度拖動(dòng),斷點(diǎn)續(xù)傳等功能。使用這個(gè)框架做類似于QQ音樂(lè),酷狗音樂(lè)等音頻類App完全可以勝任。第三種解決方案使用第三方音頻解析框架FreeStream,這個(gè)也是老外寫(xiě)的一個(gè)音頻解析框架。對(duì)于這個(gè)框架而言,它是使用C++進(jìn)行音頻的解析。雖然是C++的Objc調(diào)用,卻沒(méi)有額外的性能消耗。這款音頻解析框架主要特點(diǎn)是性能優(yōu)越,內(nèi)存占用小,是一個(gè)不錯(cuò)的選擇。但由于這個(gè)框架要想做更多功能就要開(kāi)發(fā)者自己去修改這個(gè)框架來(lái)滿足自己的項(xiàng)目需求。
    所以我綜上對(duì)比選擇了第二種解決方案,使用了AudioStreamer。AudioStreamer雖然作者自己把網(wǎng)絡(luò)數(shù)據(jù)解析和本地?cái)?shù)據(jù)解析封裝好了,但我們實(shí)際上并不需要。我們可以根據(jù)自己的需求寫(xiě)自己的網(wǎng)絡(luò)數(shù)據(jù)解析。關(guān)于AudioStream源碼的分析,由于個(gè)人能力有限,并不能完全看懂。有興趣的讀者可以去研究一下源碼。
    下面根據(jù)我自己的經(jīng)驗(yàn)說(shuō)一下這個(gè)框架在項(xiàng)目中該如何使用。也許我們并非一開(kāi)始就去研究框架源碼。這樣是不明智的,就這個(gè)框架來(lái)說(shuō),它涉及到了CoreAudio的知識(shí)。首先你要非常了解蘋(píng)果的音頻隊(duì)列服務(wù),對(duì)CFNetwork也要很了解。
    一般來(lái)說(shuō)我們使用第三方框架都會(huì)看.h中給我們所提供的接口。能滿足需求就無(wú)需修改,不能滿足則在進(jìn)行擴(kuò)展。下面我們一起看看AudioPlayer.h中給我們提供了哪些接口。
AudioPlayer.h
1.緩沖設(shè)置
緩沖數(shù)據(jù)的大小設(shè)置  此處設(shè)置的是2M,在iPhone4上測(cè)試會(huì)發(fā)出內(nèi)存溢出的警告, 故這個(gè)值不宜設(shè)置的太大,一般是1 * 1024 或者 2 * 1024。設(shè)置這個(gè)緩沖大小,可以實(shí)現(xiàn)音頻的斷點(diǎn)續(xù)傳的功能。

#define AudioPlayerDefaultNumberOfAudioQueueBuffers (2 * 1024)


2.播放網(wǎng)絡(luò)狀態(tài)
typedef enum
{
    AudioPlayerInternalStateInitialised = 0,
    AudioPlayerInternalStateRunning = 1,
    AudioPlayerInternalStatePlaying = (1 << 1) | AudioPlayerInternalStateRunning, // 數(shù)據(jù)加載成功,進(jìn)入音頻播放狀態(tài)
    AudioPlayerInternalStateStartingThread = (1 << 2) | AudioPlayerInternalStateRunning,   // 開(kāi)始進(jìn)行音頻的播放
    AudioPlayerInternalStateWaitingForData = (1 << 3) | AudioPlayerInternalStateRunning, // 等待數(shù)據(jù)的加載,緩沖數(shù)據(jù)中
    AudioPlayerInternalStateWaitingForQueueToStart = (1 << 4) | AudioPlayerInternalStateRunning, // 等待音頻隊(duì)列開(kāi)始播放
    AudioPlayerInternalStatePaused = (1 << 5) | AudioPlayerInternalStateRunning, //  暫停音頻的播放,數(shù)據(jù)停止加載
    AudioPlayerInternalStateRebuffering = (1 << 6) | AudioPlayerInternalStateRunning, // 開(kāi)始數(shù)據(jù)的重新加載
    AudioPlayerInternalStateStopping = (1 << 7), // 一個(gè)音頻數(shù)據(jù)加載完畢,停止播放。
    AudioPlayerInternalStateStopped = (1 << 8), // 數(shù)據(jù)加載完成,播放狀態(tài)為停止?fàn)顟B(tài)
    AudioPlayerInternalStateDisposed = (1 << 9), // 數(shù)據(jù)加載失敗,一般是無(wú)效數(shù)據(jù)
    AudioPlayerInternalStateError = (1 << 10)    //   數(shù)據(jù)加載出錯(cuò),一般是網(wǎng)絡(luò)錯(cuò)誤。
}
AudioPlayerInternalState;

3. 播放器的播放狀態(tài)
typedef enum
{
    AudioPlayerStateReady, // 播放器已經(jīng)準(zhǔn)備好
    AudioPlayerStateRunning = 1, // 播放器正在運(yùn)行中
    AudioPlayerStatePlaying = (1 << 1) | AudioPlayerStateRunning, // 播放器開(kāi)始播放音頻
    AudioPlayerStatePaused = (1 << 2) | AudioPlayerStateRunning,
    AudioPlayerStateStopped = (1 << 3), // 暫停播放和停止播放
    AudioPlayerStateError = (1 << 4), // 播放音頻錯(cuò)誤,一般是網(wǎng)絡(luò)數(shù)據(jù)錯(cuò)誤
    AudioPlayerStateDisposed = (1 << 5) // 播放錯(cuò)誤,一般是由無(wú)效數(shù)據(jù)導(dǎo)致的錯(cuò)誤
}
AudioPlayerState;

4. 監(jiān)聽(tīng)播放器播放停止的原因
typedef enum
{
    AudioPlayerStopReasonNoStop = 0, // 未知原因停止
    AudioPlayerStopReasonEof, // 播放到文件末尾導(dǎo)致的停止
    AudioPlayerStopReasonUserAction,// 用戶操作導(dǎo)致的停止
    AudioPlayerStopReasonUserActionFlushStop // 用戶刷新播放導(dǎo)致的停止
}
AudioPlayerStopReason;

5. 播放狀態(tài)碼
typedef enum
{
    AudioPlayerErrorNone = 0, // 一般錯(cuò)誤
    AudioPlayerErrorDataSource, // 數(shù)據(jù)錯(cuò)誤
    AudioPlayerErrorStreamParseBytesFailed, // 解析數(shù)據(jù)流失敗
    AudioPlayerErrorDataNotFound, // 數(shù)據(jù)沒(méi)有找到
    AudioPlayerErrorQueueStartFailed, // 音頻隊(duì)列準(zhǔn)備失敗
    AudioPlayerErrorQueuePauseFailed, // 音頻隊(duì)列暫停失敗
    AudioPlayerErrorUnknownBuffer,    // 不知名的數(shù)據(jù)緩沖
    AudioPlayerErrorQueueStopFailed,  // 音頻隊(duì)列停止失敗
    AudioPlayerErrorOther       // 其他錯(cuò)誤
}
AudioPlayerErrorCode;

@class AudioPlayer;

// 播放代理
@protocol AudioPlayerDelegate <NSObject>
// 播放狀態(tài)f發(fā)生變化的調(diào)用
-(void) audioPlayer:(AudioPlayer*)audioPlayer stateChanged:(AudioPlayerState)state;
// 播放出錯(cuò)的調(diào)用
-(void) audioPlayer:(AudioPlayer*)audioPlayer didEncounterError:(AudioPlayerErrorCode)errorCode;
// 開(kāi)始播放 得到itemId
-(void) audioPlayer:(AudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId;
// 緩沖完成的調(diào)用
-(void) audioPlayer:(AudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId;
// 已經(jīng)播放結(jié)束的回調(diào)
-(void) audioPlayer:(AudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(AudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration;

@optional

-(void) audioPlayer:(AudioPlayer*)audioPlayer logInfo:(NSString*)line;
// 播放網(wǎng)絡(luò)變化的回調(diào)
-(void) audioPlayer:(AudioPlayer*)audioPlayer internalStateChanged:(AudioPlayerInternalState)state;

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

@class QueueEntry;

typedef struct
{
    AudioQueueBufferRef ref; // 音頻隊(duì)列緩沖引用
    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;
}

// 音頻的總時(shí)間  這個(gè)時(shí)間是由播放器自己計(jì)算出來(lái)的。
@property (readonly) double duration;
// 音頻當(dāng)前播放的進(jìn)度
@property (readonly) double progress;
// 播放器的狀態(tài)
@property (readwrite) AudioPlayerState state;
// 停止播放時(shí)的原因
@property (readonly) AudioPlayerStopReason stopReason;
@property (readwrite, unsafe_unretained) id<AudioPlayerDelegate> delegate;
@property (readwrite) BOOL meteringEnabled;

// 對(duì)外接口
-(id) init;

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

// 從URL地址獲取數(shù)據(jù)源
-(DataSource*) dataSourceFromURL:(NSURL*)url;

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

-(void) queueDataSource:(DataSource*)dataSource withQueueItemId:(NSObject*)queueItemId;
// 設(shè)置數(shù)據(jù)源
-(void) setDataSource:(DataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId;
// 設(shè)置播放進(jìn)度
-(void) seekToTime:(double)value;

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

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

@end

今天先寫(xiě)到這,以后有時(shí)間可以研究一下AudioPlayer.m中的具體實(shí)現(xiàn)。




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 99re6在线 | 9久久 | 一区二区免费在线 | 91精品国产色综合久久 | 国产成人99久久亚洲综合精品 | 日韩欧美久久精品 | 国产黄色av网站 | 欧美精品一区二区三区四区五区 | 一区二区三区久久 | 国产欧美三区 | 青青草综合网 | a国产视频 | 蜜桃毛片 | 国产精品99久久久久久www | 亚洲精品国产电影 | 国产视频一区二区 | 亚洲成av人片在线观看 | 午夜精品导航 | 五月天婷婷激情 | 99免费精品视频 | 久久精品91久久久久久再现 | 欧美亚洲国产日韩 | 亚洲九九精品 | 亚洲国产成人精品女人久久久 | 91av免费看 | 久在线观看 | 欧美日本在线观看 | 国产精品久久久久久一级毛片 | av在线免费播放 | 91精品国产91久久久久青草 | 久久伊| 欧美综合国产精品久久丁香 | 91影院在线观看 | 91毛片网 | 国产丝袜一区二区三区免费视频 | 艹逼网 | 日韩一区二区在线观看 | 欧美日韩一区在线观看 | 成人激情免费视频 | 午夜视频在线视频 | 日日摸日日添日日躁av |