上篇讲了智能手表上音频相关的驱动。本篇开始讲具体的功能,先讲音频文件播放。
音频文件格式众多,目前我们仅支持了最常见的几种:WAV/MP3/AAC/AMR(主要用于播放录音文件)。相对于播放WAV(即PCM),MP3/AAC/AMR多了个解码过程。音频文件播放时只有AP和ADSP在运行。音频可以从speaker(即内置codec)放出来,也可以从蓝牙耳机放出来。这两种方式不管是AP/ADSP的交互过程还是audio data path都有差异。下面分开讲。
1,音频从speaker放出来
下图是其audio data path的软件框图:
从上图看出,AP把音乐流(当是WAV文件时是PCM数据,当是其他支持的文件类型时是比特流)送给ADSP。ADSP收到后做解码(WAV文件没有这一步)、重采样(系统把内置codec的采样率固定在48K,不是48K的都要转到48K)、音效处理(比如EQ)、混音后送给audio driver,通过speaker播放出来。
下图是speaker播放音频文件时AP 与ADSP的主要交互命令:
1) AP给ADSP发命令STREAM_DEV_SELECT,告诉ADSP选择哪个device(内置codec或者BT)播放
2) AP给ADSP发命令ENABLE_STREAM,告诉ADSP使能哪一条stream。系统中定义了很多条stream(music / voice / record / ……),每一条都有相对应的ID。
3) ADSP给AP发命令DATA_REQ,stream被使能后,ADMA中断就会等间隔的来。前面文章说过,内置codec下系统就是靠ADMA中断转起来的。ADMA中断触发去取采集到的音频数据送给ADSP的audio buffer,以及从ADSP的audio buffer里取数据去播放。Stream使能后,ADSP没数据播放(音频文件在AP上),因此ADSP向AP发DATA_REQ来请求音频数据。
4) AP收到ADSP发来的DATA_REQ后就会给ADSP回DATA_REQ_ACK,带上音频数据(AP把音频数据放在双方都能访问的share memory里,实际上在命令里带上的是这块音频数据在share memory里的起始地址, ADSP收到命令后从这个起始地址处拿音频数据)。ADSP收到音频数据后会做解码等,最终播放出来,来消耗从AP收到的音频数据。当消耗到快没有时,又会向AP发DATA_REQ。AP收到后又会通过DATA_REQ_ACK向ADSP发送音频数据。如此反复完成整个音频文件的播放。
5) AP给ADSP发命令DISABLE_STREAM,告诉ADSP停止哪一条stream。ADSP收到后将停止这条stream相关的处理。
6) ADSP给AP发命令DISABLE_STREAM_ACK,告诉AP这条stream已停止处理。AP收到后做相应处理。
2,音频从BT放出来
下图是其audio data path的软件框图:
从上图看出,AP把音乐流送给ADSP。ADSP收到后做解码、重采样、音效处理、混音后送给BT SBC encoder做编码处理,得到SBC码流后将其发送给AP,最终AP上的BT host将SBC码流通过UART发送给BT chip,BT chip再通过蓝牙的空口将码流送给蓝牙耳机,音频从蓝牙耳机播放出来。这里BT chip 做master,蓝牙耳机做slave。ADSP在BT播放音频的场景中起加速器的作用,音频流从AP到ADSP,ADSP处理后又把音频流(这时是SBC码流)送给AP。这跟speaker播放音频是有明显差异的。
下图是BT播放音频文件时AP 与ADSP的主要交互命令:
1) AP给ADSP发命令STREAM_DEV_SELECT,告诉ADSP选择哪个device(内置codec或者BT)播放
2) AP给ADSP发命令SET_BT_PARAM,告诉ADSP做SBC编码时用的参数。这些参数包括bitpool(2--250) / subband(4 / 8) / blocks(4 / 8 / 12 / 16) / mode(MONO/DUAL/STEREO/JOINT STEREO) / allocation(LOUDNESS / SNR)。
3) AP给ADSP发命令ENABLE_STREAM,告诉ADSP使能哪一条stream。
4) AP给ADSP发命令A2DP_DATA_REQ,告诉ADSP A2DP模块需要多少字节的SBC码流数据。音频播放中都是靠数据消耗者来驱动的。这里A2DP是数据消耗者,因此由它来要播放的数据。
5) ADSP给AP发命令DATA_REQ。 Stream使能后,ADSP没数据播放(音频文件在AP上),因此ADSP向AP发DATA_REQ来请求音频数据。
6) AP收到ADSP发来的DATA_REQ后就会给ADSP回DATA_REQ_ACK,带上音频数据(AP把音频数据放在双方都能访问的share memory里,实际上在命令里带上的是这块音频数据在share memory里的起始地址, ADSP收到命令后从这个起始地址处拿音频数据)。
7) ADSP给AP发命令A2DP_DATA_REQ_ACK。ADSP上音频数据后就做相关处理,直到得到SBC码流。当SBC码流的字节数达到A2DP_DATA_REQ请求的个数时就会给AP发A2DP_DATA_REQ_ACK。SBC码流也是放在双方都能访问的share memory里,在命令里带上的是这块SBC码流在share memory里的起始地址, AP收到命令后从这个起始地址处拿SBC码流。这SBC码流会被BT host通过UART发给BT chip。当SBC码流消耗到快没有时,又会向ADSP发A2DP_DATA_REQ。ADSP没有音频数据时又会通过DATA_REQ向AP要音频数据,AP收到后会向ADSP发送音频数据,当SBC码流的字节数达到A2DP_DATA_REQ请求的个数时又会给AP发A2DP_DATA_REQ_ACK。如此反复完成整个音频文件的播放。
8) AP给ADSP发命令DISABLE_STREAM,告诉ADSP停止哪一条stream。ADSP收到后将停止这条stream相关的处理。
9) ADSP给AP发命令DISABLE_STREAM_ACK,告诉AP这条stream已停止处理。AP收到后做相应处理。
至此两种场景下的音频文件播放就讲完了。最后再上一张ADSP上的音频数据流向图,它把不同stream(PCM stream / bit stream)以及不同的播放方式(speaker / BT)都呈现出来。图中有多个FIFO(也就是ring buffer),主要是保证播放的流畅性。