188 lines
5.3 KiB
C++
188 lines
5.3 KiB
C++
|
#include "RkAudio.h"
|
||
|
#include "BoostLog.h"
|
||
|
#include <cstring>
|
||
|
#include <rkmedia/rkmedia_api.h>
|
||
|
|
||
|
namespace RkAudio {
|
||
|
|
||
|
static SAMPLE_FORMAT_E rkAiFormat(Format::SampleType sampleType) {
|
||
|
SAMPLE_FORMAT_E ret = RK_SAMPLE_FMT_NONE;
|
||
|
switch (sampleType) {
|
||
|
case Format::SampleType::Unknown:
|
||
|
ret = RK_SAMPLE_FMT_NONE;
|
||
|
break;
|
||
|
case Format::SampleType::SignedInt16:
|
||
|
ret = RK_SAMPLE_FMT_S16;
|
||
|
break;
|
||
|
case Format::SampleType::SignedInt:
|
||
|
ret = RK_SAMPLE_FMT_S32;
|
||
|
break;
|
||
|
case Format::SampleType::Float:
|
||
|
ret = RK_SAMPLE_FMT_FLT;
|
||
|
break;
|
||
|
default:
|
||
|
LOG(error) << "unkonwn sample type: " << static_cast<int>(sampleType);
|
||
|
ret = RK_SAMPLE_FMT_NONE;
|
||
|
break;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
Input::Input() {
|
||
|
}
|
||
|
|
||
|
Input::~Input() {
|
||
|
if (m_channel >= 0) {
|
||
|
stop();
|
||
|
}
|
||
|
}
|
||
|
bool Input::open(const Format &format) {
|
||
|
bool ret = false;
|
||
|
// RK_MPI_SYS_DumpChn(RK_ID_AI);
|
||
|
m_channel = 0;
|
||
|
|
||
|
AI_CHN_ATTR_S parameter = {0};
|
||
|
parameter.pcAudioNode = "default";
|
||
|
parameter.enAiLayout = AI_LAYOUT_MIC_REF; // remove ref channel, and output mic mono
|
||
|
parameter.enSampleFormat = rkAiFormat(format.sampleType);
|
||
|
parameter.u32Channels = format.channels;
|
||
|
parameter.u32SampleRate = format.sampleRate;
|
||
|
parameter.u32NbSamples = format.sampleRate / 1000 * format.period;
|
||
|
|
||
|
int status = RK_MPI_AI_SetChnAttr(m_channel, ¶meter);
|
||
|
if (status) {
|
||
|
LOG(error) << "RK_MPI_AI_SetChnAttr() failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
status = RK_MPI_AI_EnableChn(m_channel);
|
||
|
if (status) {
|
||
|
LOG(error) << "RK_MPI_AI_EnableChn() failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
AI_TALKVQE_CONFIG_S config = {0};
|
||
|
status = RK_MPI_AI_GetTalkVqeAttr(m_channel, &config);
|
||
|
if (status) {
|
||
|
LOG(error) << "RK_MPI_AI_GetTalkVqeAttr() failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
// LOG(info) << "param file: " << config.aParamFilePath;
|
||
|
config.s32WorkSampleRate = format.sampleRate;
|
||
|
config.s32FrameSample = format.sampleRate / 1000 * format.period;
|
||
|
config.u32OpenMask = AI_TALKVQE_MASK_AEC | AI_TALKVQE_MASK_ANR | AI_TALKVQE_MASK_AGC;
|
||
|
strncpy(config.aParamFilePath, ParamFilePath, sizeof(config.aParamFilePath));
|
||
|
|
||
|
RK_MPI_AI_SetTalkVqeAttr(m_channel, &config);
|
||
|
fprintf(stderr, "end\n");
|
||
|
if (status) {
|
||
|
LOG(error) << "RK_MPI_AI_SetTalkVqeAttr() failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
status = RK_MPI_AI_EnableVqe(m_channel);
|
||
|
if (status) {
|
||
|
LOG(error) << "RK_MPI_AI_EnableVqe() failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
status = RK_MPI_AI_StartStream(0);
|
||
|
if (status) {
|
||
|
LOG(info) << "start AI failed, status: " << status;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
m_exit = false;
|
||
|
m_thread = std::thread(&Input::run, this);
|
||
|
ret = true;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void Input::stop() {
|
||
|
m_exit = true;
|
||
|
if (m_thread.joinable()) m_thread.join();
|
||
|
|
||
|
if (m_channel >= 0) {
|
||
|
RK_MPI_AI_DisableVqe(m_channel);
|
||
|
RK_MPI_AI_DisableChn(m_channel);
|
||
|
m_channel = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Input::setDataCallback(const ReadCallback &callback) {
|
||
|
m_callback = callback;
|
||
|
}
|
||
|
|
||
|
void Input::run() {
|
||
|
while (!m_exit) {
|
||
|
auto mediaBuffer = RK_MPI_SYS_GetMediaBuffer(RK_ID_AI, 0, -1);
|
||
|
if (!mediaBuffer) {
|
||
|
LOG(error) << "RK_MPI_SYS_GetMediaBuffer() failed.";
|
||
|
continue;
|
||
|
}
|
||
|
if (m_callback) {
|
||
|
Frame frame;
|
||
|
frame.data = reinterpret_cast<uint8_t *>(RK_MPI_MB_GetPtr(mediaBuffer));
|
||
|
frame.byteSize = RK_MPI_MB_GetSize(mediaBuffer);
|
||
|
frame.frameSize = frame.byteSize / m_format.channels / sizeof(uint16_t);
|
||
|
frame.timestamp = std::chrono::system_clock::now();
|
||
|
m_callback(frame);
|
||
|
}
|
||
|
RK_MPI_MB_ReleaseBuffer(mediaBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Output::Output() {
|
||
|
}
|
||
|
|
||
|
Output::~Output() {
|
||
|
close();
|
||
|
}
|
||
|
|
||
|
bool Output::open(uint32_t sampleSize, uint32_t sampleRate, uint32_t channels) {
|
||
|
|
||
|
m_channel = 0;
|
||
|
AO_CHN_ATTR_S parameter = {0};
|
||
|
parameter.pcAudioNode = "default";
|
||
|
parameter.enSampleFormat = RK_SAMPLE_FMT_S16;
|
||
|
parameter.u32NbSamples = sampleRate / 1000 * 20;
|
||
|
parameter.u32SampleRate = sampleRate;
|
||
|
parameter.u32Channels = channels;
|
||
|
|
||
|
RK_MPI_AO_SetChnAttr(m_channel, ¶meter);
|
||
|
RK_MPI_AO_EnableChn(m_channel);
|
||
|
|
||
|
AO_VQE_CONFIG_S config = {0};
|
||
|
config.s32WorkSampleRate = sampleRate;
|
||
|
config.s32FrameSample = parameter.u32NbSamples;
|
||
|
config.u32OpenMask = AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
|
||
|
strncpy(config.aParamFilePath, ParamFilePath, sizeof(config.aParamFilePath));
|
||
|
|
||
|
RK_MPI_AO_SetVqeAttr(m_channel, &config);
|
||
|
RK_MPI_AO_EnableVqe(m_channel);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void Output::close() {
|
||
|
if (m_channel >= 0) {
|
||
|
RK_MPI_AO_DisableVqe(m_channel);
|
||
|
RK_MPI_AO_DisableChn(m_channel);
|
||
|
m_channel = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Output::write(const uint8_t *data, uint32_t byteSize) {
|
||
|
if (m_channel < 0) return;
|
||
|
auto buffer = RK_MPI_MB_CreateAudioBuffer(byteSize, RK_FALSE);
|
||
|
if (buffer != nullptr) {
|
||
|
memcpy(RK_MPI_MB_GetPtr(buffer), data, byteSize);
|
||
|
RK_MPI_MB_SetSize(buffer, byteSize);
|
||
|
RK_MPI_SYS_SendMediaBuffer(RK_ID_AO, m_channel, buffer);
|
||
|
RK_MPI_MB_ReleaseBuffer(buffer);
|
||
|
} else {
|
||
|
LOG(error) << "RK_MPI_MB_CreateAudioBuffer() failed.";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace RkAudio
|