AudioRecord 프로세스를 통해 Android 오디오 시스템 설명

Android API AudioRecorder 구성 프로세스에서 시작 :

생성자는 native_setup 기본 함수를 호출합니다. android_media_AudioRecorder.cpp jni 파일에서 기본 API 인터페이스는 기본 인터페이스에 해당합니다.

    private native final int native_setup(Object audiorecord_this,
            Object /*AudioAttributes*/ attributes,
            int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
            int buffSizeInBytes, int[] sessionId, String opPackageName,
            long nativeRecordInJavaObj);

    private native final int native_start(int syncEvent, int sessionId);

    private native final int native_read_in_byte_array(byte[] audioData,
            int offsetInBytes, int sizeInBytes, boolean isBlocking);

android_media_AudioRecord_setup

lpRecorder = new AudioRecord (String16 (opPackageNameStr.c_str ()));

lpRecorder-> set, openRecord_l을 호출하고 AF openRecord에 액세스하여 IAudioRecord를 가져옵니다.

sp <IAudioRecord> AudioFlinger :: openRecord

recordingAllowed (opPackageName, tid, clientUid) 패키지 이름 등을 기반으로 권한을 확인합니다.

RecordThread * thread = checkRecordThread_l (input) audio_io_handle에 따라 mRecordThreads에서 recordthread를 가져옵니다.

client = registerPid (pid)는 AudioFlinger :: Client 객체를 생성하고, clinet은 주로 1024 * 1024 메모리를 포함하고, 클라이언트를 mClients.add (pid, client)에 추가합니다.

AudioFlinger :: RecordThread :: createRecordTrack_l은 recordthread를 사용하여 트랙을 만듭니다.

recordHandle = new RecordHandle (recordTrack); 利用 recordtrack 生成 recordHandle

return recordHandle; RecordHandle은 BnAudioRecord에서 상속하고 사용을 위해 AudioRecorder로 반환되는 sp <IAudioRecord> 유형의 bindler 개체를 반환합니다.

IAudioFlinger는 AudioFlinger의 Bindler 호출 인터페이스입니다. 클라이언트 계층은 AudioRecorder.cpp가 실행하는 계층이기도합니다. AF bindler 객체는 AudioSystem에서 제공하는 인터페이스를 통해 얻습니다. 실제 프로세스는 ServiceManager를 통해 Bindler 서비스를 찾아 bindler 객체를 얻고 AudioSystem에 정적 상태를 저장하는 것입니다. 값.

sp <IAudioFlinger> & audioFlinger = AudioSystem :: get_audio_flinger ()

AF의 bindler 객체는 표준 Bindler 호출 인 openRcorder의 동작을 수행합니다. 많은 코드가 삭제되고 Bindler 호출 만 유지됩니다. 데이터와 응답은 각각 호출의 직렬화와 리턴의 직렬화입니다. Bindler 호출에 대해 remote ()-> transact 수행 , IAudioRecord Bindler 개체가 반환됩니다.

