From 46d172d253ccd0a6eb1908de258d4c3969163d3d Mon Sep 17 00:00:00 2001 From: deadwood Date: Wed, 11 Nov 2015 13:44:44 +0000 Subject: [PATCH] alsa.audio: add volume control NOTE: The driver controls the Master volume on Linux side git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@51209 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- workbench/devs/AHI/Drivers/Alsa/DriverData.h | 6 ++ workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.c | 59 ++++++++++++++- workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.h | 5 ++ .../AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.c | 14 ++++ .../AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.h | 14 ++++ workbench/devs/AHI/Drivers/Alsa/alsa-init.c | 7 ++ workbench/devs/AHI/Drivers/Alsa/alsa-main.c | 88 ++++++++++++++++++++++ 7 files changed, 191 insertions(+), 2 deletions(-) diff --git a/workbench/devs/AHI/Drivers/Alsa/DriverData.h b/workbench/devs/AHI/Drivers/Alsa/DriverData.h index 95c2123a9a..c2f1afaceb 100644 --- a/workbench/devs/AHI/Drivers/Alsa/DriverData.h +++ b/workbench/devs/AHI/Drivers/Alsa/DriverData.h @@ -11,6 +11,12 @@ struct AlsaBase { struct DriverBase driverbase; struct DosLibrary* dosbase; + + /* Mixer properties */ + APTR al_MixerHandle; + APTR al_MixerElem; + LONG al_MinVolume; + LONG al_MaxVolume; }; #define DRIVERBASE_SIZEOF (sizeof (struct AlsaBase)) diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.c b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.c index ffb6d0a1a0..cc7ee2a90e 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.c +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.c @@ -6,6 +6,9 @@ #include "alsa.h" #include "alsa_hostlib.h" +#define CARDNAME "default" +#define VOLUMENAME "Master" + BOOL ALSA_Init() { return ALSA_HostLib_Init(); @@ -16,12 +19,64 @@ VOID ALSA_Cleanup() ALSA_HostLib_Cleanup(); } +VOID ALSA_MixerInit(APTR * handle, APTR * elem, LONG * min, LONG * max) +{ + snd_mixer_t * _handle; + snd_mixer_selem_id_t * _sid; + snd_mixer_elem_t * _elem; + + *handle = NULL; + *elem = NULL; + + ALSACALL(snd_mixer_open,&_handle, 0); + ALSACALL(snd_mixer_attach,_handle, CARDNAME); + ALSACALL(snd_mixer_selem_register,_handle, NULL, NULL); + ALSACALL(snd_mixer_load,_handle); + + ALSACALL(snd_mixer_selem_id_malloc,&_sid); + ALSACALL(snd_mixer_selem_id_set_index,_sid, 0); + ALSACALL(snd_mixer_selem_id_set_name,_sid, VOLUMENAME); + _elem = ALSACALL(snd_mixer_find_selem,_handle, _sid); + + if (_elem != NULL) + { + long a,b; + ALSACALL(snd_mixer_selem_get_playback_volume_range,_elem, &a, &b); + + *handle = _handle; + *elem = _elem; + *min = (LONG)a; + *max = (LONG)b; + } + + ALSACALL(snd_mixer_selem_id_free,_sid); +} + +VOID ALSA_MixerCleanup(APTR handle) +{ + ALSACALL(snd_mixer_close,handle); +} + +LONG ALSA_MixerGetVolume(APTR elem) +{ + long _ret = 0; + + ALSACALL(snd_mixer_selem_get_playback_volume, elem, + SND_MIXER_SCHN_FRONT_LEFT, &_ret); + return (LONG)_ret; +} + +VOID ALSA_MixerSetVolume(APTR elem, LONG volume) +{ + ALSACALL(snd_mixer_selem_set_playback_volume_all, elem, volume); +} + APTR ALSA_Open() { snd_pcm_t * handle = NULL; - if (ALSACALL(snd_pcm_open, &handle, "default", + if (ALSACALL(snd_pcm_open, &handle, CARDNAME, SND_PCM_STREAM_PLAYBACK, 0) < 0) return NULL; @@ -39,7 +94,7 @@ VOID ALSA_DropAndClose(APTR handle) BOOL ALSA_SetHWParams(APTR handle, ULONG * rate) { - snd_pcm_hw_params_t *hw_params; + snd_pcm_hw_params_t * hw_params; LONG dir = 0; int r = 0; ALSACALL(snd_pcm_hw_params_malloc, &hw_params); diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.h b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.h index 7fa9d81b69..a866860789 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.h +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa.h @@ -10,6 +10,11 @@ BOOL ALSA_Init(); VOID ALSA_Cleanup(); +VOID ALSA_MixerInit(APTR * handle, APTR * elem, LONG * min, LONG * max); +VOID ALSA_MixerCleanup(APTR handle); +LONG ALSA_MixerGetVolume(APTR elem); +VOID ALSA_MixerSetVolume(APTR elem, LONG volume); + APTR ALSA_Open(); VOID ALSA_DropAndClose(APTR handle); diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.c b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.c index 6bdb93b6ac..91cd038f2a 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.c +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.c @@ -29,6 +29,20 @@ static const char *alsa_func_names[] = "snd_pcm_hw_params_get_buffer_size", "snd_pcm_hw_params_set_buffer_size", "snd_pcm_drop", + + "snd_mixer_open", + "snd_mixer_close", + "snd_mixer_load", + "snd_mixer_attach", + "snd_mixer_find_selem", + "snd_mixer_selem_register", + "snd_mixer_selem_id_malloc", + "snd_mixer_selem_id_free", + "snd_mixer_selem_id_set_index", + "snd_mixer_selem_id_set_name", + "snd_mixer_selem_get_playback_volume_range", + "snd_mixer_selem_get_playback_volume", + "snd_mixer_selem_set_playback_volume_all", }; #define ALSA_NUM_FUNCS (sizeof(alsa_func_names) / sizeof(alsa_func_names[0])) diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.h b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.h index c056a1cfee..a0adfc98ea 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.h +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-bridge/alsa_hostlib.h @@ -23,6 +23,20 @@ struct alsa_func int (*snd_pcm_hw_params_get_buffer_size)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); int (*snd_pcm_hw_params_set_buffer_size)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); int (*snd_pcm_drop)(snd_pcm_t *pcm); + + int (*snd_mixer_open)(snd_mixer_t **mixer, int mode); + int (*snd_mixer_close)(snd_mixer_t *mixer); + int (*snd_mixer_load)(snd_mixer_t *mixer); + int (*snd_mixer_attach)(snd_mixer_t *mixer, const char *name); + snd_mixer_elem_t *(*snd_mixer_find_selem)(snd_mixer_t *mixer, const snd_mixer_selem_id_t *id); + int (*snd_mixer_selem_register)(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); + int (*snd_mixer_selem_id_malloc)(snd_mixer_selem_id_t **ptr); + void (*snd_mixer_selem_id_free)(snd_mixer_selem_id_t *obj); + void (*snd_mixer_selem_id_set_index)(snd_mixer_selem_id_t *obj, unsigned int val); + void (*snd_mixer_selem_id_set_name)(snd_mixer_selem_id_t *obj, const char *val); + int (*snd_mixer_selem_get_playback_volume_range)(snd_mixer_elem_t *elem, long *min, long *max); + int (*snd_mixer_selem_get_playback_volume)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); + int (*snd_mixer_selem_set_playback_volume_all)(snd_mixer_elem_t *elem, long value); }; extern struct alsa_func alsa_func; diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-init.c b/workbench/devs/AHI/Drivers/Alsa/alsa-init.c index feff6387b2..6e89347fcb 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-init.c +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-init.c @@ -29,6 +29,10 @@ DriverInit( struct DriverBase* AHIsubBase ) if (!ALSA_Init()) return FALSE; + + ALSA_MixerInit(&AlsaBase->al_MixerHandle, &AlsaBase->al_MixerElem, + &AlsaBase->al_MinVolume, &AlsaBase->al_MaxVolume); + D(bug("[Alsa]: DriverInit() completed\n")); return TRUE; @@ -46,5 +50,8 @@ DriverCleanup( struct DriverBase* AHIsubBase ) ALSA_Cleanup(); + if (AlsaBase->al_MixerHandle) + ALSA_MixerCleanup(AlsaBase->al_MixerHandle); + CloseLibrary( (struct Library*) DOSBase ); } diff --git a/workbench/devs/AHI/Drivers/Alsa/alsa-main.c b/workbench/devs/AHI/Drivers/Alsa/alsa-main.c index aaccf06e15..1fca5e0bd6 100644 --- a/workbench/devs/AHI/Drivers/Alsa/alsa-main.c +++ b/workbench/devs/AHI/Drivers/Alsa/alsa-main.c @@ -33,6 +33,63 @@ static const LONG frequencies[] = #define FREQUENCIES (sizeof frequencies / sizeof frequencies[ 0 ]) +static const ULONG table_5bit[] = { + 0xb53c, + 0x804e, + 0x5ad5, + 0x404e, + 0x2d86, + 0x203a, + 0x16d1, + 0x1027, + 0x0b6f, + 0x0818, + 0x05bb, + 0x040f, + 0x02df, + 0x0209, + 0x0171, + 0x0105, + 0x00b9, + 0x0083, + 0x005d, + 0x0042, + 0x002e, + 0x0021, + 0x0017, + 0x0010, + 0x000c, + 0x0008, + 0x0006, + 0x0004, + 0x0003, + 0x0002, + 0x0001, + 0x0000 +}; + +static UWORD LinToLog(ULONG vol) +{ + int i; + + if (!vol) return 0x20; + + for (i = 0; i < 32; i++) + { + if (vol > table_5bit[i]) + { + return i; + } + } + return 0x1f; +} + +static ULONG LogToLin(UWORD i) +{ + if (i > 31) return 0x10000; + return table_5bit[i]; +} + /****************************************************************************** ** AHIsub_AllocAudio ********************************************************** ******************************************************************************/ @@ -335,6 +392,15 @@ _AHIsub_GetAttr( ULONG attribute, case AHIDB_Output: return (IPTR) "Alsa"; // We have only one "output"! + case AHIDB_MinOutputVolume: + return 0x00000; + + case AHIDB_MaxOutputVolume: + if (AlsaBase->al_MixerElem) + return 0x10000; + else + return 0x00000; + default: return def; } @@ -353,5 +419,27 @@ _AHIsub_HardwareControl( ULONG attribute, { struct AlsaBase* AlsaBase = (struct AlsaBase*) AHIsubBase; + switch(attribute) + { + case AHIC_OutputVolume: + if (AlsaBase->al_MixerElem) + { + LONG val = (0x20 - LinToLog(argument)) * AlsaBase->al_MaxVolume / 0x20; + ALSA_MixerSetVolume(AlsaBase->al_MixerElem, (LONG)val); + } + + return TRUE; + + case AHIC_OutputVolume_Query: + if (AlsaBase->al_MixerElem) + { + LONG val = ALSA_MixerGetVolume(AlsaBase->al_MixerElem); + val = val * 0x20 / AlsaBase->al_MaxVolume; + return LogToLin(0x20 - val); + } + + return 0; + } + return 0; } -- 2.11.4.GIT