Android系统音频模块 - Java 层初始化工作

前言

Android的音频模块相对来说是Android系统中比较简单的一个模块,但是仅仅是相对来说,Android系统中任何一个模块都非常的复杂,但是如果想学习framework相关的知识,我觉得音频模块是一个很好的切入点。Android系统中的音频模块几乎涵盖了Android系统中的所有层次,下图是它的框图:

audio_1

简单的介绍下这张图,Framework层和JNI层的工作相对来说比较简单,主要是对数据的一个验证、校验、封装传输的作用,核心的地方都是在Native层处理,包括对音频数据流的处理,音频策略的选择,HAL层主要是根据Native层选择的策略正确的将音频流写入声卡中,还有支持对上层的数据访问。而TinyAlsa是Linux一个轻量级的音频开源库,这里我们就不需要过多的了解,因为还要了解很多音频的相关专业知识,我们只需要知道音频pcm流是如何传输的,音频策略是如何选择的,整个音频框架是什么样的?这样就达到我们对音频模块的学习。

源码分析

由于篇幅问题,本篇先来学习下音频模块Java层的初始化流程,首先我们来看下AudioTrack的API使用,相信应用层的同学一般使用MediaPlayer比较多,而AudioTrack是更为底层的音频API接口,只能播放pcm流,没有编解码的功能。

        int minBuffSize = AudioTrack.getMinBufferSize(8000,        //采样率
                AudioFormat.CHANNEL_OUT_STEREO,  //声道数: 双声道
                AudioFormat.ENCODING_PCM_16BIT); //采样精度: 16bit      

AudioTrack player = new AudioTrack.Builder()
                .setAudioAttributes(new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_ALARM)
                        .setContentType(CONTENT_TYPE_MUSIC)
                        .build())
                .setAudioFormat(new AudioFormat.Builder()
                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                        .setSampleRate(441000)
                        .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                        .build())
                .setBufferSizeInBytes(minBuffSize)
                .build();

        player.play();

        player.write(bytes, 0 , bytes.length);
        player.stop();
        player.release();

首先需要通过查询硬件机器支持的最小buffer是多少,这个buffer和音频流传输有关,后文在分析。首先看看getMinBufferSize()方法的JNI调用:

// ----------------------------------------------------------------------------
// returns the minimum required size for the successful creation of a streaming AudioTrack
// returns -1 if there was an error querying the hardware.
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,  jobject thiz,
    jint sampleRateInHertz, jint channelCount, jint audioFormat) {

    size_t frameCount;
    const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
            sampleRateInHertz);
    if (status != NO_ERROR) {
        ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
                sampleRateInHertz, status);
        return -1;
    }
    const audio_format_t format = audioFormatToNative(audioFormat);
    if (audio_is_linear_pcm(format)) {
        const size_t bytesPerSample = audio_bytes_per_sample(format);
        return frameCount * channelCount * bytesPerSample;
    } else {
        return frameCount;
    }
}

从代码中我们可以看出决定最小buffer大小的和传入的参数和机器的参数有着密不可分的关系,详细的参数含义这里就不介绍了,最后调用了audioFormatToNative(),最后hal层会根据audioFormat查询硬件参数,返回相应的结果。再来看看对AudioTrack对象的构造:

    public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int mode, int sessionId)
                    throws IllegalArgumentException {
        // mState already == STATE_UNINITIALIZED

        //参数校验...

        int rate = 0;
        if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
        {
            rate = format.getSampleRate();
        } else {
            rate = AudioSystem.getPrimaryOutputSamplingRate();
            if (rate <= 0) {
                rate = 44100;
            }
        }
        int channelIndexMask = 0;
        if ((format.getPropertySetMask()
                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
            channelIndexMask = format.getChannelIndexMask();
        }
        int channelMask = 0;
        if ((format.getPropertySetMask()
                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
            channelMask = format.getChannelMask();
        } else if (channelIndexMask == 0) { // if no masks at all, use stereo
            channelMask = AudioFormat.CHANNEL_OUT_FRONT_LEFT
                    | AudioFormat.CHANNEL_OUT_FRONT_RIGHT;
        }
        int encoding = AudioFormat.ENCODING_DEFAULT;
        if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0) {
            encoding = format.getEncoding();
        }
        audioParamCheck(rate, channelMask, channelIndexMask, encoding, mode);
        mStreamType = AudioSystem.STREAM_DEFAULT;

        audioBuffSizeCheck(bufferSizeInBytes);

        mAttributes = new AudioAttributes.Builder(attributes).build();

        //...

        // 调用jni方法
        int initResult = native_setup(new WeakReference<Audi
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值