Bindler가 호출하는 코드는 OPEN_RECORD이며 코드에 따라 서버 측에서 호출 할 수 있습니다.

    virtual sp<IAudioRecord> openRecord(
                                audio_io_handle_t input,
                                uint32_t sampleRate,
                                audio_format_t format,...)
    {
        Parcel data, reply;
        sp<IAudioRecord> record;

        data.writeInt32((int32_t) input);      
        data.writeInt32(format);
      
        status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
        if (lStatus != NO_ERROR) {
            ALOGE("openRecord error: %s", strerror(-lStatus));
        } else {
            
            size_t lNotificationFrames = (size_t) reply.readInt64();
  
            lStatus = reply.readInt32();
            record = interface_cast<IAudioRecord>(reply.readStrongBinder());
            cblk = interface_cast<IMemory>(reply.readStrongBinder());

            buffers = interface_cast<IMemory>(reply.readStrongBinder())
}

Android 시스템에서 코드를 설계 할 때 일반적으로 Bindler 서버 수신 구현과 클라이언트 호출 구현은 하나의 파일에 있습니다. 여기 IAudioFlinger에서 BnAudioFlinger는 서버 측 인터페이스를 나타내고 onTransact는 Bindler 호출을받습니다.

다음 코드는 Bindler 호출의 일부만 유지합니다. 여기서 BnAudioFlinger는 AudioFlinger의 상위 클래스이므로 openRecord에 대한 호출은 AudioFlinger의 멤버이므로 오디오 서비스 AudioFlinger에 대한 호출이 한 번 실행됩니다. 그리고 Bindler 객체를 포함하여 반환도 직렬화됩니다.

status_t BnAudioFlinger::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
        case OPEN_RECORD: {
            CHECK_INTERFACE(IAudioFlinger, data, reply);
            audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
            
            sp<IAudioRecord> record = openRecord(input,
                    sampleRate, format, channelMask, opPackageName, &frameCount, &flags,
                    pid, tid, clientUid, &sessionId, &notificationFrames, cblk, buffers,
                    &status);
        
            reply->writeInt32(status);
            reply->writeStrongBinder(IInterface::asBinder(record));
            reply->writeStrongBinder(IInterface::asBinder(cblk));
            reply->writeStrongBinder(IInterface::asBinder(buffers));

 

 

AudioFlinger :: RecordThread :: createRecordTrack_l은 recordthread를 사용하여 트랙을 만듭니다.

track = new RecordTrack (this, client, sampleRate,

                      형식, channelMask, frameCount, NULL, sessionId, uid,

                      * flags, TrackBase :: TYPE_DEFAULT); RecordBufferConverter AudioRecordServerProxy ResamplerBufferProvider를 포함합니다.

mTracks.add (track); mTracks는 벡터입니다.

sp <RecordTrack> 개체 반환

AudioRecorder는 클라이언트 측에서 AF에 액세스 할 수있는 Bindler 개체 IAudioRecord를 가져와 mAudioRecord에 할당했으며 공유 메모리를 사용하는 것도 매우 중요합니다.

이 시점에서 레코더 초기화가 완료되었습니다.


API

startRecording의 해당 프로세스는 다음과 같습니다.


native_start는 native start를 호출합니다.

android_media_AudioRecord_start jni 함수 시작

sp <AudioRecord> lpRecorder = getAudioRecord (env, thiz); 이전에 생성되어 Java 계층에 저장된 AudioRecorder 개체를 가져옵니다.

lpRecorder-> start ((AudioSystem :: sync_event_t) event, (audio_session_t) triggerSession)은 AudioRecorder의 시작을 호출하고 triggerSession은 Java API에서 전달되며 기본값은 0입니다.

status_t AudioRecord :: start

status = mAudioRecord-> start (event, triggerSession); 이전에 AF에서 얻은 IAudioRecorder Bindler 개체 mAudioRecord를 호출합니다. 호출 할 수있는 인터페이스는 두 개뿐입니다. 트랜잭션 코드는 Bindler가 호출하는 유형을 나타냅니다.

enum {
    UNUSED_WAS_GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
    START,
    STOP
};

status_t BnAudioRecord :: onTransact는 서버 측 시작을 실행하고 RecordHandle은 BnAudioRecord에서 상속하므로 BnAudioRecorder에서 start를 호출하는 것은 AudioFlinger :: RecordHandle :: start 멤버 함수입니다.

audioflinger / Tracks.cpp에서 AudioFlinger :: RecordHandle 구현

mRecordTrack-> start ((AudioSystem :: sync_event_t) event, triggerSession); 실제로 트랙을 실행하는 메서드를 호출합니다 .RecordHandle은 RecordTrack의 Bindler 캡슐화 여야합니다.

status_t AudioFlinger :: RecordThread :: RecordTrack :: start RecordTrack과 RecordThread는 밀접한 관련이 있습니다.

트랙의 정의는 RecordTrack.h에 있으며 audioflinger 디렉토리의 Tracks.cpp에서 구현됩니다.

recordThread-> start (this, event, triggerSession); RecordThread에서 start를 호출하고 현재 트랙 객체를 RecordThread에 전달하고 이벤트에 SYNC_EVENT_NONE을 사용합니다 (Java에 의해 전달, AudioSystem에 의해 매핑 됨).

AudioFlinger :: RecordThread :: start

        mActiveTracks.add (recordTrack); 활성 대기열에 참여

        mActiveTracksGen ++, 활성 카운트 증가

        recordTrack-> mResamplerBufferProvider-> reset (); 일부 재설정 ...

        // 새 데이터가 불연속 적이기 때문에 변환기 상태를 지 웁니다.

        recordTrack-> mRecordBufferConverter-> reset ();

        recordTrack-> mState = TrackBase :: STARTING_2; 시작 状态

        // 시작할 스레드 신호

        mWaitWorkCV.broadcast (); 스레드 시작 알림

다음은이 mActiveTracks 및 내부 트랙을 사용하는 방법을 보여줍니다.

AudioFlinger :: RecordThread :: threadLoop () AudioFlinger 및 AudioPolicyService의 시작 단계에서 생성 된 레코더 스레드 실행 본문.

for (;;) {스레드 루프

size_t 크기 = mActiveTracks.size (); 

mWaitWorkCV.wait (mLock); 활성 트랙이 0이면 CV wait를 사용하여 레코더가 시작될 때 생성 된 트랙을 대기열에 추가하고 CV 신호가 여기에서 작업을 시작하도록 알려줍니다.

            for (size_t i = 0; i <size;) {각 레코드 트랙 순회

                activeTrack = mActiveTracks [i];

                트랙 상태를 확인하려면 전환하십시오. mActiveTracks의 항목도 비활성 상태 일 수 있습니다. PAUSING STARTING_1 STARTING_2 ACTIVE IDLE

               activeTracks.add (activeTrack); 로컬 대기열에 활성 상태를 추가합니다.

또한 hw에서 버퍼로 오디오 데이터를 읽는 레코드 threadloop에는 핵심 작업이 있습니다.

Threadloop는 hw에서 버퍼로 오디오 데이터를 읽습니다 .mRsmpInBuffer는 버퍼 버퍼, mRsmpInRear는 버퍼 쓰기 데이터 오프셋,


        // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
        // Only the client(s) that are too slow will overrun. But if even the fastest client is too
        // slow, then this RecordThread will overrun by not calling HAL read often enough.
        // If destination is non-contiguous, first read past the nominal end of buffer, then
        // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.

        int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
        ssize_t framesRead;

        // If an NBAIO source is present, use it to read the normal capture's data
        if (mPipeSource != 0) {
            size_t framesToRead = mBufferSize / mFrameSize;
            framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
                    framesToRead);
            if (framesRead == 0) {
                // since pipe is non-blocking, simulate blocking input
                sleepUs = (framesToRead * 1000000LL) / mSampleRate;
            }
        // otherwise use the HAL / AudioStreamIn directly
        } else {
            ATRACE_BEGIN("read");
            ssize_t bytesRead = mInput->stream->read(mInput->stream,
                    (uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize);
            ATRACE_END();
            if (bytesRead < 0) {
                framesRead = bytesRead;
            } else {
                framesRead = bytesRead / mFrameSize;
            }
        }

 

레코드 threadloop에서 실제 활성 트랙 로컬 큐를 통과합니다.

        size = activeTracks.size ();

        // 각 활성 트랙을 반복합니다.

        for (size_t i = 0; i <size; i ++) {

            activeTrack = activeTracks [i];

            각 트랙의 버퍼 루프 업데이트

업데이트 버퍼 프로세스 추적,

activeTrack-> mResamplerBufferProvider-> sync (& framesIn, & hasOverrun); 

 mResamplerBufferProvider는 트랙의 멤버 객체입니다. 트랙이 생성되고이 트랙 참조가 전달 될 때 생성됩니다. 따라서 mResamplerBufferProvider에는 트랙에 대한 참조가 있고 트랙에 RecordThread 응용 프로그램이 있으며 동기화 된 recordThread에 대한 참조를 가져올 수 있습니다.

오디오 버퍼의 상태는 스레드에 저장되며 이러한 상태는 mResamplerBufferProvider로 업데이트됩니다.

    const int32_t rear = recordThread-> mRsmpInRear;

    const int32_t 앞 = mRsmpInFront;

    const ssize_t filled = 후면-전면;


    // RecordThread 버퍼 공급자에서 RecordTrack 버퍼로 프레임 처리

   framesOut = activeTrack-> mRecordBufferConverter-> convert (activeTrack-> mSink.raw, activeTrack-> mResamplerBufferProvider, framesOut);


    // 프레임 정보 업데이트 및 타임 스탬프 푸시

   activeTrack-> updateTrackFrameInfo (activeTrack-> mServerProxy-> framesReleased (),

                    mTimestamp.mPosition [ExtendedTimestamp :: LOCATION_SERVER],

                    mSampleRate, mTimestamp);

ResamplerBufferProvider 및 RecordBufferConverter의 구현은 AudioFlinger.cpp에 있으며,이 두 가지 유형의 객체는 오디오 캡처 프로세스에서 트랙을 지원하는 트랙에 속합니다.

RecorderBufferConverter가 빌드 될 때 리샘플링을 위해 mResampler = AudioResampler :: create를 생성했습니다.

RecordBufferConverter :: conver 프로세스는 mResampler를 사용하여 입력을 다시 샘플링하고 activeTrack-> mSink.raw에 복사하는 것입니다.


해당 API 읽기 과정은 다음과 같습니다.


 

native_read_in_byte_array jni 实现

lpRecorder-> read 调用 AudioRecorder 네이티브 읽기

ssize_t AudioRecord :: read (void * buffer, size_t userSize, bool blocking)

 status_t err = getBuffer (& audioBuffer,

                차단? & ClientProxy :: kForever : & ClientProxy :: kNonBlocking); 오디오 수를 audioBuffer로 가져 오기 위해 주기적으로 호출

getBuffer 실행 프로세스는 openRecord 단계에서 생성 된 AudioRecordClientProxy를 사용합니다.

mProxy = new AudioRecordClientProxy (cblk, buffers, mFrameCount, mFrameSize);

buffers =  bufferMem- > pointer (); buffers 공유 메모리에있는 버퍼의 시작 주소입니다.

bufferMem 은 AF openRecord 프로세스에 의해 생성 된 공유 메모리입니다.

cblk는 버퍼 제어 블록 인 iMem을 가리 킵니다.

    sp <IMemory> iMem; // cblk 용

    sp <IMemory>  bufferMem ;

    sp <IAudioRecord> 레코드 = audioFlinger-> openRecord (input,

                                                       mSampleRate,

                                                       mFormat,

                                                       mChannelMask,

                                                       opPackageName,

                                                       & temp,

                                                       플래그,

                                                       mClientPid,

                                                       시각,

                                                       mClientUid;

                                                       & mSessionId,

                                                       & notificationFrames,

                                                       iMem,

                                                       bufferMem ,

                                                       &상태);

class AudioRecordClientProxy : public ClientProxy는 AudioTrackShared.h에 정의 된 ClientProxy에서 상속되며 AudioTrack은 동일한 구현을 가지고 있으며 주로 클라이언트와 서버 간의 데이터 전송을 공유하는 크로스 프로세스 메모리에 사용됩니다.

getBuffer는 상위 클래스 ClientProxy의 멤버이고 getBuffer는 공유 메모리를 읽는 위치이며 포인터는 해당 지점을 가리 킵니다.

            buffer-> mFrameCount = part1;

            buffer-> mRaw = part1> 0?

                    & ((char *) mBuffers) [(mIsOut? rear : front) * mFrameSize] : NULL; mBuffers는 Porxy를 만들 때 전달되는 공유 메모리 객체입니다.

getBuffer는 for (;;) 루프를 통해 AF 서비스에서 생성 된 오디오 데이터를 가져오고 데이터를 중단하거나 가져온 후 반환하는 차단 호출입니다.

위에서 언급 한 컨트롤 블록의 데이터를 통해 사용 가능한 데이터가 있는지 판단하고, 후면에 쓰기, 전면에서 읽기

        int32_t front;
        int32_t rear;
        if (mIsOut) {
            // The barrier following the read of mFront is probably redundant.
            // We're about to perform a conditional branch based on 'filled',
            // which will force the processor to observe the read of mFront
            // prior to allowing data writes starting at mRaw.
            // However, the processor may support speculative execution,
            // and be unable to undo speculative writes into shared memory.
            // The barrier will prevent such speculative execution.
            front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
            rear = cblk->u.mStreaming.mRear;
        } else {
            // On the other hand, this barrier is required.
            rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
            front = cblk->u.mStreaming.mFront;
        }
        // write to rear, read from front
        ssize_t filled = rear - front;

 

AudioRecord :: read가 getBuffer를 호출하여 공유 메모리의 읽기 주소를 얻은 후 데이터를 사용자 버퍼에 복사하고 데이터 읽기를 완료합니다 .getBuffer 프로세스는 데이터의 한 프레임 만 얻고 read는 getBuffer를 호출하여 루프의 사용자 버퍼에 여러 데이터 프레임을 가져올 수 있습니다.

size_t bytesRead = audioBuffer.size;

 memcpy (buffer, audioBuffer.i8, bytesRead);


AudioRecord는 클라이언트 측에서 AudioFlinger 서버를 호출 할 때 IMemory 유형의 두 공유 메모리 개체를 전달합니다.

iMem 애플리케이션 제어, bufferMem은 공유 메모리 버퍼입니다.

    sp<IMemory> iMem;           // for cblk
    sp<IMemory> bufferMem;
    sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                       mSampleRate,
                                                       mFormat,
                                                       mChannelMask,
                                                       opPackageName,
                                                       &temp,
                                                       &flags,
                                                       mClientPid,
                                                       tid,
                                                       mClientUid,
                                                       &mSessionId,
                                                       &notificationFrames,
                                                       iMem,
                                                       bufferMem,
                                                       &status);

sp <IAudioRecord> AudioFlinger :: openRecord 공유 메모리 구현, recorderTrack 메서드에 의해 획득, 클라이언트가 트랙에 해당하는 openRecord를 한 번 호출하므로 오디오 전송을 위해 각 클라이언트와 서버간에 공유 메모리가 하나만 있습니다.

    cblk = recordTrack-> getCblk ();  

    buffers = recordTrack-> getBuffers ();

recordTrack은 Bindler 객체 IAudioRecord로 패키징되어 클라이언트에 반환되며 실제로 각 클라이언트는 해당 IAudioRecord를 통해 서버를 호출합니다.

recordHandle = new RecordHandle (recordTrack);

return recordHandle; 반환 값은 sp <IAudioRecord>이고 RecordHandle은 BnAudioRecord에서 상속됩니다.

AudioFlinger openRecord 프로세스는 두 개의 대기열을 포함하는 RecordTrack을 생성합니다.

mTracks 및 mActiveTracks

mTracks : 방금 생성 된이 대기열에 참여합니다.

mActiveTracks : 시작 후이 대기열에 참여합니다.

RecordTrack은 TrackBase에서 상속되며 AudioFlinger :: Client 개체를 참조합니다. clinet에는 주로 1024 * 1024 메모리가 포함되어 있습니다. 클라이언트는 RecordTrack이 빌드되기 전에 만들어 져서 RecordTrack이 빌드 될 때 RecordTrack으로 전달되며 이는 서버의 클라이언트 인스턴스를 나타냅니다.

TrackBase의 구성 프로세스는 공유 메모리를 생성합니다.

mCblkMemory 및 mBufferMemory는 제어 블록 및 공유 메모리에 해당하며 다음 호출에서 반환됩니다.

    cblk = recordTrack-> getCblk ();  

    buffers = recordTrack-> getBuffers ();

위의 프로세스는 공유 메모리를 읽는 프로세스이며 일부 공유 메모리 프로세스는 RecodThread의 스레드 루프에 있습니다.

status_t 상태 = activeTrack-> getNextBuffer (& activeTrack-> mSink);  

status_t status = mServerProxy-> obtainBuffer (& buf) ServerProxy의 getBuffer의 실제 구현은 ClientProxy와 동일합니다.

추천

출처blog.csdn.net/u012759483/article/details/109618950