summaryrefslogtreecommitdiffstats
path: root/plugins/alsa
diff options
context:
space:
mode:
authorThierry Bultel <thierry.bultel@iot.bzh>2018-06-22 17:11:38 +0200
committerThierry Bultel <thierry.bultel@iot.bzh>2018-06-22 17:17:17 +0200
commitb124cc00e9714ac20fdf96f480fc7f08e06a2150 (patch)
tree9ef21b4aafe0164f7e9e1df078f73cda8e221f13 /plugins/alsa
parentaa13829d133356cd5dabbfacc6127ae9368233fc (diff)
pcm core: fixed spurious XRUN issues
This fixes the numerous XRUN issues seen on some cards. The trick is to set the buffer_size & period size in hw parameters. These ones are calculated from an expected maximum latency. Also, the writei is done in a loop to be robust to overruns and partial writes. Signed-off-by: Thierry Bultel <thierry.bultel@iot.bzh>
Diffstat (limited to 'plugins/alsa')
-rw-r--r--plugins/alsa/alsa-core-pcm.c328
-rw-r--r--plugins/alsa/alsa-softmixer.h24
2 files changed, 257 insertions, 95 deletions
diff --git a/plugins/alsa/alsa-core-pcm.c b/plugins/alsa/alsa-core-pcm.c
index aed5f22..7cec020 100644
--- a/plugins/alsa/alsa-core-pcm.c
+++ b/plugins/alsa/alsa-core-pcm.c
@@ -29,6 +29,9 @@ for the specific language governing permissions and
#include <sys/syscall.h>
#include <sched.h>
+static int xrun(snd_pcm_t * pcm);
+static int suspend(snd_pcm_t * pcm);
+
STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
int pcmSampleSize;
@@ -60,29 +63,46 @@ STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
return pcmSampleSize;
}
-PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts) {
+PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts, int mode) {
int error;
snd_pcm_hw_params_t *pxmHwParams;
snd_pcm_sw_params_t *pxmSwParams;
snd_pcm_format_t format;
snd_pcm_access_t access;
+ AFB_ApiInfo(mixer->api,
+ "%s: mixer info %s uid %s , pcm %s, mode %d",
+ __func__, mixer->info, mixer->uid, pcm->cid.cardid, mode);
+
// retrieve hardware config from PCM
snd_pcm_hw_params_alloca(&pxmHwParams);
- snd_pcm_hw_params_any(pcm->handle, pxmHwParams);
+ error = snd_pcm_hw_params_any(pcm->handle, pxmHwParams);
+ if (error < 0) {
+ AFB_ApiError(mixer->api, "%s: Failed to get parameters: %s", __func__, snd_strerror(error));
+ goto OnErrorExit;
+ }
+
+ AFB_ApiNotice(mixer->api, "PARAMS before:\n");
+ AlsaDumpPcmParams(mixer, pxmHwParams);
+
+ if (!opts->access)
+ opts->access = SND_PCM_ACCESS_RW_INTERLEAVED;
- if (!opts->access) opts->access = SND_PCM_ACCESS_RW_INTERLEAVED;
snd_pcm_hw_params_get_access(pxmHwParams, &access);
error = snd_pcm_hw_params_set_access(pcm->handle, pxmHwParams, opts->access);
if (error) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Set_Interleave=%d Fail current=%d mode error=%s", mixer->uid, pcm->cid.cardid, opts->access, access, snd_strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s set_access failed (ignore this error): mixer=%s cardid=%s access=%d Fail current=%d mode error=%s",
+ __func__, mixer->uid, pcm->cid.cardid, opts->access, access, snd_strerror(error));
//Fulup goto OnErrorExit;
};
if (opts->format != SND_PCM_FORMAT_UNKNOWN) {
snd_pcm_hw_params_get_format(pxmHwParams, &format);
if ((error = snd_pcm_hw_params_set_format(pcm->handle, pxmHwParams, opts->format)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Set_Format=%d Fail current=%d error=%s", mixer->uid, pcm->cid.cardid, opts->format, format, snd_strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s Set_Format=%s (%d) FAILED current=%d error=%s",
+ __func__, mixer->uid, pcm->cid.cardid, opts->formatS, opts->format, format, snd_strerror(error));
AlsaDumpFormats(mixer, pcm->handle);
goto OnErrorExit;
}
@@ -102,8 +122,6 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts
}
}
-
-
if (opts->channels) {
if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, opts->channels)) < 0) {
AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Set_Channels=%d Fail error=%s",mixer->uid, pcm->cid.cardid, opts->channels, snd_strerror(error));
@@ -111,19 +129,55 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts
};
}
+ int err;
+ unsigned buffer_time = 0;
+ unsigned period_time = 0;
+ snd_pcm_uframes_t buffer_frames = 0;
+ snd_pcm_uframes_t period_frames = 0;
+
+ err = snd_pcm_hw_params_get_buffer_time_max(pxmHwParams, &buffer_time, 0);
+ if (buffer_time > 500000)
+ buffer_time = 500000;
+
+ if (period_time == 0 && period_frames == 0) {
+ if (buffer_time > 0)
+ period_time = buffer_time / 4;
+ else
+ period_frames = buffer_frames / 4;
+ }
+ if (period_time > 0)
+ err = snd_pcm_hw_params_set_period_time_near(pcm->handle, pxmHwParams, &period_time, 0);
+ else
+ err = snd_pcm_hw_params_set_period_size_near(pcm->handle, pxmHwParams, &period_frames, 0);
+
+ assert(err >= 0);
+
+ if (buffer_time > 0) {
+ err = snd_pcm_hw_params_set_buffer_time_near(pcm->handle, pxmHwParams, &buffer_time, 0);
+ } else {
+ err = snd_pcm_hw_params_set_buffer_size_near(pcm->handle, pxmHwParams, &buffer_frames);
+ }
+
+ assert(err >= 0);
+
// store selected values
if ((error = snd_pcm_hw_params(pcm->handle, pxmHwParams)) < 0) {
AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Fail apply hwparams error=%s", mixer->uid, pcm->cid.cardid, snd_strerror(error));
goto OnErrorExit;
}
+ AFB_ApiNotice(mixer->api, "PARAMS after:\n");
+ AlsaDumpPcmParams(mixer, pxmHwParams);
+
// check we effective hw params after optional format change
snd_pcm_hw_params_get_channels(pxmHwParams, &opts->channels);
snd_pcm_hw_params_get_format(pxmHwParams, &opts->format);
snd_pcm_hw_params_get_rate(pxmHwParams, &opts->rate, 0);
opts->sampleSize = AlsaPeriodSize(opts->format);
if (opts->sampleSize == 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Fail unsupported format format=%d", mixer->uid, pcm->cid.cardid, opts->format);
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s Fail unsupported format format=%d",
+ __func__, mixer->uid, pcm->cid.cardid, opts->format);
goto OnErrorExit;
}
@@ -131,14 +185,16 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts
snd_pcm_sw_params_alloca(&pxmSwParams);
snd_pcm_sw_params_current(pcm->handle, pxmSwParams);
- if ((error = snd_pcm_sw_params_set_avail_min(pcm->handle, pxmSwParams, 16)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Fail set_buffersize error=%s", mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ if ((error = snd_pcm_sw_params_set_avail_min(pcm->handle, pxmSwParams, 1024)) < 0) {
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s Fail set_buffersize error=%s",
+ __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
goto OnErrorExit;
};
// push software params into PCM
if ((error = snd_pcm_sw_params(pcm->handle, pxmSwParams)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Fail to push params error=%s", mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Fail to push SW params error=%s", mixer->uid, pcm->cid.cardid, snd_strerror(error));
goto OnErrorExit;
};
@@ -149,16 +205,17 @@ OnErrorExit:
return -1;
}
-
STATIC int AlsaPcmReadCB(sd_event_source* src, int fd, uint32_t revents, void* userData) {
char string[32];
- int error;
- snd_pcm_sframes_t framesIn, framesOut, availIn, availOut;
+
+ snd_pcm_sframes_t framesIn, framesOut, availIn, availOut, readIn;
AlsaPcmCopyHandleT *pcmCopyHandle = (AlsaPcmCopyHandleT*) userData;
// PCM has was closed
if ((revents & EPOLLHUP) != 0) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s hanghup/disconnected", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
+ AFB_ApiNotice(pcmCopyHandle->api,
+ "%s PCM=%s hanghup/disconnected",
+ __func__, ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
goto ExitOnSuccess;
}
@@ -167,75 +224,85 @@ STATIC int AlsaPcmReadCB(sd_event_source* src, int fd, uint32_t revents, void* u
goto ExitOnSuccess;
}
- // retrieve PCM state
- snd_pcm_state_t pcmState = snd_pcm_state(pcmCopyHandle->pcmIn);
-
- // When pause flush remaining frame and wait
- if (pcmState == SND_PCM_STATE_PAUSED) {
- framesIn = snd_pcm_readi(pcmCopyHandle->pcmIn, pcmCopyHandle->buffer, pcmCopyHandle->frameCount);
- AFB_ApiInfo(pcmCopyHandle->api, "AlsaPcmReadCB: paused frame:%ld ignored", framesIn);
- goto ExitOnSuccess;
- }
-
- // When XRNS append try to restore PCM
- if (pcmState == SND_PCM_STATE_XRUN) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s XRUN", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
- snd_pcm_prepare(pcmCopyHandle->pcmIn);
- }
-
- // when PCM suspending loop until ready to go
- if (pcmState == SND_PCM_STATE_SUSPENDED) {
- while (1) {
- if ((error = snd_pcm_resume(pcmCopyHandle->pcmIn)) < 0) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED fail to resume", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
- sleep(1); // Fulup should be replace with corresponding AFB_timer
- } else {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED success to resume", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
- }
- }
- }
-
// do we have waiting frame
availIn = snd_pcm_avail_update(pcmCopyHandle->pcmIn);
if (availIn <= 0) {
+ if (availIn == -EPIPE) {
+ xrun(pcmCopyHandle->pcmIn);
+ }
goto ExitOnSuccess;
}
// do we have space to push frame
availOut = snd_pcm_avail_update(pcmCopyHandle->pcmOut);
- if (availOut <= 0) {
- snd_pcm_prepare(pcmCopyHandle->pcmOut);
- goto ExitOnSuccess;
+ if (availOut < 0) {
+ if (availOut == -EPIPE) {
+ xrun(pcmCopyHandle->pcmOut);
+ goto ExitOnSuccess;
+ }
+ if (availOut == -ESTRPIPE) {
+ suspend(pcmCopyHandle->pcmOut);
+ goto ExitOnSuccess;
+ }
}
+ if (availOut == 0)
+ goto ExitOnSuccess;
+
+ readIn = availIn;
+
// make sure we can push all input frame into output pcm without locking
- if (availOut < availIn) availIn = availOut;
+ if (readIn > availOut)
+ readIn = availOut;
// we get too many data ignore some
- if (availIn > pcmCopyHandle->frameCount) {
- availIn = pcmCopyHandle->frameCount;
+ if (readIn > pcmCopyHandle->buf_size) {
+ readIn = pcmCopyHandle->buf_size;
}
// effectively read pcmIn and push frame to pcmOut
- framesIn = snd_pcm_readi(pcmCopyHandle->pcmIn, pcmCopyHandle->buffer, availIn);
- if (framesIn < 0 || framesIn != availIn) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmIn=%s UNDERUN framesIn=%ld, availIn %ld, max %d",
- ALSA_PCM_UID(pcmCopyHandle->pcmIn, string), framesIn, availIn, pcmCopyHandle->frameCount);
- snd_pcm_prepare(pcmCopyHandle->pcmIn);
+ framesIn = snd_pcm_readi(pcmCopyHandle->pcmIn, pcmCopyHandle->buf, readIn);
+ if (framesIn < 0 || framesIn != readIn) {
+ AFB_ApiNotice(pcmCopyHandle->api,
+ "%s PcmIn=%s READ UNDERUN framesIn=%ld, availIn %ld, max %ld, err %s",
+ __func__, ALSA_PCM_UID(pcmCopyHandle->pcmIn, string), framesIn, readIn, pcmCopyHandle->buf_count, snd_strerror((int)framesIn));
+ xrun(pcmCopyHandle->pcmIn);
goto ExitOnSuccess;
}
- // In/Out frames transfer through buffer copy
- framesOut = snd_pcm_writei(pcmCopyHandle->pcmOut, pcmCopyHandle->buffer, framesIn);
- //framesOut = snd_pcm_mmap_writei (pcmCopyHandle->pcmOut, pcmCopyHandle->buffer, framesIn);
- if (framesOut < 0 || framesOut != framesIn) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmOut=%s UNDERUN frame=%ld=>%ld error=%s", ALSA_PCM_UID(pcmCopyHandle->pcmOut, string), framesOut ,framesIn, snd_strerror((int)framesOut));
- snd_pcm_prepare(pcmCopyHandle->pcmOut);
- goto ExitOnSuccess;
+ unsigned long count = framesIn;
+ char * data = pcmCopyHandle->buf;
+
+ while (count > 0) {
+ // In/Out frames transfer through buffer copy
+
+ framesOut = snd_pcm_writei(pcmCopyHandle->pcmOut, data, count);
+
+ if (framesOut == -EAGAIN) {
+ printf("Write EAGAIN\n");
+ snd_pcm_wait(pcmCopyHandle->pcmOut, 100);
+ goto ExitOnSuccess;
+ }
+ if (framesOut == -EPIPE) {
+ xrun(pcmCopyHandle->pcmOut);
+ goto ExitOnSuccess;
+ }
+ if (framesOut == -ESTRPIPE) {
+ suspend(pcmCopyHandle->pcmOut);
+ goto ExitOnSuccess;
+ }
+ if (framesOut < 0 ) {
+ printf("UNKNOWN ERROR\n");
+ goto ExitOnSuccess;
+ }
+ count -= framesOut;
+ data += framesOut * pcmCopyHandle->frame_size;
}
if (framesIn != framesOut) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s Loosing frames=%ld", ALSA_PCM_UID(pcmCopyHandle->pcmOut, string), (framesIn - framesOut));
+ AFB_ApiNotice(pcmCopyHandle->api,
+ "%s PCM=%s Loosing frames=%ld",
+ __func__, ALSA_PCM_UID(pcmCopyHandle->pcmOut, string), (framesIn - framesOut));
goto ExitOnSuccess;
}
@@ -246,30 +313,72 @@ ExitOnSuccess:
return 0;
}
+
+static int xrun( snd_pcm_t * pcm)
+{
+ int err;
+
+ printf("xrun !\n");
+
+ if ((err = snd_pcm_prepare(pcm)) < 0) {
+ printf("xrun: prepare failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int suspend( snd_pcm_t * pcm)
+{
+ int err;
+
+ printf("suspend !\n");
+
+ while ((err = snd_pcm_resume(pcm)) == -EAGAIN) {
+ printf("%s: again\n", __func__);
+ usleep(1);
+ }
+ if (err < 0)
+ return xrun(pcm);
+ return 0;
+}
+
+
static void *LoopInThread(void *handle) {
AlsaPcmCopyHandleT *pcmCopyHandle = (AlsaPcmCopyHandleT*) handle;
int count = 0;
int watchdog = MAINLOOP_WATCHDOG * 1000;
pcmCopyHandle->tid = (int) syscall(SYS_gettid);
- AFB_ApiNotice(pcmCopyHandle->api, "LoopInThread:%s/%d Started", pcmCopyHandle->info, pcmCopyHandle->tid);
-
+ AFB_ApiNotice(pcmCopyHandle->api,
+ "%s :%s/%d Started",
+ __func__, pcmCopyHandle->info, pcmCopyHandle->tid);
/* loop until end */
for (;;) {
int res = sd_event_run(pcmCopyHandle->sdLoop, watchdog);
if (res == 0) {
- AFB_ApiInfo(pcmCopyHandle->api, "LoopInThread:%s/%d Idle count=%d", pcmCopyHandle->info, pcmCopyHandle->tid, count++);
+ AFB_ApiInfo(pcmCopyHandle->api,
+ "%s:%s/%d Idle count=%d",
+ __func__, pcmCopyHandle->info, pcmCopyHandle->tid, count++);
continue;
}
if (res < 0) {
- AFB_ApiError(pcmCopyHandle->api, "LoopInThread:%s/%d ERROR=%i Exit errno=%s.\n", pcmCopyHandle->info, pcmCopyHandle->tid, res, strerror(res));
+ AFB_ApiError(pcmCopyHandle->api,
+ "%s:%s/%d ERROR=%i Exit errno=%s.\n",
+ __func__, pcmCopyHandle->info, pcmCopyHandle->tid, res, strerror(res));
break;
}
}
pthread_exit(0);
}
+static inline snd_pcm_uframes_t time_to_frames(unsigned int rate,
+ unsigned long long time)
+{
+ return (time * rate) / 1000000ULL;
+}
+
PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts) {
char string[32];
struct pollfd *pcmInFds;
@@ -277,69 +386,113 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
// Fulup need to check https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___direct.html
- //AlsaDumpPcmInfo(mixer,"PcmIn",pcmIn->handle);
- //AlsaDumpPcmInfo(mixer,"PcmOut",pcmOut->handle);
+ AlsaDumpPcmInfo(mixer,"PcmIn",pcmIn->handle);
+ AlsaDumpPcmInfo(mixer,"PcmOut",pcmOut->handle);
+
+ AFB_ApiInfo(mixer->api, "%s: Configure CAPTURE PCM", __func__);
// prepare PCM for capture and replay
- error = AlsaPcmConf(mixer, pcmIn, opts);
- if (error) goto OnErrorExit;
+ error = AlsaPcmConf(mixer, pcmIn, opts, SND_PCM_STREAM_CAPTURE);
+ if (error) {
+ AFB_ApiError(mixer->api, "%s: PCM configuration for capture failed", __func__);
+ goto OnErrorExit;
+ }
+ AFB_ApiInfo(mixer->api, "%s: Configure PLAYBACK PCM", __func__);
+
// input and output should match
- error = AlsaPcmConf(mixer, pcmOut, opts);
- if (error) goto OnErrorExit;
+ error = AlsaPcmConf(mixer, pcmOut, opts, SND_PCM_STREAM_PLAYBACK);
+ if (error) {
+ AFB_ApiError(mixer->api, "%s: PCM configuration for playback failed", __func__);
+ goto OnErrorExit;
+ }
// Prepare PCM for usage
if ((error = snd_pcm_prepare(pcmOut->handle)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail to prepare PCM=%s error=%s", ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
+ AFB_ApiError(mixer->api, "%s: Fail to prepare PLAYBACK PCM=%s error=%s", __func__, ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
goto OnErrorExit;
};
// Prepare PCM for usage
+ if ((error = snd_pcm_prepare(pcmIn->handle)) < 0) {
+ AFB_ApiError(mixer->api, "%s: Fail to prepare CAPTURE PCM=%s error=%s", __func__, ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
+ goto OnErrorExit;
+ };
+
+ // Start PCM
+ if ((error = snd_pcm_start(pcmOut->handle)) < 0) {
+ AFB_ApiError(mixer->api, "%s: Fail to start PLAYBACK PCM=%s error=%s", __func__, ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
+ goto OnErrorExit;
+ };
+
+ // Start PCM
if ((error = snd_pcm_start(pcmIn->handle)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail to prepare PCM=%s error=%s", ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
+ AFB_ApiError(mixer->api, "%s: Fail to start CAPTURE PCM=%s error=%s", __func__, ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
goto OnErrorExit;
};
AlsaPcmCopyHandleT *cHandle= calloc(1, sizeof(AlsaPcmCopyHandleT));
- cHandle = cHandle;
+
cHandle->info = "pcmCpy";
cHandle->pcmIn = pcmIn->handle;
cHandle->pcmOut = pcmOut->handle;
cHandle->api = mixer->api;
cHandle->channels = opts->channels;
- cHandle->frameSize = opts->channels * opts->sampleSize;
- cHandle->frameCount = ALSA_BUFFER_FRAMES_COUNT;
- cHandle->buffer = malloc(cHandle->frameCount * cHandle->frameSize);
+
+ cHandle->latency_reqtime = 10000;
+ cHandle->latency = time_to_frames(opts->rate, cHandle->latency_reqtime);
+ AFB_ApiInfo(mixer->api, "%s: Latency = %ld", __func__, cHandle->latency);
+
+ cHandle->frame_size = (snd_pcm_format_physical_width(opts->format) / 8) * opts->channels;
+
+ AFB_ApiInfo(mixer->api, "%s: Frame size is %zu", __func__, cHandle->frame_size);
+
+ size_t size = cHandle->latency * 2;
+ cHandle->buf = calloc(1, size*cHandle->frame_size);
+ cHandle->buf_count = 0;
+ cHandle->buf_size = size;
+ AFB_ApiInfo(mixer->api, "%s Copy buf size is %zu", __func__, size);
+
// get FD poll descriptor for capture PCM
int pcmInCount = snd_pcm_poll_descriptors_count(cHandle->pcmIn);
if (pcmInCount <= 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail pcmIn=%s get fds count error=%s", ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s: Fail pcmIn=%s get fds count error=%s",
+ __func__, ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
goto OnErrorExit;
};
pcmInFds = alloca(sizeof (*pcmInFds) * pcmInCount);
if ((error = snd_pcm_poll_descriptors(pcmIn->handle, pcmInFds, pcmInCount)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail pcmIn=%s get pollfds error=%s", ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s: Fail pcmIn=%s get pollfds error=%s",
+ __func__, ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
goto OnErrorExit;
};
// add poll descriptor to AGL systemd mainloop
if ((error = sd_event_new(&cHandle->sdLoop)) < 0) {
- fprintf(stderr, "LaunchCallRequest: fail pcmin=%s creating a new loop: %s\n", ALSA_PCM_UID(pcmOut->handle, string), strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s: fail pcmin=%s creating a new loop: %s\n",
+ __func__, ALSA_PCM_UID(pcmOut->handle, string), strerror(error));
goto OnErrorExit;
}
for (int idx = 0; idx < pcmInCount; idx++) {
if ((error = sd_event_add_io(cHandle->sdLoop, &cHandle->evtsrc, pcmInFds[idx].fd, EPOLLIN, AlsaPcmReadCB, cHandle)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail pcmIn=%s sd_event_add_io err=%d", ALSA_PCM_UID(pcmIn->handle, string), error);
+ AFB_ApiError(mixer->api,
+ "%s: Fail pcmIn=%s sd_event_add_io err=%d",
+ __func__, ALSA_PCM_UID(pcmIn->handle, string), error);
goto OnErrorExit;
}
}
// start a thread with a mainloop to monitor Audio-Agent
if ((error = pthread_create(&cHandle->thread, NULL, &LoopInThread, cHandle)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmCopy: Fail create waiting thread pcmIn=%s err=%d", ALSA_PCM_UID(pcmIn->handle, string), error);
+ AFB_ApiError(mixer->api,
+ "%s Fail create waiting thread pcmIn=%s err=%d",
+ __func__, ALSA_PCM_UID(pcmIn->handle, string), error);
goto OnErrorExit;
}
@@ -348,14 +501,15 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
error= pthread_setschedparam(cHandle->thread, SCHED_FIFO, &params);
if (error) {
- AFB_ApiWarning(mixer->api, "AlsaPcmCopy: Fail create increase stream thread priority pcmIn=%s err=%s", ALSA_PCM_UID(pcmIn->handle, string), strerror(error));
+ AFB_ApiWarning(mixer->api,
+ "%s: Failed to increase stream thread priority pcmIn=%s err=%s",
+ __func__, ALSA_PCM_UID(pcmIn->handle, string), strerror(error));
}
-
return 0;
OnErrorExit:
- AFB_ApiError(mixer->api, "AlsaPcmCopy: - pcmIn=%s" , ALSA_PCM_UID(pcmIn->handle, string));
- AFB_ApiError(mixer->api, "AlsaPcmCopy: - pcmOut=%s", ALSA_PCM_UID(pcmOut->handle, string));
+ AFB_ApiError(mixer->api, "%s: - pcmIn=%s" , __func__, ALSA_PCM_UID(pcmIn->handle, string));
+ AFB_ApiError(mixer->api, "%s: - pcmOut=%s", __func__, ALSA_PCM_UID(pcmOut->handle, string));
return -1;
}
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index f435b3f..6c1519d 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <assert.h>
#include <alsa/asoundlib.h>
+#include <stdbool.h>
#include "ctl-plugin.h"
#include "wrap-json.h"
@@ -44,7 +45,7 @@
#define MAINLOOP_WATCHDOG 30000
#define ALSA_DEFAULT_PCM_RATE 48000
#define ALSA_DEFAULT_PCM_VOLUME 80
-#define ALSA_BUFFER_FRAMES_COUNT 1024
+
#define ALSA_CARDID_MAX_LEN 64
@@ -82,14 +83,22 @@ typedef struct {
snd_pcm_t *pcmOut;
AFB_ApiT api;
sd_event_source* evtsrc;
- void* buffer;
- size_t frameSize;
- unsigned int frameCount;
+
+ size_t frame_size;
+ snd_pcm_uframes_t latency; /* final latency in frames */
+ unsigned int latency_reqtime; /* in us */
+
+ // IO Job
+ void * buf;
+ snd_pcm_uframes_t buf_count; /* filled samples */
+ snd_pcm_uframes_t buf_size; /* buffer size in frames */
+
unsigned int channels;
sd_event *sdLoop;
pthread_t thread;
int tid;
char* info;
+
} AlsaPcmCopyHandleT;
typedef struct {
@@ -137,6 +146,7 @@ typedef struct {
AlsaDevInfoT cid;
snd_pcm_t *handle;
AlsaPcmHwInfoT *params;
+ uint32_t avail_min;
} AlsaPcmCtlT;
typedef struct {
@@ -258,12 +268,10 @@ PUBLIC int AlsaCtlSubscribe(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *snd
PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT *pcmdev, RegistryNumidT type, int numid);
// alsa-core-pcm.c
-PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts);
+PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts, int mode);
PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
-
// alsa-plug-*.c _snd_pcm_PLUGIN_open_ see macro ALSA_PLUG_PROTO(plugin)
-PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts);
PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *streamAudio, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
PUBLIC AlsaPcmCtlT* AlsaCreateSoftvol(SoftMixerT *mixer, AlsaStreamAudioT *stream, char *slaveid, AlsaSndCtlT *sndcard, char* ctlName, int max, int open);
PUBLIC AlsaPcmCtlT* AlsaCreateRoute(SoftMixerT *mixer, AlsaSndZoneT *zone, int open);
@@ -290,4 +298,4 @@ PUBLIC int ApiZoneAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, j
PUBLIC AlsaVolRampT *ApiRampGetByUid(SoftMixerT *mixer, const char *uid);
PUBLIC int AlsaVolRampApply(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaStreamAudioT *stream, json_object *rampJ);
-#endif \ No newline at end of file
+#endif