Android Audio 系统的主要内容:

  • AudioManager:这个主要是用来管理Audio系统的,需要考虑整个系统上声音的策略问题,例如来电话铃声,短信铃声等,主要是策略上的问题。
  • AudioTrack:这个主要是用来播放声音的
  • AudioRecord:这个主要是用来录音的

当前分析AudioTrack的文章较多,先以AudioTrack为例进行分析。

JAVA层的AudioTrack class:framework\base\media\java\android\media\AudioTrack.java中。

AudioTrack的使用方法实例:

 1 //根据采样率,采样精度,单双声道来得到frame的大小。 2 int bufsize = AudioTrack.getMinBufferSize(8000,//每秒8K个点 3 AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道 4 AudioFormat.ENCODING_PCM_16BIT);//一个采样点16比特-2个字节 5 //注意,按照数字音频的知识,这个算出来的是一秒钟buffer的大小。 6 //创建AudioTrack 7 AudioTrack trackplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 8 AudioFormat.CHANNEL_CONFIGURATION_ STEREO, 9 AudioFormat.ENCODING_PCM_16BIT,bufsize,AudioTrack.MODE_STREAM);//10 trackplayer.play() ;//开始11 trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ;//往track中写数据12 ….13 trackplayer.stop();//停止播放14 trackplayer.release();//释放底层资源。

  AudioTrack.MODE_STREAMAudioTrack中有MODE_STATIC和MODE_STREAM两种分类。STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。

  StreamType:这个在构造AudioTrack的第一个参数中使用。这个参数和Android中的AudioManager有关系,涉及到手机上的音频管理策略。Android将系统的声音分为以下几类常见的(未写全):

  • STREAM_ALARM:警告声
  • STREAM_MUSCI:音乐声,例如music等
  • STREAM_RING:铃声
  • STREAM_SYSTEM:系统声音
  • STREAM_VOCIE_CALL:电话声音

  为什么要分这么多呢?以前在台式机上开发的时候很少知道有这么多的声音类型,不过仔细思考下,发现这样做是有道理的。例如你在听music的时候接到电话,这个时候music播放肯定会停止,此时你只能听到电话,如果你调节音量的话,这个调节肯定只对电话起作用。当电话打完了,再回到music,你肯定不用再调节音量了。其实系统将这几种声音的数据分开管理,所以,这个参数对AudioTrack来说,它的含义就是告诉系统,我现在想使用的是哪种类型的声音,这样系统就可以对应管理他们了。

  从AudioTrack的使用实例来逐个分析其中用到的方法,首先是getMinBufferSize:

  getMinBufferSize

