iOS中聲音播放的各種方法總結(jié)

前言

這兩天禁(晉)煙(嫣)的秀恩愛氓仲,身為程序員的我們又被默默的送了一把狗糧酌儒,這段時間一直在忙公司項目,兩個多月都沒有寫過文章了,今天閑來無事想把iOS中播放音樂(包括段音效)的部分拿出來總結(jié)一下愉舔。

主要部分:

1.音效的播放
2.音樂的播放(本地, 網(wǎng)絡(luò))
3.音頻隊列服務(wù)

1.音效播放(AudioToolbox/AudioToolbox.h)

音頻文件必須打包成.caf伙菜、.aif轩缤、.wav中的一種(注意這是官方文檔的說法,實際測試發(fā)現(xiàn)一些.mp3也可以播放)
這個段音效播放不能大于30s贩绕,這個30s不是我說的火的,是蘋果的API說的


AudioServices_h.png
創(chuàng)建音效的ID,音效的播放和銷毀都靠這個ID來執(zhí)行

AudioServicesCreateSystemSoundID(CFURLRef inFileURL, SystemSoundID* outSystemSoundID)

播放音效

AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID)

iOS9以后可以用的淑倾,帶有block回調(diào)的播放

AudioServicesPlaySystemSoundWithCompletion(SystemSoundID inSystemSoundID, void (^__nullable inCompletionBlock)(void))

帶有震動的播放

AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID)

iOS9以后可以用的馏鹤,帶有block回調(diào)的播放

AudioServicesPlayAlertSoundWithCompletion( SystemSoundID inSystemSoundID,void (^__nullable inCompletionBlock)(void))

在iOS9之前,如何判斷一個音效是否播放完成呢娇哆?(利用下面的方法)

AudioServicesAddSystemSoundCompletion(SystemSoundID inSystemSoundID,CFRunLoopRef __nullable inRunLoop, CFStringRef __nullable inRunLoopMode,AudioServicesSystemSoundCompletionProc inCompletionRoutine,void * __nullable inClientData)

銷毀音效的播放

AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID)

下面對上面的方法的演示湃累,播放一些音效, 播放48s的mp3時會報錯

static SystemSoundID soundID = 0;

- (IBAction)play:(id)sender {
    
//    NSString *str = [[NSBundle mainBundle] pathForResource:@"vcyber_waiting" ofType:@"wav"];
    NSString *str = [[NSBundle mainBundle] pathForResource:@"28s" ofType:@"mp3"];
//    NSString *str = [[NSBundle mainBundle] pathForResource:@"48s" ofType:@"mp3"];
    NSURL *url = [NSURL fileURLWithPath:str];
    
    
    AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);
//
//    AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallBack, NULL);
//    
//    //AudioServicesPlaySystemSound(soundID);
//    
//    AudioServicesPlayAlertSound(soundID);

    
//    AudioServicesPlaySystemSoundWithCompletion(soundID, ^{
//        NSLog(@"播放完成");
//        AudioServicesDisposeSystemSoundID(soundID);
//    });
    
    AudioServicesPlayAlertSoundWithCompletion(soundID, ^{
        NSLog(@"播放完成");
    });
    
}

void soundCompleteCallBack(SystemSoundID soundID, void * clientDate) {
    NSLog(@"播放完成");
    AudioServicesDisposeSystemSoundID(soundID);
}

- (IBAction)stop:(id)sender {
    AudioServicesDisposeSystemSoundID(soundID);
}

2.本地音樂播放

AVAudioPlayer

AVAudioPlayer是播放本地音樂最常到的勃救,這個類對于大多數(shù)人來說應(yīng)該很常用,這里不多說治力,說一下它的基本用法和代理的用法蒙秒,直接上代碼,代碼注釋很詳細(xì)

@interface LocalMusicViewController ()<AVAudioPlayerDelegate>

/**
 播放器
 */
@property (nonatomic, strong) AVAudioPlayer *player;

/**
 播放進(jìn)度條
 */
@property (weak, nonatomic) IBOutlet UIProgressView *progress;

/**
 改變播放進(jìn)度滑塊
 */
@property (weak, nonatomic) IBOutlet UISlider *progressSlide;

/**
 改變聲音滑塊
 */
