summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-core-pcm.c
diff options
context:
space:
mode:
authorThierry Bultel <thierry.bultel@iot.bzh>2018-12-04 23:11:20 +0100
committerThierry Bultel <thierry.bultel@iot.bzh>2018-12-19 23:09:21 +0100
commite0f57e523112e1bc73a04e8615d7a21355f0ce0e (patch)
tree19198c38d7433862cee733fde3efca8170228279 /plugins/alsa/alsa-core-pcm.c
parent7df040a3742af8d800852dd39f8e921cd82a4cf2 (diff)
Add support for bluetooth telephonyguppy_6.99.3guppy/6.99.36.99.3
This adds support for bluetooth telephony. A big rework in the softmixer internals has been mandatory, in order to support dynamic streams creation and deletions. Bluetooth telephony relies on the recent evolutions of bluez-alsa, the most important one being the support of HFP over Ofono. The softmixer opens PCM ioplugs provided by bluez-alsa. Bluetooth SCO needs 2 streams, one for listening and the other for talking. These streams are created upon requests sent by the hal-manager. The hal manager subscribes for bluez-alsa events and request the list of availalble transports. For each "attach" transaction verb, the softmixer maintains a list of the all created objects (sources, sinks, zones, ramps, streams, and more) Additionnally, it creates a new verb when the attach succeeds, that verb is typically something like "sco_XX:XX:XX:XX:XX:XX", and the only supported action at the present time is {"action":"remove"}, that performs all the cleanup of the registered objects. Change-Id: I1b119e6c079e60daf771e63c083a1ef33a39f379 Signed-off-by: Thierry Bultel <thierry.bultel@iot.bzh>
Diffstat (limited to 'plugins/alsa/alsa-core-pcm.c')
-rw-r--r--plugins/alsa/alsa-core-pcm.c307
1 files changed, 192 insertions, 115 deletions
diff --git a/plugins/alsa/alsa-core-pcm.c b/plugins/alsa/alsa-core-pcm.c
index 25872ae..adceebc 100644
--- a/plugins/alsa/alsa-core-pcm.c
+++ b/plugins/alsa/alsa-core-pcm.c
@@ -34,6 +34,16 @@ for the specific language governing permissions and
static int xrun(snd_pcm_t * pcm, int error);
static int suspend(snd_pcm_t * pcm, int error);
+typedef enum {
+ PCM_COPY_MUTE,
+ PCM_COPY_UNMUTE,
+ PCM_COPY_END,
+ PCM_COPY_LAST // Do not put anything after
+} PcmCopyEventType;
+
+typedef struct {
+ PcmCopyEventType eventType;
+} PcmCopyEvent;
STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
int pcmSampleSize;
@@ -81,12 +91,13 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
snd_pcm_access_t access;
AlsaPcmHwInfoT * opts = pcm->params;
+ const char * card = pcm->cid.cardid;
const char * modeS = mode==SND_PCM_STREAM_PLAYBACK?"PLAYBACK":"CAPTURE";
- AFB_ApiInfo(mixer->api,
- "%s: mixer info %s uid %s , pcm %s, mode %s",
- __func__, mixer->info, mixer->uid, pcm->cid.cardid, modeS);
+ AFB_ApiDebug(mixer->api,
+ "%s: mixer info %s uid %s, pcm %s, mode %s",
+ __func__, mixer->info, mixer->uid, card, modeS);
// retrieve hardware config from PCM
snd_pcm_hw_params_alloca(&pxmHwParams);
@@ -96,7 +107,7 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
goto OnErrorExit;
}
- AFB_ApiDebug(mixer->api, "PARAMS before:\n");
+ AFB_ApiDebug(mixer->api, "(%s): PARAMS before:", card);
AlsaDumpPcmParams(mixer, pxmHwParams);
if (!opts->access)
@@ -106,8 +117,8 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
error = snd_pcm_hw_params_set_access(pcm->handle, pxmHwParams, opts->access);
if (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));
+ "%s (%s) set_access failed (ignore this error): mixer=%s access=%d Fail current=%d mode error=%s",
+ __func__, card, mixer->uid, opts->access, access, snd_strerror(error));
//Fulup goto OnErrorExit;
};
@@ -115,8 +126,8 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
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,
- "%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));
+ "%s (%s) mixer=%s Set_Format=%s (%d) FAILED current=%d error=%s",
+ __func__, card, mixer->uid, opts->formatS, opts->format, format, snd_strerror(error));
AlsaDumpFormats(mixer, pcm->handle);
goto OnErrorExit;
}
@@ -124,22 +135,22 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
if (opts->rate > 0 ) {
- AFB_ApiInfo(mixer->api," %s: set rate to %d", __func__, opts->rate);
+ AFB_ApiDebug(mixer->api,"%s (%s): set rate to %d", __func__, card, opts->rate);
unsigned int pcmRate = opts->rate;
/* Attempt to set the rate. Failing on a capture dev is acceptable */
error = snd_pcm_hw_params_set_rate_near(pcm->handle, pxmHwParams, &opts->rate, 0);
if ( mode == SND_PCM_STREAM_PLAYBACK && error < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s FailSet_Rate=%d error=%s",
- __func__, mixer->uid, pcm->cid.cardid, opts->rate, snd_strerror(error));
+ "%s (%s): mixer=%s FailSet_Rate=%d error=%s",
+ __func__, card, mixer->uid, opts->rate, snd_strerror(error));
goto OnErrorExit;
}
// check we got requested rate
if (mode == SND_PCM_STREAM_PLAYBACK && opts->rate != pcmRate) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Set_Rate Fail ask=%dHz get=%dHz",
- __func__, mixer->uid, pcm->cid.cardid,pcmRate, opts->rate);
+ "%s (%s): mixer=%s Set_Rate Fail ask=%dHz get=%dHz",
+ __func__, card, mixer->uid, pcmRate, opts->rate);
goto OnErrorExit;
}
}
@@ -147,8 +158,8 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
if (opts->channels) {
if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, opts->channels)) < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Set_Channels=%d Fail error=%s",
- __func__, mixer->uid, pcm->cid.cardid, opts->channels, snd_strerror(error));
+ "%s (%s): mixer=%s Set_Channels=%d Fail error=%s",
+ __func__, card, mixer->uid, opts->channels, snd_strerror(error));
goto OnErrorExit;
};
}
@@ -165,7 +176,7 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
error = snd_pcm_hw_params_get_buffer_time_max(pxmHwParams, &buffer_time, 0);
- AFB_ApiInfo(mixer->api, "HW_BUFFER_TIME MAX is %d\n", buffer_time);
+ AFB_ApiDebug(mixer->api, "(%s) HW_BUFFER_TIME MAX is %d", card, buffer_time);
if (buffer_time > 500000)
buffer_time = 500000;
@@ -178,45 +189,45 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
}
if (period_time > 0) {
- AFB_ApiInfo(mixer->api, "SET PERIOD TIME to %d", period_time);
+ AFB_ApiDebug(mixer->api, "(%s) SET PERIOD TIME to %d", card, period_time);
error = snd_pcm_hw_params_set_period_time_near(pcm->handle, pxmHwParams, &period_time, 0);
}
else {
- AFB_ApiInfo(mixer->api, "SET PERIOD SIZE...");
+ AFB_ApiDebug(mixer->api, "(%s) SET PERIOD SIZE...", card);
error = snd_pcm_hw_params_set_period_size_near(pcm->handle, pxmHwParams, &period_frames, 0);
}
if (error < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail to set period in hwparams error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s Fail to set period in hwparams error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
}
if (buffer_time > 0) {
- AFB_ApiInfo(mixer->api, "SET BUFFER TIME to %d", buffer_time);
+ AFB_ApiDebug(mixer->api, "(%s) SET BUFFER TIME to %d", card, buffer_time);
error = snd_pcm_hw_params_set_buffer_time_near(pcm->handle, pxmHwParams, &buffer_time, 0);
} else {
- AFB_ApiInfo(mixer->api, "SET BUFFER SIZE...");
+ AFB_ApiDebug(mixer->api, "(%s) SET BUFFER SIZE to %ld...", card, buffer_frames);
error = snd_pcm_hw_params_set_buffer_size_near(pcm->handle, pxmHwParams, &buffer_frames);
}
if (error < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail to set buffer in hwparams error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s Fail to set buffer in hwparams error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
}
// store selected values
if ((error = snd_pcm_hw_params(pcm->handle, pxmHwParams)) < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail to apply hwparams error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s Fail to apply hwparams error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
}
- AFB_ApiDebug(mixer->api, "PARAMS after:\n");
+ AFB_ApiDebug(mixer->api, "(%s) PARAMS after:", card);
AlsaDumpPcmParams(mixer, pxmHwParams);
// check we effective hw params after optional format change
@@ -224,13 +235,13 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
snd_pcm_hw_params_get_format(pxmHwParams, &opts->format);
snd_pcm_hw_params_get_rate(pxmHwParams, &opts->rate, 0);
- AFB_ApiInfo(mixer->api, "rate is %d", opts->rate);
+ AFB_ApiDebug(mixer->api, "(%s) rate is %d", card, opts->rate);
opts->sampleSize = AlsaPeriodSize(opts->format);
if (opts->sampleSize == 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail unsupported format format=%d",
- __func__, mixer->uid, pcm->cid.cardid, opts->format);
+ "%s (%s): mixer=%s Fail unsupported format format=%d",
+ __func__, card, mixer->uid, opts->format);
goto OnErrorExit;
}
@@ -240,8 +251,8 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
snd_pcm_hw_params_get_buffer_size(pxmHwParams, &buffer_size);
if (chunk_size == buffer_size) {
AFB_ApiError(mixer->api,
- "Can't use period equal to buffer size (%lu == %lu)",
- chunk_size, buffer_size);
+ "(%s) Can't use period equal to buffer size (%lu == %lu)",
+ card, chunk_size, buffer_size);
goto OnErrorExit;
}
@@ -263,8 +274,8 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
if ((error = snd_pcm_sw_params_set_avail_min(pcm->handle, pxmSwParams, n)) < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail set_buffersize error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s Fail set_buffersize error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
};
@@ -285,39 +296,39 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
if (start_threshold > n/2)
start_threshold = n/2;
- AFB_ApiInfo(mixer->api, "CALCULATED START THRESHOLD: %ld", start_threshold);
+ AFB_ApiDebug(mixer->api, "(%s) CALCULATED START THRESHOLD: %ld", card, start_threshold);
if (mode == SND_PCM_STREAM_PLAYBACK) {
start_threshold = 1;
}
- AFB_ApiInfo(mixer->api, "%s: Set start threshold to %ld", modeS, start_threshold);
+ AFB_ApiDebug(mixer->api, "(%s) %s: Set start threshold to %ld", card, modeS, start_threshold);
error = snd_pcm_sw_params_set_start_threshold(pcm->handle, pxmSwParams, start_threshold);
if (error < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s failed set start_threshold, error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s failed set start_threshold, error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
}
// push software params into PCM
if ((error = snd_pcm_sw_params(pcm->handle, pxmSwParams)) < 0) {
AFB_ApiError(mixer->api,
- "%s: mixer=%s cardid=%s Fail to push SW params error=%s",
- __func__, mixer->uid, pcm->cid.cardid, snd_strerror(error));
+ "%s (%s): mixer=%s Fail to push SW params error=%s",
+ __func__, card, mixer->uid, snd_strerror(error));
goto OnErrorExit;
};
AFB_ApiNotice(mixer->api,
- "%s: mixer=%s cardid=%s Done channels=%d rate=%d format=%d access=%d ... done !",
- __func__, mixer->uid, pcm->cid.cardid, opts->channels, opts->rate, opts->format, opts->access);
+ "%s (%s): mixer=%s Done channels=%d rate=%d format=%d access=%d ... DONE !",
+ __func__, card, mixer->uid, opts->channels, opts->rate, opts->format, opts->access);
return 0;
OnErrorExit:
return -1;
}
-STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandle) {
+STATIC int AlsaPcmReadCB( AlsaPcmCopyHandleT * pcmCopyHandle) {
char string[32];
snd_pcm_sframes_t availIn;
@@ -327,19 +338,6 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
int err;
- // PCM has was closed
- if ((pfd->revents & POLLHUP) != 0) {
- AFB_ApiNotice(pcmCopyHandle->api,
- "%s PCM=%s hanghup/disconnected",
- __func__, ALSA_PCM_UID(pcmIn, string));
- goto ExitOnSuccess;
- }
-
- // ignore any non input events. This is not supposed to happen ever
- if ((pfd->revents & EPOLLIN) == 0) {
- goto ExitOnSuccess;
- }
-
// do we have waiting frames ?
availIn = snd_pcm_avail_update(pcmIn);
if (availIn <= 0) {
@@ -465,16 +463,20 @@ static void *readThreadEntry(void *handle) {
AlsaPcmCopyHandleT *pcmCopyHandle = (AlsaPcmCopyHandleT*) handle;
pcmCopyHandle->tid = (int) syscall(SYS_gettid);
+ int ix;
AFB_ApiNotice(pcmCopyHandle->api,
"%s :%s/%d Started, muted=%d",
__func__, pcmCopyHandle->info, pcmCopyHandle->tid, pcmCopyHandle->pcmIn->mute);
- struct pollfd * mutePfd = &pcmCopyHandle->pollFds[0];
- struct pollfd * framePfd = &pcmCopyHandle->pollFds[1];
+ struct pollfd * eventFd = &pcmCopyHandle->pollFds[0];
+ struct pollfd * framePfds = &pcmCopyHandle->pollFds[1];
- mutePfd->events = POLLIN | POLLHUP;
- framePfd->events = POLLIN | POLLHUP;
+ eventFd->events = POLLIN | POLLHUP;
+
+ for (ix = 0; ix <pcmCopyHandle->nbPcmFds-1; ix++) {
+ framePfds[ix].events = POLLIN | POLLHUP;
+ }
bool muted = pcmCopyHandle->pcmIn->mute;
@@ -492,48 +494,60 @@ static void *readThreadEntry(void *handle) {
if (err == 0) {
/* timeout */
- AFB_ApiDebug(pcmCopyHandle->api, "%s(%s) alive, mute %d", __func__, pcmCopyHandle->pcmIn->cid.cardid, muted );
+// AFB_ApiDebug(pcmCopyHandle->api, "%s(%s) alive, mute %d", __func__, pcmCopyHandle->pcmIn->cid.cardid, muted );
continue;
}
- // handle the un/mute order
- if ((mutePfd->revents & EPOLLIN) != 0) {
- bool mute;
-
- size_t ret = read(mutePfd->fd, &mute, sizeof(mute));
- if (ret <= 0)
- continue;
+ // handle the incoming events/mute order
+ if ((eventFd->revents & EPOLLIN) != 0) {
+ PcmCopyEvent event;
- if (mute == muted)
- continue;
-
- muted = mute;
+ size_t ret = read(eventFd->fd, &event, sizeof(event));
+ if (ret <= 0)
+ continue;
- if (muted) {
- readSuspend(pcmCopyHandle);
- } else {
- readResume(pcmCopyHandle);
+ switch (event.eventType) {
+ case PCM_COPY_MUTE:
+ if (!muted) {
+ readSuspend(pcmCopyHandle);
+ muted = true;
+ }
+ break;
+ case PCM_COPY_UNMUTE:
+ if (muted) {
+ readResume(pcmCopyHandle);
+ muted = false;
+ };
+ break;
+ case PCM_COPY_END:
+ AFB_ApiDebug(pcmCopyHandle->api, "%s ending -> EXIT", __func__);
+ goto done;
+ break;
+ case PCM_COPY_LAST:
+ default:
+ AFB_ApiError(pcmCopyHandle->api, "%s: Unexpected event 0x%x", __func__, event.eventType);
+ break;
}
continue;
}
unsigned short revents;
- int ret = snd_pcm_poll_descriptors_revents(pcmCopyHandle->pcmIn->handle, &pcmCopyHandle->pollFds[1], 1, &revents);
+ int res = snd_pcm_poll_descriptors_revents(pcmCopyHandle->pcmIn->handle, framePfds, pcmCopyHandle->nbPcmFds, &revents);
- if (ret == -ENODEV) {
+ if (res == -ENODEV) {
sleep(1);
continue;
}
- if (framePfd->revents & POLLHUP) {
+ if (revents & POLLHUP) {
AFB_ApiNotice(pcmCopyHandle->api, "Frame POLLHUP");
continue;
}
- AlsaPcmReadCB(&pcmCopyHandle->pollFds[1], pcmCopyHandle);
+ AlsaPcmReadCB(pcmCopyHandle);
}
-
+done:
pthread_exit(0);
return NULL;
}
@@ -554,6 +568,8 @@ static void *writeThreadEntry(void *handle) {
snd_pcm_status(pcmOut, pcmOutStatus);
pcmOutSize = snd_pcm_status_get_avail_max(pcmOutStatus);
+ const char * cardid = pcmCopyHandle->pcmOut->cid.cardid;
+
/* This threshold is the expected space available in the hw output buffer
* The aim is to wait to have a significant amount of space, in order to
* avoid to write to the device too often, or take a very small amount of
@@ -566,17 +582,23 @@ static void *writeThreadEntry(void *handle) {
sem_wait(&pcmCopyHandle->sem);
while (true) {
+
+ if (pcmCopyHandle->ending) {
+ AFB_ApiDebug(pcmCopyHandle->api, "%s: ending -> EXIT", __func__);
+ goto done;
+ }
+
snd_pcm_sframes_t used, nbWritten;
snd_pcm_sframes_t availOut = snd_pcm_avail(pcmOut);
if (availOut < 0) {
if (availOut == -EPIPE) {
- AFB_ApiDebug(pcmCopyHandle->api, "write update EPIPE");
+ AFB_ApiDebug(pcmCopyHandle->api, "%s: write update EPIPE", cardid);
xrun(pcmOut, (int)availOut);
continue;
}
if (availOut == -ESTRPIPE) {
- AFB_ApiDebug(pcmCopyHandle->api, "write update ESTRPIPE");
+ AFB_ApiDebug(pcmCopyHandle->api, "%s: write update ESTRPIPE", cardid);
suspend(pcmOut, (int)availOut);
continue;
}
@@ -606,7 +628,8 @@ static void *writeThreadEntry(void *handle) {
if (nbWritten <= 0) {
if (nbWritten == -EPIPE) {
int err = xrun(pcmOut, (int)nbWritten);
- AFB_ApiDebug(pcmCopyHandle->api, "XXX write EPIPE (%d), recov %d", ++pcmCopyHandle->write_err_count , err);
+ AFB_ApiDebug(pcmCopyHandle->api, "XXX %s write EPIPE (%d), recov %d",
+ pcmCopyHandle->pcmOut->cid.cardid, ++pcmCopyHandle->write_err_count , err);
continue;
} else if (nbWritten == -ESTRPIPE) {
@@ -620,30 +643,70 @@ static void *writeThreadEntry(void *handle) {
}
}
-
+done:
pthread_exit(0);
return NULL;
}
PUBLIC int AlsaPcmCopyMuteSignal(SoftMixerT *mixer, AlsaPcmCtlT *pcmIn, bool mute) {
- ssize_t ret = write(pcmIn->muteFd, &mute, sizeof(mute));
+
+ PcmCopyEvent event;
+ event.eventType = mute?PCM_COPY_MUTE:PCM_COPY_UNMUTE;
+ ssize_t ret = write(pcmIn->eventFd, &event, sizeof(event));
(void) ret;
return 0;
}
+static int AlsaPcmCopyEndSignal(SoftMixerT *mixer, AlsaPcmCtlT *pcmIn) {
+ PcmCopyEvent event;
+ event.eventType = PCM_COPY_END;
+ ssize_t ret = write(pcmIn->eventFd, &event, sizeof(event));
+ (void) ret;
+ return 0;
+}
+
+static int AlsaPcmCopyEnd(SoftMixerT *mixer, AlsaPcmCopyHandleT * handle) {
+
+ handle->ending = true;
+ // wake up the reader through the eventfd
+ AlsaPcmCopyEndSignal(mixer, handle->pcmIn);
+ // wake up the writer through the wait semaphore
+ sem_post(&handle->sem);
-PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts) {
+ return 0;
+}
+
+PUBLIC int AlsaPcmCopyStop(SoftMixerT *mixer, AlsaPcmCopyHandleT * handle) {
+
+ AFB_ApiDebug(mixer->api, "%s: Stopping copy threads of %s", __func__, handle->stream->uid);
+
+ AlsaPcmCopyEnd(mixer, handle);
+
+ if (pthread_join(handle->wthread, NULL) != 0)
+ AFB_ApiDebug(mixer->api, "%s: Failed to join write thread", __func__);
+
+ if (pthread_join(handle->rthread, NULL) != 0)
+ AFB_ApiDebug(mixer->api, "%s: Failed to join read thread", __func__);
+
+ sem_destroy(&handle->sem);
+
+ AFB_ApiDebug(mixer->api, "%s: Copy threads of %s are STOPPED", __func__, handle->stream->uid);
+
+ return 0;
+
+}
+
+PUBLIC int AlsaPcmCopyStart(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts) {
char string[32];
int error;
+ AlsaPcmCopyHandleT *cHandle=NULL;
// 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);
- AFB_ApiInfo(mixer->api, "%s: Configure CAPTURE PCM", __func__);
-
/* remember configuration of capture */
pcmIn->params = (AlsaPcmHwInfoT*)malloc(sizeof(AlsaPcmHwInfoT));
memcpy(pcmIn->params, opts, sizeof(AlsaPcmHwInfoT));
@@ -654,7 +717,7 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
pcmIn->mixer = mixer;
pcmOut->mixer = mixer;
- AFB_ApiInfo(mixer->api, "%s: Configure CAPTURE PCM", __func__);
+ AFB_ApiDebug(mixer->api, "%s: Configure CAPTURE PCM", __func__);
// prepare PCM for capture and replay
error = AlsaPcmConf(mixer, pcmIn, SND_PCM_STREAM_CAPTURE);
@@ -663,7 +726,7 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
goto OnErrorExit;
}
- AFB_ApiInfo(mixer->api, "%s: Configure PLAYBACK PCM", __func__);
+ AFB_ApiDebug(mixer->api, "%s: Configure PLAYBACK PCM", __func__);
// input and output should match
error = AlsaPcmConf(mixer, pcmOut, SND_PCM_STREAM_PLAYBACK);
@@ -696,26 +759,35 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
goto OnErrorExit;
};
- AlsaPcmCopyHandleT *cHandle= calloc(1, sizeof(AlsaPcmCopyHandleT));
+ cHandle = calloc(1, sizeof(AlsaPcmCopyHandleT));
+ if (cHandle == NULL) {
+ SOFTMIXER_NOMEM(mixer->api);
+ goto OnErrorExit;
+ }
cHandle->info = "pcmCpy";
cHandle->pcmIn = pcmIn;
cHandle->pcmOut = pcmOut;
cHandle->api = mixer->api;
cHandle->channels = opts->channels;
+ cHandle->stream = stream;
cHandle->frame_size = (snd_pcm_format_physical_width(opts->format) / 8) * opts->channels;
+ AFB_ApiDebug(mixer->api, "%s: Frame size is %zu", __func__, cHandle->frame_size);
+ AFB_ApiDebug(mixer->api, "%s: Buffer delay is %d ms", __func__, stream->delayms);
- AFB_ApiInfo(mixer->api, "%s: Frame size is %zu", __func__, cHandle->frame_size);
-
- snd_pcm_uframes_t nbFrames = 2 * opts->rate; // Exactly 2 second of buffer
+ snd_pcm_uframes_t nbFrames = (stream->delayms * opts->rate)/1000;
cHandle->rbuf = alsa_ringbuf_new(nbFrames, cHandle->frame_size);
+ if (!cHandle->rbuf) {
+ SOFTMIXER_NOMEM(mixer->api);
+ goto OnErrorExit;
+ }
cHandle->read_err_count = 0;
cHandle->write_err_count = 0;
- AFB_ApiInfo(mixer->api, "%s Copy buffer nbframes is %zu", __func__, nbFrames);
+ AFB_ApiDebug(mixer->api, "%s Copy buffer: nbframes is %zu", __func__, nbFrames);
// get FD poll descriptor for capture PCM
int pcmInCount = snd_pcm_poll_descriptors_count(pcmIn->handle);
@@ -724,17 +796,16 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
"%s: Fail pcmIn=%s get fds count error=%s",
__func__, ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
goto OnErrorExit;
- };
+ }
- if (pcmInCount > 1) {
- AFB_ApiError(mixer->api,
- "%s: Fail, pcmIn=%s; having more than one FD on capture PCM is not supported (here, %d)",
- __func__, ALSA_PCM_UID(pcmOut->handle, string) , pcmInCount);
+ cHandle->nbPcmFds = pcmInCount+1;
+ cHandle->pollFds = (struct pollfd *) malloc((cHandle->nbPcmFds)*sizeof(struct pollfd));
+ if (cHandle->pollFds == NULL){
+ SOFTMIXER_NOMEM(mixer->api);
goto OnErrorExit;
}
- struct pollfd pcmInFd;
- if ((error = snd_pcm_poll_descriptors(pcmIn->handle, &pcmInFd, 1)) < 0) {
+ if ((error = snd_pcm_poll_descriptors(pcmIn->handle, cHandle->pollFds+1, pcmInCount)) < 0) {
AFB_ApiError(mixer->api,
"%s: Fail pcmIn=%s get pollfds error=%s",
__func__, ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
@@ -742,27 +813,22 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
};
// create the mute pipe
- int pMuteFd[2];
- error = pipe(pMuteFd);
+ int eventFdPipe[2];
+ error = pipe(eventFdPipe);
if (error < 0) {
AFB_ApiError(mixer->api,
"Unable to create the mute signaling pipe");
goto OnErrorExit;
}
- struct pollfd mutePFd;
+ struct pollfd * eventPollFd = &cHandle->pollFds[0];
// read end
- mutePFd.fd = pMuteFd[0];
- mutePFd.events = POLLIN;
- mutePFd.revents = 0;
+ eventPollFd->fd = eventFdPipe[0];
+ eventPollFd->events = POLLIN;
+ eventPollFd->revents = 0;
// write end
- pcmIn->muteFd = pMuteFd[1];
-
- cHandle->pollFds[0] = mutePFd;
- cHandle->pollFds[1] = pcmInFd;
-
- cHandle->nbPcmFds = pcmInCount+1;
+ pcmIn->eventFd = eventFdPipe[1];
error = sem_init(&cHandle->sem, 0 , 0);
if (error < 0) {
@@ -818,11 +884,22 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
__func__, ALSA_PCM_UID(pcmOut->handle, string), strerror(error));
}
+ stream->copy = cHandle;
+
return 0;
OnErrorExit:
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));
+
+ if (cHandle &&cHandle->pollFds) {
+ free (cHandle->pollFds);
+ cHandle->pollFds = NULL;
+ }
+
+ if (cHandle)
+ free(cHandle);
+
return -1;
}