Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
用原生SoundRecorder apk为例,以sample rate, channel及buffer size这些参数为线索来跟踪,,流程如下:
openRecord_l ->
AudioSystem::getInputForAttr ->
aps->getInputForAttr ->
AudioPolicyManager::getInputForAttr ->
getInputProfile -> 根据上apk给的profileSamplingRate, profileFormat以及profileChannelMask找到对应的profile
mpClientInterface->openInput -> 上层的录音参数传递给HAL.
AudioFlinger::openInput_l ->
inHwHal->open_input_stream ->
adev_open_input_stream -> audio_hw.c
static int adev_open_input_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
struct audio_stream_in **stream_in, //传进来是新的
audio_input_flags_t flags,
const char *address __unused,
audio_source_t source __unused)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_in *in;
int ret;
*stream_in = NULL;
//不管它传进来是哪种,直接定死为双声道.
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
#ifdef ALSA_IN_DEBUG
//用来调试抓取pcm数据
in_debug = fopen("/data/debug.pcm","wb");//please touch /data/debug.pcm first
#endif
......
in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
if (!in)
return -ENOMEM;
......
//SoundRecorder apk使用的是8kHz的采样率.
in->requested_rate = config->sample_rate;
......
//上面定死为双通道.
in->channel_mask = config->channel_mask;
......
//默认用的是pcm_config_in
//struct pcm_config pcm_config_in = {
//.channels = 2,
//.rate = 44100,
//.period_size = 16,
//.period_count = 128,
//.format = PCM_FORMAT_S16_LE,
//};
struct pcm_config *pcm_config = flags & AUDIO_INPUT_FLAG_FAST ?
&pcm_config_in_low_latency : &pcm_config_in;
in->config = pcm_config;
//用pcm_config_in的配置来计算, audio_stream_in_frame_size(&in->stream)调用的是
//in_get_format(),固定是AUDIO_FORMAT_PCM_16_BIT, audio_channel_count_from_out_mask()用来转换
//channel宏定义为实际的number.不过这里有疑问的是这样不是多了一个pcm_config->channels了?
//audio_stream_in_frame_size()已经包含了channel了啊!
in->buffer = malloc(pcm_config->period_size * pcm_config->channels
* audio_stream_in_frame_size(&in->stream));
......
//当上层采样率和HAL配置的采样率不想等时,要resample,当然,数据最终也是从resample后的buffer中获取.
if (in->requested_rate != pcm_config->rate) {
//和正常非resample的获取kernel录音数据方式一样.
in->buf_provider.get_next_buffer = get_next_buffer;
in->buf_provider.release_buffer = release_buffer;
ALOGD("pcm_config->rate:%d,in->requested_rate:%d,in->channel_mask:%d",
pcm_config->rate,in->requested_rate,audio_channel_count_from_in_mask(in->channel_mask));
ret = create_resampler(pcm_config->rate, //44.1kHz
in->requested_rate, //8kHz
audio_channel_count_from_in_mask(in->channel_mask), //2
RESAMPLER_QUALITY_DEFAULT,
&in->buf_provider,
&in->resampler);
......
}
......
}
数据读取:
in_read(): audio_hw.c
static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
size_t bytes)
{
......
//将要读取的字节数转换成frames, 一个frame=channel * format.
size_t frames_rq = bytes / audio_stream_in_frame_size(stream);
......
pthread_mutex_lock(&in->lock);
if (in->standby) {
pthread_mutex_lock(&adev->lock);
//打开及设置录音
ret = start_input_stream(in);
pthread_mutex_unlock(&adev->lock);
if (ret < 0)
goto exit;
in->standby = false;
}
//读取数据,读取的buffer和frame count是上层提供.
ret = read_frames(in, buffer, frames_rq);
......
}
start_input_stream():
static int start_input_stream(struct stream_in *in)
{
struct audio_device *adev = in->dev;
//打印信息
in_dump(in, 0);
//路径相关,这里不关注
route_pcm_open(getRouteFromDevice(in->device | AUDIO_DEVICE_BIT_IN));
//打开录音设备,设置也在里面,调用tinyalsa库里面的代码.
in->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_IN, in->config);
......
//传进来的是8kHz,HAL配置的是44.1kHz,需要重采样,这里做复位初始化工作.
if (in->resampler)
in->resampler->reset(in->resampler);
in->frames_in = 0;
adev->input_source = in->input_source;
adev->in_device = in->device;
adev->in_channel_mask = in->channel_mask;
......
}
read_frames:
static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames)
{
//记录累积读取到帧数.
ssize_t frames_wr = 0;
size_t frame_size = audio_stream_in_frame_size(&in->stream);
//循环读完为止
while (frames_wr < frames) {
//剩余要读的帧数为总共读的帧数减掉已经读到的帧数
size_t frames_rd = frames - frames_wr;
if (in->resampler != NULL) {
//用从采样的库函数来获取buffer
in->resampler->resample_from_provider(in->resampler,
//读一次,根据frames_wr的值偏移一下
(int16_t *)((char *)buffer +
frames_wr * frame_size),
//实际一次读取到的帧数
&frames_rd);
} else {
......
}
......
//累计总共读取到的帧数.
frames_wr += frames_rd;
}
return frames_wr;
}
resampler_resample_from_provider():
int resampler_resample_from_provider(struct resampler_itfe *resampler,
int16_t *out,
size_t *outFrameCount)
{
struct resampler *rsmp = (struct resampler *)resampler;
......
size_t framesRq = *outFrameCount;
if (framesRq != rsmp->frames_rq) {
//换算成实际采样率需要采的帧率.
rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
rsmp->frames_rq = framesRq;
}
size_t framesWr = 0;
spx_uint32_t inFrames = 0;
while (framesWr < framesRq) {
if (rsmp->frames_in < rsmp->frames_needed) {
// make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
// least the number of frames needed to produce the number of frames requested at
// the output sampling rate
if (rsmp->in_buf_size < rsmp->frames_needed) {
//更新buffer size
rsmp->in_buf_size = rsmp->frames_needed;
//分配buffer
rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
}
struct resampler_buffer buf;
//每次想获取的frame count.
buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
//获取buffer的核心函数
rsmp->provider->get_next_buffer(rsmp->provider, &buf);
if (buf.raw == NULL) {
break;
}
//拷贝buf.frame_count大小(这个值可能在get_next_buffer()中被修改)到rsmp->in_buf,
//偏移没* sizeof(int16_t)是因为in_buf是int16类型.
memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
buf.raw,
buf.frame_count * rsmp->channel_count * sizeof(int16_t));
//记录总共读取的帧数
rsmp->frames_in += buf.frame_count;
//用好就释放掉,实际只是更新了in->frames_in,这样前面拿过的数据不会再会重复拿了.
rsmp->provider->release_buffer(rsmp->provider, &buf);
}
//
spx_uint32_t outFrames = framesRq - framesWr;
//一次要处理的帧数
inFrames = rsmp->frames_in;
if (rsmp->channel_count == 1) {
......
} else {
//inFrames会被改成实际能处理的帧数
//outFrames返回世界写到out buffer中的帧数
speex_resampler_process_interleaved_int(rsmp->speex_resampler,
rsmp->in_buf,
&inFrames,
out + framesWr * rsmp->channel_count,
&outFrames);
}
//累计更新实际处理帧数
framesWr += outFrames;
//如果输入帧数全部处理完,那么rsmp->frames_in和inFrames的值应该是是一样.
rsmp->frames_in -= inFrames;
//当上面说到的两个值都不一致,也就是输入和输出的实际值都不是我们想要达到的值时
//就会提示警告信息.
ALOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0),
"ReSampler::resample() remaining %zu frames in and %zu frames out",
rsmp->frames_in, (framesRq - framesWr));
}
//最后把未能处理的帧数直接copy到in_buf开头,等到下一次再处理.
if (rsmp->frames_in) {
memmove(rsmp->in_buf,
rsmp->in_buf + inFrames * rsmp->channel_count,
rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
}
//更新处理掉的帧
*outFrameCount = framesWr;
return 0;
}
get_next_buffer():
static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
struct resampler_buffer* buffer)
{
struct stream_in *in;
size_t i,size;
......
in = (struct stream_in *)((char *)buffer_provider -
offsetof(struct stream_in, buf_provider));
......
//start_input_stream()中设置为0,第一次进来
if (in->frames_in == 0) {
//size好像没用到???
size = pcm_frames_to_bytes(in->pcm,pcm_get_buffer_size(in->pcm));
//调用tinyalsa接口,从kernel读取录音数据.
in->read_status = pcm_read(in->pcm,
//放在之前adev_open_input_stream()中申请的in->buffer中,
//之前的疑问是in->buffer申请多乘了一个channel,这里应证了,因为
//pcm_frames_to_bytes()就是period_size*channel*format
(void*)in->buffer,pcm_frames_to_bytes(in->pcm, in->config->period_size));
......
//看这个参数貌似用来保存帧大小
in->frames_in = in->config->period_size;
......
}
//buffer->frame_count为要获取的帧数,非resample时就是上层一次要读取的总frame
//resample时会经过一个sample rate的比例转换. 得到的结果表明实际需要读取的字节数,
//如果in->frames_in比buffer->frame_count,那么我们只需要buffer->frame_count大小就够了.
buffer->frame_count = (buffer->frame_count > in->frames_in) ?
in->frames_in : buffer->frame_count;
//调试结果是in->config->period_size 和in->frames_in一直一样,因此上面if语句里已经赋值了,
//那就一直是从buffer开头存放没有再次利用了. 当in->frames_in比buffer->frame_count大的时候
//release_buffer()会改变in->frames_in的值,偏移段前面的内容表示已经释放掉了.
buffer->i16 = in->buffer +
(in->config->period_size - in->frames_in) *
audio_channel_count_from_in_mask(in->channel_mask);
return in->read_status;
}