使用openAL播放音频流

作者: 温暖C | 来源:发表于2016-09-17 15:14 被阅读1404次

上一篇文章写了解码AAC音频流,那么解码后的音频流如何播放呢?下面,我就讲解使用openAL播放音频流。
1.同样,创建一个文件专门用来播放,对外暴露回调方法。

#import <Foundation/Foundation.h>

@interface DDOpenALAudioPlayer : NSObject

+(id)sharePalyer;

/**
 *  播放
 *
 *  @param data       数据
 *  @param dataSize   长度
 *  @param samplerate 采样率
 *  @param channels   通道
 *  @param bit        位数
 */
-(void)openAudioFromQueue:(uint8_t *)data dataSize:(size_t)dataSize samplerate:(int)samplerate channels:(int)channels bit:(int)bit;

/**
 *  停止播放
 */
-(void)stopSound;

@end

2.在.m中实现对外暴露的方法

#import "DDOpenALAudioPlayer.h"
#import <OpenAL/al.h>
#import <OpenAL/alc.h>
#import <OpenAL/oalMacOSX_OALExtensions.h>

@interface DDOpenALAudioPlayer ()
{
    ALCcontext *mContext;
    ALCdevice *mDevice;
    ALuint outSourceId;
    ALuint buff;
}

@end

@implementation DDOpenALAudioPlayer
static DDOpenALAudioPlayer *_player;

+ (id)sharePalyer {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_player == nil) {
            _player = [[DDOpenALAudioPlayer alloc] init];
            [_player initOpenAL];
        }
    });
    return _player;
}

// 初始化openAL
- (void)initOpenAL {
    mDevice=alcOpenDevice(NULL);
    if (mDevice) {
        mContext = alcCreateContext(mDevice, NULL);
        alcMakeContextCurrent(mContext);
    }
    
    alGenSources(1, &outSourceId);
    alSpeedOfSound(1.0);
    alDopplerVelocity(1.0);
    alDopplerFactor(1.0);
    alSourcef(outSourceId, AL_PITCH, 1.0f);
    alSourcef(outSourceId, AL_GAIN, 1.0f);
    alSourcei(outSourceId, AL_LOOPING, AL_FALSE);
    alSourcef(outSourceId, AL_SOURCE_TYPE, AL_STREAMING);
}

// 播放回调
- (void)openAudioFromQueue:(uint8_t *)data dataSize:(size_t)dataSize samplerate:(int)samplerate channels:(int)channels bit:(int)bit {
    NSCondition* ticketCondition= [[NSCondition alloc] init];
    [ticketCondition lock];
    
    if (!mContext) {
        [self initOpenAL];
    }
    
    ALuint bufferID = 0;
    alGenBuffers(1, &bufferID);
    NSData * tmpData = [NSData dataWithBytes:data length:dataSize];
    int aSampleRate,aBit,aChannel;
    aSampleRate = samplerate;
    aBit = bit;
    aChannel = channels;
    ALenum format = 0;
    if (aBit == 8) {
        if (aChannel == 1)
            format = AL_FORMAT_MONO8;
        else if(aChannel == 2)
            format = AL_FORMAT_STEREO8;
        else if( alIsExtensionPresent( "AL_EXT_MCFORMATS" ) )
        {
            if( aChannel == 4 )
            {
                format = alGetEnumValue( "AL_FORMAT_QUAD8" );
            }
            if( aChannel == 6 )
            {
                format = alGetEnumValue( "AL_FORMAT_51CHN8" );
            }
        }
    }else if( aBit == 16 ){
        if( aChannel == 1 )
        {
            format = AL_FORMAT_MONO16;
        }
        if( aChannel == 2 )
        {
            format = AL_FORMAT_STEREO16;
        }
        if( alIsExtensionPresent( "AL_EXT_MCFORMATS" ) )
        {
            if( aChannel == 4 )
            {
                format = alGetEnumValue( "AL_FORMAT_QUAD16" );
            }
            if( aChannel == 6 )
            {
                format = alGetEnumValue( "AL_FORMAT_51CHN16" );
            }
        }
    }
    alBufferData(bufferID, format, (char*)[tmpData bytes], (ALsizei)[tmpData length],aSampleRate);
    alSourceQueueBuffers(outSourceId, 1, &bufferID);
    [self updataQueueBuffer];
    
    ALint stateVaue;
    alGetSourcei(outSourceId, AL_SOURCE_STATE, &stateVaue);
    
    [ticketCondition unlock];
    ticketCondition = nil;
    
}

- (BOOL)updataQueueBuffer {
    ALint stateVaue;
    int processed, queued;
    
    alGetSourcei(outSourceId, AL_BUFFERS_PROCESSED, &processed);
    alGetSourcei(outSourceId, AL_BUFFERS_QUEUED, &queued);
    
    alGetSourcei(outSourceId, AL_SOURCE_STATE, &stateVaue);
    
    if (stateVaue == AL_STOPPED ||
        stateVaue == AL_PAUSED ||
        stateVaue == AL_INITIAL) {
        [self playSound];
    } else if (stateVaue == AL_PLAYING && queued < 1){
        [self pauseSound];
    } else if(stateVaue == 4116){
        return NO;
    }
    while(processed--) {
        alSourceUnqueueBuffers(outSourceId, 1, &buff);
        alDeleteBuffers(1, &buff);
    }
    return YES;
}

