diff options
author | fulup <fulup.arfoll@iot.bzh> | 2017-07-03 15:38:35 +0200 |
---|---|---|
committer | fulup <fulup.arfoll@iot.bzh> | 2017-07-03 15:38:35 +0200 |
commit | 85a4c0a1e0f666505cf2a2922c12e78b3c83c062 (patch) | |
tree | a52de3541fca1f7847ab2b083034d93ac8d69205 /ALSA-afb/Alsa-AddCtl.c | |
parent | 1abf42ee54f669b523bb1a6f4d57d15d78ce0255 (diff) |
Moved to V2
Diffstat (limited to 'ALSA-afb/Alsa-AddCtl.c')
-rw-r--r-- | ALSA-afb/Alsa-AddCtl.c | 161 |
1 files changed, 133 insertions, 28 deletions
diff --git a/ALSA-afb/Alsa-AddCtl.c b/ALSA-afb/Alsa-AddCtl.c index 2edec5f..5754c15 100644 --- a/ALSA-afb/Alsa-AddCtl.c +++ b/ALSA-afb/Alsa-AddCtl.c @@ -13,6 +13,10 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * References: + * https://kernel.readthedocs.io/en/sphinx-samples/writing-an-alsa-driver.html#control-names + * https://01.org/linuxgraphics/gfx-docs/drm/sound/designs/control-names.html */ #define _GNU_SOURCE // needed for vasprintf @@ -21,25 +25,95 @@ #include <systemd/sd-event.h> #include "Alsa-ApiHat.h" +#include <sys/ioctl.h> + +typedef struct _snd_ctl_ops { + int (*close)(snd_ctl_t *handle); + int (*nonblock)(snd_ctl_t *handle, int nonblock); + int (*async)(snd_ctl_t *handle, int sig, pid_t pid); + int (*subscribe_events)(snd_ctl_t *handle, int subscribe); + int (*card_info)(snd_ctl_t *handle, snd_ctl_card_info_t *info); + int (*element_list)(snd_ctl_t *handle, snd_ctl_elem_list_t *list); + int (*element_info)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_add)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_replace)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_remove)(snd_ctl_t *handle, snd_ctl_elem_id_t *id); + int (*element_read)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); + int (*element_write)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); + int (*element_lock)(snd_ctl_t *handle, snd_ctl_elem_id_t *lock); + int (*element_unlock)(snd_ctl_t *handle, snd_ctl_elem_id_t *unlock); + int (*element_tlv)(snd_ctl_t *handle, int op_flag, unsigned int numid, + unsigned int *tlv, unsigned int tlv_size); + int (*hwdep_next_device)(snd_ctl_t *handle, int *device); + int (*hwdep_info)(snd_ctl_t *handle, snd_hwdep_info_t * info); + int (*pcm_next_device)(snd_ctl_t *handle, int *device); + int (*pcm_info)(snd_ctl_t *handle, snd_pcm_info_t * info); + int (*pcm_prefer_subdevice)(snd_ctl_t *handle, int subdev); + int (*rawmidi_next_device)(snd_ctl_t *handle, int *device); + int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info); + int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev); + int (*set_power_state)(snd_ctl_t *handle, unsigned int state); + int (*get_power_state)(snd_ctl_t *handle, unsigned int *state); + int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event); + int (*poll_descriptors_count)(snd_ctl_t *handle); + int (*poll_descriptors)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space); + int (*poll_revents)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +} snd_ctl_ops_t; + +typedef struct private_snd_ctl { + void *open_func; + char *name; + snd_ctl_type_t type; + const snd_ctl_ops_t *ops; + void *private_data; + int nonblock; + int poll_fd; + void *async_handlers; +} private_snd_ctl_t; + +typedef struct { + int card; + int fd; + unsigned int protocol; +} snd_ctl_hw_t; + +static int snd_ctl_hw_elem_replace(snd_ctl_t *ctlDev, snd_ctl_elem_info_t *info, snd_ctl_elem_id_t *elemId) { + size_t len=snd_ctl_elem_info_sizeof(); + private_snd_ctl_t *handle= (private_snd_ctl_t*) ctlDev; + snd_ctl_hw_t *hw = handle->private_data; + + NOTICE ("count=%d ITEMNAME=%s writable=%d owner=%d", snd_ctl_elem_info_get_count(info), snd_ctl_elem_info_get_name(info) + , snd_ctl_elem_info_is_writable(info), snd_ctl_elem_info_get_owner(info)); + snd_ctl_elem_lock(ctlDev, elemId); + + int err= handle->ops->element_replace (ctlDev, info); + NOTICE ("count=%d ITEMNAME=%s writable=%d isowner=%d islocked=%d innactiv=%d", snd_ctl_elem_info_get_count(info), snd_ctl_elem_info_get_name(info) + , snd_ctl_elem_info_is_writable(info), snd_ctl_elem_info_is_owner(info), snd_ctl_elem_info_is_locked(info), snd_ctl_elem_info_is_inactive(info)); + return err; +} + + STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) { - int err; - json_object *jName, *jNumid, *jTmp; + int err, ctlExist; + json_object *jTmp; const char *ctlName; - int ctlNumid, ctlMax, ctlMin, ctlStep, ctlCount, ctlSubDev; + int ctlNumid, ctlMax, ctlMin, ctlStep, ctlCount, ctlSubDev, ctlSndDev; snd_ctl_elem_type_t ctlType; + snd_ctl_elem_id_t *elemId; snd_ctl_elem_info_t *elemInfo; - + snd_ctl_elem_value_t *elemValue; // parse json ctl object - json_object_object_get_ex (ctlJ, "name" , &jName); - json_object_object_get_ex (ctlJ, "numid", &jNumid); - if (!jName || !jNumid) { - afb_req_fail_f (request, "ctl-invalid", "crl=%s name/numid missing", json_object_to_json_string(ctlJ)); + json_object_object_get_ex (ctlJ, "name" , &jTmp); + if (!jTmp) { + afb_req_fail_f (request, "ctl-invalid", "crl=%s name missing", json_object_get_string(ctlJ)); goto OnErrorExit; - } + } + ctlName = json_object_get_string(jTmp); - ctlName = json_object_to_json_string(jName); - ctlNumid = json_object_get_int(jNumid); + // default value when not present => 0 + json_object_object_get_ex (ctlJ, "numid" , &jTmp); + ctlNumid = json_object_get_int(jTmp); // default for json_object_get_int is zero json_object_object_get_ex (ctlJ, "min" , &jTmp); @@ -57,32 +131,56 @@ STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) if (!jTmp) ctlCount=2; else ctlCount = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "snddev" , &jTmp); + ctlSndDev = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "subdev" , &jTmp); ctlSubDev = json_object_get_int(jTmp); json_object_object_get_ex (ctlJ, "type" , &jTmp); - if (!jTmp) ctlType=SND_CTL_ELEM_TYPE_INTEGER; + if (!jTmp) ctlType=SND_CTL_ELEM_TYPE_BOOLEAN; else ctlType = json_object_get_int(jTmp); - // set info event ID and get value + // Add requested ID into elemInfo snd_ctl_elem_info_alloca(&elemInfo); - snd_ctl_elem_info_set_name (elemInfo, ctlName); // map ctlInfo to ctlId elemInfo is updated !!! - snd_ctl_elem_info_set_numid(elemInfo, ctlNumid); // map ctlInfo to ctlId elemInfo is updated !!! + snd_ctl_elem_id_alloca(&elemId); + snd_ctl_elem_id_set_numid (elemId, ctlNumid); + snd_ctl_elem_id_set_name (elemId, ctlName); + snd_ctl_elem_id_set_interface(elemId, SND_CTL_ELEM_IFACE_HWDEP); + snd_ctl_elem_id_set_device(elemId, ctlSndDev); + snd_ctl_elem_id_set_subdevice(elemId, ctlSubDev); - if (snd_ctl_elem_info(ctlDev, elemInfo) >= 0) { - afb_req_fail_f (request, "ctl-already-exist", "crl=%s name/numid not unique", json_object_to_json_string(ctlJ)); - goto OnErrorExit; + // Assert that this ctls is not used + snd_ctl_elem_info_set_id (elemInfo, elemId); + ctlExist= !snd_ctl_elem_info(ctlDev, elemInfo); + if (ctlExist) { + NOTICE ("1:ctl exist ctlName=%s NUMID=%d NAME=%s", ctlName, snd_ctl_elem_info_get_numid(elemInfo), snd_ctl_elem_info_get_name(elemInfo)); + snd_ctl_elem_id_set_name (elemId, ctlName); + snd_ctl_elem_info_set_name (elemInfo, ctlName); + err= snd_ctl_hw_elem_replace (ctlDev, elemInfo, elemId); + if (err) { + NOTICE ("Fail changing ctlname error=%s", snd_strerror(err)); + } + NOTICE ("2:ctl exist ctlName=%s NUMID=%d NAME=%s", ctlName, snd_ctl_elem_info_get_numid(elemInfo), snd_ctl_elem_info_get_name(elemInfo)); } - - snd_ctl_elem_info_set_subdevice(elemInfo, ctlSubDev); - - switch (ctlType) { + + // try to normalise ctl name + snd_ctl_elem_value_alloca(&elemValue); + snd_ctl_elem_id_set_name (elemId, ctlName); + snd_ctl_elem_value_set_id(elemValue, elemId); + + if (!ctlExist) switch (ctlType) { case SND_CTL_ELEM_TYPE_BOOLEAN: err = snd_ctl_add_boolean_elem_set(ctlDev, elemInfo, 1, ctlCount); if (err) { - afb_req_fail_f (request, "ctl-invalid-bool", "crl=%s invalid boolean data", json_object_to_json_string(ctlJ)); + afb_req_fail_f (request, "ctl-invalid-bool", "devid=%s crl=%s invalid boolean data", snd_ctl_name(ctlDev), json_object_get_string(ctlJ)); goto OnErrorExit; } + + // Provide FALSE as default value + for (int idx=0; idx < ctlCount; idx ++) { + snd_ctl_elem_value_set_boolean (elemValue, idx, 0); + } break; case SND_CTL_ELEM_TYPE_INTEGER: @@ -98,9 +196,16 @@ STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) break; default: - afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_to_json_string(ctlJ)); + afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_get_string(ctlJ)); goto OnErrorExit; - } + } + + err = snd_ctl_elem_write (ctlDev, elemValue); + if (err < 0) { + afb_req_fail_f (request, "ctl-write-fail", "crl=%s fail to write data data", json_object_get_string(ctlJ)); + goto OnErrorExit; + } + return 0; @@ -122,7 +227,7 @@ PUBLIC void alsaAddCustomCtls(afb_req request) { } // open control interface for devid - err = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY); + err = snd_ctl_open(&ctlDev, devid, 0); if (err < 0) { afb_req_fail_f (request, "devid-unknown", "SndCard devid=[%s] Not Found err=%s", devid, snd_strerror(err)); goto OnErrorExit; @@ -141,14 +246,14 @@ PUBLIC void alsaAddCustomCtls(afb_req request) { break; case json_type_array: - for (int idx= 1; idx < json_object_array_length (ctlsJ); idx++) { + for (int idx= 0; idx < json_object_array_length (ctlsJ); idx++) { json_object *ctlJ = json_object_array_get_idx (ctlsJ, idx); addOneSndCtl(request, ctlDev, ctlJ) ; } break; default: - afb_req_fail_f (request, "ctls-invalid","ctls=%s not valid JSON array", json_object_to_json_string(ctlsJ)); + afb_req_fail_f (request, "ctls-invalid","ctls=%s not valid JSON array", json_object_get_string(ctlsJ)); goto OnErrorExit; } |