* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "alsa_snd_capture.h"
#include "common.h"
#define HDF_LOG_TAG HDF_AUDIO_HAL_CAPTURE
static enum AudioCategory g_currentScene = AUDIO_MMAP_NOIRQ;
typedef struct _CAPTURE_DATA_ {
struct AlsaMixerCtlElement ctrlLeftVolume;
struct AlsaMixerCtlElement ctrlRightVolume;
long tempVolume;
}CaptureData;
static int32_t CaptureSetHwParamsImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData);
static int32_t CaptureInitImpl(struct AlsaCapture* captureIns);
static int32_t UpdateAudioCaptureRoute(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
int32_t ret;
int32_t devCount = handleData->captureMode.hwInfo.pathSelect.deviceInfo.deviceNum;
AUDIO_FUNC_LOGI("UpdateAudioCaptureRoute devCount:%{public}d!", devCount);
if (devCount < 0 || devCount > PATHPLAN_COUNT - 1) {
AUDIO_FUNC_LOGE("devCount is error!");
return HDF_FAILURE;
}
struct AlsaMixerCtlElement elems[devCount];
for (int i = 0; i < devCount; i++) {
SndElementItemInit(&elems[i]);
elems[i].numid = 0;
elems[i].name = handleData->captureMode.hwInfo.pathSelect.deviceInfo.deviceSwitchs[i].deviceSwitch;
elems[i].value = handleData->captureMode.hwInfo.pathSelect.deviceInfo.deviceSwitchs[i].value;
}
ret = SndElementGroupWrite(cardIns, elems, devCount);
if (ret < 0) {
AUDIO_FUNC_LOGE("capture SndElementGroupWrite fail");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static void PcmCloseHandle(struct AlsaSoundCard *cardIns)
{
AUDIO_FUNC_LOGE("capture PcmCloseHandle enter");
int32_t ret;
if (cardIns == NULL) {
AUDIO_FUNC_LOGE("cardIns is NULL");
return;
}
if (cardIns->cardStatus > 0) {
cardIns->cardStatus -= 1;
}
if (cardIns->cardStatus == 0) {
if (cardIns->pcmHandle != NULL) {
ret = snd_pcm_close(cardIns->pcmHandle);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_close fail: %{public}s", snd_strerror(ret));
}
cardIns->pcmHandle = NULL;
}
if (cardIns->mixerHandle != NULL) {
ret = snd_mixer_close(cardIns->mixerHandle);
if (ret < 0) {
AUDIO_FUNC_LOGE("mixer close error: %{public}s.", snd_strerror(ret));
}
cardIns->mixerHandle = NULL;
}
}
AUDIO_FUNC_LOGE("capture PcmCloseHandle end");
}
static int32_t ConfigurePcm(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData,
struct AlsaSoundCard *cardIns)
{
int32_t ret = 0;
ret = UpdateAudioCaptureRoute(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams UpdateAudioCaptureRoute fail");
return HDF_FAILURE;
}
ret = CaptureSetHwParamsImpl(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams CaptureSetHwParamsImpl fail");
return HDF_FAILURE;
}
ret = snd_pcm_prepare(cardIns->pcmHandle);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_prepare fail: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t ReOpenPcmAndSetParams(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
AUDIO_FUNC_LOGE("capture ReOpenPcmAndSetParams enter.");
int32_t ret;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
enum AudioCategory scene = handleData->frameCaptureMode.attrs.type;
uint32_t dev = CaptureGetSceneDev(scene);
AUDIO_FUNC_LOGE("capture ReOpenPcmAndSetParams scene: %{public}d, dev: %{public}d.", scene, dev);
ret = SndSaveCardListInfo(SND_PCM_STREAM_PLAYBACK, dev);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Failed to save card device info.");
return HDF_FAILURE;
}
const char *adapterName = handleData->captureMode.hwInfo.adapterName;
ret = SndMatchSelAdapter(&captureIns->soundCard, adapterName);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SndMatchSelAdapter faild.");
SndCloseHandle(&captureIns->soundCard);
return HDF_FAILURE;
}
ret = snd_pcm_open(&cardIns->pcmHandle, cardIns->devName, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
AUDIO_FUNC_LOGI("capture snd_pcm_open devName: %{public}s!", cardIns->devName);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_open fail: %{public}s!", snd_strerror(ret));
SndCloseHandle(&captureIns->soundCard);
return HDF_FAILURE;
}
ret = SndOpenMixer(&captureIns->soundCard);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SndOpenMixer failed");
SndCloseHandle(&captureIns->soundCard);
return HDF_FAILURE;
}
ret = CaptureInitImpl(captureIns);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams CaptureInitImpl fail");
return HDF_FAILURE;
}
ret = ConfigurePcm(captureIns, handleData, cardIns);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams ConfigurePcm fail");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t CaptureInitImpl(struct AlsaCapture* captureIns)
{
if (captureIns->priData != NULL) {
return HDF_SUCCESS;
}
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CaptureData *priData = (CaptureData *)OsalMemCalloc(sizeof(CaptureData));
if (priData == NULL) {
AUDIO_FUNC_LOGE("Failed to allocate memory!");
return HDF_FAILURE;
}
SndElementItemInit(&priData->ctrlLeftVolume);
SndElementItemInit(&priData->ctrlRightVolume);
priData->ctrlLeftVolume.numid = SND_NUMID_DACL_CAPTURE_VOL;
priData->ctrlLeftVolume.name = SND_ELEM_DACL_CAPTURE_VOL;
priData->ctrlRightVolume.numid = SND_NUMID_DACR_CAPTURE_VOL;
priData->ctrlRightVolume.name = SND_ELEM_DACR_CAPTURE_VOL;
CaptureSetPriData(captureIns, (CapturePriData)priData);
return HDF_SUCCESS;
}
static bool CheckSceneIsChange(enum AudioCategory scene)
{
if (scene != AUDIO_IN_CALL) {
if (g_currentScene == AUDIO_IN_CALL || g_currentScene == AUDIO_MMAP_NOIRQ) {
return true;
} else {
return false;
}
} else {
if (g_currentScene != AUDIO_IN_CALL) {
return true;
} else {
return false;
}
}
}
static int32_t CaptureSelectSceneImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
int32_t ret = HDF_SUCCESS;
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl enter");
captureIns->descPins = handleData->captureMode.hwInfo.deviceDescript.pins;
enum AudioCategory scene = handleData->frameCaptureMode.attrs.type;
if (CheckSceneIsChange(scene)) {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl change scene");
if (g_currentScene == AUDIO_MMAP_NOIRQ) {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl scene is AUDIO_MMAP_NOIRQ");
ret = UpdateAudioCaptureRoute(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("capture UpdateAudioCaptureRoute fail");
return HDF_FAILURE;
}
g_currentScene = scene;
} else {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl scene is not AUDIO_MMAP_NOIRQ scene: %{public}d", scene);
if (captureIns->soundCard.pcmHandle != NULL) {
snd_pcm_drop(captureIns->soundCard.pcmHandle);
}
PcmCloseHandle(&captureIns->soundCard);
if (!SndisBusy(&captureIns->soundCard)) {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl pcm is NULL");
g_currentScene = scene;
}
}
} else {
g_currentScene = scene;
if (scene == AUDIO_IN_CALL) {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl change device");
ret = UpdateAudioCaptureRoute(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("capture UpdateAudioCaptureRoute fail");
return HDF_FAILURE;
}
}
}
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl end");
return HDF_SUCCESS;
}
static int32_t CaptureGetVolThresholdImpl(struct AlsaCapture *captureIns, long *volMin, long *volMax)
{
int32_t ret;
long volMinVal = 0;
long volMaxVal = 0;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CaptureData *priData = CaptureGetPriData(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(priData);
ret = SndElementReadRange(cardIns, &priData->ctrlLeftVolume, &volMinVal, &volMaxVal);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SndElementReadRange fail!");
return HDF_FAILURE;
}
*volMin = volMinVal;
*volMax = volMaxVal;
return HDF_SUCCESS;
}
static int32_t CaptureGetVolumeImpl(struct AlsaCapture *captureIns, long *volume)
{
int32_t ret;
long volLeft = 0;
long volRight = 0;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CaptureData *priData = CaptureGetPriData(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(priData);
ret = SndElementReadInt(cardIns, &priData->ctrlLeftVolume, &volLeft);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Read left volume fail!");
return HDF_FAILURE;
}
ret = SndElementReadInt(cardIns, &priData->ctrlRightVolume, &volRight);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Read right volume fail!");
return HDF_FAILURE;
}
*volume = (volLeft + volRight) >> 1;
return HDF_SUCCESS;
}
static int32_t CaptureSetVolumeImpl(struct AlsaCapture *captureIns, long volume)
{
int32_t ret;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CaptureData *priData = CaptureGetPriData(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(priData);
ret = SndElementWriteInt(cardIns, &priData->ctrlLeftVolume, volume);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Write left volume fail!");
return HDF_FAILURE;
}
ret = SndElementWriteInt(cardIns, &priData->ctrlRightVolume, volume);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Write right volume fail!");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t CaptureSetMuteImpl(struct AlsaCapture *captureIns, bool muteFlag)
{
int32_t ret;
CaptureData *priData = CaptureGetPriData(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(priData);
struct AlsaMixerCtlElement elem;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
SndElementItemInit(&elem);
elem.numid = CAPTURE_MUTE_NUMID;
elem.name = CAPTURE_MUTE_PATH;
elem.value = muteFlag ? OPEN_MIC : CLOSE_MIC;
ret = SndElementWrite(cardIns, &elem);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("write capture fail!");
return HDF_FAILURE;
}
captureIns->muteState = muteFlag;
return HDF_SUCCESS;
}
static int32_t CaptureStartImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
AUDIO_FUNC_LOGI("CaptureStartImpl enter!");
uint32_t ret;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
if (g_currentScene == AUDIO_IN_CALL) {
if (cardIns->pcmHandle) {
ret = snd_pcm_start(cardIns->pcmHandle);
AUDIO_FUNC_LOGI("CaptureStartImpl use snd_pcm_start ret:%{public}d", ret);
AUDIO_FUNC_LOGI("CaptureStartImpl call cardIns->devName: %{public}s!", cardIns->devName);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_start fail: %{public}s, ret: %{public}d", snd_strerror(ret), ret);
}
return HDF_SUCCESS;
}
return HDF_FAILURE;
} else {
if (!SndisBusy(cardIns)) {
AUDIO_FUNC_LOGI("CaptureStartImpl pcmHandle is NULL");
ret = ReOpenPcmAndSetParams(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams fail");
return HDF_FAILURE;
}
}
}
AUDIO_FUNC_LOGI("CaptureStartImpl end!");
return HDF_SUCCESS;
}
static int32_t CaptureStopImpl(struct AlsaCapture *captureIns)
{
AUDIO_FUNC_LOGI("CaptureStopImpl enter!");
if (g_currentScene == AUDIO_IN_CALL) {
return HDF_SUCCESS;
}
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns->soundCard.pcmHandle);
snd_pcm_drop(captureIns->soundCard.pcmHandle);
PcmCloseHandle(&captureIns->soundCard);
AUDIO_FUNC_LOGI("CaptureStopImpl end!");
return HDF_SUCCESS;
}
static int32_t CaptureGetGainThresholdImpl(struct AlsaCapture *captureIns, float *gainMin, float *gainMax)
{
AUDIO_FUNC_LOGE("not support gain operation");
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
(void)gainMin;
(void)gainMax;
return HDF_SUCCESS;
}
static int32_t CaptureGetGainImpl(struct AlsaCapture *captureIns, float *volume)
{
AUDIO_FUNC_LOGE("not support gain operation");
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
(void)volume;
return HDF_SUCCESS;
}
static int32_t CaptureSetGainImpl(struct AlsaCapture *captureIns, float volume)
{
AUDIO_FUNC_LOGE("not support gain operation");
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
(void)volume;
return HDF_SUCCESS;
}
static bool CaptureGetMuteImpl(struct AlsaCapture *captureIns)
{
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
return captureIns->muteState;
}
static int32_t CaptureDataCopyVdi(struct AudioHwCaptureParam *handleData, char *buffer, uint64_t frames)
{
int32_t ret;
uint32_t channels;
uint32_t format;
uint64_t recvDataSize;
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
CHECK_NULL_PTR_RETURN_DEFAULT(buffer);
if (frames == 0) {
AUDIO_FUNC_LOGE("Capture buffer size is empty!");
return HDF_FAILURE;
}
if (handleData->frameCaptureMode.buffer == NULL) {
AUDIO_FUNC_LOGE("frameCaptureMode.buffer is NULL!");
return HDF_FAILURE;
}
channels = handleData->frameCaptureMode.attrs.channelCount;
format = (uint32_t)handleData->frameCaptureMode.attrs.format;
recvDataSize = (uint64_t)(frames * channels * format);
ret = memcpy_s(handleData->frameCaptureMode.buffer, FRAME_DATA, buffer, recvDataSize);
if (ret != EOK) {
AUDIO_FUNC_LOGE("memcpy frame data failed!");
return HDF_FAILURE;
}
handleData->frameCaptureMode.bufferSize = recvDataSize;
handleData->frameCaptureMode.bufferFrameSize = frames;
return HDF_SUCCESS;
}
static int32_t CapturePcmReadiVdi(snd_pcm_t *pcm, uint64_t *frameCnt, char *dataBuf, snd_pcm_uframes_t bufSize)
{
int32_t ret;
long frames;
int32_t tryNum = AUDIO_ALSALIB_RETYR;
CHECK_NULL_PTR_RETURN_DEFAULT(pcm);
CHECK_NULL_PTR_RETURN_DEFAULT(frameCnt);
CHECK_NULL_PTR_RETURN_DEFAULT(dataBuf);
if (bufSize == 0) {
AUDIO_FUNC_LOGE("Capture data buf is empty.");
return HDF_FAILURE;
}
while (bufSize > 0) {
AUDIO_FUNC_LOGI("snd_pcm_mmap_readi begin bufSize: %{public}ld", bufSize);
frames = snd_pcm_mmap_readi(pcm, dataBuf, bufSize);
AUDIO_FUNC_LOGI("snd_pcm_mmap_readi end frames: %{public}ld", frames);
if (frames > 0) {
*frameCnt = (uint64_t)frames;
bufSize -= frames;
return HDF_SUCCESS;
}
if (frames == -EBADFD) {
AUDIO_FUNC_LOGE("Capture PCM is not in the right state: %{public}s", snd_strerror(frames));
ret = snd_pcm_prepare(pcm);
if (ret < 0) {
AUDIO_FUNC_LOGE("Capture snd_pcm_prepare fail: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
} else if (frames == -EAGAIN) {
AUDIO_FUNC_LOGE("snd_pcm_mmap_writei faild snd_pcm_wait");
snd_pcm_wait(pcm, PCM_WAIT_TIMEOUT_MS);
tryNum--;
if (tryNum == 0) {
return HDF_SUCCESS;
}
} else {
* stream is suspended and waiting for an application recovery.
* -EPIPE: an underrun occurred.
*/
ret = snd_pcm_recover(pcm, frames, 0);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_mmap_readi failed: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
}
}
return HDF_SUCCESS;
}
static int32_t CheckPcmStatus(struct AlsaCapture *captureIns, struct AudioHwCaptureParam *handleData)
{
int32_t ret;
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
ret = snd_pcm_wait(captureIns->soundCard.pcmHandle, PCM_WAIT_TIMEOUT_MS);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_wait failed: %{public}s.", snd_strerror(ret));
if (captureIns->soundCard.pcmHandle != NULL) {
snd_pcm_drop(captureIns->soundCard.pcmHandle);
}
PcmCloseHandle(&captureIns->soundCard);
if (!SndisBusy(&captureIns->soundCard)) {
AUDIO_FUNC_LOGI("CaptureSelectSceneImpl pcm is NULL");
ret = ReOpenPcmAndSetParams(captureIns, handleData);
if (ret < 0) {
AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams fail");
return HDF_FAILURE;
}
}
return HDF_FAILURE;
}
if (snd_pcm_state(captureIns->soundCard.pcmHandle) == SND_PCM_STATE_SETUP) {
ret = snd_pcm_prepare(captureIns->soundCard.pcmHandle);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_prepare fail: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
static int32_t CheckCapFrameBufferSize(struct AudioHwCaptureParam *handleData, snd_pcm_uframes_t *periodSize)
{
uint32_t capFrameSize;
uint64_t capReqBufferSize;
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
CHECK_NULL_PTR_RETURN_DEFAULT(periodSize);
capFrameSize = handleData->frameCaptureMode.attrs.channelCount * handleData->frameCaptureMode.attrs.format;
if (capFrameSize == 0) {
AUDIO_FUNC_LOGE("Capture frame size is zero!");
return HDF_FAILURE;
}
capReqBufferSize = capFrameSize * (*periodSize);
if (capReqBufferSize > FRAME_DATA) {
*periodSize = FRAME_DATA / capFrameSize;
}
return HDF_SUCCESS;
}
static int32_t CaptureReadImpl(struct AlsaCapture *captureIns, struct AudioHwCaptureParam *handleData)
{
int32_t ret;
uint64_t frames = 0;
char *buffer = NULL;
snd_pcm_uframes_t bufferSize = 0;
snd_pcm_uframes_t periodSize = 0;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
if (cardIns->pauseState) {
AUDIO_FUNC_LOGE("Currently in pause, please check!");
return HDF_FAILURE;
}
ret = snd_pcm_get_params(cardIns->pcmHandle, &bufferSize, &periodSize);
if (ret < 0) {
AUDIO_FUNC_LOGE("Get capture params error: %{public}s.", snd_strerror(ret));
return HDF_FAILURE;
}
if (CheckCapFrameBufferSize(handleData, &periodSize) != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("CheckCapFrameBufferSize failed.");
return HDF_FAILURE;
}
if (CheckPcmStatus(captureIns, handleData) != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("CheckPcmStatus failed.");
return HDF_FAILURE;
}
buffer = OsalMemCalloc(ALSA_CAP_BUFFER_SIZE);
if (buffer == NULL) {
AUDIO_FUNC_LOGE("Failed to Calloc buffer");
return HDF_FAILURE;
}
ret = CapturePcmReadiVdi(cardIns->pcmHandle, &frames, buffer, periodSize);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("CapturePcmReadiVdi is error!");
AudioMemFree((void **)&buffer);
return ret;
}
ret = CaptureDataCopyVdi(handleData, buffer, frames);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("Failed to copy data. It may be paused. Check the status!");
AudioMemFree((void **)&buffer);
return ret;
}
AudioMemFree((void **)&buffer);
return HDF_SUCCESS;
}
static int32_t SaveHwParams(struct AlsaSoundCard *cardIns, const struct AudioHwCaptureParam *handleData)
{
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
cardIns->hwParams.streamType = AUDIO_CAPTURE_STREAM;
cardIns->hwParams.channels = handleData->frameCaptureMode.attrs.channelCount;
cardIns->hwParams.rate = handleData->frameCaptureMode.attrs.sampleRate;
cardIns->hwParams.periodSize = handleData->frameCaptureMode.periodSize;
cardIns->hwParams.periodCount = handleData->frameCaptureMode.periodCount;
cardIns->hwParams.format = handleData->frameCaptureMode.attrs.format;
cardIns->hwParams.period = handleData->frameCaptureMode.attrs.period;
cardIns->hwParams.frameSize = handleData->frameCaptureMode.attrs.frameSize;
cardIns->hwParams.isBigEndian = handleData->frameCaptureMode.attrs.isBigEndian;
cardIns->hwParams.isSignedData = handleData->frameCaptureMode.attrs.isSignedData;
cardIns->hwParams.startThreshold = handleData->frameCaptureMode.attrs.startThreshold;
cardIns->hwParams.stopThreshold = handleData->frameCaptureMode.attrs.stopThreshold;
cardIns->hwParams.silenceThreshold = handleData->frameCaptureMode.attrs.silenceThreshold;
return HDF_SUCCESS;
}
static int32_t ConfigureCaptur(snd_pcm_t *handle, snd_pcm_hw_params_t *hwParams, struct AlsaCapture *captureIns)
{
snd_pcm_uframes_t size = 0;
int32_t ret;
captureIns->periodSize = CAPTURE_PERIOD_SIZE_CALL;
captureIns->bufferSize = CAPTURE_BUFFER_SIZE_CALL;
size = captureIns->periodSize;
ret = snd_pcm_hw_params_set_period_size_near(handle, hwParams, &size, 0);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWParamsCall Set period size failed!");
return ret;
}
AUDIO_FUNC_LOGI("SetHWParamsCall use snd_pcm_hw_params_set_period_size_near");
size = captureIns->bufferSize;
ret = snd_pcm_hw_params_set_buffer_size_near(handle, hwParams, &size);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWParamsCall Set buffer size failed!");
return ret;
}
ret = snd_pcm_hw_params(handle, hwParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("SetHWParamsCall Unable to set hw params for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SetHWParamsCall(struct AlsaSoundCard *cardIns)
{
int32_t ret;
uint32_t channel = CHANNEL_CALL;
uint32_t rRate = RATE_CALL;
int32_t dir = 0;
snd_pcm_format_t pcmFormat = SND_PCM_FORMAT_S16_LE;
snd_pcm_hw_params_t *hwParams = NULL;
snd_pcm_t *handle = cardIns->pcmHandle;
struct AlsaCapture *captureIns = (struct AlsaCapture*)cardIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handle);
snd_pcm_hw_params_alloca(&hwParams);
ret = snd_pcm_hw_params_any(handle, hwParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("Broken configuration for capture: %{public}s.", snd_strerror(ret));
return HDF_FAILURE;
}
snd_pcm_access_mask_t *mask = malloc(snd_pcm_access_mask_sizeof());
snd_pcm_access_mask_none(mask);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
ret = snd_pcm_hw_params_set_access_mask(handle, hwParams, mask);
if (ret < 0) {
AUDIO_FUNC_LOGE("snd_pcm_hw_params_set_access_mask failed: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
ret = snd_pcm_hw_params_set_format(handle, hwParams, pcmFormat);
if (ret < 0) {
AUDIO_FUNC_LOGE("Sample format not available for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
ret = snd_pcm_hw_params_set_channels(handle, hwParams, channel);
if (ret < 0) {
AUDIO_FUNC_LOGE("Channels count (%{public}d) not available for capture: %{public}s", ret, snd_strerror(ret));
return HDF_FAILURE;
}
ret = snd_pcm_hw_params_set_rate_near(handle, hwParams, &rRate, &dir);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("snd_pcm_hw_params_set_rate_near failed!");
return ret;
}
ret = ConfigureCaptur(handle, hwParams, captureIns);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("ConfigureCaptur Set period size failed!");
return ret;
}
return HDF_SUCCESS;
}
static int32_t SetHWParamsSubVdi(
struct AlsaSoundCard *cardIns, snd_pcm_hw_params_t *params)
{
int32_t ret;
snd_pcm_format_t pcmFormat;
snd_pcm_t *handle = cardIns->pcmHandle;
struct AlsaCapture *captureIns = (struct AlsaCapture *)cardIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(params);
ret = snd_pcm_hw_params_set_rate_resample(handle, params, captureIns->resample);
if (ret < 0) {
AUDIO_FUNC_LOGE("Resampling setup failed for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
snd_pcm_access_mask_t *mask = malloc(snd_pcm_access_mask_sizeof());
snd_pcm_access_mask_none(mask);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
ret = snd_pcm_hw_params_set_access_mask(handle, params, mask);
if (ret < 0) {
AUDIO_FUNC_LOGE("Access type not available for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
ret = SndConverAlsaPcmFormat(&cardIns->hwParams, &pcmFormat);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SndConverAlsaPcmFormat error.");
return ret;
}
ret = snd_pcm_hw_params_set_format(handle, params, pcmFormat);
if (ret < 0) {
AUDIO_FUNC_LOGE("Sample format not available for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
AUDIO_FUNC_LOGI("SetHWParamsSubVdi channels:%{public}d", cardIns->hwParams.channels);
ret = snd_pcm_hw_params_set_channels(handle, params, CHANNEL_CALL);
if (ret < 0) {
AUDIO_FUNC_LOGE("Channels count (%{public}u) not available for capture: %{public}s", cardIns->hwParams.channels,
snd_strerror(ret));
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SetHWRate(struct AlsaSoundCard *cardIns, snd_pcm_hw_params_t *params)
{
int32_t ret;
uint32_t rRate;
int32_t dir = 0;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(params);
rRate = cardIns->hwParams.rate;
AUDIO_FUNC_LOGI("SetHWRate first rRate: %{public}du", rRate);
ret = snd_pcm_hw_params_set_rate_near(cardIns->pcmHandle, params, &rRate, &dir);
if (ret < 0) {
AUDIO_FUNC_LOGE("Rate %{public}uHz not available for capture: %{public}s",
cardIns->hwParams.rate, snd_strerror(ret));
return HDF_FAILURE;
}
if (rRate != cardIns->hwParams.rate) {
ret = snd_pcm_hw_params_set_rate_near(cardIns->pcmHandle, params, &rRate, &dir);
if (ret < 0) {
AUDIO_FUNC_LOGE("Rate %{public}uHz not available for capture: %{public}s",
cardIns->hwParams.rate, snd_strerror(ret));
return HDF_FAILURE;
}
}
cardIns->hwParams.rate = rRate;
AUDIO_FUNC_LOGI("SetHWRate sconed rRate: %{public}du", rRate);
return HDF_SUCCESS;
}
static int32_t SetHWBufferAndPeriod(struct AlsaSoundCard *cardIns, snd_pcm_hw_params_t *params)
{
int32_t ret;
snd_pcm_uframes_t size = 0;
struct AlsaCapture *captureIns = (struct AlsaCapture*)cardIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(params);
captureIns->periodSize = CAPTURE_PERIOD_SIZE_DEFAULT;
captureIns->bufferSize = CAPTURE_BUFFER_SIZE_DEFAULT;
size = captureIns->periodSize;
ret = snd_pcm_hw_params_set_period_size_near(cardIns->pcmHandle, params, &size, 0);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWParamsCall Set period size failed!");
return ret;
}
size = captureIns->bufferSize;
ret = snd_pcm_hw_params_set_buffer_size_near(cardIns->pcmHandle, params, &size);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWParamsCall Set buffer size failed!");
return ret;
}
return HDF_SUCCESS;
}
static int32_t SetHWParamsVdi(struct AlsaSoundCard *cardIns)
{
AUDIO_FUNC_LOGI("SetHWParamsVdi enter!");
int32_t ret;
snd_pcm_hw_params_t *hwParams = NULL;
snd_pcm_t *handle = cardIns->pcmHandle;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handle);
snd_pcm_hw_params_alloca(&hwParams);
ret = snd_pcm_hw_params_any(handle, hwParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("Broken configuration for capture: no configurations available: %{public}s.",
snd_strerror(ret));
return HDF_FAILURE;
}
ret = SetHWParamsSubVdi(cardIns, hwParams);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWParamsSubVdi failed!");
return ret;
}
ret = SetHWRate(cardIns, hwParams);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWRate failed!");
return ret;
}
AUDIO_FUNC_LOGI("SetHWParams SetHWBufferAndPeriod begin!");
ret = SetHWBufferAndPeriod(cardIns, hwParams);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("SetHWBuffer failed!");
return ret;
}
AUDIO_FUNC_LOGI("SetHWParamsVdi snd_pcm_hw_params begin!");
ret = snd_pcm_hw_params(handle, hwParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set hw params for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
AUDIO_FUNC_LOGI("SetHWParamsVdi snd_pcm_hw_params end!");
cardIns->canPause = snd_pcm_hw_params_can_pause(hwParams);
AUDIO_FUNC_LOGI("hardware driver %{public}s pause", cardIns->canPause ? "supports" : "does not support");
return HDF_SUCCESS;
}
static int32_t ConfigureTransfer(snd_pcm_t *handle, snd_pcm_sw_params_t *swParams, struct AlsaCapture *captureIns)
{
int32_t ret;
snd_pcm_sframes_t startThresholdSize = 1;
snd_pcm_sframes_t stopThresholdSize = -1;
if (g_currentScene == AUDIO_IN_CALL) {
ret = snd_pcm_sw_params_set_avail_min(handle, swParams, 0);
ret = snd_pcm_sw_params_set_start_threshold(handle, swParams, 0);
ret = snd_pcm_sw_params_set_silence_size(handle, swParams, 0);
ret = snd_pcm_sw_params_set_silence_threshold(handle, swParams, 0);
ret = snd_pcm_sw_params_set_stop_threshold(handle, swParams, stopThresholdSize);
} else {
ret = snd_pcm_sw_params_set_start_threshold(handle, swParams, startThresholdSize);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set start threshold mode for capture: %{public}s.", snd_strerror(ret));
return HDF_FAILURE;
}
ret = snd_pcm_sw_params_set_avail_min(handle, swParams,
captureIns->periodEvent ? captureIns->bufferSize : captureIns->periodSize);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set avail min for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
static int32_t SetSWParams(struct AlsaSoundCard *cardIns)
{
int32_t ret;
snd_pcm_sw_params_t *swParams = NULL;
snd_pcm_t *handle = cardIns->pcmHandle;
struct AlsaCapture *captureIns = (struct AlsaCapture *)cardIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handle);
snd_pcm_sw_params_alloca(&swParams);
ret = snd_pcm_sw_params_current(handle, swParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to determine current swparams for capture: %{public}s.", snd_strerror(ret));
return HDF_FAILURE;
}
if (captureIns->periodSize == 0) {
AUDIO_FUNC_LOGE("error: g_periodSize cannot be zero!");
return HDF_FAILURE;
}
ret = ConfigureTransfer(handle, swParams, captureIns);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set ConfigureTransfer for capture: %{public}s.", snd_strerror(ret));
return HDF_FAILURE;
}
if (captureIns->periodEvent) {
ret = snd_pcm_sw_params_set_period_event(handle, swParams, 1);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set period event: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
}
ret = snd_pcm_sw_params(handle, swParams);
if (ret < 0) {
AUDIO_FUNC_LOGE("Unable to set sw params for capture: %{public}s", snd_strerror(ret));
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t CaptureSetParams(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
int32_t ret;
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
SaveHwParams(cardIns, handleData);
if (g_currentScene != AUDIO_IN_CALL) {
ret = SetHWParamsVdi(cardIns);
} else {
ret = SetHWParamsCall(cardIns);
}
if (ret < 0) {
AUDIO_FUNC_LOGE("Setting of hwparams failed.");
return HDF_FAILURE;
}
ret = SetSWParams(cardIns);
if (ret < 0) {
AUDIO_FUNC_LOGE("Setting of swparams failed.");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t CaptureSetHwParamsImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
int32_t ret;
CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
ret = CaptureSetParams(captureIns, handleData);
if (ret != HDF_SUCCESS) {
AUDIO_FUNC_LOGE("capture set parameters failed!");
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
int32_t CaptureOverrideFunc(struct AlsaCapture *captureIns)
{
if (captureIns == NULL) {
return HDF_FAILURE;
}
struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)captureIns;
CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);
if (cardIns->cardType == SND_CARD_PRIMARY) {
captureIns->Init = CaptureInitImpl;
captureIns->SelectScene = CaptureSelectSceneImpl;
captureIns->Start = CaptureStartImpl;
captureIns->Stop = CaptureStopImpl;
captureIns->GetVolThreshold = CaptureGetVolThresholdImpl;
captureIns->GetVolume = CaptureGetVolumeImpl;
captureIns->SetVolume = CaptureSetVolumeImpl;
captureIns->GetGainThreshold = CaptureGetGainThresholdImpl;
captureIns->GetGain = CaptureGetGainImpl;
captureIns->SetGain = CaptureSetGainImpl;
captureIns->GetMute = CaptureGetMuteImpl;
captureIns->SetMute = CaptureSetMuteImpl;
captureIns->Read = CaptureReadImpl;
captureIns->SetParams = CaptureSetHwParamsImpl;
}
return HDF_SUCCESS;
}
int32_t CaptureGetSceneDev(enum AudioCategory scene)
{
if (scene < AUDIO_IN_MEDIA || scene > AUDIO_MMAP_NOIRQ) {
scene = AUDIO_IN_MEDIA;
}
if (scene == AUDIO_IN_CALL) {
return SND_CALL_PCM_DEV;
} else {
return SND_DEFAULT_PCM_DEV;
}
}