/**     * Returns the minimum buffer size required for the successful creation of an AudioTrack     * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't     * guarantee a smooth playback under load, and higher values should be chosen according to     * the expected frequency at which the buffer will be refilled with additional data to play.     * For example, if you intend to dynamically set the source sample rate of an AudioTrack     * to a higher value than the initial source sample rate, be sure to configure the buffer size     * based on the highest planned sample rate.     * @param sampleRateInHz the source sample rate expressed in Hz.     * @param channelConfig describes the configuration of the audio channels.     *   See {@link AudioFormat#CHANNEL_OUT_MONO} and     *   {@link AudioFormat#CHANNEL_OUT_STEREO}     * @param audioFormat the format in which the audio data is represented.     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and     *   {@link AudioFormat#ENCODING_PCM_8BIT}     * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,     *   or {@link #ERROR} if unable to query for output properties,     *   or the minimum buffer size expressed in bytes.     */    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {        int channelCount = 0;        switch(channelConfig) {        case AudioFormat.CHANNEL_OUT_MONO:        case AudioFormat.CHANNEL_CONFIGURATION_MONO:            channelCount = 1;            break;        case AudioFormat.CHANNEL_OUT_STEREO:        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:            channelCount = 2;            break;        default:            if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {                // input channel configuration features unsupported channels                loge("getMinBufferSize(): Invalid channel configuration.");                return ERROR_BAD_VALUE;            } else {                channelCount = Integer.bitCount(channelConfig);            }        }      //目前只支持PCM8和PCM16精度的音频        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {            loge("getMinBufferSize(): Invalid audio format.");            return ERROR_BAD_VALUE;        }     //ft,对采样频率也有要求,太低或太高都不行,人耳分辨率在20HZ到40KHZ之间        // sample rate, note these values are subject to change        if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) {            loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");            return ERROR_BAD_VALUE;        }     //调用native函数        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);        if (size <= 0) {            loge("getMinBufferSize(): error querying hardware");            return ERROR;        }        else {            return size;        }    }
View Code

  native_get_min_buff_size函数进入了framework/base/core/jni/android_media_AudioTrack.cpp中的android_media_AudioTrack_get_min_buff_size:

// 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 nbChannels, jint audioFormat) {    size_t frameCount = 0;    if (AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,sampleRateInHertz) != NO_ERROR) {        return -1;    }    return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);}

  根据最小的framecount计算最小的buffersize。音频中最常见的是frame这个单位,一个frame就是1个采样点的字节数*声道。为啥搞个frame出来?因为对于多//声道的话,用1个采样点的字节数表示不全,因为播放的时候肯定是多个声道的数据都要播出来//才行。所以为了方便,就说1秒钟有多少个frame,这样就能抛开声道数,把意思表示全了getMinBufSize函数完了后,我们得到一个满足最小要求的缓冲区大小。这样用户分配缓冲区就有了依据。下面就需要创建AudioTrack对象了

创建AudioTrack对象

先看AudioTrack.java中的构造函数:

/**     * Class constructor with audio session. Use this constructor when the AudioTrack must be     * attached to a particular audio session. The primary use of the audio session ID is to     * associate audio effects to a particular instance of AudioTrack: if an audio session ID     * is provided when creating an AudioEffect, this effect will be applied only to audio tracks     * and media players in the same session and not to the output mix.     * When an AudioTrack is created without specifying a session, it will create its own session     * which can be retrieved by calling the {@link #getAudioSessionId()} method.     * If a non-zero session ID is provided, this AudioTrack will share effects attached to this     * session     * with all other media players or audio tracks in the same session, otherwise a new session     * will be created for this track if none is supplied.     * @param streamType the type of the audio stream. See     *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},     *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC},     *   {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}.     * @param sampleRateInHz the initial source sample rate expressed in Hz.     * @param channelConfig describes the configuration of the audio channels.     *   See {@link AudioFormat#CHANNEL_OUT_MONO} and     *   {@link AudioFormat#CHANNEL_OUT_STEREO}     * @param audioFormat the format in which the audio data is represented.     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and     *   {@link AudioFormat#ENCODING_PCM_8BIT}     * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read     *   from for playback. If using the AudioTrack in streaming mode, you can write data into     *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,     *   this is the maximum size of the sound that will be played for this instance.     *   See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size     *   for the successful creation of an AudioTrack instance in streaming mode. Using values     *   smaller than getMinBufferSize() will result in an initialization failure.     * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}     * @param sessionId Id of audio session the AudioTrack must be attached to     * @throws java.lang.IllegalArgumentException     */    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,            int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException {        // mState already == STATE_UNINITIALIZED        // remember which looper is associated with the AudioTrack instantiation        Looper looper;
     // 获得主线程的Looper,这个在MediaScanner中有相关介绍。
if ((looper = Looper.myLooper()) == null) { looper = Looper.getMainLooper(); } mInitializationLooper = looper;
     //检查参数是否合法之类的,可以不管它 audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode); audioBuffSizeCheck(bufferSizeInBytes);
if (sessionId < 0) { throw new IllegalArgumentException("Invalid audio session ID: "+sessionId); } int[] session = new int[1]; session[0] = sessionId; // native initialization
     // 调用native层的native_setup,把自己的WeakReference传进去了 int initResult = native_setup(new WeakReference<AudioTrack>(this), mStreamType, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED } mSessionId = session[0]; if (mDataLoadMode == MODE_STATIC) { mState = STATE_NO_STATIC_DATA; } else { mState = STATE_INITIALIZED; } }

native_setup函数进入了framework/base/core/jni/android_media_AudioTrack.cpp中的android_media_AudioTrack_native_setup:

static int android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,        jint streamType, jint sampleRateInHertz, jint javaChannelMask,        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession){    ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",        sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);    uint32_t afSampleRate;    size_t afFrameCount;    if (AudioSystem::getOutputFrameCount(&afFrameCount, (audio_stream_type_t) streamType) != NO_ERROR) {        ALOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");        return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;    }    if (AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType) != NO_ERROR) {        ALOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");        return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;    }    // Java channel masks don't map directly to the native definition, but it's a simple shift    // to skip the two deprecated channel configurations "default" and "mono".    uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;    if (!audio_is_output_channel(nativeChannelMask)) {        ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);        return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;    }   //popCount是统计一个整数中有多少位为1的算法    int nbChannels = popcount(nativeChannelMask);    // check the stream type    audio_stream_type_t atStreamType;    switch (streamType) {    case AUDIO_STREAM_VOICE_CALL:    case AUDIO_STREAM_SYSTEM:    case AUDIO_STREAM_RING:    case AUDIO_STREAM_MUSIC:    case AUDIO_STREAM_ALARM:    case AUDIO_STREAM_NOTIFICATION:    case AUDIO_STREAM_BLUETOOTH_SCO:    case AUDIO_STREAM_DTMF:        atStreamType = (audio_stream_type_t) streamType;        break;    default:        ALOGE("Error creating AudioTrack: unknown stream type.");        return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;    }    // check the format.    // This function was called from Java, so we compare the format against the Java constants    if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) {        ALOGE("Error creating AudioTrack: unsupported audio format.");        return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;    }    // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class    // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled    // in android_media_AudioTrack_native_write_byte()    if ((audioFormat == ENCODING_PCM_8BIT)&& (memoryMode == MODE_STATIC)) {        ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \            buff size of %dbytes, switching to 16bit, buff size of %dbytes",            buffSizeInBytes, 2*buffSizeInBytes);        audioFormat = ENCODING_PCM_16BIT;        // we will need twice the memory to store the data        buffSizeInBytes *= 2;    }    // compute the frame count    int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;    audio_format_t format = audioFormat == ENCODING_PCM_16BIT ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;   //根据Buffer大小和一个Frame大小来计算帧数。    int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);    jclass clazz = env->GetObjectClass(thiz);    if (clazz == NULL) {        ALOGE("Can't find %s when setting up callback.", kClassPathName);        return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;    }    if (jSession == NULL) {        ALOGE("Error creating AudioTrack: invalid session ID pointer");        return AUDIOTRACK_ERROR;    }    jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);    if (nSession == NULL) {        ALOGE("Error creating AudioTrack: Error retrieving session id pointer");        return AUDIOTRACK_ERROR;    }    int sessionId = nSession[0];    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);    nSession = NULL;    // create the native AudioTrack object  //创建真正的AudioTrack对象    sp<AudioTrack> lpTrack = new AudioTrack();    // initialize the callback information:    // this data will be passed with every AudioTrack callback  // AudioTrackJniStorage,就是一个保存一些数据的地方,这里边有一些有用的知识,下面再详细解释    AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();    lpJniStorage->mStreamType = atStreamType;    lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);    // we use a weak reference so the AudioTrack object can be garbage collected.    lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);    lpJniStorage->mCallbackData.busy = false;    // initialize the native AudioTrack object    switch (memoryMode) {    case MODE_STREAM:        lpTrack->set(            atStreamType,// stream type            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            0,// shared mem            true,// thread can call Java            sessionId);// audio session ID        break;    case MODE_STATIC:        // AudioTrack is using shared memory    //如果是static模式,需要用户一次性把数据写进去,然后再由audioTrack自己去把数据读出来,    //所以需要一个共享内存这里的共享内存是指C++ AudioTrack和AudioFlinger之间共享的内容因为真正播放的工作是由AudioFlinger来完成的。        if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {            ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");            goto native_init_failure;        }        lpTrack->set(            atStreamType,// stream type            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        break;    default:        ALOGE("Unknown mode %d", memoryMode);        goto native_init_failure;    }    if (lpTrack->initCheck() != NO_ERROR) {        ALOGE("Error initializing AudioTrack");        goto native_init_failure;    }    nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);    if (nSession == NULL) {        ALOGE("Error creating AudioTrack: Error retrieving session id pointer");        goto native_init_failure;    }    // read the audio session ID back from AudioTrack in case we create a new session    nSession[0] = lpTrack->getSessionId();    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);    nSession = NULL;    {   // scope for the lock        Mutex::Autolock l(sLock);        sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);    }    // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field    // of the Java object (in mNativeTrackInJavaObj)    setAudioTrack(env, thiz, lpTrack);    //把C++AudioTrack对象指针保存到JAVA对象的一个变量中,这样,Native层的AudioTrack对象就和JAVA层的AudioTrack对象关联起来了.// save the JNI resources so we can free them later    //ALOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);    env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);    return AUDIOTRACK_SUCCESS;    // failures: native_init_failure:    if (nSession != NULL) {        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);    }    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);    delete lpJniStorage;    env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);    return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;}
View Code

AudioTrackJniStorage

  这个类其实就是一个辅助类,但是里边有一些知识很重要,尤其是Android封装的一套共享内存的机制。把这块搞清楚了,我们就能轻松得在两个进程间进行内存的拷贝。

class AudioTrackJniStorage {    public:        sp<MemoryHeapBase>         mMemHeap;        sp<MemoryBase>             mMemBase;        audiotrack_callback_cookie mCallbackData;        audio_stream_type_t        mStreamType;    AudioTrackJniStorage() {        mCallbackData.audioTrack_class = 0;        mCallbackData.audioTrack_ref = 0;        mStreamType = AUDIO_STREAM_DEFAULT;    }    ~AudioTrackJniStorage() {        mMemBase.clear();        mMemHeap.clear();    }    bool allocSharedMem(int sizeInBytes) {        mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");        if (mMemHeap->getHeapID() < 0) {            return false;        }        mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
    //注意用法,先弄一个MemoryHeapBase,再把MemoryHeapBase传入到MemoryBase中去。
return true; }};

  MemroyHeapBase,MemoryBaseAndroid搞的一套基于Binder机制的对内存操作的类。既然是Binder机制,那么肯定有一个服务端Bnxxx,一个代理端Bpxxx

MemoryXXX大概的使用方法如下:

  BnXXX端先分配BnMemoryHeapBase和BnMemoryBase,

  然后把BnMemoryBase传递到BpXXX

  BpXXX就可以使用BpMemoryBase得到BnXXX端分配的共享内存了。

注意,既然是进程间共享内存,那么Bp端肯定使用memcpy之类的函数来操作内存,这些函数是没有同步保护的,而且Android也不可能在系统内部为这种共享内存去做增加同步保护。所以看来后续在操作这些共享内存的时候,肯定存在一个跨进程的同步保护机制。我们在后面讲实际播放的时候会碰到。

  另外,这里的SharedBuffer最终会在Bp端也就是AudioFlinger那用到。

play和write

JAVA层到这一步后就是调用play和write了。JAVA层这两个函数没什么内容,都是直接转到native层干活了。先看看play函数对应的JNI函数:

static voidandroid_media_AudioTrack_start(JNIEnv *env, jobject thiz){
  //从JAVA那个AudioTrack对象获取保存的C++层的AudioTrack对象指针
  //从int类型直接转换成指针。要是以后ARM变成64位平台了,看google怎么改! sp
<AudioTrack> lpTrack = getAudioTrack(env, thiz); if (lpTrack == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Unable to retrieve AudioTrack pointer for start()"); return; } lpTrack->start();}

再看write。我们写的是short数组

static jint android_media_AudioTrack_native_write_short(JNIEnv *env,  jobject thiz,                                                  jshortArray javaAudioData,                                                  jint offsetInShorts, jint sizeInShorts,                                                  jint javaAudioFormat) {    jint written = android_media_AudioTrack_native_write_byte(env, thiz,                                                 (jbyteArray) javaAudioData,                                                 offsetInShorts*2, sizeInShorts*2,                                                 javaAudioFormat);    if (written > 0) {        written /= 2;    }    return written;}
static jint android_media_AudioTrack_native_write_byte(JNIEnv *env,  jobject thiz,                                                  jbyteArray javaAudioData,                                                  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);    if (lpTrack == NULL) {        jniThrowException(env, "java/lang/IllegalStateException",            "Unable to retrieve AudioTrack pointer for write()");        return 0;    }    // get the pointer for the audio data from the java array    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such    // a way that it becomes much more efficient. When doing so, we will have to prevent the    // AudioSystem callback to be called while in 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 source of audio data to play, can't play");            return 0; // out of memory or no data to load        }    } else {        ALOGE("NULL java array of audio data 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;}
jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,                  jint offsetInBytes, jint sizeInBytes) {    // give the data to the native AudioTrack object (the data starts at the offset)    ssize_t written = 0;    // regular write() or copy the data to the AudioTrack's shared memory?    if (track->sharedBuffer() == 0) {
    //创建的是流的方式,所以没有共享内存在track中 written
= track->write(data + offsetInBytes, sizeInBytes); // for compatibility with earlier behavior of write(), return 0 in this case if (written == (ssize_t) WOULD_BLOCK) { written = 0; } } else { if (audioFormat == ENCODING_PCM_16BIT) { // writing to shared memory, check for capacity if ((size_t)sizeInBytes > track->sharedBuffer()->size()) { sizeInBytes = track->sharedBuffer()->size(); }
       //STATIC模式的,就直接把数据拷贝到共享内存里 memcpy(track
->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes); written = sizeInBytes; } else if (audioFormat == ENCODING_PCM_8BIT) {
       //PCM8格式的要先转换成PCM16
// data contains 8bit data we need to expand to 16bit before copying // to the shared memory // writing to shared memory, check for capacity, // note that input data will occupy 2X 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 wrote 2*sizeInBytes, we only report sizeInBytes as written to hide // the 8bit mixer restriction from the user of this function written = sizeInBytes; } } return written;}

到这里,似乎很简单,JAVA层的AudioTrack,无非就是调用write函数,而实际由JNI层的C++ AudioTrack write数据。

未完,看累了,歇几天继续

Reprinted from:http://www.cnblogs.com/innost/archive/2011/01/09/1931457.html

更多相关文章

  1. androidのsms,mms短彩信数据库
  2. Android学习09-----Android中数据的存储和访问 (3) By SQLite
  3. Android数据存储(总结篇)
  4. android APK 带数据库
  5. android 通过usb 读取数据
  6. android开发数据存储方式
  7. Android数据传递
  8. Android下使用camera2和Surfaceview预览图像并取得YUV420p数据回
  9. android 进程间的内存分配

随机推荐

  1. 如何在命令中传递对象参数?
  2. Java中的两种XML解析技术DOM和SAX
  3. 云星数据---Apache Flink实战系列(精品版
  4. 正在学习C#的新手请教:ASP.NET、HTML5, ja
  5. java 中 数值不超过3万. 用short好 还是i
  6. jbpm在rest API中修改 task Variable
  7. Java日志框架——查看“完整的执行的SQL
  8. JavaScript与WebAssembly进行比较
  9. 20165111 实验一Java开发环境的熟悉1,2
  10. Java操作ini文件 ,解决properties文件中无