@property (weak, nonatomic) IBOutlet UISlider *volum;

/**
 改變進(jìn)度條滑塊顯示的定時器
 */
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation LocalMusicViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSError *err;
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"1" withExtension:@"mp3"];
//    初始化播放器
    _player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&err];
    self.volum.value = 0.5;
//    設(shè)置播放器聲音
    _player.volume = self.volum.value;
//    設(shè)置代理
    _player.delegate = self;
//    設(shè)置播放速率
    _player.rate = 1.0;
//    設(shè)置播放次數(shù) 負(fù)數(shù)代表無限循環(huán)
    _player.numberOfLoops = -1;
//    準(zhǔn)備播放
    [_player prepareToPlay];
    self.progress.progress = 0;
    self.progressSlide.value = 0;
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(change) userInfo:nil repeats:YES];
    
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
}

- (void)change {
    self.progress.progress = _player.currentTime / _player.duration;
}

- (IBAction)progressChange:(UISlider *)sender {
//    改變當(dāng)前的播放進(jìn)度
    _player.currentTime = sender.value * _player.duration;
    self.progress.progress = sender.value;
    
}
- (IBAction)volumChange:(UISlider *)sender {
//    改變聲音大小
    _player.volume = sender.value;
}

- (IBAction)player:(id)sender {
//    開始播放
    [_player play];
}

- (IBAction)stop:(id)sender {
//    暫停播放
    [_player stop];
}

#pragma mark --AVAudioPlayerDelegate
/**
 完成播放宵统, 但是在打斷播放和暫停晕讲、停止不會調(diào)用
 */
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    
}

/**
 播放過程中解碼錯誤時會調(diào)用
 */
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error {
    
}

/**
 播放過程被打斷

 */
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player NS_DEPRECATED_IOS(2_2, 8_0) {
    
}

/**
 打斷結(jié)束
*/
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags NS_DEPRECATED_IOS(6_0, 8_0) {
    
}

/**
 打斷結(jié)束

 */
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags NS_DEPRECATED_IOS(4_0, 6_0) {
    
}

/**
 這個方法被上面的方法代替了
 */
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player NS_DEPRECATED_IOS(2_2, 6_0) {
    
}

網(wǎng)絡(luò)音樂播放(AVPlayer)

AVPlayer是播放網(wǎng)絡(luò)音樂和網(wǎng)絡(luò)視頻最常用到的,它可以自己緩存網(wǎng)絡(luò)數(shù)據(jù)马澈,然后播放瓢省,AVPlayer在播放視頻時必須創(chuàng)建一個AVPlayerLayer用來展示視頻,如果播放音樂箭券,聲音就不用創(chuàng)建這個對象净捅。這里簡單演示一下網(wǎng)絡(luò)播放音樂

1. 通過網(wǎng)絡(luò)鏈接創(chuàng)建AVPlayerItem

AVPlayerItem的初始化方法很多疑枯,我這里直接用initWithURL:這個方法創(chuàng)建

