AudioRecord READ_BLOCKING 与 READ_NON_BLOCKING的区别

AudioRecord 录音时有两种读取模式,一种是AudioRecord.READ_BLOCKING,另外一种是AudioRecord.READ_NON_BLOCKING,但是对这两种模式的定义却比较模糊

/**
 * The read mode indicating the read operation will block until all data
 * requested has been read.
 */
public final static int READ_BLOCKING = 0;

/**
 * The read mode indicating the read operation will return immediately after
 * reading as much audio data as possible without blocking.
 */
public final static int READ_NON_BLOCKING = 1;

只说一种是会阻塞直到数据读取成功,另外一种是立刻返回尽可能多的数据而不阻塞。那么假设我选择READ_NON_BLOCKING模式,会不会导致读取到的数据长度是变化的?这两种模式究竟有什么区别?

我们跟踪安卓的源码,AudioRecord.read最终会调用到frameworks/av/media/libaudioclient/AudioRecord.cpp:

ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking)
{
    if (mTransfer != TRANSFER_SYNC) {
        return INVALID_OPERATION;
    }

    if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
        // Validation. user is most-likely passing an error code, and it would
        // make the return value ambiguous (actualSize vs error).
        ALOGE("%s(%d) (buffer=%p, size=%zu (%zu)",
                __func__, mPortId, buffer, userSize, userSize);
        return BAD_VALUE;
    }

    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);
        }

        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;
        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
    }
    return read;
}

可以看到,java层传过来的参数最终转换成布尔值blocking。在正常读取的时候,无论是否blocking,都会等到读取userSize之后再返回;在读取出错时,假设读取到了数据,无论是否blocking,最终也都会返回已读取的这部分数据。唯一的区别点在于obtainBuffer的传参,blocking等待时间为:ClientProxy::kForever,即INT_MAX sec,non_blocking等待时间为ClientProxy::kNonBlocking,即0。

const struct timespec ClientProxy::kForever = {INT_MAX /*tv_sec*/, 0 /*tv_nsec*/};
const struct timespec ClientProxy::kNonBlocking = {0 /*tv_sec*/, 0 /*tv_nsec*/};

需要注意的是,这个地方只是默认值,在obtainBuffer内部某些case下blocking也会被修改为non_blocking,例如
在这里插入图片描述
同时,在obtainBuffer内部也会进行一些状态判定,例如如果是未初始化等,无论是否blocking,都会直接返回error,只有状态正常,但是未能读取到数据时该参数才会生效
在这里插入图片描述

在这里插入图片描述
综上:

  1. 无论是否blocking,正常状态下都会读取到我们设置的bufferSize然后再返回;
  2. 无论是否blocking,在一些异常状态下都会不阻塞直接返回,例如状态错误等;
  3. 出错时无论是否blocking,都会返回已read的这部分size,有可能小于我们设置的bufferSize;
  4. 只有在状态正常但是数据未读取到时,blocking模式会进行阻塞等待,non_blocking直接返回WOULD_BLOCK的错误;

实际项目中验证发现情况4出现的概率还挺高的,会导致录音概率性有空白,推荐使用阻塞模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值