SmartAudio/package/allwinner/peq/demo/tsound_ctrl.c

466 lines
14 KiB
C
Executable File

#define LOG_TAG "tsoundcontrol"
//#include "tlog.h"
#include "tsound_ctrl.h"
#include <pthread.h>
#include <sys/time.h>
#include <assert.h>
//#include "auGaincom.h"
#define c600
#if 0
#define TLOGD(fmt, arg...) printf("line<%d>, func<%s> : "fmt"\n", __LINE__, __func__, ##arg)
#define TLOGE(fmt, arg...) printf("error line<%d>, func<%s> : "fmt"\n", __LINE__, __func__, ##arg)
#else
#define TLOGD(fmt, arg...)
#define TLOGE(fmt, arg...)
#endif
#define TP_CHECK
int BLOCK_MODE = 0;
int NON_BLOCK_MODE = 1;
static int openSoundDevice(SoundCtrlContext* sc,int mode);
static int closeSoundDevice(SoundCtrlContext* sc);
static int setSoundDeviceParams(SoundCtrlContext* sc);
static int openSoundDevice(SoundCtrlContext* sc ,int mode)
{
int ret = 0;
TLOGD("openSoundDevice() in dmix style");
TP_CHECK(sc);
if(!sc->alsa_handler){
//if((ret = snd_pcm_open(&sc->alsa_handler, "default",SND_PCM_STREAM_PLAYBACK ,mode))<0){
//if use dimix func,use the below parms open the sound card
#if !defined(c600)
if((ret = snd_pcm_open(&sc->alsa_handler, "plug:dmix",SND_PCM_STREAM_PLAYBACK ,mode))<0)
#else
if((ret = snd_pcm_open(&sc->alsa_handler, "default",SND_PCM_STREAM_PLAYBACK ,mode))<0)
#endif
{
TLOGE("open audio device failed:%s, errno = %d",strerror(errno),errno);
/*
if(errno == 16){//the device is busy,sleep 2 second and try again.notice:this will not happen when open in dmix mode
sleep(2);
if((ret = snd_pcm_open(&sc->alsa_handler, "default",SND_PCM_STREAM_PLAYBACK ,mode))<0){
TLOGE("second open audio device failed:%s, errno = %d",strerror(errno),errno);
}
}
*/
}
}else{
TLOGD("the audio device has been opened");
}
return ret;
}
static int closeSoundDevice(SoundCtrlContext* sc)
{
int ret = 0;
TLOGD("closeSoundDevice()");
TP_CHECK(sc);
if (sc->alsa_handler){
if ((ret = snd_pcm_close(sc->alsa_handler)) < 0)
{
TLOGE("snd_pcm_close failed:%s",strerror(errno));
}
else
{
sc->alsa_handler = NULL;
TLOGE("alsa-uninit: pcm closed");
}
}
return ret;
}
static int setSoundDeviceParams(SoundCtrlContext* sc)
{
int ret = 0;
TLOGD("setSoundDeviceParams()");
TP_CHECK(sc);
sc->bytes_per_sample = sc->nChannelNum*snd_pcm_format_physical_width(sc->alsa_format) / 8;
sc->alsa_fragcount = 8;//cache count
sc->chunk_size = 1024;//each cache size,unit : sample
if ((ret = snd_pcm_hw_params_malloc(&sc->alsa_hwparams)) < 0)
{
TLOGE("snd_pcm_hw_params_malloc failed:%s",strerror(errno));
return ret;
}
if ((ret = snd_pcm_hw_params_any(sc->alsa_handler, sc->alsa_hwparams)) < 0)
{
TLOGE("snd_pcm_hw_params_any failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
if ((ret = snd_pcm_hw_params_set_access(sc->alsa_handler, sc->alsa_hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
TLOGE("snd_pcm_hw_params_set_access failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
if ((ret = snd_pcm_hw_params_test_format(sc->alsa_handler, sc->alsa_hwparams,
sc->alsa_format)) < 0)
{
TLOGE("snd_pcm_hw_params_test_format fail , MSGTR_AO_ALSA_FormatNotSupportedByHardware");
sc->alsa_format = SND_PCM_FORMAT_S16_LE;
}
if ((ret = snd_pcm_hw_params_set_format(sc->alsa_handler, sc->alsa_hwparams,
sc->alsa_format)) < 0)
{
TLOGE("snd_pcm_hw_params_set_format failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
if ((ret = snd_pcm_hw_params_set_channels_near(sc->alsa_handler,
sc->alsa_hwparams, &sc->nChannelNum)) < 0) {
TLOGE("snd_pcm_hw_params_set_channels_near failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
if ((ret = snd_pcm_hw_params_set_rate_near(sc->alsa_handler, sc->alsa_hwparams,
&sc->nSampleRate, NULL)) < 0) {
TLOGE("snd_pcm_hw_params_set_rate_near failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
if ((ret = snd_pcm_hw_params_set_period_size_near(sc->alsa_handler,
sc->alsa_hwparams, &sc->chunk_size, NULL)) < 0) {
TLOGE("snd_pcm_hw_params_set_period_size_near fail , MSGTR_AO_ALSA_UnableToSetPeriodSize");
goto SET_PAR_ERR;
} else {
TLOGD("alsa-init: chunksize set to %ld", sc->chunk_size);
}
if ((ret = snd_pcm_hw_params_set_periods_near(sc->alsa_handler,
sc->alsa_hwparams, (unsigned int*)&sc->alsa_fragcount, NULL)) < 0)
{
TLOGE("snd_pcm_hw_params_set_periods_near fail , MSGTR_AO_ALSA_UnableToSetPeriods");
goto SET_PAR_ERR;
} else {
TLOGD("alsa-init: fragcount=%d", sc->alsa_fragcount);
}
if ((ret = snd_pcm_hw_params(sc->alsa_handler, sc->alsa_hwparams)) < 0) {
TLOGE("snd_pcm_hw_params failed:%s",strerror(errno));
goto SET_PAR_ERR;
}
sc->alsa_can_pause = snd_pcm_hw_params_can_pause(sc->alsa_hwparams);
TLOGD("setSoundDeviceParams():sc->alsa_can_pause = %d",sc->alsa_can_pause);
SET_PAR_ERR:
snd_pcm_hw_params_free(sc->alsa_hwparams);
return ret;
}
void* TSoundDeviceCreate(AudioFrameCallback callback,void* pUser, int rat, int ch){
SoundCtrlContext* s;
s = (SoundCtrlContext*)malloc(sizeof(SoundCtrlContext));
TLOGD("TinaSoundDeviceInit()");
if(s == NULL)
{
TLOGE("malloc SoundCtrlContext fail.");
return NULL;
}
memset(s, 0, sizeof(SoundCtrlContext));
//s->base.ops = &mSoundControlOps;
s->alsa_access_type = SND_PCM_ACCESS_RW_INTERLEAVED;
s->nSampleRate = rat;
s->nChannelNum = ch;
s->alsa_format = SND_PCM_FORMAT_S16_LE;
s->alsa_can_pause = 0;
s->sound_status = STATUS_STOP;
s->mVolume = 0;
s->mAudioframeCallback = callback;
s->pUserData = pUser;
pthread_mutex_init(&s->mutex, NULL);
openSoundDevice(s, BLOCK_MODE);
return (void*)&s->base;
}
void TSoundDeviceDestroy(void* s){
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
pthread_mutex_lock(&sc->mutex);
TLOGD("TinaSoundDeviceRelease(),close sound device");
closeSoundDevice(sc);
pthread_mutex_unlock(&sc->mutex);
pthread_mutex_destroy(&sc->mutex);
free(sc);
sc = NULL;
}
#if 0
void TSoundDeviceSetFormat(void* s, CdxPlaybkCfg* cfg){
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
pthread_mutex_lock(&sc->mutex);
TLOGD("TinaSoundDeviceSetFormat(),sc->sound_status == %d",sc->sound_status);
if(sc->sound_status == STATUS_STOP){
TLOGD("TinaSoundDeviceSetFormat()");
sc->nSampleRate = cfg->nSamplerate;
sc->nChannelNum = cfg->nChannels;
sc->alsa_format = SND_PCM_FORMAT_S16_LE;
sc->bytes_per_sample = sc->nChannelNum*snd_pcm_format_physical_width(sc->alsa_format) / 8;
TLOGD("TinaSoundDeviceSetFormat()>>>sample_rate:%d,channel_num:%d,sc->bytes_per_sample:%d",
cfg->nSamplerate,cfg->nChannels,sc->bytes_per_sample);
}
pthread_mutex_unlock(&sc->mutex);
}
#endif
int TSoundDeviceStart(void* s){
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
pthread_mutex_lock(&sc->mutex);
int ret = 0;
TLOGD("TinaSoundDeviceStart(): sc->sound_status = %d",sc->sound_status);
if(sc->sound_status == STATUS_START){
TLOGD("Sound device already start.");
pthread_mutex_unlock(&sc->mutex);
return ret;
}else if(sc->sound_status == STATUS_PAUSE){
if(snd_pcm_state(sc->alsa_handler) == SND_PCM_STATE_SUSPENDED){
TLOGD("MSGTR_AO_ALSA_PcmInSuspendModeTryingResume");
while((ret = snd_pcm_resume(sc->alsa_handler)) == -EAGAIN){
sleep(1);
}
}
if(sc->alsa_can_pause){
if((ret = snd_pcm_pause(sc->alsa_handler, 0))<0){
TLOGE("snd_pcm_pause failed:%s",strerror(errno));
pthread_mutex_unlock(&sc->mutex);
return ret;
}
}else{
if ((ret = snd_pcm_prepare(sc->alsa_handler)) < 0)
{
TLOGE("snd_pcm_prepare failed:%s",strerror(errno));
pthread_mutex_unlock(&sc->mutex);
return ret;
}
}
sc->sound_status = STATUS_START;
}
else if(sc->sound_status == STATUS_STOP){
ret = setSoundDeviceParams(sc);
if(ret < 0){
TLOGE("setSoundDeviceParams fail , ret = %d",ret);
pthread_mutex_unlock(&sc->mutex);
return ret;
}
sc->sound_status = STATUS_START;
}
pthread_mutex_unlock(&sc->mutex);
return ret;
}
int TSoundDeviceStop(void* s){
int ret = 0;
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
pthread_mutex_lock(&sc->mutex);
TLOGD("TinaSoundDeviceStop():sc->sound_status = %d",sc->sound_status);
if(sc->sound_status == STATUS_STOP)
{
TLOGD("Sound device already stopped.");
pthread_mutex_unlock(&sc->mutex);
return ret;
}else{
if ((ret = snd_pcm_drop(sc->alsa_handler)) < 0)
{
TLOGE("snd_pcm_drop():MSGTR_AO_ALSA_PcmPrepareError");
pthread_mutex_unlock(&sc->mutex);
return ret;
}
if ((ret = snd_pcm_prepare(sc->alsa_handler)) < 0)
{
TLOGE("snd_pcm_prepare():MSGTR_AO_ALSA_PcmPrepareError");
pthread_mutex_unlock(&sc->mutex);
return ret;
}
sc->sound_status = STATUS_STOP;
}
pthread_mutex_unlock(&sc->mutex);
return ret;
}
int TSoundDevicePause(void* s){
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
pthread_mutex_lock(&sc->mutex);
int ret = 0;
TLOGD("TinaSoundDevicePause(): sc->sound_status = %d",sc->sound_status);
if(sc->sound_status == STATUS_START){
if(sc->alsa_can_pause){
TLOGD("alsa can pause,use snd_pcm_pause");
ret = snd_pcm_pause(sc->alsa_handler, 1);
if(ret<0){
TLOGE("snd_pcm_pause failed:%s",strerror(errno));
pthread_mutex_unlock(&sc->mutex);
return ret;
}
}else{
TLOGD("alsa can not pause,use snd_pcm_drop");
if ((ret = snd_pcm_drop(sc->alsa_handler)) < 0)
{
TLOGE("snd_pcm_drop failed:%s",strerror(errno));
pthread_mutex_unlock(&sc->mutex);
return ret;
}
}
sc->sound_status = STATUS_PAUSE;
}else{
TLOGD("TinaSoundDevicePause(): pause in an invalid status,status = %d",sc->sound_status);
}
pthread_mutex_unlock(&sc->mutex);
return ret;
}
int TSoundDeviceWrite(void* s, void* pData, int nDataSize){
int ret = 0;
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
//TLOGD("TinaSoundDeviceWrite:sc->bytes_per_sample = %d\n",sc->bytes_per_sample);
if(sc->bytes_per_sample == 0){
sc->bytes_per_sample = 4;
}
if(sc->sound_status == STATUS_STOP || sc->sound_status == STATUS_PAUSE)
{
return ret;
}
//TLOGD("TinaSoundDeviceWrite>>> pData = %p , nDataSize = %d\n",pData,nDataSize);
int num_frames = nDataSize / sc->bytes_per_sample;
snd_pcm_sframes_t res = 0;
if (!sc->alsa_handler)
{
TLOGE("MSGTR_AO_ALSA_DeviceConfigurationError");
return ret;
}
if (num_frames == 0){
TLOGE("num_frames == 0");
return ret;
}
//store the pcm data and callback to tplayer
SoundPcmData pcmData;
memset(&pcmData, 0x00, sizeof(SoundPcmData));
pcmData.pData = pData;
pcmData.nSize = nDataSize;
pcmData.samplerate = sc->nSampleRate;
pcmData.channels = sc->nChannelNum;
pcmData.accuracy = 16;
if (sc->mAudioframeCallback)
{
sc->mAudioframeCallback(sc->pUserData,&pcmData);
}
#if !defined(c600)
//adjust the pcm data
AudioGain audioGain;
audioGain.preamp = sc->mVolume;
audioGain.InputChan = (int)sc->nChannelNum;
audioGain.OutputChan = (int)sc->nChannelNum;
audioGain.InputLen = nDataSize;
audioGain.InputPtr = (short*)pData;
audioGain.OutputPtr = (short*)pData;
int gainRet = tina_do_AudioGain(&audioGain);
if(gainRet == 0){
TLOGE("tina_do_AudioGain fail");
}
#endif
do {
//TLOGD("snd_pcm_writei begin,nDataSize = %d",nDataSize);
res = snd_pcm_writei(sc->alsa_handler, pData, num_frames);
//TLOGD("snd_pcm_writei finish,res = %ld",res);
if (res == -EINTR)
{
/* nothing to do */
res = 0;
} else if (res == -ESTRPIPE)
{ /* suspend */
TLOGD("MSGTR_AO_ALSA_PcmInSuspendModeTryingResume");
while ((res = snd_pcm_resume(sc->alsa_handler)) == -EAGAIN)
sleep(1);
}
if (res < 0)
{
TLOGE("MSGTR_AO_ALSA_WriteError,res = %ld",res);
if ((res = snd_pcm_prepare(sc->alsa_handler)) < 0)
{
TLOGE("MSGTR_AO_ALSA_PcmPrepareError");
return res;
}
}
} while (res == 0);
return res < 0 ? res : res * sc->bytes_per_sample;
}
int TSoundDeviceReset(void* s){
TLOGD("TinaSoundDeviceReset()");
TP_CHECK(s);
return TSoundDeviceStop(s);
}
int TSoundDeviceGetCachedTime(void* s){
int ret = 0;
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
TP_CHECK(sc);
//TLOGD("TinaSoundDeviceGetCachedTime()");
if (sc->alsa_handler)
{
snd_pcm_sframes_t delay = 0;
//notify:snd_pcm_delay means the cache has how much data(the cache has been filled with pcm data),
//snd_pcm_avail_update means the free cache,
if ((ret = snd_pcm_delay(sc->alsa_handler, &delay)) < 0){
TLOGE("TinaSoundDeviceGetCachedTime(),ret = %d , delay = %ld",ret,delay);
return 0;
}
//TLOGD("TinaSoundDeviceGetCachedTime(),snd_pcm_delay>>> delay = %d",delay);
//delay = snd_pcm_avail_update(sc->alsa_handler);
//TLOGD("TinaSoundDeviceGetCachedTime(), snd_pcm_avail_update >>> delay = %d\n",delay);
if (delay < 0) {
/* underrun - move the application pointer forward to catch up */
#if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
snd_pcm_forward(sc->alsa_handler, -delay);
#endif
delay = 0;
}
//TLOGD("TinaSoundDeviceGetCachedTime(),ret = %d , delay = %ld",ret,delay);
ret = ((int)((float) delay * 1000000 / (float) sc->nSampleRate));
}
return ret;
}
int TSoundDeviceGetFrameCount(void* s){
//to do
TP_CHECK(s);
return 0;
}
#if 0
int TSoundDeviceSetPlaybackRate(void* s,const XAudioPlaybackRate *rate){
//to do
TP_CHECK(s);
return 0;
}
#endif
int TSoundDeviceSetVolume(void* s,int volume){
SoundCtrlContext* sc;
sc = (SoundCtrlContext*)s;
if(sc){
sc->mVolume = volume;
return 0;
}else{
return -1;
}
}