- (AVPlayerItem *)getItemWithIndex:(NSInteger)index {
    NSURL *url = [NSURL URLWithString:self.musicArray[index]];
    AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:url];
    //KVO監(jiān)聽播放狀態(tài)
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    //KVO監(jiān)聽緩存大小
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //通知監(jiān)聽item播放完畢
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playOver:) name:AVPlayerItemDidPlayToEndTimeNotification object:item];
    return item;
}
2.實現(xiàn)KVO的方法辩块,根據(jù)keyPath來判斷觀察的屬性是哪一個
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    
    AVPlayerItem *item = object;
    
    if ([keyPath isEqualToString:@"status"]) {
        switch (self.player.status) {
            case AVPlayerStatusUnknown:
                NSLog(@"未知狀態(tài),不能播放");
                break;
            case AVPlayerStatusReadyToPlay:
                NSLog(@"準(zhǔn)備完畢荆永,可以播放");
                break;
            case AVPlayerStatusFailed:
                NSLog(@"加載失敗, 網(wǎng)絡(luò)相關(guān)問題");
                break;
                
            default:
                break;
        }
    }
    
    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        NSArray *array = item.loadedTimeRanges;
        //本次緩存的時間
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
        NSTimeInterval totalBufferTime = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration); //緩存的總長度
        self.bufferProgress.progress = totalBufferTime / CMTimeGetSeconds(item.duration);
    }
}
3.懶加載AVPlayer
- (AVPlayer *)player {
    if (!_player) {
//        根據(jù)鏈接數(shù)組獲取第一個播放的item废亭, 用這個item來初始化AVPlayer
        AVPlayerItem *item = [self getItemWithIndex:self.currentIndex];
//        初始化AVPlayer
        _player = [[AVPlayer alloc] initWithPlayerItem:item];
        __weak typeof(self)weakSelf = self;
//        監(jiān)聽播放的進(jìn)度的方法,addPeriodicTime: ObserverForInterval: usingBlock:
        /*
         DMTime 每到一定的時間會回調(diào)一次具钥,包括開始和結(jié)束播放
         block回調(diào)豆村,用來獲取當(dāng)前播放時長
         return 返回一個觀察對象,當(dāng)播放完畢時需要骂删,移除這個觀察
         */
        _timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
            float current = CMTimeGetSeconds(time);
            if (current) {
                [weakSelf.progressView setProgress:current / CMTimeGetSeconds(item.duration) animated:YES];
                weakSelf.progressSlide.value = current / CMTimeGetSeconds(item.duration);
            }
        }];
    }
    return _player;
}
4.播放和暫停
//  播放
- (IBAction)play:(id)sender {
    [self.player play];
}

//暫停
- (IBAction)pause:(id)sender {
    [self.player pause];
}
5.下一首和上一首
- (IBAction)next:(UIButton *)sender {
    [self removeObserver];
   self.currentIndex ++;
    if (self.currentIndex >= self.musicArray.count) {
        self.currentIndex = 0;
    }
//  這個方法是用一個item取代當(dāng)前的item
    [self.player replaceCurrentItemWithPlayerItem:[self getItemWithIndex:self.currentIndex]];
    [self.player play];
}

- (IBAction)last:(UIButton *)sender {
    [self removeObserver];
    self.currentIndex --;
    if (self.currentIndex < 0) {
        self.currentIndex = 0;
    }
//  這個方法是用一個item取代當(dāng)前的item
    [self.player replaceCurrentItemWithPlayerItem:[self getItemWithIndex:self.currentIndex]];
    [self.player play];
}

