]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
ctl: card: add an API to add/replace user-defined elements
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 18 Nov 2019 04:22:44 +0000 (13:22 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 12 Dec 2019 05:29:12 +0000 (14:29 +0900)
src/ctl/alsactl.map
src/ctl/card.c
src/ctl/card.h
tests/alsactl-card

index 44585d66a0d1f4e158fcc8e6fc5876425e353089..1a5637d81edb47fe9e79988009e29054f4d451a8 100644 (file)
@@ -21,6 +21,8 @@ ALSA_GOBJECT_0_0_0 {
     "alsactl_card_write_elem_tlv";
     "alsactl_card_read_elem_tlv";
     "alsactl_card_command_elem_tlv";
+    "alsactl_card_add_elems";
+    "alsactl_card_replace_elems";
 
     "alsactl_card_info_get_type";
 
index e0b47742a5fe2918a7e69cbd006c6f55b9e92a79..94b474178af7e73ebdcd4deea261e14274d93cbc 100644 (file)
@@ -478,3 +478,137 @@ void alsactl_card_command_elem_tlv(ALSACtlCard *self,
 
     g_free(packet);
 }
+
+static int prepare_enum_names(struct snd_ctl_elem_info *info, const gchar **labels)
+{
+    unsigned int count;
+    unsigned int length;
+    char *pos;
+
+    for (count = 0; labels[count] != NULL; ++count) {
+        const gchar *label = labels[count];
+
+        if (strlen(label) >= 64)
+            return -EINVAL;
+
+        length += strlen(label) + 1;
+    }
+
+    if (length > 64 * 1024)
+        return -EINVAL;
+
+    pos = g_malloc0(length);
+    if (pos == NULL)
+        return -ENOMEM;
+    info->value.enumerated.names_ptr = (__u64)pos;
+    info->value.enumerated.names_length = length;
+
+    for (count = 0; labels[count] != NULL; ++count) {
+        const gchar *label = labels[count];
+        strcpy(pos, label);
+        pos[strlen(label)] = '\0';
+        pos += strlen(label) + 1;
+    }
+    info->value.enumerated.items = count;
+
+    return 0;
+}
+
+static void add_or_replace_elems(int fd, const ALSACtlElemId *elem_id,
+                                 guint elem_count, ALSACtlElemInfo *elem_info,
+                                 gboolean replace, GList **entries,
+                                 GError **error)
+{
+    struct snd_ctl_elem_info *info;
+    long request;
+    int i;
+
+    ctl_elem_info_refer_private(elem_info, &info);
+
+    info->id = *elem_id;
+
+    if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+        const gchar **labels;
+        int err;
+
+        g_object_get(elem_info, "labels", &labels, NULL);
+        err = prepare_enum_names(info, labels);
+        g_strfreev((gchar **)labels);
+        if (err < 0) {
+            generate_error(error, -err);
+            return;
+        }
+    }
+
+    if (!replace)
+        request = SNDRV_CTL_IOCTL_ELEM_ADD;
+    else
+        request = SNDRV_CTL_IOCTL_ELEM_REPLACE;
+
+    info->owner = (__kernel_pid_t)elem_count;
+    if (ioctl(fd, request, info) < 0)
+        generate_error(error, errno);
+    g_free((void *)info->value.enumerated.names_ptr);
+    if (*error != NULL)
+        return;
+
+    for (i = 0; i < elem_count; ++i) {
+        ALSACtlElemId *entry = g_boxed_copy(ALSACTL_TYPE_ELEM_ID, &info->id);
+        *entries = g_list_append(*entries, (gpointer)entry);
+
+        ++info->id.numid;
+        ++info->id.index;
+    }
+}
+
+/**
+ * alsactl_card_add_elems:
+ * @self: A #ALSACtlCard.
+ * @elem_id: A #ALSACtlElemId.
+ * @elem_count: The number of elements going to be added.
+ * @elem_info: A %ALSACtlElemInfo.
+ * @entries: (element-type ALSACtl.ElemId)(out): The list of added element IDs.
+ * @error: A #GError.
+ *
+ * Add user-defined elements.
+ */
+void alsactl_card_add_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
+                            guint elem_count, ALSACtlElemInfo *elem_info,
+                            GList **entries, GError **error)
+{
+    ALSACtlCardPrivate *priv;
+
+    g_return_if_fail(ALSACTL_IS_CARD(self));
+    g_return_if_fail(elem_id != NULL);
+    g_return_if_fail(ALSACTL_IS_ELEM_INFO(elem_info));
+    priv = alsactl_card_get_instance_private(self);
+
+    add_or_replace_elems(priv->fd, elem_id, elem_count, elem_info, FALSE,
+                         entries, error);
+}
+
+/**
+ * alsactl_card_replace_elems:
+ * @self: A #ALSACtlCard.
+ * @elem_id: A #ALSACtlElemId.
+ * @elem_count: The number of elements going to be added.
+ * @elem_info: A %ALSACtlElemInfo.
+ * @entries: (element-type ALSACtl.ElemId)(out): The list of renewed element IDs.
+ * @error: A #GError.
+ *
+ * Add user-defined elements instead of given elements.
+ */
+void alsactl_card_replace_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
+                            guint elem_count, ALSACtlElemInfo *elem_info,
+                            GList **entries, GError **error)
+{
+    ALSACtlCardPrivate *priv;
+
+    g_return_if_fail(ALSACTL_IS_CARD(self));
+    g_return_if_fail(elem_id != NULL);
+    g_return_if_fail(ALSACTL_IS_ELEM_INFO(elem_info));
+    priv = alsactl_card_get_instance_private(self);
+
+    add_or_replace_elems(priv->fd, elem_id, elem_count, elem_info, TRUE,
+                         entries, error);
+}
index c4c56818c15a748f93f6230984d370526243d164..171ff8cf096801bb3dd537ee397e6e9588a57a21 100644 (file)
@@ -77,6 +77,13 @@ void alsactl_card_command_elem_tlv(ALSACtlCard *self,
                             gint32 *const *container, gsize *container_count,
                             GError **error);
 
+void alsactl_card_add_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
+                            guint elem_count, ALSACtlElemInfo *elem_info,
+                            GList **entries, GError **error);
+void alsactl_card_replace_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
+                            guint elem_count, ALSACtlElemInfo *elem_info,
+                            GList **entries, GError **error);
+
 G_END_DECLS
 
 #endif
index 83b93ee6065c99d1dc239e50d39086c0c843e200..8c6a6643a0de3c085d197e9f7a827b08c845ceb5 100644 (file)
@@ -23,6 +23,8 @@ methods = (
     'write_elem_tlv',
     'read_elem_tlv',
     'command_elem_tlv',
+    'add_elems',
+    'replace_elems',
 )
 signals = ()