欢迎光临
我们一直在努力

Android音频系列(05)-AudioTrack从Java到native调用

目录

1. AudioTrack初始化

1. 1 New AudioTrack

1. 2  Jni 函数

1.3  创建Native AudioTrack,并调用set函数

2. AudioTrack 播放

2.1  AudioTrack.java层play

2. native层调用

3. AudioTrack 写流

3.1 从java到native

3.2 native层调用

 AudioTrack提供音频播放功能,从App调用AudioTrack,函数调用从java层一直到native层,从App进程,一直调到底层AudioServer进程,也会到Audio hal层,当然,也会牵扯到SystemServer进程。

图1  AudioTrack从java到native

下面就AudioTrack,从java层,一直分析到底层,看看调用是如何跟底层交互的。

1. AudioTrack初始化

1. 1 New AudioTrack

首先会new AudioTrack,AudioTrack有多个构造函数,其中有个构造函数会调用

private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,

            int mode, int sessionId, boolean offload, int encapsulationMode,
            @Nullable TunerConfiguration tunerConfiguration){
              ……
           int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode, session, 0 ,
                offload, encapsulationMode, tunerConfiguration,
                getCurrentOpPackageName());
}

1. 2  Jni 函数

 Jni在文件frameworks\\base\\core\\jni的android_media_AudioTrack.cpp文件里,当然native_setup函数在进程启动时就已经注册,注册了static const JNINativeMethod gMethods[]函数数组,注册如下:

static const JNINativeMethod gMethods[] = {

        // name,              signature,     funcPtr

        {"native_is_direct_output_supported", "(IIIIIII)Z",
         (void *)android_media_AudioTrack_is_direct_output_supported},
        {"native_start", "()V", (void *)android_media_AudioTrack_start},
        {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
        {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
        {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
        {"native_setup",
         "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
         (void *)android_media_AudioTrack_setup},
        {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
        {"native_release", "()V", (void *)android_media_AudioTrack_release},
}

1.3  创建Native AudioTrack,并调用set函数

lpTrack = new AudioTrack(attributionSource);
……
status = lpTrack->set(AUDIO_STREAM_DEFAULT,…)

set 函数调用createTrack_l 函数

status_t AudioTrack::set(
        audio_stream_type_t streamType,
         ……)
{

……

if (cbf != NULL) {
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        // thread begins in paused state, and will not reference us until start()
    }
    // create the IAudioTrack
    {
        AutoMutex lock(mLock);
        status = createTrack_l();
    }

}

最终AudioTrack通过AudioSystem拿到AudioFlinger对象,调用AudioFlinger->CreateTrack,  再调用到AudioFlinger::PlaybackThread->CreateTrack_l函数,具体可参考图2

图2 AudioTrack初始化调用流程

2. AudioTrack 播放

2.1  AudioTrack.java层play

Play函数会调用startImpl函数,会调用native_start函数到native层。

public void play()
    throws IllegalStateException {
……
        try {

           startImpl();

       } catch (IllegalStateException e) {
……
        }

       }
 }

2. native层调用

native_start调用mAudioTrack的start()函数,这是个binder接口,函数定义在frameworks/av/media/libmedia/IAudioTrack.aidl,  由AudioFlinger::PlaybackThread实现

status_t AudioTrack::start()

{
……

if (!(flags & CBLK_INVALID)) {
        mAudioTrack->start(&status);
        if (status == DEAD_OBJECT) {
            flags |= CBLK_INVALID;
        }
    }
……

}

图3 AudioTrack play调用流程

当然PlaybackThread有子类MixerThread等,最终实现由其他子类实现。

3. AudioTrack 写流

3.1 从java到native

上述播放是控制AudioTrack进入播放状态,但实际播放是,需要喂流,在其他文章中描述过,AudioTrack可以以静态模式一次性写入,也可以按照stream方式喂流。

调用都差不多,一直调到native层

public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
            @WriteMode int writeMode) {
     ……

        final int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,writeMode == WRITE_BLOCKING);

  ……
        return ret;

}

3.2 native层调用

会调用AudioTrack的Write

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
{
……

while (userSize >= mFrameSize) {
        audioBuffer.frameCount = userSize / mFrameSize;
        status_t err = obtainBuffer(&audioBuffer,
                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
        if (err < 0) {
            if (written > 0) {
                break;
            }
            if (err == TIMED_OUT || err == -EINTR) {
                err = WOULD_BLOCK;
            }
            return ssize_t(err);
        }

        size_t toWrite = audioBuffer.size;
        memcpy(audioBuffer.i8, buffer, toWrite);
        buffer = ((const char *) buffer) + toWrite;
        userSize -= toWrite;
        written += toWrite;
        releaseBuffer(&audioBuffer);
    }
……

}

AudioTrack::write() 从 Java 层接收音频数据后,最终将数据写入一块由 AudioFlinger 和 AudioTrack 共享的环形缓冲区(Shared Memory Ring Buffer)中。AudioFlinger 的播放线程(如 MixerThread)会从该缓冲区读取数据,混音后送入 HAL(硬件抽象层)进行播放。

图4  AudioTrack Write函数

赞(0)
未经允许不得转载:171主机测评 » Android音频系列(05)-AudioTrack从Java到native调用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址