Android Audio Subsystem - AudioTrack - write

本文详细解析了Android系统中AudioTrack的写入机制,包括write()方法的实现原理、JNI层面的native_write函数以及writeToTrack函数的工作流程。探讨了不同模式下数据如何被正确写入,并解释了共享内存和控制结构在这一过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

 

 

 

1.        AudioTrack:: write ()

Frameworks/base/media/java/android/media/AudioTrack.java

public intwrite(byte[] audioData, int offsetInBytes, int sizeInBytes) {

 

        if (mState == STATE_UNINITIALIZED) {

            return ERROR_INVALID_OPERATION;

        }

 

        if ( (audioData == null) ||(offsetInBytes < 0 ) || (sizeInBytes < 0)

                || (offsetInBytes + sizeInBytes< 0)    // detect integer overflow

                || (offsetInBytes + sizeInBytes >audioData.length)) {

            return ERROR_BAD_VALUE;

        }

 

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

 

        if ((mDataLoadMode == MODE_STATIC)

                && (mState ==STATE_NO_STATIC_DATA)

                && (ret > 0)) {

            // benign race with respect toother APIs that read mState

            mState = STATE_INITIALIZED;

        }

 

        return ret;

    }

 

    public int write(short[] audioData, intoffsetInShorts, int sizeInShorts) {

 

        if (mState == STATE_UNINITIALIZED) {

            return ERROR_INVALID_OPERATION;

        }

 

        if ( (audioData == null) ||(offsetInShorts < 0 ) || (sizeInShorts < 0)

                || (offsetInShorts +sizeInShorts < 0)  // detect integeroverflow

                || (offsetInShorts +sizeInShorts > audioData.length)) {

            return ERROR_BAD_VALUE;

        }

 

        int ret =native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);

 

        if ((mDataLoadMode == MODE_STATIC)

                && (mState ==STATE_NO_STATIC_DATA)

                && (ret > 0)) {

            // benign race with respect toother APIs that read mState

            mState = STATE_INITIALIZED;

        }

 

        return ret;

    }

 

2.       android_media_AudioTrack_native_write_short ()

frameworks/base/core/jni/android_media_AudioTrack.cpp

static jintandroid_media_AudioTrack_native_write_byte(JNIEnv *env,  jobject thiz,

                                                  jbyteArrayjavaAudioData,

                                                 jint offsetInBytes, jint sizeInBytes,

                                                 jint javaAudioFormat) {

    //ALOGV("android_media_AudioTrack_native_write_byte(offset=%d,sizeInBytes=%d) called",

    //   offsetInBytes, sizeInBytes);

 

   sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);

 

// JAVA 环境中得到本地 AudioTrack对象

 

    if (lpTrack == NULL) {

        jniThrowException(env,"java/lang/IllegalStateException",

            "Unable to retrieve AudioTrackpointer for write()");

        return 0;

    }

 

    // get the pointer for the audio data fromthe java array

    // NOTE: We may useGetPrimitiveArrayCritical() when the JNI implementation changes in such

    // a way that it becomes much moreefficient. When doing so, we will have to prevent the

    // AudioSystem callback to be called whilein critical section (in case of media server

    // process crash for instance)

    jbyte* cAudioData = NULL;

    if (javaAudioData) {

        cAudioData = (jbyte*)env->GetByteArrayElements(javaAudioData, NULL);

        if (cAudioData == NULL) {

            ALOGE("Error retrieving sourceof audio data to play, can't play");

            return 0; // out of memory or no datato load

        }

    } else {

        ALOGE("NULL java array of audiodata to play, can't play");

        return 0;

    }

 

    jint written =writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);

 

    env->ReleaseByteArrayElements(javaAudioData,cAudioData, 0);

 

    //ALOGV("write wrote %d (tried %d)bytes in the native AudioTrack with offset %d",

    //    (int)written, (int)(sizeInBytes), (int)offsetInBytes);

    return written;

}

 

 

 

 

 

static jintandroid_media_AudioTrack_native_write_short(JNIEnv *env,  jobject thiz,

                                                 jshortArray javaAudioData,

                                                 jint offsetInShorts, jint sizeInShorts,

                                                  jintjavaAudioFormat) {

    return(android_media_AudioTrack_native_write_byte(env, thiz,

                                                (jbyteArray) javaAudioData,

                                                offsetInShorts*2, sizeInShorts*2,

                                                javaAudioFormat)

            / 2);

}

 

 

