summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-softmixer.h
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-softmixer.h
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-softmixer.h')
-rw-r--r--plugins/alsa/alsa-softmixer.h148
1 files changed, 109 insertions, 39 deletions
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index e7218bd..a8cc6de 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -21,7 +21,6 @@
#ifndef _ALSA_SOFTMIXER_
#define _ALSA_SOFTMIXER_
-//#include <afb/afb-binding.h>
#include <json-c/json_object.h>
#include <stdlib.h>
#include <stdio.h>
@@ -31,11 +30,15 @@
#include <systemd/sd-event.h>
#include <semaphore.h>
+#include <urcu/list.h>
+
#include "ctl-plugin.h"
#include "wrap-json.h"
#include "alsa-ringbuf.h"
+#include "alsa-transaction.h"
+
#ifndef PUBLIC
#define PUBLIC
#endif
@@ -51,7 +54,7 @@
#define ALSA_CARDID_MAX_LEN 64
-#define SMIXER_SUBDS_CTLS 3
+#define SMIXER_SUBDS_CTLS 16
#define SMIXER_DEFLT_LOOPS 4
#define SMIXER_DEFLT_SINKS 8
#define SMIXER_DEFLT_SOURCES 32
@@ -59,9 +62,16 @@
#define SMIXER_DEFLT_STREAMS 32
#define SMIXER_DEFLT_RAMPS 8
+#define SMIXER_DEFLT_DELAYMS 1000
+
+#define SOFTMIXER_VERB_NONE "none"
+
#define ALSA_PLUG_PROTO(plugin) \
int _snd_pcm_ ## plugin ## _open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode)
+#define SOFTMIXER_NOMEM(api) \
+ AFB_ApiError((api), "%s: Insufficient memory", __func__)
+
// auto switch from Log to API request depending on request presence.
#define AFB_IfReqFailF(mixer, request, status, format, ...) \
if (request) AFB_ReqFailF(request, status, format, __VA_ARGS__); \
@@ -101,16 +111,20 @@ typedef struct {
} AlsaPcmHwInfoT;
typedef struct {
+ const char * name;
int ccount;
bool mute;
- int muteFd;
+ int eventFd;
AlsaDevInfoT cid;
snd_pcm_t *handle;
AlsaPcmHwInfoT *params;
- void * mixer;
+ struct SoftMixerT_ * mixer;
snd_pcm_uframes_t avail_min;
+
+ bool closeAtDeletion; // intermediate pcms in the pcm chain must not be closed, else it make libasound abort()
+ bool isPcmPlug;
} AlsaPcmCtlT;
typedef struct {
@@ -138,12 +152,15 @@ typedef struct {
char* info;
int nbPcmFds;
- struct pollfd pollFds[2];
+ struct pollfd * pollFds;
sem_t sem;
pthread_mutex_t mutex;
int saveFd;
+ bool ending;
+
+ struct AlsaStreamAudioT_ * stream;
} AlsaPcmCopyHandleT;
@@ -156,87 +173,112 @@ typedef struct {
long step;
} AlsaSndControlT;
+
typedef struct {
const char*uid;
int port;
+ double volume;
+ struct cds_list_head list;
} AlsaPcmChannelT;
-
typedef struct {
const char *uid;
int delay; // delay between volset in us
int stepDown; // linear %
int stepUp; // linear %
+ struct cds_list_head list;
} AlsaVolRampT;
-
-
-
typedef struct {
int numid;
RegistryNumidT type;
AlsaPcmCtlT *pcm;
+ struct cds_list_head cardListEntry; /* node to list in AlsaSndCtlT */
+ struct AlsaSndCtlT_ *sndcard; /* ref to owner */
} RegistryEntryPcmT;
-typedef struct {
- long rcount;
+
+typedef struct AlsaSndCtlT_ {
AlsaDevInfoT cid;
snd_ctl_t *ctl;
AlsaPcmHwInfoT *params;
- RegistryEntryPcmT **registry;
+ long nbRegistry;
+ struct cds_list_head registryList;
+ struct SubscribeHandleT_ * eventSubscribeHandle;
} AlsaSndCtlT;
typedef struct {
const char *uid;
- AlsaPcmChannelT **sources;
- AlsaPcmChannelT **sinks;
+ unsigned int nbSources;
+ AlsaPcmChannelT sources;
+ unsigned int nbSinks;
+ AlsaPcmChannelT sinks;
int ccount;
AlsaPcmHwInfoT *params;
+ struct cds_list_head list;
+ snd_config_t * routeConfig;
+ bool isPcmPlug;
} AlsaSndZoneT;
typedef struct {
const char *uid;
const char *verb;
- unsigned int ccount;
AlsaSndCtlT *sndcard;
AlsaSndControlT volume;
AlsaSndControlT mute;
- AlsaPcmChannelT **channels;
+ unsigned int nbChannels;
+ AlsaPcmChannelT channels;
snd_pcm_stream_t direction;
+ struct cds_list_head list;
+ bool isPcmPlug;
+ void * apiVerbHandle;
} AlsaSndPcmT;
typedef struct {
const char*uid;
int index;
int numid;
+ struct cds_list_head list;
} AlsaLoopSubdevT;
-typedef struct {
+
+struct SoftMixerT_;
+
+typedef struct AlsaSndLoopT {
const char *uid;
+ struct SoftMixerT_ * mixer; /* owner */
int playback;
int capture;
- long scount;
AlsaSndCtlT *sndcard;
- AlsaLoopSubdevT **subdevs;
+ int nbSubdevs;
+ AlsaLoopSubdevT subdevs;
+ struct cds_list_head list;
} AlsaSndLoopT;
-typedef struct {
+typedef struct AlsaStreamAudioT_ {
const char *uid;
const char *verb;
const char *info;
const char *sink;
+ const char *playback;
const char *source;
const char *ramp;
int volume;
int mute;
+ unsigned int delayms;
AlsaPcmHwInfoT *params;
AlsaPcmCopyHandleT *copy;
+ struct cds_list_head list; /* link to the global list*/
+ AlsaPcmCtlT * softvol;
+ snd_config_t * softvolConfig;
+ snd_config_t * rateConfig;
+ void * verbApiHandle;
} AlsaStreamAudioT;
-typedef struct {
+typedef struct SoftMixerT_{
const char *uid;
const char *info;
AFB_ApiT api;
@@ -250,17 +292,27 @@ typedef struct {
unsigned int streams;
unsigned int ramps;
} max;
- AlsaSndLoopT **loops;
- AlsaSndPcmT **sinks;
- AlsaSndPcmT **sources;
- AlsaSndZoneT **zones;
- AlsaStreamAudioT **streams;
- AlsaVolRampT **ramps;
+ unsigned int nbLoops;
+ AlsaSndLoopT loops;
+ unsigned int nbSinks;
+ AlsaSndPcmT sinks;
+ unsigned int nbSources;
+ AlsaSndPcmT sources;
+ unsigned int nbZones;
+ AlsaSndZoneT zones;
+ unsigned int nbStreams;
+ AlsaStreamAudioT streams;
+ unsigned int nbRamps;
+ AlsaVolRampT ramps;
+
+ AlsaMixerTransaction * transaction;
} SoftMixerT;
// alsa-utils-bypath.c
PUBLIC snd_ctl_card_info_t *AlsaByPathInfo(SoftMixerT *mixer, const char *devpath);
-PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcm(SoftMixerT *mixer, AlsaDevInfoT *pcmId, snd_pcm_stream_t direction);
+PUBLIC AlsaPcmCtlT * AlsaPcmCtlNew(SoftMixerT*, const char*);
+PUBLIC void AlsaPcmCtlDelete(SoftMixerT *mixer, void *);
+PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcmCtl(SoftMixerT *mixer, AlsaDevInfoT *pcmId, snd_pcm_stream_t direction);
PUBLIC snd_ctl_t *AlsaByPathOpenCtl(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *dev);
// alsa-utils-dump.c
@@ -279,7 +331,7 @@ PUBLIC void AlsaDumpCtlConfig(SoftMixerT *mixer, const char* info, snd_config_t
// alsa-core-ctl.c
PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numid) ;
PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const char *ctlName) ;
-PUBLIC snd_ctl_t *AlsaCtlOpenCtl(SoftMixerT *mixer, const char *cardid) ;
+
PUBLIC int CtlElemIdGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, snd_ctl_elem_id_t *elemId, long *value) ;
PUBLIC int CtlElemIdSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, snd_ctl_elem_id_t *elemId, long value) ;
PUBLIC snd_ctl_card_info_t *AlsaCtlGetCardInfo(SoftMixerT *mixer, const char *cardid) ;
@@ -288,37 +340,55 @@ PUBLIC int AlsaCtlNumidGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi
PUBLIC int AlsaCtlNameSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const char *ctlName, long value) ;
PUBLIC int AlsaCtlNameGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const char *ctlName, long* value) ;
PUBLIC int AlsaCtlCreateControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, char* ctlName, int ctlCount, int ctlMin, int ctlMax, int ctlStep, long value) ;
-PUBLIC snd_ctl_t* AlsaCrlFromPcm(SoftMixerT *mixer, snd_pcm_t *pcm) ;
+
PUBLIC int AlsaCtlSubscribe(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *sndcard) ;
+
+PUBLIC void AlsaCtlUnregister(SoftMixerT* mixer, void *);
PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT *pcmdev, RegistryNumidT type, int numid);
// alsa-core-pcm.c
PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode);
-PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
+PUBLIC int AlsaPcmCopyStart(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
+PUBLIC int AlsaPcmCopyStop(SoftMixerT *mixer, AlsaPcmCopyHandleT * handle);
// alsa-plug-*.c _snd_pcm_PLUGIN_open_ see macro ALSA_PLUG_PROTO(plugin)
-PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *streamAudio, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
PUBLIC int AlsaPcmCopyMuteSignal(SoftMixerT *mixer, AlsaPcmCtlT *pcmIn, bool mute);
+
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);
-PUBLIC AlsaPcmCtlT* AlsaCreateRate(SoftMixerT *mixer, const char* pcmName, AlsaPcmCtlT *pcmSlave, AlsaPcmHwInfoT *params, int open);
+PUBLIC AlsaPcmCtlT* AlsaCreateRate(SoftMixerT *mixer, AlsaStreamAudioT *stream, const char* pcmName, AlsaPcmCtlT *pcmSlave, AlsaPcmHwInfoT *params, int open);
PUBLIC AlsaPcmCtlT* AlsaCreateDmix(SoftMixerT *mixer, const char* pcmName, AlsaSndPcmT *pcmSlave, int open);
// alsa-api-*
+
+PUBLIC int ApiLoopAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object * argsJ);
+PUBLIC int ApiSourceAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object * argsJ);
+PUBLIC int ApiSinkAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object * argsJ);
+PUBLIC int ApiStreamAttach(SoftMixerT *mixer, AFB_ReqT request, const char * uid, const char *prefix, json_object * argsJ);
+PUBLIC int ApiZoneAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object * argsJ);
+PUBLIC int ApiRampAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object *argsJ);
+
+// helper used for attach verb,and also by the streams API for fake zones
+PUBLIC AlsaSndZoneT * zoneCreate(SoftMixerT* mixer, const char * uid, json_object * argsJ);
+
PUBLIC AlsaLoopSubdevT *ApiLoopFindSubdev(SoftMixerT *mixer, const char *streamUid, const char *targetUid, AlsaSndLoopT **loop);
-PUBLIC int ApiLoopAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object * argsJ);
+
PUBLIC AlsaPcmHwInfoT *ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json_object *paramsJ);
+PUBLIC void ApiPcmDelParams(SoftMixerT*, AlsaPcmHwInfoT*);
+
PUBLIC AlsaSndPcmT *ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm_stream_t direction, json_object *argsJ);
+PUBLIC AlsaSndPcmT * ApiPcmNew(SoftMixerT* mixer);
+PUBLIC void ApiPcmDelete(SoftMixerT * mixer, AlsaSndPcmT * pcm);
+
PUBLIC AlsaVolRampT *ApiRampGetByUid(SoftMixerT *mixer, const char *uid);
-PUBLIC int ApiRampAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object *argsJ);
+
PUBLIC AlsaPcmHwInfoT *ApiSinkGetParamsByZone(SoftMixerT *mixer, const char *target);
-PUBLIC int ApiSinkAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object * argsJ);
+
PUBLIC AlsaSndPcmT *ApiSinkGetByUid(SoftMixerT *mixer, const char *target);
PUBLIC AlsaSndCtlT *ApiSourceFindSubdev(SoftMixerT *mixer, const char *target);
-PUBLIC int ApiSourceAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object * argsJ);
-PUBLIC int ApiStreamAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, const char *prefix, json_object * argsJ);
+
+
PUBLIC AlsaSndZoneT *ApiZoneGetByUid(SoftMixerT *mixer, const char *target);
-PUBLIC int ApiZoneAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object * argsJ);
// alsa-effect-ramp.c
PUBLIC AlsaVolRampT *ApiRampGetByUid(SoftMixerT *mixer, const char *uid);