概念1:Audio Playback channel:
Sam感觉,Audio Playback channel可以将之理解为“一个可以解析并播放PCM数据的硬件单元”。
既然是硬件,那就可以打开,关闭,设置,并向其中填充(PCM)数据.
1.1:Open Audio Playback channel:
打开硬件。
NEXUS_AudioPlaybackHandle handle;
handle = NEXUS_AudioPlayback_Open(0, NULL);
if ( NULL == handle )
{
fprintf(stderr, "Unable to open playback channel\n");
return 0;
}
1.2: Setting Audio Playback channel and start :
设置硬件接收数据的格式,并开始播放。(但此时buffer 中没有数据,所以不会发出声音)
NEXUS_AudioPlaybackStartSettings settings;
NEXUS_AudioPlayback_GetDefaultStartSettings(&settings);
settings.sampleRate = 48000;
settings.bitsPerSample = 16;
settings.signedData = true;
settings.stereo = true;
settings.dataCallback.callback = data_callback;
settings.dataCallback.context = handle;
settings.dataCallback.param = (int)event;
NEXUS_AudioPlayback_Start(handle, &settings); //有数据则播放
callback function如下:
static void data_callback(void *pParam1, int param2)
{
pParam1=pParam1;
BKNI_SetEvent((BKNI_EventHandle)param2);
}
讲解如下:
struct NEXUS_AudioPlaybackStartSettings
{
NEXUS_Timebase timebase; //
unsigned sampleRate; // 波特率
unsigned bitsPerSample; // 只支持 8/16
size_t startThreshold; // 如果不为0,则hardware会在buffer头跳过这么多字节再开始播放
bool stereo; // 如果为true,则视数据为立体声。如果为false,则为单声道
bool signedData; // 如果为true,则视数据为有符号,否则视为无符号
NEXUS_CallbackDesc dataCallback; //回调函数及其参数1,参数2。
//当向Hardware送PCM数据的Buffer变得可用时,会回调此函数。(但之前需要调用 NEXUS_AudioPlayback_GetBuffer)
}
1.3: 将Audio Playback channel与硬件Output连起来:
Sam感觉,Audio Playback channel就是一个解析和播放PCM的硬件,但这个硬件要与Output联系起来,才可以将声音播放出来。(注意,在关闭Audio Playback channel时,也要断开此连接)
NEXUS_AudioOutput_AddInput(NEXUS_AudioDac_GetConnector(config.outputs.audioDacs[0]),
NEXUS_AudioPlayback_GetConnector(handle));
这里为audio output添加了一个input(就是Audio Playback channel)
1.4: Get Audio Playback channel Buffer.
得到向Audio Playback Buffer.
NEXUS_AudioPlayback_GetBuffer(handle, (void **)&pBuffer, &bufferSize);
参数1: AudioPlayback Handle
参数2: 此AudioPlayback 可用的传数据的buffer头。
参数3: 此次可用buffer的长度。
如果长度为0. 则表明当前没有可用的buffer用来传数据。此时则可以使用BKNI_WaitForEvent(event,1000)来等待buffer可用时回调函数发出的event.
在得到buffer头之后,可以向其中填充PCM数据。
1.5:通知Nexus Playback channel向buffer中填充了多少数据:
NEXUS_AudioPlayback_ReadComplete(handle, bufferSize);
注意,因为之前已经使用NEXUS_AudioPlayback_Start(),所以当向 Nexus Audio Playback Channel buffer中填充数据后,Hardware会去播放这些数据。
1.6:Audio Playback Stop Play :
停止播放数据并清空buffer.
1.7: 与Audio Output断开连接:
NEXUS_AudioOutput_RemoveInput(NEXUS_AudioDac_GetConnector(config.outputs.audioDacs[0]), NEXUS_AudioPlayback_GetConnector(handle));
1.8: Close Audio Playback channel:
关闭硬件。
NEXUS_AudioPlayback_Close(handle)
概念2:Mixer:
Sam感觉Mixer就是一个混音器,多路AudioPlayback和Audio Decoder可以作为Mixer的Input. 而Mixer又作为Audio Output(DAC)的Input. 这样就可以做到多路混音。
Audio Decoder应该是硬件接入的Audio信号(如DVR的麦)。我们主要讲Audio Playback.
Audio Playback可以有2路,所以就可以做到2路混音。
//打开2路audio playback
gAudioPlayback_Handle1 = NEXUS_AudioPlayback_Open(0, NULL); // audio playback 0
gAudioPlayback_Handle2 = NEXUS_AudioPlayback_Open(1, NULL); // audio playback 1
//打开混音器
gMixer = NEXUS_AudioMixer_Open(NULL);
//将audio playback 作为Mixer的Input与之连接起来
NEXUS_AudioMixer_AddInput(gMixer, NEXUS_AudioPlayback_GetConnector(gAudioPlayback_Handle1));
NEXUS_AudioMixer_AddInput(gMixer, NEXUS_AudioPlayback_GetConnector(gAudioPlayback_Handle2));
//将Mixer作为Audio Output(DAC)的Input与之连接
NEXUS_AudioOutput_AddInput(NEXUS_AudioDac_GetConnector(config.outputs.audioDacs[0]), NEXUS_AudioMixer_GetConnector(gMixer));
此时再按照上一节的例子,分别往2路Audio Playback Buffer中填充PCM数据。则可以发现成功混音了。
概念3:Audio Output(DAC)
Sam感觉Audio Output就是一个将数据转换为模拟信号发出的设备。简单的说,Audio Playback是将PCM数据解析出来,并把此数据传递给Audio Output。Audio Output 则将此数据转化为模拟信号。(模拟信号就是可以通过音响播放出来)
设置:
struct NEXUS_AudioOutputSettings
{
NEXUS_Timebase timebase;
NEXUS_AudioChannelMode channelMode;
NEXUS_AudioVolumeType volumeType; //音量设置单位
int32_t leftVolume; //左声道音量
int32_t rightVolume; //右声道音量
bool muted;
unsigned additionalDelay;
NEXUS_AudioOutputPll pll;
unsigned defaultSampleRate;
}
讲解:
NEXUS_AudioVolumeType volumeType; //音量设置单位
音量设置单位有2种:
NEXUS_AudioVolumeType_eDecibel: dB(Decibel:分贝)。
NEXUS_AudioVolumeType_eLinear:线性变化。
如果设置如下:
volumeType = NEXUS_AudioVolumeType_eDecibel;
则音量 0 - -9000 之间变化。