3.      writeToTrack ()

frameworks/base/core/jni/android_media_AudioTrack.cpp

jintwriteToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte*data,

                  jint offsetInBytes, jintsizeInBytes) {

    // give the data to the native AudioTrackobject (the data starts at the offset)

    ssize_t written = 0;

    // regular write() or copy the data to theAudioTrack's shared memory?

    if (track->sharedBuffer() == 0) {

 

// stream mode

// 调用本地的write方法

 

        written =track->write(data + offsetInBytes, sizeInBytes);

 

    } else {  // static mode

        if (audioFormat ==javaAudioTrackFields.PCM16) {

            // writing to shared memory, checkfor capacity

            if ((size_t)sizeInBytes >track->sharedBuffer()->size()) {

                sizeInBytes =track->sharedBuffer()->size();

            }

           memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes,sizeInBytes);

            written = sizeInBytes;

        } else if (audioFormat ==javaAudioTrackFields.PCM8) {

            // data contains 8bit data we needto expand to 16bit before copying

            // to the shared memory

            // writing to shared memory, checkfor capacity,

            // note that input data will occupy2X the input space due to 8 to 16bit conversion

            if (((size_t)sizeInBytes)*2 >track->sharedBuffer()->size()) {

                sizeInBytes =track->sharedBuffer()->size() / 2;

            }

            int count = sizeInBytes;

            int16_t *dst = (int16_t*)track->sharedBuffer()->pointer();

            const int8_t *src = (const int8_t*)(data + offsetInBytes);

            while (count--) {

                *dst++ = (int16_t)(*src++^0x80)<< 8;

            }

            // even though we wrote2*sizeInBytes, we only report sizeInBytes as written to hide

            // the 8bit mixer restriction fromthe user of this function

            written = sizeInBytes;

        }

    }

    return written;

 

}

 

 

 

 

 

 

 

 

4.      说明

一块共享内存

一个控制结构

通过共享内存传递数据

通过控制结构协调生产者和消费者线程

 

5.      AudioTrack::write()

Frameworks/av/media/libmedia/AudioTrack.cpp

 

ssize_t AudioTrack::write(const void* buffer, size_t userSize)

{

 

    if (mSharedBuffer != 0 ||mIsTimed) {

        returnINVALID_OPERATION;

    }

 

    if (ssize_t(userSize) <0) {

        // Sanity-check: useris most-likely passing an error code, and it would

        // make the returnvalue ambiguous (actualSize vs error).

       ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",

                buffer,userSize, userSize);

        return BAD_VALUE;

    }

 

    ALOGV("write %p: %dbytes, mActive=%d", this, userSize, mActive);

 

    if (userSize == 0) {

        return 0;

    }

 

    // acquire a strongreference on the IMemory and IAudioTrack so that they cannot be destroyed

// while we are accessing the cblk

 

    mLock.lock();

   sp<IAudioTrack> audioTrack = mAudioTrack;

   sp<IMemory> iMem = mCblkMemory;

    mLock.unlock();

 

    // since mLock is unlockedthe IAudioTrack and shared memory may be re-created,

    // so all cblk referencesmight still refer to old shared memory, but that should be benign

 

    ssize_t written = 0;

    const int8_t *src = (constint8_t *)buffer;

    Buffer audioBuffer;

    size_t frameSz =frameSize();

 

    do {

        audioBuffer.frameCount= userSize/frameSz;

 

       status_t err = obtainBuffer(&audioBuffer, -1);

 

        if (err < 0) {

            // out of buffers,return #bytes written

            if (err ==status_t(NO_MORE_BUFFERS)) {

                break;

            }

            returnssize_t(err);

        }

 

        size_t toWrite;

 

        if (mFormat ==AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {

            // Divide capacityby 2 to take expansion into account

            toWrite =audioBuffer.size>>1;

           memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) src, toWrite);

        } else {

            toWrite =audioBuffer.size;

           memcpy(audioBuffer.i8, src, toWrite);

        }

        src += toWrite;

        userSize -= toWrite;

        written += toWrite;

 

       releaseBuffer(&audioBuffer);

 

    } while (userSize >=frameSz);

 

    return written;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值