ios音频播放大总结

今天是周末乘着这点空闲时间总结一下ios的音频播放

1、AVFoundation

该类既可以播放音频又可以播放视频。常用的音频输出类为AVAudioSession

AVAudioSession *audioSession = [AVAudioSession sharedInstance];

实例化对象之后就可以设置其Category属性了

             AVAudioSessionCategorySoloAmbient

这个类别非常像AVAudioSessionCategoryAmbient类别,除了会停止其他程序的音频回放,比如iPod程序。当设备被设置为静音模式,你的音频回放将会停止。

             AVAudioSessionCategoryRecord

这会停止其他应用的声音(比如iPod)并让你的应用也不能初始化音频回放,即使你的设备屏幕被用户锁定了,应用的录音仍会继续。

                       AVAudioSessionCategoryPlayback

这个类别会静止其他应用的音频回放即使屏幕被锁定或者设备为静音模式,音频回放都会继续

             AVAudioSessionCategoryPlayAndRecord

这个类别允许你的应用中同时进行声音的播放和录制。即使屏幕被锁定或者设备为静音模式,音频回放和录制都会继续

                      AVAudioSessionCategoryAudioProcessing

个类别用于应用中进行音频处理的情形,而不是音频回放或录制设置了这种模式,你在应用中就不能播放和录制任何声音

                     AVAudioSessionCategoryAmbient

这个类别不会停止其他应用的声音,相反,它允许你的音频播放于其他应用的声音之上用户锁屏时,你的应用将停止所有正在回放的音频。仅当你的应用是唯一播放该音频文件的应用时,静音模式将停止你程序的音频回放

2、AudioToolBox

该类提供了读取本地音频数据包进行音频播放功能。该类还提供了检测设备的输入输出属性。(拔插耳机)

读取本地数据包进行音频播放功能是调用函数AudioFileOpenURL

具体做法请看代码

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioToolbox/AudioFile.h>
#define NUM_BUFFERS 3
@interface AudioPlayer : NSObject
{
    //播放音频文件ID
    AudioFileID audioFile;
    //音频流描述对象
    AudioStreamBasicDescription dataFormat;
    //音频队列
    AudioQueueRef queue;
    SInt64 packetIndex;
    UInt32 numPacketsToRead;
    UInt32 bufferByteSize;
    AudioStreamPacketDescription *packetDescs;
    AudioQueueBufferRef buffers[NUM_BUFFERS];
}

//定义队列为实例属性
@property AudioQueueRef queue;

//播放方法定义
- (void) play:(CFURLRef) path;

//定义缓存数据读取方法
- (void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue
                       queueBuffer:(AudioQueueBufferRef)audioQueueBuffer;
//定义回调(Callback)函数
static void BufferCallback(void *inUserData, AudioQueueRef inAQ,
                           AudioQueueBufferRef buffer);
//定义包数据的读取方法
- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;
@end


#import "AudioPlayer.h"
static UInt32 gBufferSizeBytes = 0x10000;

@implementation AudioPlayer
@synthesize queue;
// 回调(Callback)函数的实现

static void BufferCallback(void *inUserData, AudioQueueRef inAQ,
                           AudioQueueBufferRef buffer)
{
    AudioPlayer* player = (__bridge AudioPlayer*)inUserData;
    [player  audioQueueOutputWithQueue:inAQ queueBuffer:buffer];
}

//初始化方法(为NSObject中定义的初始化方法)
- (id) init {
    for(int i=0; i<NUM_BUFFERS; i++) {
        AudioQueueEnqueueBuffer(queue,buffers[i],0,nil);
    }
    return self;
}

//缓存数据读取方法的实现

- (void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue
                       queueBuffer:(AudioQueueBufferRef)audioQueueBuffer {
    OSStatus status;
    // 读取包数据
    UInt32  numBytes;
    UInt32  numPackets = numPacketsToRead;
    status = AudioFileReadPackets(
                                  audioFile, NO, &numBytes, packetDescs,
                                  packetIndex, &numPackets, audioQueueBuffer->mAudioData);
    // 成功读取时
    if (numPackets > 0) {
        //将缓冲的容量设置为与读取的音频数据一样大小(确保内存空间)
        audioQueueBuffer->mAudioDataByteSize = numBytes;
        // 完成给队列配置缓存的处理
        status = AudioQueueEnqueueBuffer(
                                         audioQueue, audioQueueBuffer, numPackets, packetDescs);
                // 移动包的位置
        packetIndex += numPackets;
    }
}

//音频播放方法的实现
-(void) play:(CFURLRef)path
{
    UInt32      size, maxPacketSize;
    char        *cookie;
    int         i;
    OSStatus status;
    // 打开音频文件
    status = AudioFileOpenURL(path, kAudioFileReadPermission, 0, &audioFile);
    if (status != noErr) {
        // 错误处理
        return;
    }
    // 取得音频的
    // 取得音频数据格式
    size = sizeof(dataFormat);
    AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat,
                         &size, &dataFormat);
    // 创建播放用的音频队列
    AudioQueueNewOutput(&dataFormat, BufferCallback,
                        (__bridge void *)(self), nil, nil, 0, &queue);
    //计算单位时间包含的包数
    if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0)
    {
        size = sizeof(maxPacketSize);
        AudioFileGetProperty(audioFile,
                             kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
        if (maxPacketSize > gBufferSizeBytes)
        {
            maxPacketSize = gBufferSizeBytes;
        }
        // 算出单位时间内含有的包数
        //
        numPacketsToRead = gBufferSizeBytes / maxPacketSize;
        packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead);
    }
    else
    {
        numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket;
        packetDescs = nil;
    }
    //设置Magic Cookie,参见第二十七章的相关介绍
    AudioFileGetPropertyInfo(audioFile,
                             kAudioFilePropertyMagicCookieData, &size, nil);
    if (size > 0)
    {
        cookie = malloc(sizeof(char) * size);
        AudioFileGetProperty(audioFile,
                             kAudioFilePropertyMagicCookieData, &size, cookie);
        AudioQueueSetProperty(queue,
                              kAudioQueueProperty_MagicCookie, cookie, size);
        free(cookie);
    }
    // 创建并分配缓存空间
    packetIndex = 0;
    for (i = 0; i < NUM_BUFFERS; i++)
    {
        AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]);
        //读取包数据
        if ([self readPacketsIntoBuffer:buffers[i]] == 0)
        {
            break;
        }
    }
    Float32 gain = 1.0;
    //设置音量
    AudioQueueSetParameter (
                            queue,
                            kAudioQueueParam_Volume,
                            gain
                            );
    //队列处理开始,此后系统会自动调用回调(Callback)函数
    AudioQueueStart(queue, nil);
}

- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer
{
    UInt32      numBytes, numPackets;
    // 从文件中接受包数据并保存到缓存(buffer)中
    numPackets = numPacketsToRead;
    AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs,
                         packetIndex, &numPackets, buffer->mAudioData);
    if (numPackets > 0) {
        buffer->mAudioDataByteSize = numBytes;
        AudioQueueEnqueueBuffer(queue, buffer,
                                (packetDescs ? numPackets : 0), packetDescs);
        packetIndex += numPackets;
    }
    return numPackets;
    
}

@endl


检测声音的输出设备

设备自身的外放(iTouch/iPad/iPhone都有),一种是当前是否插入了带外放的耳机

通过查看文档,IOS的所有输出设备有

  • /* Known values of route: 
  • * "Headset" 
  • * "Headphone" 
  • * "Speaker" 
  • * "SpeakerAndMicrophone" 
  • * "HeadphonesAndMicrophone" 
  • * "HeadsetInOut" 
  • * "ReceiverAndMicrophone" 
  • * "Lineout" 

  • CFStringRef route;  
  • UInt32 propertySize = sizeof(CFStringRef);  
  • AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route);

    检测rout中是否包含上述设备的字符名称。

    3、AudioUnit

    该类主要提供了remote IO声音的输入输入输出功能,不多说了,附上代码段


    // comment组件,个人理解是ios的音频设备一样,初始化这个设备,

    // (要想播放音频要得有东西啊,对不)

    AudioComponentDescription desc;
        desc.componentType = kAudioUnitType_Output;
        desc.componentSubType = kAudioUnitSubType_RemoteIO;
        desc.componentFlags = 0;
        desc.componentFlagsMask = 0;
        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
        // Get component
        inputComponent = AudioComponentFindNext(NULL, &desc);
        // Get audio units
        AudioComponentInstanceNew(inputComponent, &audioUnit);


    // 音频流的一些设置,从远处过来的数据流需要配置一下。

    AudioStreamBasicDescription audioFormat = {0};
        audioFormat.mSampleRate            = 8000.00;
        audioFormat.mFormatID            = kAudioFormatLinearPCM;
        audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked|kAudioFormatFlagIsNonInterleaved;
        audioFormat.mFramesPerPacket    = 1;
        audioFormat.mChannelsPerFrame    = 1;
        audioFormat.mBitsPerChannel        = 16;
        audioFormat.mBytesPerPacket        = 2;
        audioFormat.mBytesPerFrame        = 2;


    // 设置输入输出的属性
    AudioUnitSetProperty(audioUnit,
                                      kAudioUnitProperty_StreamFormat,
                                      kAudioUnitScope_Input,
                                      kOutputBus,
                                      &audioFormat,
                                      sizeof(audioFormat));

    AudioUnitSetProperty(audioUnit,
                                          kAudioUnitProperty_StreamFormat,
                                          kAudioUnitScope_Output,
                                          kInputBus,
                                          &audioFormat,
                                          sizeof(audioFormat));


    // Set 回调函数名称:pushDataIntoUnit
        AURenderCallbackStruct callbackStruct;
        callbackStruct.inputProc = pushDataIntoUnit;
        callbackStruct.inputProcRefCon = self;

    // 初始化unit并开始播放
        AudioUnitInitialize(audioUnit);
        AudioOutputUnitStart(audioUnit);


    // 接下来就是回调函数啦

    static OSStatus pushDataIntoUnit (
                            void                        *inRefCon,
                            AudioUnitRenderActionFlags  *ioActionFlags,
                            const AudioTimeStamp        *inTimeStamp,
                            UInt32                      inBusNumber,
                            UInt32                      inNumberFrames,
                            AudioBufferList             *ioData
                            );

    个人总结到此结束,睡觉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值