Android10 音频系统之音频输出通道

一、AudioTrack的使用

//设置音频属性
AudioAttributes audioAttributes = new AudioAttributes.Builder()
									.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
									.setUsage(AudioAttributes.USAGE_MEDIA)
									.build();
//设置音频格式
AudioFormat audioFormat = new AudioFormat.Builder()
							.setEncoding(AudioFormat.ENCODING_PCM_8BIT)
							.setSampleRate(44100)
							.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
							.build();
//计算最小缓冲区
int bufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO,             
                AudioFormat.ENCODING_PCM_8BIT);

//创建AudioTrack对象
final AudioTrack audioTracker = new AudioTrack(audioAttributes, audioFormat, bufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE);

//开始播放
audioTracker.play();

//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Runnable() {
    @Override
    public void run() {
        byte[] data = new byte[1024]; // small buffer size to not overflow AudioTrack's internal buffer
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(new File(PCM_FILE));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        int readSize = 0;
        while (readSize != -1) {
            try {
                readSize = fileInputStream.read(data);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
            Log.d(TAG, "start play read size is " + readSize);
            if (readSize > 0) {
                //写入数据
                audioTracker.write(data, 0, readSize);
            }
        }
        try {
            fileInputStream.close();
        }
        catch (IOException e) {
            // handle exception
        }
        //播放结束
        audioTracker.stop();
        //释放资源
        audioTracker.release();
    }
});

       1.mode模式:  mode分为MODE_STREAM和MODE_STATIC模式,static模式是指将数据一次性写入到共享内存;stream模式是指将数据分多次写入共享内存。

        2.输出流程: (attr、format、mode等) -> streamType -> strategy ->device -> output

二、output输出通道的选择

private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
        int mode, int sessionId, boolean offload)
                throws IllegalArgumentException {
    
	........................................................................................

    // Check if we should enable deep buffer mode
    if (shouldEnablePowerSaving(mAttributes, format, bufferSizeInBytes, mode)) {
        mAttributes = new AudioAttributes.Builder(mAttributes)
            .replaceFlags((mAttributes.getAllFlags()
                    | AudioAttributes.FLAG_DEEP_BUFFER)
                    & ~AudioAttributes.FLAG_LOW_LATENCY)
            .build();
    }

    .......................................................................................

    int[] sampleRate = new int[] {mSampleRate};
    int[] session = new int[1];
    session[0] = sessionId;
    // native initialization
    int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
            sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
            mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
            offload);
    
	.......................................................................................
	
}

        应用层创建AudioTrack,会调用native_setup方法,native_setup方法对应android_media_AudioTrack.cpp类中的android_media_AudioTrack_setup方法。

xref: /frameworks/base/core/jni/android_media_AudioTrack.cpp

static const JNINativeMethod gMethods[] = {
    ..............................................................................

    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
                                         (void *)android_media_AudioTrack_setup},
    .............................................................................
};
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
        jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
        jlong nativeAudioTrack, jboolean offload) {

    ............................................................................................

    // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
    if (nativeAudioTrack == 0) {
        
		............................................................................................

        // 创建native端的AudioTrack对象
        lpTrack = new AudioTrack();

        ............................................................................................

        switch (memoryMode) {// 针对两种不同的模式设置不同的参数
        case MODE_STREAM:// 多次写入数据模式
            status = lpTrack->set(
                    AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                    sampleRateInHertz,
                    format,// word length, PCM
                    nativeChannelMask,
                    offload ? 0 : frameCount,
                    offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE,
                    audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
                    0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
                    0,// shared mem
                    true,// thread can call Java
                    sessionId,// audio session ID
                    offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
                    offload ? &offloadInfo : NULL,
                    -1, -1,                       // default uid, pid values
                    paa.get());

            break;

        case MODE_STATIC:// 一次写入数据模式
            // AudioTrack is using shared memory

            if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
                ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
                goto native_init_failure;
            }

            status = lpTrack->set(
                    AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                    sampleRateInHertz,
                    format,// word length, PCM
                    nativeChannelMask,
                    frameCount,
                    AUDIO_OUTPUT_FLAG_NONE,
                    audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
                    0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
                    lpJniStorage->mMemBase,// shared mem
                    true,// thread can call Java
                    sessionId,// audio session ID
                    AudioTrack::TRANSFER_SHARED,
                    NULL,                         // default offloadInfo
                    -1, -1,                       // default uid, pid values
                    paa.get());
            break;

        ............................................................................................

    } else {  // end if (nativeAudioTrack == 0)
        ............................................................................................

}

        lpTrack = new AudioTrack()创建AudioTrack,pTrack->set调用AudioTrack.cpp的set方法设置参数。

xref: /frameworks/av/media/libaudioclient/AudioTrack.cpp

status_t AudioTrack::set(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        audio_output_flags_t flags,
        callback_t cbf,
        void* user,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        bool threadCanCallJava,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        uid_t uid,
        pid_t pid,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
{

    .............................................................................................
	
    mCbf = cbf;

    if (cbf != NULL) {// 如果设置了回调函数,则创建AudioTrackThread线程来提供音频数据
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        // thread begins in paused state, and will not reference us until start()
    }

    // 创建IAudioTrack
    {
        AutoMutex lock(mLock);
        status = createTrack_l();
    }
    if (status != NO_ERROR) {
        if (mAudioTrackThread != 0) {
            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
            mAudioTrackThread->requestExitAndWait();
            mAudioTrackThread.clear();
        }
        goto exit;
    }

    .............................................................................................
	
}

        streamType: 音频流类型,如 Music、Voice-Call、DTMF、Alarm 等等

        sampleRate: 音频采样率,如 16KHz、44.1KHz、48KHz 等等

        format:音频格式,如 PCM、MP3、AAC 等等

        channelMask: 声道数, 如 Mono(单声道)、Stereo(双声道)

        frameCount: 帧数, 用于audioFlinger申请内存

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值