Android 音频源码分析——AndroidRecord录音(二)
发布日期:2021-05-10 11:30:53 浏览次数:27 分类:精选文章

本文共 10449 字,大约阅读时间需要 34 分钟。

Android ������ AudioRecord.read ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� AudioRecord.read ������������������������������


1. AudioRecord.read ������������

Java ���������

Java ������ read ��������������� native_read_in_byte_array ��������������������������������� buffer ������������������������������������������������������ byte���short���float���ByteBuffer��������������������������������� JNI ������������������ Java ������������������ native ���������������������������readMode ���������������������������READ_BLOCKING��������������� READ_NON_BLOCKING������������������

���������������

public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
}
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode) {
// ������������
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION;
}
// ������ readMode ������������
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
return ERROR_BAD_VALUE;
}
// ���������������������
if (audioData == null || offsetInBytes < 0 || sizeInBytes < 0 ||
(offsetInBytes + sizeInBytes) < 0 || (offsetInBytes + sizeInBytes) > audioData.length) {
return ERROR_BAD_VALUE;
}
// ������ native ������
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes, readMode == READ_BLOCKING);
}
// ��������� JNI ������
template
static jint android_media_AudioRecord_readInArray(JNIEnv *env, jobject thiz, T javaAudioData,
jint offsetInSamples, jint sizeInSamples, jboolean isReadBlocking) {
// ������ AudioRecord ������
sp
lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == null) {
return (jint)AUDIO_JAVA_INVALID_OPERATION;
}
// ������������������������������
if (javaAudioData == null) {
return (jint)AUDIO_JAVA_BAD_VALUE;
}
// ������������������
auto *recordBuff = envGetArrayElements(env, javaAudioData, null);
if (recordBuff == null) {
return (jint)AUDIO_JAVA_BAD_VALUE;
}
// ������������������������
size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
ssize_t readSize = lpRecorder->read(recordBuff + offsetInSamples, sizeInBytes,
isReadBlocking ? JNI_TRUE : JNI_FALSE);
// ������������������
envReleaseArrayElements(env, javaAudioData, recordBuff, 0);
if (readSize < 0) {
return (jint)interpretReadSizeError(readSize);
}
return (jint)(readSize / sizeof(*recordBuff));
}

C++ ���������

C++ ������ read ��������������������� audioBuffer ������������������������������������������������������������ buffer ������

���������������

ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking) {
// ������������������������������
if (mTransfer != TRANSFER_SYNC) {
return INVALID_OPERATION;
}
if (userSize < 0 || (buffer == null && userSize != 0)) {
return BAD_VALUE;
}
// ������������������ userSize ������ mFrameSize
ssize_t read = 0;
Buffer audioBuffer;
while (userSize >= mFrameSize) {
audioBuffer.frameCount = userSize / mFrameSize;
status_t err = obtainBuffer(&audioBuffer, blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
if (err < 0) {
// ������������������
if (read > 0) {
break;
}
if (err == TIMED_OUT || err == -EINTR) {
err = WOULD_BLOCK;
}
return (ssize_t)err;
}
// ��������������������� buffer
size_t bytesRead = audioBuffer.size;
memcpy(buffer, audioBuffer.i8, bytesRead);
buffer = ((char*)buffer) + bytesRead;
userSize -= bytesRead;
read += bytesRead;
releaseBuffer(&audioBuffer);
}
// ���������������������������
if (read > 0) {
mFramesRead += read / mFrameSize;
}
return read;
}

obtainBuffer ������������ obtainBuffer ��������������� AudioRecord ��������������������������������������������������������������������������������� AudioTrack ��� obtainBuffer ���������������������������������������������������

���������������

status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec* requested, 
struct timespec* elapsed, size_t* nonContig) {
// ������������
AutoMutex lock(mLock);
// ���������������������������������������������
uint32_t oldSequence = 0;
uint32_t newSequence;
Proxy::Buffer buffer;
status_t status = NO_ERROR;
static const int32_t kMaxTries = 5;
int32_t tryCounter = kMaxTries;
do {
// ������ AudioTrackClientProxy ������
sp
proxy = mProxy;
// ������������������������
sp
iMem = mCblkMemory;
sp
bufferMem = mBufferMemory;
AutoMutex lockScope;
// ������������
newSequence = mSequence;
if (status == DEAD_OBJECT) {
// ������������������������������������
if (newSequence == oldSequence) {
// ������������������
status = restoreRecord_l("obtainBuffer");
if (status != NO_ERROR) {
buffer.mFrameCount = 0;
buffer.mRaw = null;
buffer.mNonContig = 0;
break;
}
}
}
oldSequence = newSequence;
// ������ proxy ������
proxy = mProxy;
// ���������������
if (!mActive) {
requested = &ClientProxy::kNonBlocking;
}
// ������������������
buffer.mFrameCount = audioBuffer->frameCount;
// ������ AudioTrackClientProxy::obtainBuffer
status = proxy->obtainBuffer(&buffer, requested, elapsed);
} while ((status == DEAD_OBJECT) && (tryCounter-- > 0));
// ������ audioBuffer ���������
audioBuffer->frameCount = buffer.mFrameCount;
audioBuffer->size = buffer.mFrameCount * mFrameSize;
audioBuffer->raw = buffer.mRaw;
if (nonContig != null) {
*nonContig = buffer.mNonContig;
}
return status;
}