// 在播放另一個時掌动,要移除當(dāng)前item的觀察者,還要移除item播放完成的通知
- (void)removeObserver {
    [self.player.currentItem removeObserver:self forKeyPath:@"status"];
    [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
6.控制播放進(jìn)度宁玫,這個也有很多的方法粗恢,如果不是太精確,用- (void)seekToTime:(CMTime)time:這個方法就行欧瘪,如果要精確的用這個- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter
- (IBAction)changeProgress:(UISlider *)sender {
    if (self.player.status == AVPlayerStatusReadyToPlay) {
        [self.player seekToTime:CMTimeMake(CMTimeGetSeconds(self.player.currentItem.duration) * sender.value, 1)];
    }
}

音頻隊列服務(wù)(Audio Queue Services)

在AudioToolbox框架中的音頻隊列服務(wù)眷射,是用來播放網(wǎng)絡(luò)流媒體的一個框架,它完全可以做到音頻播放和錄制佛掖,一個音頻服務(wù)隊列有三個部分組成:
1.三個緩沖器Buffers:沒個緩沖器都是一個存儲音頻數(shù)據(jù)的臨時倉庫妖碉。
2.一個緩沖隊列Buffer Queue:一個包含音頻緩沖器的有序隊列。
3.一個回調(diào)CallBack:一個自定義的隊列回調(diào)函數(shù)芥被。
在音頻播放緩沖隊列中欧宜,將音頻讀取到緩沖器中,一旦一個緩沖器填充滿之后就放到緩沖隊列中拴魄,然后繼續(xù)填充其他緩沖器冗茸;當(dāng)開始播放時猛拴,則從第一個緩沖器中讀取音頻進(jìn)行播放;一旦播放完之后就會觸發(fā)回調(diào)函數(shù)蚀狰,開始播放下一個緩沖器中的音頻愉昆,同時填充第一個緩沖器放;填充滿之后再次放回到緩沖隊列麻蹋。下面是官方詳細(xì)的流程:

Playback_Audio_Queues.png

AudioQueue的工作大致流程:
1.創(chuàng)建AudioQueue,創(chuàng)建BufferArray數(shù)組跛溉,用于存放AudioQueueBufferRef
2.通過AudioQueueAllocateBuffer創(chuàng)建AudioQueueBufferRef一般2-3個,放入到BufferArray數(shù)組中
3.有數(shù)據(jù)時從buffer數(shù)組取出一個buffer扮授,memcpy數(shù)據(jù)后用AudioQueueEnqueueBuffer方法把buffer插入AudioQueue
4.AudioQueue中存在Buffer后芳室,調(diào)用AudioQueueStart播放。(具體等到填入多少buffer后再播放可以自己控制刹勃,只要能保證播放不間斷即可)
5.AudioQueue播放音樂后消耗了某個buffer堪侯,在另一個線程回調(diào)并送出該buffer,把buffer放回BufferArray供下一次使用
6.返回步驟3繼續(xù)循環(huán)直到播放結(jié)束

常用API
創(chuàng)建AudioQueue
第一個參數(shù)表示需要播放的音頻數(shù)據(jù)格式類型荔仁,是一個AudioStreamBasicDescription對象伍宦,是使用AudioFileStream或者AudioFile解析出來的數(shù)據(jù)格式信息;
第二個參數(shù)AudioQueueOutputCallback是某塊Buffer被使用之后的回調(diào)乏梁;
第三個參數(shù)為上下文對象次洼;
第四個參數(shù)inCallbackRunLoop為AudioQueueOutputCallback需要在的哪個RunLoop上被回調(diào),如果傳入NULL的話就會再AudioQueue的內(nèi)部RunLoop中被回調(diào)遇骑,所以一般傳NULL就可以了卖毁;
第五個參數(shù)inCallbackRunLoopMode為RunLoop模式,如果傳入NULL就相當(dāng)于kCFRunLoopCommonModes落萎,也傳NULL就可以了亥啦;
第六個參數(shù)inFlags是保留字段,目前沒作用练链,傳0翔脱;
第七個參數(shù),返回生成的AudioQueue實例兑宇;
返回值用來判斷是否成功創(chuàng)建(OSStatus == noErr)碍侦。
extern OSStatus             
AudioQueueNewOutput( const AudioStreamBasicDescription *inFormat,
                      AudioQueueOutputCallback        inCallbackProc,
                     void * __nullable               inUserData,
                       CFRunLoopRef __nullable         inCallbackRunLoop,
                       CFStringRef __nullable          inCallbackRunLoopMode,
                       UInt32                          inFlags,
                      AudioQueueRef __nullable * __nonnull outAQ)          

參數(shù)和上面基本相同,只是把RunLoop換成了dispatch queue
AudioQueueNewOutputWithDispatchQueue(AudioQueueRef __nullable * __nonnull outAQ,
                                    const AudioStreamBasicDescription *inFormat,
                                    UInt32                          inFlags,
                                    dispatch_queue_t                inCallbackDispatchQueue,
                                    AudioQueueOutputCallbackBlock   inCallbackBlock)        
創(chuàng)建Buffer
第一個參數(shù)方法傳入AudioQueue實例
第二個參數(shù)Buffer大小
第三個傳出的BufferArray實例隶糕;
extern OSStatus
AudioQueueAllocateBuffer(AudioQueueRef    inAQ,
                          UInt32    inBufferByteSize,
                          AudioQueueBufferRef __nullable * __nonnull outBuffer)  

比上面的方法多了一個inNumberPacketDescriptions瓷产,這個參數(shù)可以指定生成的Buffer中PacketDescriptions的個數(shù)
extern OSStatus
AudioQueueAllocateBufferWithPacketDescriptions(
                                    AudioQueueRef           inAQ,
                                    UInt32                  inBufferByteSize,
                                    UInt32                  inNumberPacketDescriptions,
                                    AudioQueueBufferRef __nullable * __nonnull outBuffer)  
釋放buffer
第一個參數(shù)AudioQueue實例
第二個參數(shù)指定的buffer
extern OSStatus
AudioQueueFreeBuffer(               AudioQueueRef           inAQ,
                                    AudioQueueBufferRef     inBuffer) 
插入buffer
第一個參數(shù)AudioQueue實例
第二個參數(shù)指定的Buffer
第三個參數(shù)數(shù)據(jù)包的個數(shù)
第四個參數(shù)數(shù)據(jù)包描述
extern OSStatus
AudioQueueEnqueueBuffer(            AudioQueueRef                       inAQ,
                                    AudioQueueBufferRef                 inBuffer,
                                    UInt32                              inNumPacketDescs,
                                    const AudioStreamPacketDescription * __nullable inPacketDescs)

上面的方法基本滿足要求,這個方法對插入的buffer進(jìn)行額外的更多的操作
extern OSStatus
AudioQueueEnqueueBufferWithParameters(
                                    AudioQueueRef                                inAQ,
                                    AudioQueueBufferRef                          inBuffer,
                                    UInt32                                       inNumPacketDescs,
                                    const AudioStreamPacketDescription * __nullable inPacketDescs,
                                    UInt32                                       inTrimFramesAtStart,
                                    UInt32                                       inTrimFramesAtEnd,
                                    UInt32                                       inNumParamValues,
                                    const AudioQueueParameterEvent * __nullable  inParamValues,
                                    const AudioTimeStamp * __nullable            inStartTime,
                                    AudioTimeStamp * __nullable                  outActualStartTime)     __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
開始播放
第一個參數(shù)AudioQueue實例
第二個參數(shù)播放時間枚驻,如果直接開始播放 傳NULL
extern OSStatus
AudioQueueStart(                    AudioQueueRef                     inAQ,
                                    const AudioTimeStamp * __nullable inStartTime)  
解碼數(shù)據(jù)濒旦,不常用,調(diào)用開始播放會自動解碼
extern OSStatus
AudioQueuePrime(                    AudioQueueRef           inAQ,
                                    UInt32                  inNumberOfFramesToPrepare,
                                    UInt32 * __nullable     outNumberOfFramesPrepared) 
停止播放
第二個參數(shù)Bool值再登,控制是否立即停止尔邓,如果傳false晾剖,會把Enqueue的所有buffer播放完成再停止
extern OSStatus
AudioQueueStop(                     AudioQueueRef           inAQ,
                                    Boolean                 inImmediate)            __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
暫停播放
extern OSStatus
AudioQueuePause(                    AudioQueueRef           inAQ)       __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
重置解碼器
這個方法會播放完隊列中的buffer后重置解碼器,防止當(dāng)前的解碼器影響下一段音頻梯嗽,比如切換歌曲的時候齿尽,如果和AudioQueueStop(AQ,false)
一起使用并不會起效,因為Stop方法的false參數(shù)也會做同樣的事情灯节。
extern OSStatus
AudioQueueFlush(                    AudioQueueRef           inAQ)            __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
重置AudioQueue
重置AudioQueue會清除所有已經(jīng)Enqueue的buffer循头,并觸發(fā)AudioQueueOutputCallback,調(diào)用AudioQueueStop方法時同樣會觸發(fā)該方法。這個方法的直接調(diào)用一般在seek時使用炎疆,用來清除殘留的buffer(seek時還有一種做法是先AudioQueueStop
卡骂,等seek完成后重新start)。
extern OSStatus
AudioQueueReset(                    AudioQueueRef           inAQ)            __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
獲取播放時間
調(diào)用時傳入AudioTimeStamp形入,從這個結(jié)構(gòu)體當(dāng)中獲取播放時間
extern OSStatus
AudioQueueGetCurrentTime(           AudioQueueRef                    inAQ,
                                    AudioQueueTimelineRef __nullable inTimeline,
                                    AudioTimeStamp * __nullable      outTimeStamp,
                                    Boolean * __nullable             outTimelineDiscontinuity)       __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
銷毀AudioQueue
參數(shù)的意義基本和AudioQueueStop一樣
extern OSStatus
AudioQueueDispose(                  AudioQueueRef           inAQ, 
                                    Boolean                 inImmediate)            __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
AudioQueue參數(shù)
AudioQueueGetParameter
AudioQueueSetParameter
參數(shù)列表
CF_ENUM(AudioQueueParameterID)
{
    kAudioQueueParam_Volume         = 1,
    kAudioQueueParam_PlayRate       = 2,
    kAudioQueueParam_Pitch          = 3,
    kAudioQueueParam_VolumeRampTime = 4,
    kAudioQueueParam_Pan            = 13
};
AudioQueue屬性
AudioQueueGetPropertySize
AudioQueueGetProperty
AudioQueueSetProperty
屬性列表
CF_ENUM(AudioQueuePropertyID) {
    kAudioQueueProperty_IsRunning               = 'aqrn',       // value is UInt32

    kAudioQueueDeviceProperty_SampleRate        = 'aqsr',       // value is Float64
    kAudioQueueDeviceProperty_NumberChannels    = 'aqdc',       // value is UInt32
    kAudioQueueProperty_CurrentDevice           = 'aqcd',       // value is CFStringRef
    
    kAudioQueueProperty_MagicCookie             = 'aqmc',       // value is void*
    kAudioQueueProperty_MaximumOutputPacketSize = 'xops',       // value is UInt32
    kAudioQueueProperty_StreamDescription       = 'aqft',       // value is AudioStreamBasicDescription
       
    kAudioQueueProperty_ChannelLayout           = 'aqcl',       // value is AudioChannelLayout
    kAudioQueueProperty_EnableLevelMetering     = 'aqme',       // value is UInt32
    kAudioQueueProperty_CurrentLevelMeter       = 'aqmv',       // value is array of AudioQueueLevelMeterState, 1 per channel
    kAudioQueueProperty_CurrentLevelMeterDB     = 'aqmd',       // value is array of AudioQueueLevelMeterState, 1 per channel

    kAudioQueueProperty_DecodeBufferSizeFrames  = 'dcbf',       // value is UInt32
    kAudioQueueProperty_ConverterError          = 'qcve',       // value is UInt32

    kAudioQueueProperty_EnableTimePitch         = 'q_tp',       // value is UInt32, 0/1
    kAudioQueueProperty_TimePitchAlgorithm      = 'qtpa',       // value is UInt32. See values below.
    kAudioQueueProperty_TimePitchBypass         = 'qtpb',       // value is UInt32, 1=bypassed
};
監(jiān)聽屬相變化相關(guān)方法
AudioQueueAddPropertyListener
AudioQueueRemovePropertyListener

總結(jié):

這里說的東西都比(能)較(力)基(有)礎(chǔ)(限)全跨,其實AudioQueue的功能還有很多,如果大家想去研究比較細(xì)致的AudioQueue的使用亿遂,這里給大家推薦兩個github地址浓若,一個是AudioStreamer,一個是FreeStreamer崩掘,這里的兩個播放都是使用AudioQueue實現(xiàn)的七嫌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市苞慢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌英妓,老刑警劉巖挽放,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔓纠,居然都是意外死亡辑畦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門腿倚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纯出,“玉大人,你說我怎么就攤上這事敷燎≡蒹荩” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵硬贯,是天一觀的道長焕襟。 經(jīng)常有香客問我,道長饭豹,這世上最難降的妖魔是什么鸵赖? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任务漩,我火速辦了婚禮,結(jié)果婚禮上它褪,老公的妹妹穿的比我還像新娘饵骨。我一直安慰自己,他們只是感情好茫打,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布宏悦。 她就那樣靜靜地躺著,像睡著了一般包吝。 火紅的嫁衣襯著肌膚如雪饼煞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天诗越,我揣著相機(jī)與錄音砖瞧,去河邊找鬼。 笑死嚷狞,一個胖子當(dāng)著我的面吹牛块促,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播床未,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼竭翠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了薇搁?” 一聲冷哼從身側(cè)響起斋扰,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啃洋,沒想到半個月后传货,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宏娄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年问裕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孵坚。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡粮宛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卖宠,到底是詐尸還是另有隱情巍杈,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布逗堵,位于F島的核電站秉氧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蜒秤。R本人自食惡果不足惜汁咏,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一亚斋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧攘滩,春花似錦帅刊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蚤假,卻和暖如春栏饮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磷仰。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工袍嬉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灶平。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓伺通,卻偏偏與公主長得像,于是被迫代替她去往敵國和親逢享。 傳聞我的和親對象是個殘疾皇子罐监,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容