Files
2026-08-24 10:03:24 +08:00

691 lines
22 KiB
C

/*
* Copyright (C) 2017 Amlogic Corporation.
*
* 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.
*/
#define LOG_TAG "audio_hw_hal_manager"
//#define LOG_NDEBUG 0
#include "aml_audio_log.h"
#include <system/audio.h>
#include <hardware/audio.h>
#include <sound/asound.h>
#include <tinyalsa/asoundlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <limits.h>
#include "audio_hw.h"
#include "alsa_manager.h"
#include "audio_hw_utils.h"
#include "alsa_device_parser.h"
#include "dolby_lib_api.h"
#include "aml_audio_stream.h"
#include "alsa_config_parameters.h"
#include "dtv_patch.h"
#include "aml_audio_timer.h"
#include "dtv_private_object.h"
#include "aml_config_data.h"
#include "aml_dump_debug.h"
#include "tv_patch_ctrl.h"
#define AML_ZERO_ADD_MIN_SIZE 1024
#define AUDIO_EAC3_FRAME_SIZE 16
#define AUDIO_AC3_FRAME_SIZE 4
#define AUDIO_TV_PCM_FRAME_SIZE 32
#define AUDIO_DEFAULT_PCM_FRAME_SIZE 4
#define MAX_AVSYNC_GAP (10*90000)
#define MAX_AVSYNC_WAIT_TIME (3*1000*1000)
#define ALSA_DELAY_THRESHOLD_MS_NORMAL (32)
#define ALSA_DELAY_THRESHOLD_MS_LLP (16)
#define ALSA_OUTPUT_PCM_FILE "alsa_pcm_write.raw"
#define ALSA_OUTPUT_SPDIF_FILE "alsa_spdif_write"
#define WAIT_COUNT_MAX 30
#define ALSA_DELAY_THRESHOLD_MS ((alsa_llp_mode) ? ALSA_DELAY_THRESHOLD_MS_LLP : ALSA_DELAY_THRESHOLD_MS_NORMAL)
static bool alsa_llp_mode;
typedef struct alsa_handle {
unsigned int card;
unsigned int pcm_index; /*used for open the alsa device*/
struct pcm_config config;
struct pcm *pcm;
int block_mode;
unsigned int alsa_port; /*refer to PORT_SPDIF, PORT***/
audio_format_t format;
uint32_t start_threshold;
uint32_t write_cnt;
uint64_t write_frames;
bool alsa_running_status;// for pcm output, av sync
bool alsa_status_changed;// for pcm output, av sync
} alsa_handle_t;
static int aml_audio_get_alsa_debug() {
return get_debug_value(AML_DEBUG_AUDIOHAL_ALSA);
}
static int aml_alsa_pcm_close(alsa_handle_t *handle)
{
struct pcm *pcm = NULL;
if (handle == NULL || handle->pcm == NULL) {
ALOGE("%s handle is NULL\n", __func__);
return -1;
}
pcm = handle->pcm;
pcm_close(pcm);
aml_audio_free(handle);
return 0;
}
void aml_alsa_set_llp(bool mode)
{
alsa_llp_mode = mode;
}
int aml_alsa_input_open(void **handle, aml_alsa_config_t * stream_config, aml_device_config_t *device_config)
{
alsa_handle_t * alsa_handle = NULL;
struct pcm_config *config = NULL;
int ret = 0;
alsa_handle = (alsa_handle_t *)aml_audio_calloc(1, sizeof(alsa_handle_t));
if (alsa_handle == NULL) {
AM_LOGE("malloc alsa_handle failed\n");
return -1;
}
config = &alsa_handle->config;
alsa_handle->card = alsa_device_get_card_index();
alsa_handle->alsa_port = device_config->device_port;
if (alsa_handle->alsa_port == PORT_BUILTINMIC) {
alsa_handle->pcm_index = aml_get_json_int_value("Builtinmic_Alsa_Dev_Id", alsa_device_update_pcm_index(PORT_BUILTINMIC, CAPTURE));
} else {
alsa_handle->pcm_index = alsa_device_update_pcm_index(alsa_handle->alsa_port, CAPTURE);
}
config->format = convert_audio_format_2_alsa_format(stream_config->format);
config->channels = audio_channel_count_from_in_mask(stream_config->channel_mask);
config->rate = stream_config->sample_rate;
config->period_size = stream_config->period_size;
config->period_count = stream_config->period_count;
config->stop_threshold = config->period_size * config->period_count;
config->silence_size = LONG_MAX;
AM_LOGI("open card(%d), device(%d)", alsa_handle->card, alsa_handle->pcm_index);
AM_LOGI("ALSA open configs: channels %d format %d period_count %d period_size %d rate %d",
config->channels, config->format, config->period_count, config->period_size, config->rate);
AM_LOGI("ALSA open configs: threshold start %lu stop %lu silence %lu silence_size %lu avail_min %lu",
config->start_threshold, config->stop_threshold, config->silence_threshold, config->silence_size, config->avail_min);
/* non-blocking read prevent 10s stuck when switching TV sources */
alsa_handle->pcm = pcm_open(alsa_handle->card, alsa_handle->pcm_index, PCM_IN | PCM_NONBLOCK, config);
if (!alsa_handle->pcm || !pcm_is_ready(alsa_handle->pcm)) {
AM_LOGE("open device failed: %s", pcm_get_error(alsa_handle->pcm));
ret = -1;
goto error;
}
*handle = (void *)alsa_handle;
error:
if (ret < 0 && alsa_handle) {
aml_alsa_pcm_close(alsa_handle);
*handle = NULL;
}
AM_LOGI("alsa_input_open handle %p, ret %d", *handle, ret);
return ret;
}
int aml_alsa_input_read(void *handle, void *buffer, int bytes) {
int ret = 0;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle == NULL || alsa_handle->pcm == NULL) {
AM_LOGE("alsa_handle or pcm is NULL!!!");
return -1;
}
ret = pcm_read(alsa_handle->pcm, (unsigned char *)buffer, bytes);
if (ret < 0) {
if (ret != -1) {
AM_LOGE("pcm_read fail, ret:%d, error info:%s", ret, strerror(errno));
memset(buffer, 0, bytes);
}
}
return ret;
}
int aml_alsa_input_flush(void *handle)
{
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle == NULL || alsa_handle->pcm == NULL) {
AM_LOGE("alsa_handle or pcm is NULL!!!");
return -1;
}
int ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_RESET, 0);
if (ret < 0) {
AM_LOGE("cannot reset pcm!");
}
return ret;
}
int aml_alsa_input_get_delay(void *handle) {
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
int ret = 0;
if (alsa_handle == NULL || alsa_handle->pcm == NULL) {
AM_LOGE("alsa_handle or pcm is NULL!!!");
return 0;
}
struct pcm *pcm = alsa_handle->pcm;
snd_pcm_sframes_t delay = 0;
int delay_frames = 0;
ret = pcm_ioctl(pcm, SNDRV_PCM_IOCTL_DELAY, &delay);
if (ret < 0) {
AM_LOGE("cannot get delay!");
} else {
delay_frames = delay;
}
return delay_frames;
}
uint64_t aml_alsa_input_get_timestamp(void *handle) {
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle == NULL || alsa_handle->pcm == NULL) {
AM_LOGE("alsa_handle or pcm is NULL!!!");
return 0;
}
return pcm_get_timestamp(alsa_handle->pcm, alsa_handle->config.rate, 0);
}
int aml_alsa_input_stop(void *handle)
{
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle == NULL || alsa_handle->pcm == NULL) {
AM_LOGE("alsa_handle or pcm is NULL!!!");
return -1;
}
int ret = pcm_stop(alsa_handle->pcm);
if (ret < 0) {
AM_LOGE("cannot stop pcm!");
}
return ret;
}
int aml_alsa_input_close(void *handle)
{
AM_LOGI("handle %p", handle);
return aml_alsa_pcm_close((alsa_handle_t *)handle);
}
int aml_alsa_output_open(void **handle, aml_alsa_config_t * stream_config, aml_device_config_t *device_config)
{
struct pcm_config *config = NULL;
int card = 0;
int alsa_port = 0;
int pcm_index = -1;
struct pcm *pcm = NULL;
alsa_handle_t * alsa_handle = NULL;
bool platform_is_tv = 0;
audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
unsigned int channels = 0;
unsigned int rate = 0;
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
alsa_handle = (alsa_handle_t *)aml_audio_calloc(1, sizeof(alsa_handle_t));
if (alsa_handle == NULL) {
AM_LOGE("malloc alsa_handle failed\n");
return -1;
}
config = &alsa_handle->config;
format = stream_config->format;
channels = audio_channel_count_from_out_mask(stream_config->channel_mask);
rate = stream_config->sample_rate;
if (audio_is_linear_pcm(format)) {
get_hardware_config_parameters(config, format, adev->default_alsa_ch, rate, platform_is_tv,
stream_config->format == AUDIO_FORMAT_IEC61937, is_low_latency_mode(adev));
} else {
get_hardware_config_parameters(config, format, channels, rate, platform_is_tv,
stream_config->format == AUDIO_FORMAT_IEC61937, is_low_latency_mode(adev));
}
config->channels = channels;
config->rate = rate;
if (config->rate == 0 || config->channels == 0) {
AM_LOGE("Invalid sampleate=%d channel=%d\n", config->rate, config->channels);
goto exit;
}
if (format == AUDIO_FORMAT_PCM_16_BIT) {
config->format = PCM_FORMAT_S16_LE;
} else if (format == AUDIO_FORMAT_PCM_32_BIT) {
config->format = PCM_FORMAT_S32_LE;
} else {
config->format = PCM_FORMAT_S16_LE;
}
config->avail_min = 0;
card = alsa_device_get_card_index();
alsa_port = device_config->device_port;
if (alsa_port < 0) {
AM_LOGE("Wrong alsa_device ID\n");
goto exit;
}
pcm_index = alsa_device_update_pcm_index(alsa_port, PLAYBACK);
if (pcm_index < 0) {
int config_pcm_index;
config_pcm_index = aml_get_json_int_value("HDMITX_HBR_PCM_INDEX", -1);
if (config_pcm_index == 2) {
pcm_index = config_pcm_index;
config->period_size = 2048;
config->start_threshold = 0;
}
}
config->silence_size = LONG_MAX;
ALOGI("In pcm open ch=%d rate=%d\n", config->channels, config->rate);
ALOGI("%s, audio open card(%d), device(%d) \n", __func__, card, pcm_index);
ALOGI("ALSA open configs: channels %d format %d period_count %d period_size %d rate %d \n",
config->channels, config->format, config->period_count, config->period_size, config->rate);
ALOGI("ALSA open configs: threshold start %lu stop %lu silence %lu silence_size %lu avail_min %lu \n",
config->start_threshold, config->stop_threshold, config->silence_threshold, config->silence_size, config->avail_min);
pcm = pcm_open(card, pcm_index, PCM_OUT | PCM_MONOTONIC, config);
if (!pcm || !pcm_is_ready(pcm)) {
ALOGE("%s, pcm %p open [ready %d] failed. error info:%s\n", __func__, pcm, pcm_is_ready(pcm), pcm_get_error(pcm));
pcm_close(pcm);
goto exit;
}
alsa_handle->card = card;
alsa_handle->pcm_index = pcm_index;
alsa_handle->pcm = pcm;
alsa_handle->alsa_port = alsa_port;
alsa_handle->format = format;
alsa_handle->write_cnt = 0;
alsa_handle->write_frames = 0;
alsa_handle->start_threshold = config->start_threshold;
*handle = (void*)alsa_handle;
return 0;
exit:
if (alsa_handle) {
aml_audio_free(alsa_handle);
}
*handle = NULL;
return -1;
}
int aml_alsa_output_close(void *handle) {
AM_LOGI("handle %p", handle);
return aml_alsa_pcm_close((alsa_handle_t *)handle);
}
int aml_alsa_output_write(void *handle, const void *buffer, int bytes) {
int ret = -1;
alsa_handle_t * alsa_handle = NULL;
alsa_handle = (alsa_handle_t *)handle;
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
int debug_enable = aml_audio_get_alsa_debug();
if (alsa_handle == NULL || alsa_handle->pcm == NULL || buffer == NULL || bytes == 0) {
//AM_LOGE("invalid param, alsa_handle:%p, pcm:%p, buffer:%p, bytes:%zu",
//alsa_handle, alsa_handle?alsa_handle->pcm:0, buffer, bytes);
return -1;
}
#if 0
//ALOGD("handle=%p pcm=%p\n",alsa_handle,alsa_handle->pcm);
/*add for work around ddp dd ouput ,ddp underrun issue */
dd_pcm = alsa_handle->pcm;
ddp_pcm = adev->pcm_handle[adev->ms12.device];
if (is_sc2_chip() && eDolbyMS12Lib == adev->dolby_lib_type && dd_pcm && ddp_pcm && (alsa_handle->format != AUDIO_FORMAT_MAT)) {
snd_pcm_sframes_t delay_ddp = 0,delay_dd = 0;
ret = pcm_ioctl(dd_pcm, SNDRV_PCM_IOCTL_DELAY, &delay_dd);
if (ret < 0) {
delay_dd = alsa_handle->config.start_threshold;
}
ret = pcm_ioctl(ddp_pcm, SNDRV_PCM_IOCTL_DELAY, &delay_ddp);
if (ret < 0) {
delay_ddp = adev->ms12_config.start_threshold;
}
if (delay_dd + write_frames >= alsa_handle->config.start_threshold * 2)
overflow_flag = 1;
/* dd write blocked and ddp delay at a low level ,so skip dd data to avoid ddp underun*/
if (overflow_flag && delay_ddp <= 2 * 6144)
underrun_flag = 1;
if ( underrun_flag ) {
ALOGI("skip dd data for delay_dd frame =%ld delay_ddp frame %ld\n",delay_dd, delay_ddp);
return 0;
}
}
#endif
{
struct snd_pcm_status status;
bool alsa_status;
pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_STATUS, &status);
if (PORT_I2S == alsa_handle->alsa_port) {// for pcm output
alsa_status = (status.state == PCM_STATE_RUNNING);
if (alsa_status != alsa_handle->alsa_running_status) {
ALOGI("alsa_running_status change from %d to %d", alsa_handle->alsa_running_status, alsa_status);
alsa_handle->alsa_running_status = alsa_status;
alsa_handle->alsa_status_changed = true;
}
}
if (status.state != PCM_STATE_RUNNING) {
AM_LOGW("format =0x%x alsa underrun(%d), state(%d)", alsa_handle->format, status.state==PCM_STATE_XRUN, status.state);
}
}
if (get_debug_value(AML_DUMP_AUDIOHAL_OUT)) {
char file_name[128] = { 0 };
if (alsa_handle->format == AUDIO_FORMAT_AC3) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "dd");
} else if (alsa_handle->format == AUDIO_FORMAT_E_AC3) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "ddp");
} else if (alsa_handle->format == AUDIO_FORMAT_MAT) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "mat");
} else if (alsa_handle->format == AUDIO_FORMAT_DTS) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "dts");
} else if (alsa_handle->format == AUDIO_FORMAT_DTS_HD) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "dtshd");
} else if(alsa_handle->format == AUDIO_FORMAT_DTS_HD_MA) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "dtshd_ma");
} else if(alsa_handle->format == AUDIO_FORMAT_MPEGH) {
snprintf(file_name, 128, "%s.%s", ALSA_OUTPUT_SPDIF_FILE, "mpegh");
} else {
snprintf(file_name, 128, "%s_%dch.%s", ALSA_OUTPUT_SPDIF_FILE, alsa_handle->config.channels, "pcm");
}
aml_dump_audio_bitstreams(file_name, buffer, bytes);
}
if (get_debug_value(AML_DEBUG_AUDIOHAL_LEVEL_DETECT) && (AUDIO_FORMAT_PCM_16_BIT == alsa_handle->format)) {
check_audio_level("alsa_pcm", buffer, bytes);
}
alsa_handle->write_cnt++;
alsa_handle->write_frames += pcm_bytes_to_frames(alsa_handle->pcm, bytes);
if (debug_enable || (alsa_handle->write_cnt % 1000) == 0 || get_debug_value(AML_DEBUG_AUDIOHAL_GAME_MODE)) {
snd_pcm_sframes_t frames = 0;
ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_DELAY, &frames);
ALOGI("alsa format =0x%x delay frames =%ld total frames=%"PRIu64" write_bytes=%d write_frame=%d", alsa_handle->format, frames, alsa_handle->write_frames, bytes, pcm_bytes_to_frames(alsa_handle->pcm, bytes));
}
if (adev->reset_hdmitx_audio && adev->active_outport == OUTPORT_HDMI &&((alsa_handle->format == adev->sink_format) || (alsa_handle->format == AUDIO_FORMAT_E_AC3))) {
pcm_stop(alsa_handle->pcm);
adev->reset_hdmitx_audio = false;
AM_LOGI("reset hdmitx alsa, output format=%x, sink format=%x", alsa_handle->format, adev->sink_format);
}
ret = pcm_write(alsa_handle->pcm, buffer, bytes);
if (ret < 0) {
AM_LOGE("write failed,pcm handle %p %s,",
alsa_handle->pcm, pcm_get_error(alsa_handle->pcm));
}
return ret;
}
int aml_alsa_output_getinfo(void *handle, alsa_info_type_t type, alsa_output_info_t * info) {
int ret = -1;
alsa_handle_t * alsa_handle = NULL;
alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
switch (type) {
case OUTPUT_INFO_DELAYFRAME: {
snd_pcm_sframes_t delay = 0;
int rate = alsa_handle->config.rate;
int rate_multiply = 1;
ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_DELAY, &delay);
if (ret < 0) {
info->delay_ms = 0;
return -1;
}
if (alsa_handle->format == AUDIO_FORMAT_MAT) {
rate_multiply = 4;
} else if (alsa_handle->format == AUDIO_FORMAT_E_AC3) {
rate_multiply = 4;
}
info->delay_ms = delay * 1000 / (rate * rate_multiply);
return 0;
}
default:
return -1;
}
return -1;
}
void *get_internal_pcm(void *handle) {
if (!handle) {
return NULL;
}
return ((alsa_handle_t *)handle)->pcm;
}
int aml_alsa_output_pause(void *handle) {
int ret = -1;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
if (alsa_handle->pcm) {
ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_PAUSE, 1);
if (ret < 0) {
ALOGE("%s error %d", __func__, ret);
}
}
return ret;
}
int aml_alsa_output_resume(void *handle) {
int ret = -1;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
if (alsa_handle->pcm) {
ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_PREPARE);
if (ret < 0) {
ALOGE("%s error %d", __func__, ret);
}
}
return ret;
}
int aml_alsa_output_stop(void *handle) {
int ret = -1;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
if (alsa_handle->pcm) {
ret = pcm_stop(alsa_handle->pcm);
if (ret < 0) {
AM_LOGE("stop pcm failed,pcm handle %p %s",
alsa_handle->pcm, pcm_get_error(alsa_handle->pcm));
}
}
return ret;
}
bool aml_alsa_output_get_alsa_status(void *handle, bool *alsa_status) {
bool ret = false;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return ret;
}
ret = alsa_handle->alsa_status_changed;
*alsa_status = alsa_handle->alsa_running_status;
return ret;
}
int aml_alsa_output_clear_alsa_status_changed_flag(void *handle) {
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
alsa_handle->alsa_status_changed = false;
return 0;
}
// ignore_default == true, means that if we can not get delay frames from alsa, we will return 0 frame
// ignore_default == false, means that if we can not get delay frames from alsa, we will return start threshold
uint64_t aml_alsa_output_get_delay_frame(void *handle, bool ignore_default)
{
uint64_t delay_frames = 0;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
int ret = -1;
snd_pcm_sframes_t frames = 0;
if (alsa_handle) {
if (alsa_handle->pcm && pcm_is_ready(alsa_handle->pcm)) {
ret = pcm_ioctl(alsa_handle->pcm, SNDRV_PCM_IOCTL_DELAY, &frames);
if (ret < 0) {
AM_LOGE("pcm_ioctl fail, ret:%#x, error info:%s",
ret, strerror(errno));
} else if (ignore_default && !alsa_handle->alsa_running_status) {
delay_frames = 0;
} else if (frames >= 0) {
delay_frames = frames;
}
}
if (ret < 0) {
if (ignore_default) {
delay_frames = 0;
} else {
delay_frames = alsa_handle->config.start_threshold;
}
}
}
return delay_frames;
}
bool aml_alsa_output_get_start_threshold(void *handle, uint32_t *start_threshold)
{
bool ret = false;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle && start_threshold) {
*start_threshold = alsa_handle->start_threshold;
ret = true;
} else {
AM_LOGE("Parameter Error: alsa_handle(%p), start_threshold(%p)", alsa_handle, start_threshold);
}
return ret;
}
int aml_alsa_output_flush(void *handle)
{
int ret = -1;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (handle == NULL) {
return -1;
}
if (alsa_handle->pcm && pcm_is_ready (alsa_handle->pcm)) {
ret = pcm_ioctl (alsa_handle->pcm, SNDRV_PCM_IOCTL_RESET, 1);
if (ret < 0) {
AM_LOGE("cannot reset alsa\n");
} else {
AM_LOGI("reset alsa success\n");
}
} else {
if (alsa_handle->pcm) {
AM_LOGE("pcm is not ready(%d)\n", pcm_is_ready(alsa_handle->pcm));
}
}
return ret;
}
int aml_alsa_output_get_timestamp(void *handle, unsigned int *avail, struct timespec *tstamp)
{
int ret = -1;
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
if (alsa_handle && alsa_handle->pcm) {
ret = pcm_get_htimestamp(alsa_handle->pcm, avail, tstamp);
}
return ret;
}
enum pcm_format convert_audio_format_2_alsa_format(audio_format_t format)
{
switch (format) {
case AUDIO_FORMAT_PCM_16_BIT:
return PCM_FORMAT_S16_LE;
case AUDIO_FORMAT_PCM_32_BIT:
return PCM_FORMAT_S32_LE;
case AUDIO_FORMAT_PCM_8_BIT:
return PCM_FORMAT_S8;
case AUDIO_FORMAT_PCM_8_24_BIT:
return PCM_FORMAT_S24_LE;
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
return PCM_FORMAT_S24_3LE;
default:
AM_LOGE("invalid format:%#x, return 16bit format.", format);
return PCM_FORMAT_S16_LE;
}
}
void aml_alsa_info_dump(void* handle, int fd)
{
alsa_handle_t * alsa_handle = (alsa_handle_t *)handle;
dprintf(fd, "\t\tcard:%d\n", alsa_handle->card);
dprintf(fd, "\t\tpcm_index:%d\n", alsa_handle->pcm_index);
dprintf(fd, "\t\talsa_port:%d\n", alsa_handle->alsa_port);
dprintf(fd, "\t\tformat:%x\n", alsa_handle->format);
}