> On Fri, Nov 22, 2024 at 10:34PM +0100, a...@caoua.org wrote: >> On Sat, Nov 16, 2024 at 09:59:32PM +0100, na...@poczta.fm wrote: >> Hi misc@, >> >> I noticed that GStreamer device monitor is not detecting any Audio/Source and Audio/Sink devices on different laptops running OpenBSD 7.6-stable and sndiod. The following command reports only the embedded web camera (Video/Source), whereas the expected output should also include at least one Audio/Source and one Audio/Sink: >> >> $ gst-device-monitor-1.0 >> >> This seems to be related to the following issue reported earlier in the context of Dino that relies on GStreamer as the selected backend: >> >> https://marc.info/?t=172654982900001&r=1&w=2 >> >> At the same time, I am able to record audio using the embedded microphone and gst-launch-1.0 in the following way: >> >> # sysctl kern.audio.record=1 >> $ gst-launch-1.0 -v sndiosrc ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=sndiosrc.ogg >> >> I wonder whether anyone else is also able to reproduce that issue, or perhaps already has identified an effective solution or workaround in that case? Any suggestions regarding further troubleshooting would of course be much appreciated. >> > > I'm able to reproduce the problem. > > It looks like the device enumeration is probably not implemented. If > so, there are just few lines missing from the sndio backend, they are > supposed to return the device "list" (a single SIO_DEVANY entry). > > After a quick look at the sources, it's not obvious how register a > "device provider" to expose the device. > >
Hi Alexandre, Thank you for your prompt reply. Following your suggestion, I analyzed the existing implementation of the ALSA plugin, and as a quick PoC, I have adapted its code to work in the sndio case --- it succesfully exposes just the default Source and Sink audio devices to applications relying on GStreamer. Please find the related code at the end of this message (hopefully it will not be mangled by the email client). What do you think? What I still need to figure out is how to enumerate all available Source/Sink sndio devices in the gst_sndio_device_provider_probe() function. Would you have any hints in that case? With best regards, Andrzej ================================================================================ --- gstsndio.c Sun Sep 1 06:43:36 2024 +++ gstsndio.c Sun Nov 24 22:07:59 2024 @@ -21,6 +21,7 @@ #include <stdio.h> #include "gstsndio.h" +#include "gstsndiodeviceprovider.h" GST_DEBUG_CATEGORY (gst_sndio_debug); #define GST_CAT_DEFAULT gst_sndio_debug @@ -33,6 +34,10 @@ { GST_DEBUG_CATEGORY_INIT (gst_sndio_debug, "sndio", 0, "sndio plugins"); + /* Register the corresponding device provider */ + if (!gst_device_provider_register (plugin, "sndiodeviceprovider", + GST_RANK_PRIMARY + 20, gst_sndio_device_provider_get_type())) + return FALSE; /* prefer sndiosrc over pulsesrc (GST_RANK_PRIMARY + 10) */ if (!gst_element_register (plugin, "sndiosrc", GST_RANK_PRIMARY + 20, gst_sndiosrc_get_type())) ================================================================================ gstsndiodeviceprovider.h: /* Based on the implementation of gstalsadeviceprovider.h available here: * https://github.com/GStreamer/gst-plugins-base/blob/master/ext/alsa/gstalsadeviceprovider.h * and documentation here: * https://gstreamer.freedesktop.org/documentation/gstreamer/gstdeviceprovider.html?gi-language=c * Original license included below. * * GStreamer * Copyright (C) 2018 Thibault Saunier <tsaun...@igalia.com> * * alsadeviceprovider.c: alsa device probing and monitoring * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __GST_SNDIODEVICEPROVIDER_H__ #define __GST_SNDIODEVICEPROVIDER_H__ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstsndio.h" #include <gst/gst.h> G_BEGIN_DECLS typedef struct _GstSndioDeviceProvider GstSndioDeviceProvider; typedef struct _GstSndioDeviceProviderClass GstSndioDeviceProviderClass; #define GST_TYPE_SNDIO_DEVICE_PROVIDER \ (gst_sndio_device_provider_get_type()) #define GST_IS_SNDIO_DEVICE_PROVIDER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SNDIO_DEVICE_PROVIDER)) #define GST_IS_SNDIO_DEVICE_PROVIDER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SNDIO_DEVICE_PROVIDER)) #define GST_SNDIO_DEVICE_PROVIDER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SNDIO_DEVICE_PROVIDER, \ GstSndioDeviceProviderClass)) #define GST_SNDIO_DEVICE_PROVIDER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SNDIO_DEVICE_PROVIDER, \ GstSndioDeviceProvider)) #define GST_SNDIO_DEVICE_PROVIDER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, \ GstSndioDeviceProviderClass)) #define GST_SNDIO_DEVICE_PROVIDER_CAST(obj) \ ((GstSndioDeviceProvider *)(obj)) struct _GstSndioDeviceProvider { GstDeviceProvider parent; }; struct _GstSndioDeviceProviderClass { GstDeviceProviderClass parent_class; }; GType gst_sndio_device_provider_get_type(void); typedef struct _GstSndioDevice GstSndioDevice; typedef struct _GstSndioDeviceClass GstSndioDeviceClass; #define GST_TYPE_SNDIO_DEVICE \ (gst_sndio_device_get_type()) #define GST_IS_SNDIO_DEVICE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SNDIO_DEVICE)) #define GST_IS_SNDIO_DEVICE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SNDIO_DEVICE)) #define GST_SNDIO_DEVICE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SNDIO_DEVICE, \ GstSndioDeviceClass)) #define GST_SNDIO_DEVICE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SNDIO_DEVICE, GstSndioDevice)) #define GST_SNDIO_DEVICE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstSndioDeviceClass)) #define GST_SNDIO_DEVICE_CAST(obj) \ ((GstSndioDevice *)(obj)) struct _GstSndioDevice { GstDevice parent; gint mode; gchar internal_name; const gchar element; }; struct _GstSndioDeviceClass { GstDeviceClass parent_class; }; GType gst_sndio_device_get_type(void); G_END_DECLS #endif /* __GST_SNDIODEVICEPROVIDER_H__ */ ================================================================================ gstsndiodeviceprovider.c: /* Based on the implementation of gstalsadeviceprovider.c available here: * https://github.com/GStreamer/gst-plugins-base/blob/master/ext/alsa/gstalsadeviceprovider.c * and documentation here: * https://gstreamer.freedesktop.org/documentation/gstreamer/gstdeviceprovider.html?gi-language=c * Original license included below. * * GStreamer * Copyright (C) 2018 Thibault Saunier <tsaun...@igalia.com> * * alsadeviceprovider.c: alsa device probing and monitoring * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstsndiodeviceprovider.h" #include "gstsndio.h" #include <gst/gst.h> #include <sndio.h> static GstDevice * gst_sndio_device_new( const gchar *device_name, GstCaps *caps, const gchar *internal_name, gint stream_mode, GstStructure *properties ); G_DEFINE_TYPE( GstSndioDeviceProvider, gst_sndio_device_provider, GST_TYPE_DEVICE_PROVIDER ); static GList * gst_sndio_device_provider_probe( GstDeviceProvider *provider ) { GList *list = NULL; gint i; gint stream_modes[] = { SIO_REC, SIO_PLAY }; GST_INFO_OBJECT( provider, "Probing sndio devices.." ); for ( i = 0; i < G_N_ELEMENTS( stream_modes ); i++ ) { struct gstsndio sio; GstDevice *device = NULL; GstStructure *properties = NULL; sio.device = g_strdup( SIO_DEVANY ); sio.mode = stream_modes[ i ]; if ( !gst_sndio_open( &sio, sio.mode ) ) { GST_INFO_OBJECT( provider, "Couldn't open sndio device" ); continue; } GST_DEBUG( "caps are %s", gst_caps_to_string( sio.cur_caps ) ); properties = gst_caps_get_structure( sio.cur_caps, 0 ); device = gst_sndio_device_new( sio.device, sio.cur_caps, sio.device, stream_modes[ i ], properties ); if ( device ) { list = g_list_prepend( list, device ); } gst_sndio_close( &sio ); } return list; } static void gst_sndio_device_provider_class_init( GstSndioDeviceProviderClass *klass ) { GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS( klass ); dm_class->probe = gst_sndio_device_provider_probe; gst_device_provider_class_set_static_metadata( dm_class, "Sndio Device Provider", "Sink/Source/Audio", "Lists and provides Sndio source and sink devices", " " ); } static void gst_sndio_device_provider_init( GstSndioDeviceProvider *self ) { } /*** GstSndioDevice implementation ******/ enum { PROP_INTERNAL_NAME = 1, }; G_DEFINE_TYPE( GstSndioDevice, gst_sndio_device, GST_TYPE_DEVICE ); static GstElement * gst_sndio_device_create_element( GstDevice *device, const gchar *name ) { GstSndioDevice *sndio_dev = GST_SNDIO_DEVICE( device ); GstElement *elem; elem = gst_element_factory_make( sndio_dev->element, name ); g_object_set( elem, "device", sndio_dev->internal_name, NULL ); return elem; } static gboolean gst_sndio_device_reconfigure_element( GstDevice *device, GstElement *element ) { GstSndioDevice *sndio_dev = GST_SNDIO_DEVICE( device ); g_object_set( element, "device", sndio_dev->internal_name, NULL ); return TRUE; } static void gst_sndio_device_get_property( GObject *object, guint prop_id, GValue *value, GParamSpec *pspec ) { GstSndioDevice *device; device = GST_SNDIO_DEVICE_CAST( object ); switch ( prop_id ) { case PROP_INTERNAL_NAME: g_value_set_string( value, device->internal_name ); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); break; } } static void gst_sndio_device_set_property( GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec ) { GstSndioDevice *device; device = GST_SNDIO_DEVICE_CAST( object ); switch ( prop_id ) { case PROP_INTERNAL_NAME: device->internal_name = g_value_dup_string( value ); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); break; } } static void gst_sndio_device_finalize( GObject *object ) { GstSndioDevice *device = GST_SNDIO_DEVICE( object ); g_free( device->internal_name ); G_OBJECT_CLASS( gst_sndio_device_parent_class )->finalize( object ); } static void gst_sndio_device_class_init( GstSndioDeviceClass *klass ) { GstDeviceClass *dev_class = GST_DEVICE_CLASS( klass ); GObjectClass *object_class = G_OBJECT_CLASS( klass ); dev_class->create_element = gst_sndio_device_create_element; dev_class->reconfigure_element = gst_sndio_device_reconfigure_element; object_class->get_property = gst_sndio_device_get_property; object_class->set_property = gst_sndio_device_set_property; object_class->finalize = gst_sndio_device_finalize; g_object_class_install_property( object_class, PROP_INTERNAL_NAME, g_param_spec_string( "internal-name", "Internal SndioAudio device name", "The internal name of the SndioAudio device", "", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ) ); } static void gst_sndio_device_init( GstSndioDevice *device ) { } /* Takes ownership of @caps and @props */ static GstDevice * gst_sndio_device_new( const gchar *device_name, GstCaps *caps, const gchar *internal_name, gint stream_mode, GstStructure *props ) { GstSndioDevice *gstdev; const gchar *element = NULL; const gchar *klass = NULL; g_return_val_if_fail( device_name, NULL ); g_return_val_if_fail( internal_name, NULL ); g_return_val_if_fail( caps, NULL ); switch ( stream_mode ) { case SIO_REC: element = "sndiosrc"; klass = "Audio/Source"; break; case SIO_PLAY: element = "sndiosink"; klass = "Audio/Sink"; break; default: g_assert_not_reached(); break; } gstdev = g_object_new( GST_TYPE_SNDIO_DEVICE, "display-name", device_name, "caps", caps, "device-class", klass, "internal-name", internal_name, "properties", props, NULL ); gstdev->mode = stream_mode; gstdev->element = element; return GST_DEVICE( gstdev ); } ================================================================================