.obtainBuffer ������������

  • ��������������������� AudioRecord ������������������������������������������������������������
  • ��������������������� AudioTrackClientProxy ��� obtainBuffer ���������������������������������������
  • ��������������������������������������������� audioBuffer ��������������� frameCount���size ��� raw���
  • ������������������������������������������������������������������ DEAD_OBJECT ������������������������������������������

  • 2. AudioRecord.stop ������������

    stop ������������������������������������������������������������������������

    ���������������

    public void stop() throws IllegalStateException {
    if (mState != STATE_INITIALIZED) {
    throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
    }
    synchronized(mRecordingStateLock) {
    handleFullVolumeRec(false);
    native_stop();
    mRecordingState = RECORDSTATE_STOPPED;
    }
    }
    // ��������� JNI ������
    static void android_media_AudioRecord_stop(JNIEnv *env, jobject thiz) {
    sp
    lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == null) {
    jniThrowException(env, "java/lang/IllegalStateException", null);
    return;
    }
    lpRecorder->stop();
    }

    native_stop ������

    void AudioRecord::stop() {
    AutoMutex lock(mLock);
    if (!mActive) {
    return;
    }
    mActive = false;
    mProxy->interrupt();
    mAudioRecord->stop();
    // ������������
    sp
    t = mAudioRecordThread;
    if (t != null) {
    t->pause();
    } else {
    setpriority(PRIO_PROCESS, 0, mPreviousPriority);
    set_sched_policy(0, mPreviousSchedulingGroup);
    }
    // ������������������
    mMediaMetrics.logStop(systemTime());
    }

    stop() ���������������

  • ��������������������� mRecordingStateLock ���������������������
  • ��������������������� mActive ���������������
  • ������ native_stop()���������������������������������������
  • ������������������������������������������������������������������������
  • ���������������������������������������������

  • 3. AudioRecord.release ������������

    release ������������������ AudioRecord ������������������������������������������������������

    ���������������

    public void release() {
    try {
    stop();
    } catch (IllegalStateException ise) {
    // ������������
    }
    native_release();
    mState = STATE_UNINITIALIZED;
    }

    native_release ������

    void AudioRecord::native_release() {
    sp
    lpRecorder = setAudioRecord(env, thiz, 0);
    if (lpRecorder == null) {
    return;
    }
    lpRecorder->stop();
    // ������ native ���������
    audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(thiz,
    javaAudioRecordFields.nativeCallbackCookie);
    env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
    // ������ callback ������
    if (lpCookie != null) {
    Mutex::Autolock l(sLock);
    while (lpCookie->busy) {
    if (lpCookie->cond.waitRelative(sLock, milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) != NO_ERROR) {
    break;
    }
    }
    sAudioRecordCallBackCookies.remove(lpCookie);
    env->DeleteGlobalRef(lpCookie->audioRecord_class);
    env->DeleteGlobalRef(lpCookie->audioRecord_ref);
    delete(lpCookie);
    }
    }

    release() ���������������

  • ��������������������� release ���������������������
  • ������ JNI ��������������� callbackCookie ������������������
  • ������ native ������������������ AudioTrack ������������������������

  • ������

    ��������� AudioRecord.read���stop ��� release ������������������������������ Android ��������������������������������������������������������������������������������������� native ���������������������������������������������������������������������������������������������������������������������������

    上一篇:Android 架构
    下一篇:Android 音频源码分析——AndroidRecord录音(一)

    发表评论

    最新留言

    表示我来过!
    [***.240.166.169]2025年04月10日 00时33分49秒