From: Takashi Sakamoto Date: Fri, 3 Jun 2022 03:36:48 +0000 (+0900) Subject: hwdep: device-common: add interface for common feature of ALSA HwDep device X-Git-Tag: v0.3.0~105 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=326a613748f3611787420e5a35c96a970d7bac38;p=alsa-gobject.git hwdep: device-common: add interface for common feature of ALSA HwDep device The protocol in ALSA HwDep character device has common feature. It's suitable for userspace implementation to have GObject interface for such features. This commit adds the interface. The implementation of interface should have four methods; open, get_protocol_version, get_device_info, and create_source. Additionally, it should emit handle-disconnection signal when detecting ENODEV error in the interation of source. It requires to notify userspace application since the application should release character device immediately. Signed-off-by: Takashi Sakamoto --- diff --git a/src/hwdep/alsahwdep.h b/src/hwdep/alsahwdep.h index cd2c2da..4791256 100644 --- a/src/hwdep/alsahwdep.h +++ b/src/hwdep/alsahwdep.h @@ -12,6 +12,8 @@ #include +#include + #include #endif diff --git a/src/hwdep/alsahwdep.map b/src/hwdep/alsahwdep.map index 973ed80..a37cca4 100644 --- a/src/hwdep/alsahwdep.map +++ b/src/hwdep/alsahwdep.map @@ -13,4 +13,10 @@ ALSA_GOBJECT_0_3_0 { "alsahwdep_get_hwdep_sysname"; "alsahwdep_get_hwdep_devnode"; "alsahwdep_get_device_info"; + + "alsahwdep_device_common_get_type"; + "alsahwdep_device_common_open"; + "alsahwdep_device_common_get_protocol_version"; + "alsahwdep_device_common_get_device_info"; + "alsahwdep_device_common_create_source"; } ALSA_GOBJECT_0_0_0; diff --git a/src/hwdep/device-common.c b/src/hwdep/device-common.c new file mode 100644 index 0000000..d6f9f75 --- /dev/null +++ b/src/hwdep/device-common.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +#include "privates.h" + +/** + * ALSAHwdepDeviceCommon: + * An interface to express common features of ALSA HwDep device. + * + * A [iface@DeviceCommon] should be implemented by any type of ALSA HwDep device. + * + * Since: 0.3. + */ + +static void alsahwdep_device_common_default_init(ALSAHwdepDeviceCommonInterface *iface); + +G_DEFINE_INTERFACE(ALSAHwdepDeviceCommon, alsahwdep_device_common, G_TYPE_OBJECT) + +static void alsahwdep_device_common_default_init(ALSAHwdepDeviceCommonInterface *iface) +{ + /** + * ALSAHwdepDeviceCommon::handle-disconnection: + * @self: A [iface@DeviceCommon]. + * + * Emitted when the sound card is not available anymore due to unbinding driver or hot + * unplugging. The owner of the object should prepare to call [method@GObject.Object.unref] + * so that ALSA HwDep character device is going to be closed and sound card is released. + */ + g_signal_new("handle-disconnection", + G_TYPE_FROM_INTERFACE(iface), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(ALSAHwdepDeviceCommonInterface, handle_disconnection), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, G_TYPE_NONE, 0); +} + +/** + * alsahwdep_device_common_open: + * @self: A [iface@DeviceCommon]. + * @card_id: The numeric identifier of sound card. + * @device_id: The numerid identifier of device. + * @open_flag: The flag of `open(2)` system call. + * @error: A [struct@GLib.Error]. + * + * Open one of ALSA hwdep character devices for the sound card. + * + * The call of function is expected to execute `open(2)` system call for ALSA hwdep character + * device. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ +gboolean alsahwdep_device_common_open(ALSAHwdepDeviceCommon *self, guint card_id, guint device_id, + gint open_flag, GError **error) +{ + char *devname; + gboolean result; + + g_return_val_if_fail(ALSAHWDEP_IS_DEVICE_COMMON(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + if (!alsahwdep_get_hwdep_devnode(card_id, device_id, &devname, error)) + return FALSE; + + result = ALSAHWDEP_DEVICE_COMMON_GET_IFACE(self)->open(self, devname, open_flag, error); + g_free(devname); + + return result; +} + +/** + * alsahwdep_device_common_get_protocol_version: + * @self: A [iface@DeviceCommon]. + * @proto_ver_triplet: (array fixed-size=3) (inout) (transfer none): The version of protocol used + * currently. + * @error: A [struct@GLib.Error]. + * + * Get the version of hwdep protocol used currently. The version is expressed as the array with + * three elements; major, minor, and micro version in the order. The length of major version is + * 16 bit, the length of minor and micro version is 8 bit each. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ +gboolean alsahwdep_device_common_get_protocol_version(ALSAHwdepDeviceCommon *self, + guint16 *const proto_ver_triplet[3], + GError **error) +{ + g_return_val_if_fail(ALSAHWDEP_IS_DEVICE_COMMON(self), FALSE); + g_return_val_if_fail(proto_ver_triplet != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + return ALSAHWDEP_DEVICE_COMMON_GET_IFACE(self)->get_protocol_version(self, proto_ver_triplet, + error); +} + +/** + * alsahwdep_device_common_get_device_info: + * @self: A [iface@DeviceCommon]. + * @device_info: (out): The information of device. + * @error: A [struct@GLib.Error]. + * + * Get the information according to given numeric IDs for card and device. The call of function is + * expected to executes `ioctl(2)` system call with `SNDRV_CTL_IOCTL_HWDEP_INFO` command to the + * character device. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ +gboolean alsahwdep_device_common_get_device_info(ALSAHwdepDeviceCommon *self, + ALSAHwdepDeviceInfo **device_info, GError **error) +{ + g_return_val_if_fail(ALSAHWDEP_IS_DEVICE_COMMON(self), FALSE); + g_return_val_if_fail(device_info != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + return ALSAHWDEP_DEVICE_COMMON_GET_IFACE(self)->get_device_info(self, device_info, error); +} + +/** + * alsahwdep_device_common_create_source: + * @self: A [iface@DeviceCommon]. + * @source: (out): A [struct@GLib.Source] to handle events from ALSA hwdep character device. + * @error: A [struct@GLib.Error]. + * + * Allocate [struct@GLib.Source] structure to handle events from ALSA hwdep character device. In + * each iteration of [struct@GLib.MainContext], the `read(2)` system call is executed to dispatch + * hwdep event, according to the result of `poll(2)` system call. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ +gboolean alsahwdep_device_common_create_source(ALSAHwdepDeviceCommon *self, GSource **source, + GError **error) +{ + g_return_val_if_fail(ALSAHWDEP_IS_DEVICE_COMMON(self), FALSE); + g_return_val_if_fail(source != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + return ALSAHWDEP_DEVICE_COMMON_GET_IFACE(self)->create_source(self, source, error); +} diff --git a/src/hwdep/device-common.h b/src/hwdep/device-common.h new file mode 100644 index 0000000..247f419 --- /dev/null +++ b/src/hwdep/device-common.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +#ifndef __ALSA_GOBJECT_ALSAHWDEP_DEVICE_COMMON_H__ +#define __ALSA_GOBJECT_ALSAHWDEP_DEVICE_COMMON_H__ + +#include + +G_BEGIN_DECLS + +#define ALSAHWDEP_TYPE_DEVICE_COMMON (alsahwdep_device_common_get_type()) + +G_DECLARE_INTERFACE(ALSAHwdepDeviceCommon, alsahwdep_device_common, ALSAHWDEP, DEVICE_COMMON, GObject) + +struct _ALSAHwdepDeviceCommonInterface { + GTypeInterface parent_iface; + + /** + * ALSAHwdepDeviceCommonInterface::open: + * @self: A [iface@DeviceCommon]. + * @path: The path to special file for ALSA HwDep character device. + * @open_flag: The flag of `open(2)` system call. + * @error: A [struct@GLib.Error]. + * + * Open one of ALSA hwdep character devices for the sound card. + * + * The call of function is expected to execute `open(2)` system call for ALSA hwdep character + * device. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ + gboolean (*open)(ALSAHwdepDeviceCommon *self, const gchar *path, gint open_flag, GError **error); + + /** + * ALSAHwdepDeviceCommonInterface::get_protocol_version: + * @self: A [iface@DeviceCommon]. + * @proto_ver_triplet: (array fixed-size=3) (inout) (transfer none): The version of protocol + * used currently. + * @error: A [struct@GLib.Error]. + * + * Virtual function to retrieve the version of hwdep protocol used currently. The version is + * expressed as the array with three elements; major, minor, and micro version in the order. + * The length of major version is 16 bit, the length of minor and micro version is 8 bit each. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ + gboolean (*get_protocol_version)(ALSAHwdepDeviceCommon *self, guint16 *const proto_ver_triplet[3], + GError **error); + + /** + * ALSAHwdepDeviceCommonInterface::get_device_info: + * @self: A [iface@DeviceCommon]. + * @device_info: (out): The information of device. + * @error: A [struct@GLib.Error]. + * + * Get the information according to given numeric IDs for card and device. The call of function is + * expected to executes `ioctl(2)` system call with `SNDRV_CTL_IOCTL_HWDEP_INFO` command to the + * character device. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ + gboolean (*get_device_info)(ALSAHwdepDeviceCommon *self, ALSAHwdepDeviceInfo **device_info, + GError **error); + + /** + * ALSAHwdepDeviceCommonInterface::create_source: + * @self: A [iface@DeviceCommon]. + * @source: (out): A [struct@GLib.Source] to handle events from ALSA hwdep character device. + * @error: A [struct@GLib.Error]. + * + * Allocate [struct@GLib.Source] structure to handle events from ALSA hwdep character device. In + * each iteration of [struct@GLib.MainContext], the `read(2)` system call is executed to dispatch + * hwdep event, according to the result of `poll(2)` system call. + * + * Returns: %TRUE when the overall operation finishes successfully, else %FALSE. + */ + gboolean (*create_source)(ALSAHwdepDeviceCommon *self, GSource **source, GError **error); + + /** + * ALSAHwdepDeviceCommonInterface::handle_disconnection: + * @self: A [iface@DeviceCommon]. + * + * Closure for the [signal@DeviceCommon::handle-disconnection] signal. + */ + void (*handle_disconnection)(ALSAHwdepDeviceCommon *self); +}; + +gboolean alsahwdep_device_common_open(ALSAHwdepDeviceCommon *self, guint card_id, guint device_id, + gint open_flag, GError **error); + +gboolean alsahwdep_device_common_get_protocol_version(ALSAHwdepDeviceCommon *self, + guint16 *const proto_ver_triplet[3], + GError **error); + +gboolean alsahwdep_device_common_get_device_info(ALSAHwdepDeviceCommon *self, + ALSAHwdepDeviceInfo **device_info, GError **error); + +gboolean alsahwdep_device_common_create_source(ALSAHwdepDeviceCommon *self, GSource **source, + GError **error); +G_END_DECLS + +#endif diff --git a/src/hwdep/meson.build b/src/hwdep/meson.build index 5a90533..0c43221 100644 --- a/src/hwdep/meson.build +++ b/src/hwdep/meson.build @@ -11,11 +11,13 @@ has_marshaller = false sources = files( 'query.c', 'device-info.c', + 'device-common.c', ) headers = files( 'query.h', 'device-info.h', + 'device-common.h', ) privates = files(