- (void)playSound {
    alSourcePlay(outSourceId);
}

- (void)pauseSound {
    ALint  state;
    alGetSourcei(outSourceId, AL_SOURCE_STATE, &state);
    if (state == AL_PLAYING) {
        alSourcePause(outSourceId);
    }
}

- (void)stopSound {
    alSourcePause(outSourceId);
    alSourceStop(outSourceId);
    [self cleanUpOpenAL];
}

- (void)cleanUpOpenAL {
    int processed;
    
    alGetSourcei(outSourceId, AL_BUFFERS_PROCESSED, &processed);
    while(processed--) {
        alDeleteBuffers(1, &buff);
    }
}

@end

相关文章

  • 使用openAL播放音频流

    上一篇文章写了解码AAC音频流,那么解码后的音频流如何播放呢?下面,我就讲解使用openAL播放音频流。1.同样,...

  • openal

    openAL是模仿openGL的播放音频的接口,底层由声卡驱动提供实现; openAL分为三种设备:Native、...

  • Android应用的音频播放和音频焦点的处理

    音频播放 应用会使用到哪些音频流? 音乐 闹铃 通知铃音 来电声音 系统声音 打电话声音 拨号音 按键控制音频播放...

  • NDK--利用AudioTrack播放FFmpeg解码后的音频流

    上次已经得到PCM编码的音频流,今天来实现播放PCM音频流,使用安卓提供的AudioTrack,方法很简单,在na...

  • iOS 音频播放器

    Wave Overview 一个简单的音频播放器的实现,可实现自定义缓存,可以播放各类音频流。 使用方式 创建一个...

  • iOS/Swift - AVFoundation(二)音频的播放

    使用AVAudioPlayer播放音频 在AVFoundation中使用AVAudioPlayer来实现音频的播放...

  • iOS Audio Queue播放PCM音频流

    PCM音频流播放主要步骤如下: 1、确定文件格式 播放PCM音频流前,我们首先需要确定播放的PCM音频的格式信息,...

  • iOS 音频

    iOS 音频播放 本地音频文件 AVPlayer / AVAudioPlayer 在线音频流 AVPlayer i...

  • AudioQueue实现音频流实时播放实战

    需求 使用Audio Queue实现实时播放音频流数据.这里以一个装着pcm数据的caf文件为例进行播放. 实现原...

  • ios 在线本地音乐视频播放器

    前言 文章没有涉及在线音频流视频流播放此播放器针对在线、离线音频播放、离线、在线视频播放本文重点是对AVPlaye...

网友评论

  • 逗比鑫:你好,openAudioFromQueue这个方法中传什么参数,我怎么老是杂音了,我传的是avcodec_decode_audio4(XCodecCtx1, Xframe, &finished, &XPackt);
    int data_size = av_samples_get_buffer_size(NULL, XCodecCtx1->channels, Xframe->nb_samples, XCodecCtx1->sample_fmt, 0);
    NSLog(@"解码音频数据");
    [player openAudioFromQueue:Xframe->data[0] withLength:data_size];
  • 小时候De_我:hi,有个问题想问下,播放实时pcm数据放音乐,但是有电话打进来后,打完电话后,音乐就没有声音了,但是依然在接收,求解。。。
  • justlego:请问一下,我在使用openal播放流媒体音频时,反复切换前台后台之后,使用alBufferData时发现buffID=0,导致音频播放异常,请问这是什么情况?
  • 佛祖拿屠刀:为啥我不能把整个音频文件播放完,每次只有一半
  • c4a7903a42a0:你好,请问文中所说的暴露出的回调,是应该在解码出buffer 后主动调用吗?
  • JoyceZhao:请问您有写好的demo吗?
    ttdiOS:话是这么说的,但是 没有demo
    烦请楼主空闲时上传你写的文章的所有demo
    ttdiOS:@温暖C 话是这么说的,但是 没有demo
    烦请楼主空闲时上传你写的文章的所有demo
    温暖C:@JoyceZhao demo和文章里面写的一样,调用解码以及播放方法时,只要传入数据是对的,应该就没有问题
  • b64d2a007678:大神,以前没接触过音频,所以想问下方便把解码和播放音频的整个的demo给我一份吗?可以的话这是我的邮箱xiang.wang@mytian.com.cn。谢谢
  • 3c58155b56e5:帅哥,有没有遇到播放速度问题。我实时播放流数据,但是声音有延时。。。(播放方法都执行完了,还会继续播放一会)
    温暖C:@牛牛321你好,请问你延时解决了么?具体怎么解决的?
    3c58155b56e5:@温暖C 我感觉是alSourceQueueBuffers 这个queue太多了,缓存进去的数据多,播放就延时了。我在网上看到一个方法是缓存多于某一个值的时候,播放线程sleep一会
    温暖C:@牛牛321 我也有这个问题,暂时还没找到解决方法
  • c1e0f39af20a:这个播放的声音不能外音内音切换啊,
    c1e0f39af20a:@温暖C 请问下。,这个播放声音的时候我关闭了。但是缓存却清不完,这个有办法解决吗
    温暖C:@feng5f 不好意思啊,我暂时还没研究这个
    c1e0f39af20a:求指教,怎么切换手机外音播放和耳机这两种播放模式

本文标题:使用openAL播放音频流

本文链接:https://www.haomeiwen.com/subject/xefwettx.html