`
yangping_Account
  • 浏览: 192822 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
社区版块
存档分类
最新评论

AudioQueue来实现音频播放功能时最主要的步骤

 
阅读更多

使用AudioQueue来实现音频播放功能时最主要的步骤,可以更简练的归纳如下。

1. 打开播放音频文件
2. 取得播放音频文件的数据格式
3. 准备播放用的队列
4. 将缓冲中的数据移动到队列中
5. 开始播放
6. 在回调函数中进行队列处理

以下是贯彻上述六个主要步骤的代码实例,只需要向[play:]中传入音频文件的路径就可以开始音频播放。稍加修改可以直接应用到自己的程序中。

Source Audioplay.h
#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

Source Audioplay.m

static UInt32 gBufferSizeBytes = 0x10000;


@implementation AudioPlayer

@synthesize queue;

// 回调(Callback)函数的实现

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

//初始化方法(为NSObject中定义的初始化方法)

- (id) init {
    for(int i=0; i<NUM_BUFFERS; i++) {
        AudioQueueEnqueueBuffer(queue,buffers,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,
                               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);

        //读取包数据
        if ([self readPacketsIntoBuffer:buffers] == 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;
}
@end

分享到:
评论

相关推荐

    ios-AudioQueue实现音频录制和播放.zip

    本教程将深入探讨如何使用AudioQueue服务来实现音频的录制和播放功能。AudioQueue是Apple提供的一个低级音频处理框架,它允许开发者进行高效且灵活的音频处理。 一、AudioQueue服务简介 AudioQueue服务是Core Audio...

    IOS AudioQueue播放PCM音频数据

    基于AudioQueue完整的PCM播放,数据来源可以是文件或网络,DEMO里演示了不间断的从文件读取PCM数据然后播放,基于本DEMO只需要将网络获取的数据扔给本DEMO里的PCMDataPlayer播放即可,实际测试每秒扔给播放器30次数据...

    Audioqueue播放缓冲区源代码

    在iOS开发中,声音播放是一个常见的需求,而`AudioQueue`服务是苹果提供的一种低级音频处理机制,它允许开发者高效地处理音频数据并实现播放功能。本项目提供的"Audioqueue播放缓冲区源代码"正是基于`AudioQueue`...

    AudioQueue-master

    1. 准备播放:创建AudioQueue并设置播放的音频格式,同样需要提供一个播放回调,这个回调会在AudioQueue需要新的音频数据来播放时被调用。 2. 加载音频数据:将要播放的音频文件加载到内存或者文件系统中,确保...

    基于audioQueue API的播放器程序,用于iOS平台的播放, 直接播放PCM.zip

    在iOS平台上开发音频播放应用时,常常会遇到各种音频处理技术。这个压缩包"基于audioQueue API的播放器程序,用于iOS平台的...通过研究这个项目,开发者可以深入理解如何利用AudioQueue服务来实现高效的音频播放功能。

    iOS 音频播放测试包

    对于非HLS流,可以使用`AVPlayerItem`的URL指向网络资源来实现播放。 3. **讯飞语音合成**:讯飞是中国领先的语音技术提供商,其iFlytek SDK为iOS开发者提供了语音合成功能。通过集成讯飞SDK,应用可以将文本转换为...

    ios播放pcm音频数据

    AudioQueue主要用于播放和记录连续的音频数据流,特别适合处理PCM格式的数据。与AudioUnit相比,AudioQueue更适合于后台播放和处理大量音频数据。 二、理解PCM音频数据 PCM音频数据包含一系列采样点,每个点代表了...

    iOS 音频播放

    在iOS平台上实现音频播放是一项常见的任务,涉及到许多技术细节。这个"iOS 音频播放"的Demo项目提供了直接引用到你的应用中的音频播放功能。在iOS中,有多种方式可以处理音频播放,包括使用AVFoundation框架、Audio...

    iOS声音采集与播放Object C

    AudioQueue主要用于实时音频处理,例如录音和播放,尤其适合处理连续的音频流。它支持多种音频格式,并且可以在后台运行,这对于音乐播放应用或游戏来说非常关键。 首先,我们需要了解声音采集的基本流程。在iOS和...

    linux下实现ffmpeg+sdl视音频播放

    在Linux环境下,使用FFmpeg和SDL(Simple DirectMedia Layer)框架可以实现高效的音视频播放功能。FFmpeg是一个强大的多媒体处理工具集,包含了多种编解码器、格式转换、音视频抽取和流化等功能。而SDL则是一个跨...

    OPENAL实现录音功能

    在iOS应用中,你可能需要结合OPENAL和AudioQueue来实现录音功能,AudioQueue负责底层的音频输入,而OPENAL则负责处理和播放数据。 综上所述,使用OPENAL实现录音功能涉及到一系列步骤,包括设置环境、创建源和缓冲...

    [IOS]播放网络上来的PCM音频数据

    通过以上步骤,你可以在iOS应用中实现网络PCM音频数据的播放。这需要对iOS音频框架有深入理解,以及良好的编程实践,以确保音频播放的稳定性和流畅性。请注意,实际的代码实现会更复杂,需要根据具体的音频格式、...

    iOS通过audio queue 进行录制和播放音频

    本篇文章将深入探讨如何利用Audio Queue Service在iOS上实现音频的录制和播放功能。 一、Audio Queue Service基础 Audio Queue Service是Core Audio框架的一部分,它提供了异步处理音频数据的能力,支持多种音频...

    IOS G711播放Demo

    本文将深入探讨如何使用AudioToolBox框架在iOS上实现G711音频格式的播放,以及如何通过修改音频参数来适应不同的音频压缩格式。 G711是一种广泛使用的音频编码标准,主要用于电话网络和VoIP通信。它有两种编码方式...

    iOS-EchoCancellation:使用AudioUnit进行声音采集,同时实现回声消除。采用AudioQueue对采集的pcm音频流进行播放

    它使用AudioQueue来播放采集到的PCM音频流,确保了流畅且低延迟的音频播放。 1. **AudioUnit框架**: AudioUnit是Apple的Core Audio框架的一部分,它提供了一种灵活的方式来处理音频数据。在这个项目中,AudioUnit...

    本地播放音乐(ios版)

    在iOS平台上,开发一款本地音乐播放器涉及到许多技术细节,特别是在处理PCM音频流和实现进度条功能时。本文将深入探讨这些关键知识点。 首先,我们要理解PCM(脉冲编码调制)音频格式。PCM是未经压缩的数字音频格式...

    iOS在线播放器接口代码

    这些方法可能使用AudioQueue的API来实现音频数据的获取和播放。 AudioStreamAnalyzer.h和AudioStreamAnalyzer.m文件则可能包含了一个用于分析音频流的辅助类。在播放过程中,我们可能需要对音频数据进行实时分析,...

Global site tag (gtag.js) - Google Analytics