Last active
May 12, 2016 16:58
-
-
Save joerg-krause/8c0a1fe1c67e1a34b28ff7efec9d5dec to your computer and use it in GitHub Desktop.
ALSA integration into Luvit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --[[ | |
| The MIT License (MIT) | |
| Copyright (c) 2016 Jörg Krause <joerg.krause@embedded.rocks> | |
| Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| --]] | |
| -------------------------------------------------------------------------------- | |
| -- LuaJIT bindings to libasound | |
| -- | |
| -- http://www.alsa-project.org/alsa-doc/alsa-lib/index.html | |
| -------------------------------------------------------------------------------- | |
| local ffi = require("ffi") | |
| ffi.cdef([[ | |
| static const int POLLERR = 0x008; | |
| static const int POLLHUP = 0x010; | |
| static const int POLLIN = 0x001; | |
| static const int POLLNVAL = 0x020; | |
| static const int POLLOUT = 0x004; | |
| struct pollfd { | |
| int fd; | |
| short int events; | |
| short int revents; | |
| }; | |
| ]]) | |
| ffi.cdef([[ | |
| struct list_head { | |
| struct list_head *next; | |
| struct list_head *prev; | |
| }; | |
| ]]) | |
| -- include/mixer.h | |
| ffi.cdef([[ | |
| typedef struct _snd_mixer snd_mixer_t; | |
| typedef struct _snd_mixer_class snd_mixer_class_t; | |
| typedef struct _snd_mixer_elem snd_mixer_elem_t; | |
| typedef struct _snd_mixer_selem_id snd_mixer_selem_id_t; | |
| typedef int(*snd_mixer_callback_t) (snd_mixer_t *ctl, unsigned int mask, snd_mixer_elem_t *elem); | |
| typedef int(*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem, unsigned int mask); | |
| typedef int(*snd_mixer_compare_t) (const void *e1, const void *e2); | |
| typedef int(*snd_mixer_event_t)(snd_mixer_class_t *class_, unsigned int mask, void *helem, snd_mixer_elem_t **melem); | |
| typedef enum _snd_mixer_elem_type { | |
| SND_MIXER_ELEM_SIMPLE, | |
| SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE | |
| } snd_mixer_elem_type_t; | |
| ]]) | |
| -- src/mixer/mixer_local.h | |
| ffi.cdef([[ | |
| typedef struct list_head bag_t; | |
| struct _snd_mixer_class { | |
| struct list_head list; | |
| snd_mixer_t *mixer; | |
| snd_mixer_event_t event; | |
| void *private_data; | |
| void (*private_free)(snd_mixer_class_t *class); | |
| snd_mixer_compare_t compare; | |
| }; | |
| struct _snd_mixer_elem { | |
| snd_mixer_elem_type_t type; | |
| struct list_head list; /* links for list of all elems */ | |
| snd_mixer_class_t *class; | |
| void *private_data; | |
| void (*private_free)(snd_mixer_elem_t *elem); | |
| snd_mixer_elem_callback_t callback; | |
| void *callback_private; | |
| bag_t helems; | |
| int compare_weight; /* compare weight (reversed) */ | |
| }; | |
| struct _snd_mixer { | |
| struct list_head slaves; /* list of all slaves */ | |
| struct list_head classes; /* list of all elem classes */ | |
| struct list_head elems; /* list of all elems */ | |
| snd_mixer_elem_t **pelems; /* array of all elems */ | |
| unsigned int count; | |
| unsigned int alloc; | |
| unsigned int events; | |
| snd_mixer_callback_t callback; | |
| void *callback_private; | |
| snd_mixer_compare_t compare; | |
| }; | |
| struct _snd_mixer_selem_id { | |
| char name[60]; | |
| unsigned int index; | |
| }; | |
| ]]) | |
| -- include/mixer.h | |
| ffi.cdef([[ | |
| int snd_mixer_open(snd_mixer_t **mixer, int mode); | |
| int snd_mixer_close(snd_mixer_t *mixer); | |
| int snd_mixer_attach(snd_mixer_t *mixer, const char * name); | |
| int snd_mixer_load(snd_mixer_t *mixer); | |
| int snd_mixer_selem_register(snd_mixer_t *mixer, void *options, snd_mixer_class_t **classp); | |
| void snd_mixer_selem_get_id(snd_mixer_elem_t *element, snd_mixer_selem_id_t *id); | |
| void snd_mixer_selem_id_set_name (snd_mixer_selem_id_t *obj, const char *val); | |
| void snd_mixer_selem_id_set_index (snd_mixer_selem_id_t *obj, unsigned int val); | |
| snd_mixer_elem_t * snd_mixer_find_selem(snd_mixer_t *mixer, const snd_mixer_selem_id_t *id); | |
| int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t * elem, long * min, long * max); | |
| int snd_mixer_selem_ask_playback_vol_dB(void * elem, long value, long * dBvalue); | |
| int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, long *min, long *max); | |
| int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t * elem, int channel, long * value); | |
| void snd_mixer_set_callback(snd_mixer_t *mixer, snd_mixer_callback_t val); | |
| int snd_mixer_wait(snd_mixer_t *mixer, int timeout); | |
| int snd_mixer_handle_events(snd_mixer_t *mixer); | |
| void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val); | |
| const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj); | |
| void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val); | |
| int snd_mixer_handle_events(snd_mixer_t *mixer); | |
| int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space); | |
| int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); | |
| ]]) | |
| local alsa = ffi.load("asound") | |
| local C = ffi.C | |
| local uv = require("uv") | |
| local Emitter = require("core").Emitter | |
| local AlsaEventListener = Emitter:extend() | |
| function AlsaEventListener:get_playback_volume() | |
| local sid_ptr = ffi.new("snd_mixer_selem_id_t") | |
| alsa.snd_mixer_selem_id_set_index(sid_ptr, 0) | |
| alsa.snd_mixer_selem_id_set_name(sid_ptr, self.selem_name) | |
| local elem = alsa.snd_mixer_find_selem(self.handle, sid_ptr) | |
| local vol | |
| if elem then | |
| vol = ffi.new("long[1]") | |
| alsa.snd_mixer_selem_get_playback_volume(elem, 0, vol) | |
| end | |
| return tonumber(vol[0]) | |
| end | |
| function AlsaEventListener:initialize(card, selem_name) | |
| assert(card) | |
| assert(selem_name) | |
| self.card = card | |
| self.selem_name = selem_name | |
| local function melem_event_cb(elem, mask) | |
| if bit.band(mask, 1) then -- SND_CTL_EVENT_MASK_VALUE | |
| self:emit("onchange") | |
| end | |
| return 0 | |
| end | |
| local function mixer_event_cb(mixer, mask, elem) | |
| if bit.band(mask, 4) then -- SND_CTL_EVENT_MASK_ADD | |
| self:emit("onadd") | |
| alsa.snd_mixer_elem_set_callback(elem, melem_event_cb); | |
| end | |
| return 0 | |
| end | |
| local function perform(err, events) | |
| local revents_ptr = ffi.new("unsigned short[1]") | |
| alsa.snd_mixer_poll_descriptors_revents(self.handle, self.fds, 1, revents_ptr) | |
| local revents = revents_ptr[0] | |
| if (bit.band(revents, C.POLLIN)) then | |
| alsa.snd_mixer_handle_events(self.handle) | |
| end | |
| return 0 | |
| end | |
| local mixer_ptr = ffi.new("snd_mixer_t *[1]") | |
| alsa.snd_mixer_open(mixer_ptr, 0) | |
| self.handle = mixer_ptr[0] | |
| alsa.snd_mixer_attach(self.handle, self.card) | |
| alsa.snd_mixer_selem_register(self.handle, nil, nil) | |
| alsa.snd_mixer_set_callback(self.handle, mixer_event_cb) | |
| alsa.snd_mixer_load(self.handle) | |
| self.fds = ffi.new("struct pollfd") | |
| alsa.snd_mixer_poll_descriptors(self.handle, self.fds, 1) | |
| self.poll = uv.new_poll(self.fds.fd) | |
| uv.poll_start(self.poll, 'r', perform) | |
| end | |
| function AlsaEventListener:close() | |
| uv.poll_stop(self.poll) | |
| uv.close(self.poll) | |
| alsa.snd_mixer_close(self.handle) | |
| end | |
| return { | |
| AlsaEventListener = AlsaEventListener | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment