rk3568_ubuntu_r60_v1.3.2/external/eq_drc_process/main.cpp
2023-11-03 06:12:44 +00:00

1873 lines
61 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <errno.h>
#include <alsa/asoundlib.h>
#include <math.h>
#include <signal.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <getopt.h>
#include "eq_log.h"
#include "Rk_wake_lock.h"
#include "Rk_socket_app.h"
#define EQ_DRC_PROCESS_VERSION "1.29 20210720"
#define SOC_IS_RK3308 (0x1)
#define SOC_IS_RK3326 (0x2)
#define ROCKCHIP_SOC SOC_IS_RK3326
#define SAMPLE_RATE 48000
#define CHANNEL 2
#define REC_DEVICE_NAME "fake_record"
#define WRITE_DEVICE_NAME "fake_play"
#define JACK_DEVICE_NAME "fake_jack"
#define JACK2_DEVICE_NAME "fake_jack2"
#define READ_FRAME_DEFAULT 1920
#define PERIOD_SIZE_DEFAULT (READ_FRAME_DEFAULT)
#define PERIOD_COUNTS_DEFAULT (8)
#define BUFFER_SIZE_DEFAULT (PERIOD_SIZE_DEFAULT * PERIOD_COUNTS_DEFAULT) /* Keeping a large buffer_size ASAP */
#define MUTE_TIME_DEFAULT (3) /* seconds */
//#define ALSA_READ_FORMAT SND_PCM_FORMAT_S32_LE
#define ALSA_READ_FORMAT SND_PCM_FORMAT_S16_LE
#define ALSA_WRITE_FORMAT SND_PCM_FORMAT_S16_LE
/*
* Select different alsa pathways based on device type.
* LINE_OUT: LR-Mix(fake_play)->EqDrcProcess(ladspa)->Speaker(real_playback)
* HEAD_SET: fake_jack -> Headset(real_playback)
* BLUETOOTH: device as bluetooth source.
*/
#define DEVICE_FLAG_LINE_OUT 0x01
#define DEVICE_FLAG_ANALOG_HP 0x02
#define DEVICE_FLAG_DIGITAL_HP 0x03
#define DEVICE_FLAG_BLUETOOTH 0x04
#define DEVICE_FLAG_BLUETOOTH_BSA 0x05
enum BT_CONNECT_STATE{
BT_DISCONNECT = 0,
BT_CONNECT_BLUEZ,
BT_CONNECT_BSA
};
#define POWER_STATE_PATH "/sys/power/state"
#define USER_PLAY_STATUS "/dev/snd/pcmC7D0p"
#define USER_CAPT_STATUS "/dev/snd/pcmC0D0c"
/**
* 0: By default and universal (Recommend)
* 1: More fast but only used for RK817 or RK809 Codec
*/
#define KEEPING_HW_CARD 0
#if KEEPING_HW_CARD
#define HW_CARD_PATH_DEFAULT "SPK"
#endif
struct user_play_inotify {
int fd;
int watch_desc;
bool stop;
};
struct user_capt_inotify {
int fd;
int watch_desc;
bool stop;
};
enum {
USER_PLAY_CLOSED = 0,
USER_PLAY_CLOSING,
USER_PLAY_OPENED,
};
enum {
USER_CAPT_CLOSED = 0,
USER_CAPT_CLOSING,
USER_CAPT_OPENED,
};
enum {
POWER_STATE_RESUME = 0,
POWER_STATE_SUSPENDING,
POWER_STATE_SUSPEND,
};
static int g_read_frame = READ_FRAME_DEFAULT;
static int g_period_size = PERIOD_SIZE_DEFAULT;
static int g_period_counts = PERIOD_COUNTS_DEFAULT;
static int g_buffer_size = BUFFER_SIZE_DEFAULT;
#if KEEPING_HW_CARD
static char g_path_name[32];
volatile static bool g_fast_codec = false;
#endif
static struct user_play_inotify g_upi;
static struct user_capt_inotify g_uci;
static char g_bt_mac_addr[17];
static enum BT_CONNECT_STATE g_bt_is_connect = BT_DISCONNECT;
static bool g_system_sleep = false;
static char sock_path[] = "/data/bsa/config/bsa_socket";
#if KEEPING_HW_CARD
static snd_pcm_t *write_handle_bak = NULL;
#endif
volatile static int power_state = POWER_STATE_RESUME;
volatile static int user_play_state = USER_PLAY_CLOSED;
volatile static int user_capt_state = USER_CAPT_CLOSED;
struct timeval tv_begin, tv_end;
//gettimeofday(&tv_begin, NULL);
extern int set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t buffer_size,
snd_pcm_uframes_t period_size, char **msg);
/* epoll for inotify */
#define EPOLL_SIZE 512
#define ARRAY_LENGTH 128
#define NAME_LENGTH 128
#define EPOLL_MAX_EVENTS 32
struct file_name_fd_desc {
int fd;
char name[32];
char base_name[NAME_LENGTH];
};
static struct epoll_event g_PendingEventItems[EPOLL_MAX_EVENTS];
static struct file_name_fd_desc g_file_name_fd_desc[ARRAY_LENGTH];
static int array_index = 0;
static const char *base_dir = "/sys/power";
/* hanlding fade-in or fade-out */
#define FADE_IN 0
#define FADE_OUT 1
#ifndef av_clipd
# define av_clipd av_clipd_c
#endif
enum CurveType { NONE = -1, TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, LOSI, SINC, ISINC, NB_CURVES };
/**
* Clip a double value into the amin-amax range.
* @param a value to clip
* @param amin minimum value of the clip range
* @param amax maximum value of the clip range
* @return clipped value
*/
static inline const double av_clipd_c(double a, double amin, double amax)
{
// eq_info("[EQ] %s - %d enter\n", __func__, __LINE__);
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
static double fade_gain(int curve, int64_t index, int64_t range)
{
#define CUBE(a) ((a)*(a)*(a))
double gain;
gain = av_clipd(1.0 * index / range, 0, 1.0);
// eq_info("[EQ] %s - %d index=%ld gain=%lf\n", __func__, __LINE__, index, gain);
switch (curve) {
case QSIN:
gain = sin(gain * M_PI / 2.0);
break;
case IQSIN:
/* 0.6... = 2 / M_PI */
gain = 0.6366197723675814 * asin(gain);
break;
case ESIN:
gain = 1.0 - cos(M_PI / 4.0 * (CUBE(2.0*gain - 1) + 1));
break;
case HSIN:
gain = (1.0 - cos(gain * M_PI)) / 2.0;
break;
case IHSIN:
/* 0.3... = 1 / M_PI */
gain = 0.3183098861837907 * acos(1 - 2 * gain);
break;
case EXP:
/* -11.5... = 5*ln(0.1) */
gain = exp(-11.512925464970227 * (1 - gain));
break;
case LOG:
gain = av_clipd(1 + 0.2 * log10(gain), 0, 1.0);
break;
case PAR:
gain = 1 - sqrt(1 - gain);
break;
case IPAR:
gain = (1 - (1 - gain) * (1 - gain));
break;
case QUA:
gain *= gain;
break;
case CUB:
gain = CUBE(gain);
break;
case SQU:
gain = sqrt(gain);
break;
case CBR:
gain = cbrt(gain);
break;
case DESE:
gain = gain <= 0.5 ? cbrt(2 * gain) / 2: 1 - cbrt(2 * (1 - gain)) / 2;
break;
case DESI:
gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2;
break;
case LOSI: {
const double a = 1. / (1. - 0.787) - 1;
double A = 1. / (1.0 + exp(0 -((gain-0.5) * a * 2.0)));
double B = 1. / (1.0 + exp(a));
double C = 1. / (1.0 + exp(0-a));
gain = (A - B) / (C - B);
}
break;
case SINC:
gain = gain >= 1.0 ? 1.0 : sin(M_PI * (1.0 - gain)) / (M_PI * (1.0 - gain));
break;
case ISINC:
gain = gain <= 0.0 ? 0.0 : 1.0 - sin(M_PI * gain) / (M_PI * gain);
break;
case NONE:
gain = 1.0;
break;
}
return gain;
}
#define FADE(name, type) \
static void fade_samples_## name (uint8_t **dst, uint8_t * const *src, \
int nb_samples, int channels, int dir, \
int64_t start, int64_t range, int curve) \
{ \
type *d = (type *)dst[0]; \
const type *s = (type *)src[0]; \
int i, c, k = 0; \
\
for (i = 0; i < nb_samples; i++) { \
double gain = fade_gain(curve, start + i * dir, range); \
for (c = 0; c < channels; c++, k++) \
d[k] = s[k] * gain; \
} \
}
FADE(dbl, double)
FADE(flt, float)
FADE(s16, int16_t)
FADE(s32, int32_t)
static int add_to_epoll(int epoll_fd, int fd)
{
int result;
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.fd = fd;
result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &eventItem);
return result;
}
static void remove_from_epoll(int epoll_fd, int fd)
{
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
static int get_name_from_fd(int fd, char **name)
{
int i;
for(i = 0; i < ARRAY_LENGTH; i++)
{
if(fd == g_file_name_fd_desc[i].fd)
{
*name = g_file_name_fd_desc[i].name;
return 0;
}
}
return -1;
}
static int inotify_ctl_info(int inotify_fd, int epoll_fd)
{
char event_buf[EPOLL_SIZE];
int event_pos = 0;
int event_size;
struct inotify_event *event;
int result;
int tmp_fd;
int i;
memset(event_buf, 0, EPOLL_SIZE);
result = read(inotify_fd, event_buf, sizeof(event_buf));
if(result < (int)sizeof(*event)) {
printf("could not get event!\n");
return -1;
}
while (result >= (int)sizeof(*event))
{
event = (struct inotify_event *)(event_buf + event_pos);
if (event->len)
{
if (event->mask & IN_CREATE)
{
sprintf(g_file_name_fd_desc[array_index].name, "%s", event->name);
sprintf(g_file_name_fd_desc[array_index].base_name, "%s/%s", base_dir, event->name);
tmp_fd = open(g_file_name_fd_desc[array_index].base_name, O_RDWR);
if(-1 == tmp_fd)
{
printf("inotify_ctl_info open error!\n");
return -1;
}
add_to_epoll(epoll_fd, tmp_fd);
g_file_name_fd_desc[array_index].fd = tmp_fd;
if(ARRAY_LENGTH == array_index)
{
array_index = 0;
}
array_index += 1;
printf("add file to epoll: %s\n", event->name);
}
else if (event->mask & IN_DELETE)
{
for(i = 0; i < ARRAY_LENGTH; i++)
{
if(!strcmp(g_file_name_fd_desc[i].name, event->name))
{
remove_from_epoll(epoll_fd, g_file_name_fd_desc[i].fd);
g_file_name_fd_desc[i].fd = 0;
memset(g_file_name_fd_desc[i].name, 0, sizeof(g_file_name_fd_desc[i].name));
memset(g_file_name_fd_desc[i].base_name, 0, sizeof(g_file_name_fd_desc[i].base_name));
printf("remove file from epoll: %s\n", event->name);
break;
}
}
}
else if (event->mask & IN_MODIFY)
{
printf("modify file to epoll: %s and will suspend, power_state: %d\n",
event->name, power_state);
if (power_state == POWER_STATE_RESUME)
power_state = POWER_STATE_SUSPENDING;
else
power_state = POWER_STATE_RESUME;
}
}
event_size = sizeof(*event) + event->len;
result -= event_size;
event_pos += event_size;
}
return 0;
}
static void *power_status_listen(void *arg)
{
int inotify_fd;
int epoll_fd;
int result;
int i;
char readbuf[EPOLL_SIZE];
int readlen;
char *tmp_name;
return NULL;
eq_info("[EQ] %s enter\n", __func__);
epoll_fd = epoll_create(1);
if(-1 == epoll_fd)
{
printf("epoll_create error!\n");
goto err;
}
inotify_fd = inotify_init();
result = inotify_add_watch(inotify_fd, base_dir, IN_MODIFY);
if(-1 == result)
{
printf("inotify_add_watch error!\n");
goto err;
}
add_to_epoll(epoll_fd, inotify_fd);
eq_info("[EQ] %s, %d add_to_epoll\n", __func__, __LINE__);
while (1)
{
result = epoll_wait(epoll_fd, g_PendingEventItems, EPOLL_MAX_EVENTS, -1);
if (-1 == result)
{
printf("epoll wait error!\n");
goto err;
}
else
{
for (i = 0; i < result; i++)
{
if (g_PendingEventItems[i].data.fd == inotify_fd)
{
if (-1 == inotify_ctl_info(inotify_fd, epoll_fd))
{
printf("inotify_ctl_info error!\n");
goto err;
}
}
else
{
if (!get_name_from_fd(g_PendingEventItems[i].data.fd, &tmp_name))
{
readlen = read(g_PendingEventItems[i].data.fd, readbuf, EPOLL_SIZE);
readbuf[readlen] = '\0';
printf("read data from %s : %s\n", tmp_name, readbuf);
}
}
}
}
}
err:
eq_info("[EQ] %s exit\n", __func__);
return NULL;
}
void alsa_fake_device_record_open(snd_pcm_t** capture_handle,int channels,uint32_t rate)
{
snd_pcm_hw_params_t *hw_params;
snd_pcm_uframes_t periodSize = g_period_size;
snd_pcm_uframes_t bufferSize = g_buffer_size;
int dir = 0;
int err;
err = snd_pcm_open(capture_handle, REC_DEVICE_NAME, SND_PCM_STREAM_CAPTURE, 0);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Unable to open capture PCM device\n");
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] snd_pcm_open\n");
//err = snd_pcm_hw_params_alloca(&hw_params);
err = snd_pcm_hw_params_malloc(&hw_params);
if(err)
{
eq_err("[EQ_RECORD_OPEN] cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] snd_pcm_hw_params_malloc\n");
err = snd_pcm_hw_params_any(*capture_handle, hw_params);
if(err)
{
eq_err("[EQ_RECORD_OPEN] cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] snd_pcm_hw_params_any!\n");
err = snd_pcm_hw_params_set_access(*capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
// err = snd_pcm_hw_params_set_access(*capture_handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Error setting interleaved mode\n");
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] snd_pcm_hw_params_set_access!\n");
err = snd_pcm_hw_params_set_format(*capture_handle, hw_params, ALSA_READ_FORMAT);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Error setting format: %s\n", snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] snd_pcm_hw_params_set_format\n");
err = snd_pcm_hw_params_set_channels(*capture_handle, hw_params, channels);
if (err)
{
eq_debug("[EQ_RECORD_OPEN] channels = %d\n",channels);
eq_err("[EQ_RECORD_OPEN] Error setting channels: %s\n", snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] channels = %d\n",channels);
err = snd_pcm_hw_params_set_buffer_size_near(*capture_handle, hw_params, &bufferSize);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Error setting buffer size (%d): %s\n", bufferSize, snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] bufferSize = %d\n",bufferSize);
err = snd_pcm_hw_params_set_period_size_near(*capture_handle, hw_params, &periodSize, 0);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Error setting period time (%d): %s\n", periodSize, snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] periodSize = %d\n",periodSize);
err = snd_pcm_hw_params_set_rate_near(*capture_handle, hw_params, &rate, 0/*&dir*/);
if (err)
{
eq_err("[EQ_RECORD_OPEN] Error setting sampling rate (%d): %s\n", rate, snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] Rate = %d\n", rate);
/* Write the parameters to the driver */
err = snd_pcm_hw_params(*capture_handle, hw_params);
if (err < 0)
{
eq_err("[EQ_RECORD_OPEN] Unable to set HW parameters: %s\n", snd_strerror(err));
exit(1);
}
eq_debug("[EQ_RECORD_OPEN] Open record device done \n");
//if(set_sw_params(*capture_handle,bufferSize,periodSize,NULL) < 0)
// exit(1);
if(hw_params)
snd_pcm_hw_params_free(hw_params);
}
int alsa_fake_device_write_open(snd_pcm_t** write_handle, int channels,
uint32_t write_sampleRate, int device_flag,
int *socket_fd)
{
snd_pcm_hw_params_t *write_params;
snd_pcm_uframes_t write_periodSize = g_period_size;
snd_pcm_uframes_t write_bufferSize = g_buffer_size;
int write_err;
int write_dir;
char bluealsa_device[256] = {0};
if (device_flag == DEVICE_FLAG_ANALOG_HP) {
eq_debug("[EQ_WRITE_OPEN] Open PCM: %s\n", JACK_DEVICE_NAME);
write_err = snd_pcm_open(write_handle, JACK_DEVICE_NAME,
SND_PCM_STREAM_PLAYBACK, 0);
} else if (device_flag == DEVICE_FLAG_DIGITAL_HP) {
eq_debug("[EQ_WRITE_OPEN] Open PCM: %s\n", JACK2_DEVICE_NAME);
write_err = snd_pcm_open(write_handle, JACK2_DEVICE_NAME,
SND_PCM_STREAM_PLAYBACK, 0);
} else if (device_flag == DEVICE_FLAG_BLUETOOTH) {
sprintf(bluealsa_device, "%s%s", "bluealsa:HCI=hci0,PROFILE=a2dp,DEV=",
g_bt_mac_addr);
eq_debug("[EQ_WRITE_OPEN] Open PCM: %s\n", bluealsa_device);
write_err = snd_pcm_open(write_handle, bluealsa_device,
SND_PCM_STREAM_PLAYBACK, 0);
} else if (device_flag == DEVICE_FLAG_BLUETOOTH_BSA) {
*socket_fd = RK_socket_client_setup(sock_path);
if (*socket_fd < 0) {
eq_err("[EQ_WRITE_OPEN] Fail to connect server socket\n");
return -1;
} else {
eq_debug("[EQ_WRITE_OPEN] Socket client connected\n");
return 0;
}
} else {
eq_debug("[EQ_WRITE_OPEN] Open PCM: %s\n", WRITE_DEVICE_NAME);
write_err = snd_pcm_open(write_handle, WRITE_DEVICE_NAME,
SND_PCM_STREAM_PLAYBACK, 0);
}
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Unable to open playback PCM device: %d\n", write_err);
return write_err;
}
eq_debug("[EQ_WRITE_OPEN] interleaved mode\n");
// snd_pcm_hw_params_alloca(&write_params);
snd_pcm_hw_params_malloc(&write_params);
eq_debug("[EQ_WRITE_OPEN] snd_pcm_hw_params_alloca\n");
snd_pcm_hw_params_any(*write_handle, write_params);
write_err = snd_pcm_hw_params_set_access(*write_handle, write_params, SND_PCM_ACCESS_RW_INTERLEAVED);
//write_err = snd_pcm_hw_params_set_access(*write_handle, write_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Error setting interleaved mode\n");
goto failed;
}
eq_debug( "[EQ_WRITE_OPEN] interleaved mode\n");
write_err = snd_pcm_hw_params_set_format(*write_handle, write_params, ALSA_WRITE_FORMAT);
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Error setting format: %s\n", snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] format successed\n");
write_err = snd_pcm_hw_params_set_channels(*write_handle, write_params, channels);
if (write_err) {
eq_err( "[EQ_WRITE_OPEN] Error setting channels: %s\n", snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] channels = %d\n", channels);
write_err = snd_pcm_hw_params_set_rate_near(*write_handle, write_params, &write_sampleRate, 0/*&write_dir*/);
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Error setting sampling rate (%d): %s\n", write_sampleRate, snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] setting sampling rate (%d)\n", write_sampleRate);
write_err = snd_pcm_hw_params_set_buffer_size_near(*write_handle, write_params, &write_bufferSize);
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Error setting buffer size (%ld): %s\n", write_bufferSize, snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] write_bufferSize = %d\n", write_bufferSize);
write_err = snd_pcm_hw_params_set_period_size_near(*write_handle, write_params, &write_periodSize, 0);
if (write_err) {
eq_err("[EQ_WRITE_OPEN] Error setting period time (%ld): %s\n", write_periodSize, snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] write_periodSize = %d\n", write_periodSize);
#if 0
snd_pcm_uframes_t write_final_buffer;
write_err = snd_pcm_hw_params_get_buffer_size(write_params, &write_final_buffer);
eq_debug(" final buffer size %ld \n" , write_final_buffer);
snd_pcm_uframes_t write_final_period;
write_err = snd_pcm_hw_params_get_period_size(write_params, &write_final_period, &write_dir);
eq_debug(" final period size %ld \n" , write_final_period);
#endif
{
int monotonic, can_pause;
monotonic = snd_pcm_hw_params_is_monotonic(write_params);
can_pause = snd_pcm_hw_params_can_pause(write_params);
eq_info("[EQ_INFO] monotonic: %d, can_pause: %d\n", monotonic, can_pause);
}
/* Write the parameters to the driver */
write_err = snd_pcm_hw_params(*write_handle, write_params);
if (write_err < 0) {
eq_err("[EQ_WRITE_OPEN] Unable to set HW parameters: %s\n", snd_strerror(write_err));
goto failed;
}
eq_debug("[EQ_WRITE_OPEN] open write device is successful\n");
if(set_sw_params(*write_handle, write_bufferSize, write_periodSize, NULL) < 0)
goto failed;
if(write_params)
snd_pcm_hw_params_free(write_params);
#if KEEPING_HW_CARD
if (device_flag == DEVICE_FLAG_LINE_OUT)
g_fast_codec = true;
#endif
return 0;
failed:
if(write_params)
snd_pcm_hw_params_free(write_params);
snd_pcm_close(*write_handle);
*write_handle = NULL;
return -1;
}
int set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t buffer_size,
snd_pcm_uframes_t period_size, char **msg) {
snd_pcm_sw_params_t *params;
snd_pcm_uframes_t threshold;
char buf[256];
int err;
//snd_pcm_sw_params_alloca(&params);
snd_pcm_sw_params_malloc(&params);
if ((err = snd_pcm_sw_params_current(pcm, params)) != 0) {
eq_err("[EQ_SET_SW_PARAMS] Get current params: %s\n", snd_strerror(err));
goto failed;
}
/* start the transfer when the buffer is full (or almost full) */
threshold = (buffer_size / period_size) * period_size;
if ((err = snd_pcm_sw_params_set_start_threshold(pcm, params, threshold)) != 0) {
eq_err("[EQ_SET_SW_PARAMS] Set start threshold: %s: %lu\n", snd_strerror(err), threshold);
goto failed;
}
/* allow the transfer when at least period_size samples can be processed */
if ((err = snd_pcm_sw_params_set_avail_min(pcm, params, period_size)) != 0) {
eq_err("[EQ_SET_SW_PARAMS] Set avail min: %s: %lu\n", snd_strerror(err), period_size);
goto failed;
}
if ((err = snd_pcm_sw_params(pcm, params)) != 0) {
eq_err("[EQ_SET_SW_PARAMS] %s\n", snd_strerror(err));
goto failed;
}
if(params)
snd_pcm_sw_params_free(params);
return 0;
failed:
if(params)
snd_pcm_sw_params_free(params);
return -1;
}
static int is_mute_frame(short *in,unsigned int size)
{
int i;
int mute_count = 0;
if (!size) {
eq_err("frame size is zero!!!\n");
return 0;
}
for (i = 0; i < size;i ++) {
if(in[i] != 0)
return 0;
}
return 1;
}
/* Determine whether to enter the energy saving mode according to
* the value of the environment variable "EQ_LOW_POWERMODE"
*/
bool low_power_mode_check()
{
char *value = NULL;
/* env: "EQ_LOW_POWERMODE=TRUE" or "EQ_LOW_POWERMODE=true" ? */
value = getenv("EQ_LOW_POWERMODE");
if (value && (!strcmp("TRUE", value) || !strcmp("true", value)))
return true;
return false;
}
/* Check device changing. */
int get_device_flag()
{
int fd = 0, ret = 0;
char buff[512] = {0};
int device_flag = DEVICE_FLAG_LINE_OUT;
#if (ROCKCHIP_SOC == SOC_IS_RK3308)
const char *path = "/sys/devices/platform/ff560000.acodec/rk3308-acodec-dev/dac_output";
#else /* else is RK3326 */
const char *path = "/sys/class/switch/h2w/state";
#endif
FILE *pp = NULL; /* pipeline */
char *bt_mac_addr = NULL;
if (g_bt_is_connect == BT_CONNECT_BLUEZ)
return DEVICE_FLAG_BLUETOOTH;
else if(g_bt_is_connect == BT_CONNECT_BSA)
return DEVICE_FLAG_BLUETOOTH_BSA;
fd = open(path, O_RDONLY);
if (fd < 0) {
eq_err("[EQ_DEVICE_FLAG] Open %s failed!\n", path);
return device_flag;
}
ret = read(fd, buff, sizeof(buff));
if (ret <= 0) {
eq_err("[EQ_DEVICE_FLAG] Read %s failed!\n", path);
close(fd);
return device_flag;
}
#if (ROCKCHIP_SOC == SOC_IS_RK3308)
if (strstr(buff, "hp out"))
device_flag = DEVICE_FLAG_ANALOG_HP;
#else /* else is RK3326 */
if (strstr(buff, "1"))
device_flag = DEVICE_FLAG_ANALOG_HP;
else if (strstr(buff, "2"))
device_flag = DEVICE_FLAG_DIGITAL_HP;
#endif
close(fd);
return device_flag;
}
/* Get device name frome device_flag */
const char *get_device_name(int device_flag)
{
const char *device_name = NULL;
switch (device_flag) {
case DEVICE_FLAG_BLUETOOTH:
case DEVICE_FLAG_BLUETOOTH_BSA:
device_name = "BLUETOOTH";
break;
case DEVICE_FLAG_ANALOG_HP:
device_name = JACK_DEVICE_NAME;
break;
case DEVICE_FLAG_DIGITAL_HP:
device_name = JACK2_DEVICE_NAME;
break;
case DEVICE_FLAG_LINE_OUT:
device_name = WRITE_DEVICE_NAME;
break;
default:
break;
}
return device_name;
}
static void user_play_inotify_handler(struct inotify_event *event)
{
// eq_info("[EQ] %s enter\n", __func__);
// eq_info("[EQ] event->mask: 0x%08x\n", event->mask);
// eq_info("[EQ] event->name: %s\n", event->name);
switch (event->mask)
{
case IN_OPEN:
user_play_state = USER_PLAY_OPENED;
eq_info("[EQ] %s USER_PLAY_OPENED\n", __func__);
break;
case IN_CLOSE_WRITE:
user_play_state = USER_PLAY_CLOSING;
eq_info("[EQ] %s USER_PLAY_CLOSING\n", __func__);
break;
default:
break;
}
}
static void user_capt_inotify_handler(struct inotify_event *event)
{
// eq_info("[EQ] %s enter\n", __func__);
// eq_info("[EQ] event->mask: 0x%08x\n", event->mask);
// eq_info("[EQ] event->name: %s\n", event->name);
switch (event->mask)
{
case IN_OPEN:
user_capt_state = USER_CAPT_OPENED;
eq_info("[EQ] %s USER_CAPT_OPENED\n", __func__);
break;
case IN_CLOSE_WRITE:
user_capt_state = USER_CAPT_CLOSING;
eq_info("[EQ] %s USER_CAPT_CLOSING\n", __func__);
break;
default:
break;
}
}
static void *user_play_status_listen(void *arg)
{
struct user_play_inotify *upi = &g_upi;
struct inotify_event *event = NULL;
FILE *fp;
char *buf;
eq_info("[EQ] %s enter\n", __func__);
buf = (char *)calloc(1024, 1);
if (!buf) {
eq_err("[EQ] %s alloc buf failed!\n", __func__);
return NULL;
}
upi->stop = 0;
upi->fd = inotify_init();
upi->watch_desc = inotify_add_watch(upi->fd, USER_PLAY_STATUS, IN_OPEN | IN_CLOSE_WRITE);
while (!upi->stop)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(upi->fd, &fds);
if (select(upi->fd + 1, &fds, NULL, NULL, NULL) > 0)
{
int len, index = 0;
while (((len = read(upi->fd, buf, 1024)) < 0) && (errno == EINTR));
while (index < len)
{
event = (struct inotify_event *)(buf + index);
user_play_inotify_handler(event);
index += sizeof(struct inotify_event) + event->len;
}
}
}
if (upi->fd >= 0) {
inotify_rm_watch(upi->fd, upi->watch_desc);
close(upi->fd);
upi->fd = -1;
}
if (buf)
free(buf);
eq_info("[EQ] %s exit\n", __func__);
return NULL;
err_out:
if (buf)
free(buf);
return NULL;
}
static void *user_capt_status_listen(void *arg)
{
struct user_capt_inotify *uci = &g_uci;
struct inotify_event *event = NULL;
FILE *fp;
char *buf;
eq_info("[EQ] %s enter\n", __func__);
buf = (char *)calloc(1024, 1);
if (!buf) {
eq_err("[EQ] %s alloc buf failed!\n", __func__);
return NULL;
}
uci->stop = 0;
uci->fd = inotify_init();
uci->watch_desc = inotify_add_watch(uci->fd, USER_CAPT_STATUS, IN_OPEN | IN_CLOSE_WRITE);
while (!uci->stop)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(uci->fd, &fds);
if (select(uci->fd + 1, &fds, NULL, NULL, NULL) > 0)
{
int len, index = 0;
while (((len = read(uci->fd, buf, 1024)) < 0) && (errno == EINTR));
while (index < len)
{
event = (struct inotify_event *)(buf + index);
user_capt_inotify_handler(event);
index += sizeof(struct inotify_event) + event->len;
}
}
}
if (uci->fd >= 0) {
inotify_rm_watch(uci->fd, uci->watch_desc);
close(uci->fd);
uci->fd = -1;
}
if (buf)
free(buf);
eq_info("[EQ] %s exit\n", __func__);
return NULL;
err_out:
if (buf)
free(buf);
return NULL;
}
void *a2dp_status_listen(void *arg)
{
int ret = 0;
char buff[100] = {0};
struct sockaddr_un clientAddr;
struct sockaddr_un serverAddr;
int sockfd;
socklen_t addr_len;
char *start = NULL;
snd_pcm_t* audio_bt_handle;
char bluealsa_device[256] = {0};
int retry_cnt = 5;
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd < 0) {
eq_err("[EQ_A2DP_LISTEN] Create socket failed!\n");
return NULL;
}
serverAddr.sun_family = AF_UNIX;
strcpy(serverAddr.sun_path, "/tmp/a2dp_master_status");
system("rm -rf /tmp/a2dp_master_status");
ret = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
if (ret < 0) {
eq_err("[EQ_A2DP_LISTEN] Bind Local addr failed!\n");
return NULL;
}
while(1) {
addr_len = sizeof(clientAddr);
memset(buff, 0, sizeof(buff));
ret = recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&clientAddr, &addr_len);
if (ret <= 0) {
eq_err("[EQ_A2DP_LISTEN]: %s\n", strerror(errno));
break;
}
eq_debug("[EQ_A2DP_LISTEN] Received a message(%s)\n", buff);
if (strstr(buff, "status:connect:bsa-source")) {
if (g_bt_is_connect == BT_DISCONNECT) {
eq_debug("[EQ_A2DP_LISTEN] bsa bluetooth source is connect\n");
g_bt_is_connect = BT_CONNECT_BSA;
}
} else if (strstr(buff, "status:connect")) {
start = strstr(buff, "address:");
if (start == NULL) {
eq_debug("[EQ_A2DP_LISTEN] Received a malformed connect message(%s)\n", buff);
continue;
}
start += strlen("address:");
if (g_bt_is_connect == BT_DISCONNECT) {
//sleep(2);
memcpy(g_bt_mac_addr, start, sizeof(g_bt_mac_addr));
sprintf(bluealsa_device, "%s%s", "bluealsa:HCI=hci0,PROFILE=a2dp,DEV=",
g_bt_mac_addr);
retry_cnt = 5;
while (retry_cnt--) {
eq_debug("[EQ_A2DP_LISTEN] try open bluealsa device(%d)\n", retry_cnt + 1);
ret = snd_pcm_open(&audio_bt_handle, bluealsa_device,
SND_PCM_STREAM_PLAYBACK, 0);
if (ret == 0) {
snd_pcm_close(audio_bt_handle);
g_bt_is_connect = BT_CONNECT_BLUEZ;
break;
}
usleep(600000); //600ms * 5 = 3s.
}
}
} else if (strstr(buff, "status:disconnect")) {
g_bt_is_connect = BT_DISCONNECT;
} else if (strstr(buff, "status:suspend")) {
g_system_sleep = true;
} else if (strstr(buff, "status:resume")) {
g_system_sleep = false;
} else {
eq_debug("[EQ_A2DP_LISTEN] Received a malformed message(%s)\n", buff);
}
}
close(sockfd);
return NULL;
}
static void sigpipe_handler(int sig)
{
eq_info("[EQ] catch the signal number: %d\n", sig);
}
static int signal_handler()
{
struct sigaction sa;
/* Install signal handler for SIGPIPE */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigpipe_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
eq_err("sigaction() failed: %s", strerror(errno));
return -1;
}
return 0;
}
#if 1
/* I/O error handler */
static int eq_drc_xrun(snd_pcm_t *handle, snd_pcm_stream_t stream)
{
snd_pcm_status_t *status;
snd_output_t *log;
int fatal_errors = 0, monotonic = 1, verbose = 1;
int res;
eq_err("[EQ] %s %d enter\n", __func__, __LINE__);
snd_output_stdio_attach(&log, stderr, 0);
snd_pcm_status_alloca(&status);
if ((res = snd_pcm_status(handle, status))<0) {
eq_err("[EQ] status error: %s\n", snd_strerror(res));
// prg_exit(EXIT_FAILURE);
}
if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
if (fatal_errors) {
eq_err("[EQ] fatal %s: %s\n",
stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun",
snd_strerror(res));
// prg_exit(EXIT_FAILURE);
}
if (monotonic) {
#ifdef HAVE_CLOCK_GETTIME
struct timespec now, diff, tstamp;
clock_gettime(CLOCK_MONOTONIC, &now);
snd_pcm_status_get_trigger_htstamp(status, &tstamp);
timermsub(&now, &tstamp, &diff);
fprintf(stderr, "%s!!! (at least %.3f ms long)\n",
stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun",
diff.tv_sec * 1000 + diff.tv_nsec / 1000000.0);
#else
fprintf(stderr, "%s !!!\n", "underrun");
#endif
} else {
struct timeval now, diff, tstamp;
gettimeofday(&now, 0);
snd_pcm_status_get_trigger_tstamp(status, &tstamp);
timersub(&now, &tstamp, &diff);
fprintf(stderr, "%s!!! (at least %.3f ms long)\n",
stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun",
diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
}
if (verbose) {
fprintf(stderr, "Status:\n");
snd_pcm_status_dump(status, log);
}
if ((res = snd_pcm_prepare(handle))<0) {
eq_err("[EQ] xrun: prepare error: %s\n", snd_strerror(res));
// prg_exit(EXIT_FAILURE);
}
goto out_xrun; /* ok, data should be accepted again */
} if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) {
if (verbose) {
fprintf(stderr, "Status(DRAINING):\n");
snd_pcm_status_dump(status, log);
}
if (stream == SND_PCM_STREAM_CAPTURE) {
fprintf(stderr, "capture stream format change? attempting recover...\n");
if ((res = snd_pcm_prepare(handle))<0) {
eq_err("[EQ] xrun(DRAINING): prepare error: %s\n", snd_strerror(res));
// prg_exit(EXIT_FAILURE);
}
goto out_xrun;
}
}
if (verbose) {
fprintf(stderr, "Status(R/W):\n");
snd_pcm_status_dump(status, log);
}
eq_err("[EQ] read/write error, state = %s\n", snd_pcm_state_name(snd_pcm_status_get_state(status)));
// prg_exit(EXIT_FAILURE);
out_xrun:
snd_output_close(log);
return 0;
}
#endif
static void usage(char *command)
{
snd_pcm_format_t k;
printf(
"Usage: %s [OPTION]...\n"
"\n"
"-h, --help help\n"
"-v --version print current version\n"
"-s, --seconds close sound card after playback is stopped seconds (default: 3s)\n"
"-p, --period-size specify the size of the frame period (default: 1920)\n"
"-n, --period-counts specify the count of the frame periods (default: 8)\n"
#if KEEPING_HW_CARD
"-P, --path-name specify the name of playback path for RK817/RK809 codec (default: SPK)\n"
#endif
,
command);
}
static long parse_long(const char *str, int *err)
{
long val;
char *endptr;
errno = 0;
val = strtol(str, &endptr, 0);
if (errno != 0 || *endptr != '\0')
*err = -1;
else
*err = 0;
return val;
}
static void get_version(char *command)
{
printf("%s: version " EQ_DRC_PROCESS_VERSION " by Rockchip\n", command);
}
int main(int argc, char *argv[])
{
int err, c;
snd_pcm_t *capture_handle, *write_handle;
char *buffer;
unsigned int sampleRate, channels;
int mute_frame_thd, mute_frame, skip_frame = 0;
/* LINE_OUT is the default output device */
int device_flag, new_flag, last_flag;
pthread_t a2dp_status_listen_thread;
pthread_t user_play_status_listen_thread;
// pthread_t user_capt_status_listen_thread;
// pthread_t power_status_listen_thread;
// struct rk_wake_lock* wake_lock;
bool low_power_mode = low_power_mode_check();
volatile bool need_close_card = false;
char *silence_data;
int socket_fd = -1;
clock_t startProcTime, endProcTime;
int mute_time = MUTE_TIME_DEFAULT;
int option_index;
static char *command = argv[0];
static const char short_options[] = "hvs:p:n:P:";
static const struct option long_options[] = {
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
{"seconds", 1, 0, 's'},
{"period-size", 1, 0, 'p'},
{"period-counts", 1, 0, 'n'},
#if KEEPING_HW_CARD
{"path-name", 1, 0, 'P'},
#endif
{0, 0, 0, 0}
};
#if KEEPING_HW_CARD
memset(g_path_name, 0, sizeof(g_path_name));
strcpy(g_path_name, HW_CARD_PATH_DEFAULT);
#endif
while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
switch (c) {
case 'h':
usage(command);
return 0;
case 'v':
get_version(command);
return 0;
case 's':
mute_time = parse_long(optarg, &err);
if (err < 0) {
eq_err("[EQ] invalid mute_time argument '%s'\n", optarg);
return -1;
}
break;
case 'p':
g_period_size = parse_long(optarg, &err);
if (err < 0) {
eq_err("[EQ] invalid g_period_size argument '%s'\n", optarg);
return -1;
}
g_read_frame = g_period_size;
break;
case 'n':
g_period_counts = parse_long(optarg, &err);
if (err < 0) {
eq_err("[EQ] invalid g_period_counts argument '%s'\n", optarg);
return -1;
}
break;
#if KEEPING_HW_CARD
case 'P':
memset(g_path_name, 0, sizeof(g_path_name));
strcpy(g_path_name, optarg);
break;
#endif
default:
eq_err("[EQ] Try `%s --help' for more information.\n", command);
return 1;
}
}
if (g_period_size == 0 || g_period_counts == 0) {
eq_err("[EQ] g_period_size:%d or g_period_size:%d is zero!\n",
g_period_size, g_period_counts);
return -1;
}
g_buffer_size = g_period_size * g_period_counts;
buffer = (char *)malloc(g_read_frame * g_period_counts * CHANNEL * sizeof(int16_t));
if (!buffer) {
eq_err("[EQ] Alloc buffer failed\n");
return -1;
}
silence_data = (char *)malloc(g_read_frame * sizeof(int16_t) * CHANNEL); /* 2ch 16bit */
if (!silence_data) {
eq_err("[EQ] Alloc silence_data failed\n");
return -1;
}
// wake_lock = RK_wake_lock_new("eq_drc_process");
if(signal_handler() < 0) {
eq_err("[EQ] Install signal_handler for SIGPIPE failed\n");
return -1;
}
/* Create a thread to listen for Bluetooth connection status. */
// pthread_create(&power_status_listen_thread, NULL, power_status_listen, NULL);
pthread_create(&user_play_status_listen_thread, NULL, user_play_status_listen, NULL);
// pthread_create(&user_capt_status_listen_thread, NULL, user_capt_status_listen, NULL);
pthread_create(&a2dp_status_listen_thread, NULL, a2dp_status_listen, NULL);
repeat:
capture_handle = NULL;
write_handle = NULL;
err = 0;
memset(buffer, 0, sizeof(buffer));
memset((char *)silence_data, 0, sizeof(silence_data));
sampleRate = SAMPLE_RATE;
channels = CHANNEL;
mute_frame_thd = (int)(SAMPLE_RATE * mute_time / g_read_frame);
mute_frame = 0;
/* LINE_OUT is the default output device */
device_flag = DEVICE_FLAG_LINE_OUT;
new_flag = DEVICE_FLAG_LINE_OUT;
last_flag = DEVICE_FLAG_LINE_OUT;
eq_debug("\n==========EQ/DRC process release version %s==============\n", EQ_DRC_PROCESS_VERSION);
eq_debug("==========KEEPING_HW_CARD: %d===============\n", KEEPING_HW_CARD);
eq_debug("===== g_read_frame:%d g_period_size:%d g_period_counts:%d g_buffer_size:%d =====\n",
g_read_frame, g_period_size, g_period_counts, g_buffer_size);
#if KEEPING_HW_CARD
eq_debug("===== g_path_name: %s =====\n", g_path_name);
#endif
alsa_fake_device_record_open(&capture_handle, channels, sampleRate);
#if KEEPING_HW_CARD
if (write_handle_bak != NULL) {
snd_pcm_close(write_handle_bak);
eq_info("[EQ] resume process and release last write_handle_bak: 0x%x\n", write_handle_bak);
write_handle_bak = NULL;
} else {
eq_info("[EQ] run process first\n");
}
#endif
device_flag = get_device_flag();
err = alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag, &socket_fd);
if (err < 0) {
eq_err("LINE: %d, first open playback device failed, and repeat\n", __LINE__);
// return -1;
goto repeat;
} else {
eq_info("LINE: %d, open write_handle: 0x%x\n", __LINE__, write_handle);
}
#if KEEPING_HW_CARD
/* Avoid start with plugged phones and crashed during close sound card. */
if (device_flag == DEVICE_FLAG_LINE_OUT)
write_handle_bak = write_handle;
eq_info("[EQ] line: %d init write_handle: 0x%x | 0x%x, device_flag: %d | %d\n",
__LINE__, write_handle, write_handle_bak, device_flag, last_flag);
#endif
// RK_acquire_wake_lock(wake_lock);
while (1) {
// startProcTime = clock();
err = snd_pcm_readi(capture_handle, buffer, g_read_frame);
// endProcTime = clock();
// printf("snd_pcm_readi cost_time: %ld us\n", endProcTime - startProcTime);
if (err != g_read_frame) {
if (err == -ESTRPIPE) {
eq_err("====[EQ] LINE: %d system suspend and resumed\n", __LINE__);
} else {
eq_err("====[EQ] LINE: %d read frame error = %d, not %d\n", __LINE__, err, g_read_frame);
}
}
if (err < 0) {
if (err == -EPIPE)
eq_err("[EQ] Overrun occurred: %d\n", err);
err = snd_pcm_recover(capture_handle, err, 0);
// Still an error, need to exit.
if (err < 0) {
eq_err("[EQ] Error occured while recording: %s, goto repeat\n", snd_strerror(err));
// usleep(200 * 1000);
if (capture_handle)
snd_pcm_close(capture_handle);
goto repeat;
}
}
if (g_system_sleep)
mute_frame = mute_frame_thd;
else if(low_power_mode && is_mute_frame((short *)buffer, channels * g_read_frame))
mute_frame ++;
else
mute_frame = 0;
if (device_flag == DEVICE_FLAG_BLUETOOTH_BSA) {
if ((g_bt_is_connect == BT_DISCONNECT) && (socket_fd >= 0)) {
eq_debug("[EQ] bsa bt source disconnect, teardown client socket\n");
RK_socket_client_teardown(socket_fd);
socket_fd = -1;
}
}
// eq_info("[EQ] user_play_state=%d\n", user_play_state);
if(mute_frame >= mute_frame_thd) {
// eq_info("[EQ] g_system_sleep=%d, power_state=%d\n", g_system_sleep, power_state);
//usleep(30*1000);
/* Reassign to avoid overflow */
// memset(buffer, 0, sizeof(buffer));
mute_frame = mute_frame_thd;
if (write_handle) {
#if 1 // fade-out
int64_t start = 0;
int fade_type = FADE_OUT;
int nb_samples = g_read_frame * g_period_counts;
int buf_bytes = g_read_frame * channels * sizeof(short) * g_period_counts;
short *fade_buf, *src_buf;
int curve_type = IQSIN;
fade_buf = (short *)calloc(buf_bytes, 1);
if (!fade_buf) {
eq_err("[EQ] alloc fade_buf failed\n");
return -1;
}
src_buf = (short *)calloc(buf_bytes, 1);
if (!src_buf) {
eq_err("[EQ] alloc src_buf failed\n");
return -1;
}
memcpy((void *)(src_buf), (void *)(buffer), buf_bytes);
eq_info("[EQ] USER_PLAY_CLOSED and fade out\n");
fade_samples_s16((uint8_t **)(&fade_buf), (uint8_t **)(&src_buf),
nb_samples, channels,
fade_type ? -1 : 1, start,
nb_samples, curve_type);
memcpy((void *)(buffer), (void *)(fade_buf), buf_bytes);
if (src_buf)
free(src_buf);
if (fade_buf)
free(fade_buf);
#endif
#if KEEPING_HW_CARD
if (device_flag == DEVICE_FLAG_LINE_OUT) {
system("amixer sset 'Playback Path' OFF");
eq_info("[EQ] disable Playback path and PA\n");
write_handle = NULL;
} else {
snd_pcm_close(write_handle);
eq_info("[EQ]: %d Close sound card\n", __LINE__);
write_handle = NULL;
}
#else
snd_pcm_close(write_handle);
write_handle = NULL;
#endif
// RK_release_wake_lock(wake_lock);
if (power_state == POWER_STATE_SUSPENDING) {
eq_err("[EQ] suspend and close write handle for you right now!\n");
power_state = POWER_STATE_SUSPEND;
} else {
eq_err("[EQ] %d second no playback, close write handle for you now!\n ", mute_time);
}
user_play_state = USER_PLAY_CLOSED;
}
#if KEEPING_HW_CARD
// if (write_handle == NULL) {
// snd_pcm_forward(write_handle_bak, g_read_frame);
// eq_info("[EQ] forward %d frames\n", g_read_frame);
// }
#endif
continue;
}
last_flag = device_flag;
new_flag = get_device_flag();
if (new_flag != device_flag) {
eq_debug("\n[EQ] Device route changed, from\"%s\" to \"%s\"\n\n",
get_device_name(device_flag), get_device_name(new_flag));
device_flag = new_flag;
#if KEEPING_HW_CARD
if (device_flag == DEVICE_FLAG_LINE_OUT) {
if (g_fast_codec == true &&
last_flag == DEVICE_FLAG_LINE_OUT &&
last_flag == device_flag) {
eq_info("[EQ]: %d Do nothing, write_handle: 0x%x | 0x%x\n",
__LINE__, device_flag, write_handle, write_handle_bak);
} else {
eq_info("[EQ]: %d Close card LINE_OUT from %d, write_handle: 0x%x | 0x%x, g_fast_codec:%d\n",
__LINE__, last_flag, write_handle, write_handle_bak, g_fast_codec);
if (write_handle) {
snd_pcm_close(write_handle);
eq_info("[EQ]: %d Close sound card\n", __LINE__);
write_handle = NULL;
write_handle_bak = NULL;
g_fast_codec = false;
}
}
} else {
eq_info("[EQ]: %d Close card, %d, write_handle: 0x%x | 0x%x, g_fast_codec:%d\n",
__LINE__, device_flag, write_handle, write_handle_bak, g_fast_codec);
if (write_handle == write_handle_bak) {
if (write_handle) {
snd_pcm_close(write_handle);
eq_info("[EQ]: %d Close sound card\n", __LINE__);
write_handle = NULL;
write_handle_bak = NULL;
g_fast_codec = false;
}
} else {
if (write_handle_bak) {
snd_pcm_close(write_handle_bak);
eq_info("[EQ]: %d Close write_handle_bak card\n", __LINE__);
write_handle_bak = NULL;
}
if (write_handle) {
snd_pcm_close(write_handle);
eq_info("[EQ]: %d Close write_handle card\n", __LINE__);
write_handle = NULL;
}
g_fast_codec = false;
}
}
#else
if (write_handle) {
snd_pcm_close(write_handle);
write_handle = NULL;
}
#endif
}
// eq_info("[EQ] device_flag: %d, %s, write_handle: 0x%x\n",
// device_flag, get_device_name(device_flag), write_handle);
while (write_handle == NULL && socket_fd < 0) {
// RK_acquire_wake_lock(wake_lock);
eq_info("[EQ] device_flag: %d, %s, write_handle: 0x%x, socket_fd: %d\n",
device_flag, get_device_name(device_flag), write_handle, socket_fd);
#if KEEPING_HW_CARD
if (device_flag == DEVICE_FLAG_LINE_OUT) {
if (g_fast_codec == true &&
last_flag == DEVICE_FLAG_LINE_OUT &&
write_handle_bak > 0) {
char cmd_str[64] = { 0 };
write_handle = write_handle_bak;
sprintf(cmd_str, "amixer sset 'Playback Path' %s", g_path_name);
system(cmd_str);
eq_info("[EQ] enable Playback path and PA, write_handle: 0x%x\n", write_handle);
// snd_pcm_forward(write_handle, g_read_frame);
// continue;
} else {
eq_info("EQ]: %d if switch device_flag: %d | %d and open start, write_handle: 0x%x | 0x%x g_fast_codec: %d\n",
__LINE__, device_flag, last_flag, write_handle, write_handle_bak, g_fast_codec);
err = alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag, &socket_fd);
if (err < 0 || (write_handle == NULL && socket_fd < 0)) {
eq_err("[EQ] line:%d Route change failed! Using default audio path.\n", __LINE__);
// last_flag = DEVICE_FLAG_LINE_OUT;
g_bt_is_connect = BT_DISCONNECT;
continue;
} else {
eq_info("LINE: %d, open write_handle: 0x%x\n", __LINE__, write_handle);
}
write_handle_bak = write_handle;
}
} else {
static int overflow = 0;
eq_info("EQ]: %d else switch device_flag: %d | %d and open start, write_handle: 0x%x | 0x%x g_fast_codec: %d\n",
__LINE__, device_flag, last_flag, write_handle, write_handle_bak, g_fast_codec);
// if (write_handle_bak) {
// snd_pcm_close(write_handle_bak);
// write_handle_bak = NULL;
// g_fast_codec = false;
// eq_info("EQ]: %d close g_fast_codec\n", __LINE__);
// }
err = alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag, &socket_fd);
if (err < 0 || (write_handle == NULL && socket_fd < 0)) {
eq_err("[EQ] line:%d Route change failed!\n", __LINE__);
// device_flag = DEVICE_FLAG_LINE_OUT;
if (device_flag == DEVICE_FLAG_DIGITAL_HP) {
/* Maybe need to more prepare some time for digital headphone */
usleep(200 * 1000);
if (overflow++ >= 12) {
/* about 3s */
eq_err("[EQ] line:%d Using default audio path: %d, overflow: %d\n",
__LINE__, DEVICE_FLAG_LINE_OUT, overflow);
last_flag = DEVICE_FLAG_DIGITAL_HP;
device_flag = DEVICE_FLAG_LINE_OUT;
overflow = 0;
}
// need_close_card = true;
} else {
eq_err("[EQ] line:%d device_flag will: %d to %d\n",
__LINE__, last_flag, DEVICE_FLAG_LINE_OUT);
if (device_flag == DEVICE_FLAG_BLUETOOTH ||
device_flag == DEVICE_FLAG_BLUETOOTH_BSA) {
g_bt_is_connect = BT_DISCONNECT;
}
last_flag = device_flag;
device_flag = DEVICE_FLAG_LINE_OUT;
}
// else if (device_flag == DEVICE_FLAG_ANALOG_HP) {
// last_flag = DEVICE_FLAG_ANALOG_HP;
// device_flag = DEVICE_FLAG_LINE_OUT;
// need_close_card = true;
// }
// g_bt_is_connect = BT_DISCONNECT;
continue;
} else {
eq_err("[EQ] line:%d Clean overflow:%d, write_handle: 0x%x\n", __LINE__, overflow, write_handle);
overflow = 0;
}
if (write_handle_bak) {
snd_pcm_close(write_handle_bak);
write_handle_bak = NULL;
g_fast_codec = false;
eq_info("EQ]: %d close g_fast_codec\n", __LINE__);
}
}
#else
err = alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag, &socket_fd);
if (err < 0 || (write_handle == NULL && socket_fd < 0)) {
eq_err("[EQ] Route change failed! Using default audio path.\n");
device_flag = DEVICE_FLAG_LINE_OUT;
g_bt_is_connect = BT_DISCONNECT;
}
#endif
skip_frame = 0;
// memset(buffer, 0xff, sizeof(buffer));
// if (capture_handle)
// snd_pcm_close(capture_handle);
// alsa_fake_device_record_open(&capture_handle, channels, sampleRate);
if (0 && low_power_mode) {
int i, num = 4;
eq_debug("[EQ] feed mute data %d frame\n", num);
for (i = 0; i < num; i++) {
if(write_handle != NULL) {
err = snd_pcm_writei(write_handle, silence_data, g_read_frame);
if(err != g_read_frame)
eq_err("====[EQ] %d, write frame error = %d, not %d\n", __LINE__, err, g_read_frame);
} else if (socket_fd >= 0) {
err = RK_socket_send(socket_fd, silence_data, g_read_frame * 4); //2ch 16bit
if(err != (g_read_frame * 4))
eq_err("====[EQ] %d, write frame error = %d, not %d\n", __LINE__, err, g_read_frame * 4);
}
}
}
}
if(write_handle != NULL) {
#if 0
if (skip_frame > 0) {
int err;
err = snd_pcm_writei(write_handle, silence_data, g_read_frame);
if(err != g_read_frame)
eq_err("====[EQ] %d, write frame error = %d, not %d\n", __LINE__, err, g_read_frame);
eq_err("skip_frame = %d\n", skip_frame);
skip_frame--;
continue;
}
#endif
//usleep(30*1000);
err = snd_pcm_writei(write_handle, buffer, g_read_frame);
if(err != g_read_frame) {
eq_err("====[EQ] %d, write frame error = %d, not %d\n", __LINE__, err, g_read_frame);
// if (err > 0) {
// snd_pcm_sframes_t frames = g_read_frame - err;
// startProcTime = clock();
// frames = snd_pcm_forward(write_handle, frames);
// endProcTime = clock();
// printf("snd_pcm_forward cost_time: %ld us\n", endProcTime - startProcTime);
// eq_err("[EQ] snd_pcm_forward frames: %d\n", frames);
// }
}
if (err < 0) {
if (err == -EPIPE) {
eq_err("[EQ] Underrun occurred from write: %d\n", err);
#if 1
err = snd_pcm_recover(write_handle, err, 0);
if (err < 0) {
eq_err( "[EQ] Error occured while writing: %s\n", snd_strerror(err));
// usleep(200 * 1000);
#if KEEPING_HW_CARD
/* Do nothing */
#else
if (write_handle) {
snd_pcm_close(write_handle);
write_handle = NULL;
}
#endif
if (device_flag == DEVICE_FLAG_BLUETOOTH)
g_bt_is_connect = BT_DISCONNECT;
}
#else
eq_drc_xrun(write_handle, SND_PCM_STREAM_PLAYBACK);
#endif
}
#if KEEPING_HW_CARD
else if (err == -EBADFD) {
int err;
eq_err("====[EQ] %d, EBADFD and re-open sound, device_flag: %d write_handle: 0x%x | 0x%x\n",
__LINE__, device_flag, write_handle, write_handle_bak);
if (write_handle) {
snd_pcm_close(write_handle);
write_handle = NULL;
write_handle_bak = NULL;
g_fast_codec = false;
}
err = alsa_fake_device_write_open(&write_handle, channels, sampleRate, device_flag, &socket_fd);
if (err < 0) {
// eq_err("LINE: %d, open playback device failed, exit eq\n", __LINE__);
eq_err("LINE: %d, open playback device failed, continue\n", __LINE__);
// write_handle_bak = write_handle;
// return -1;
continue;
} else {
eq_info("LINE: %d, open write_handle: 0x%x\n", __LINE__, write_handle);
}
write_handle_bak = write_handle;
}
#endif
}
}else if (socket_fd >= 0) {
if (g_bt_is_connect == BT_CONNECT_BSA) {
err = RK_socket_send(socket_fd, (char *)buffer, g_read_frame * 4);
if (err != g_read_frame * 4 && -EAGAIN != err)
eq_err("====[EQ] %d, write frame error = %d, not %d\n", __LINE__, err, g_read_frame * 4);
if (err < 0 && -EAGAIN != err) {
if (socket_fd >= 0) {
eq_err("[EQ] socket send err: %d, teardown client socket\n", err);
RK_socket_client_teardown(socket_fd);
socket_fd = -1;
}
g_bt_is_connect = BT_DISCONNECT;
}
} else {
if(socket_fd >= 0){
eq_debug("[EQ] bsa bt source disconnect, teardown client socket\n");
RK_socket_client_teardown(socket_fd);
socket_fd = -1;
}
}
}
}
error:
eq_debug("=== [EQ] Exit eq ===\n");
if (silence_data) {
free(silence_data);
silence_data = NULL;
}
if (buffer) {
free(buffer);
buffer = NULL;
}
g_upi.stop = 1;
if (capture_handle)
snd_pcm_close(capture_handle);
if (write_handle)
snd_pcm_close(write_handle);
if (socket_fd >= 0)
RK_socket_client_teardown(socket_fd);
pthread_cancel(a2dp_status_listen_thread);
pthread_join(a2dp_status_listen_thread, NULL);
return 0;
}