Ubuntu C-language sound peripheral programming - simple C example to read/write? - Page 1
Forum section: electronics / general

author: wb0gaz
author_rank: Frequent Contributor
timestamp: January 21, 2022, 03:48:03 pm
content: I have a need to read/write sound streams from the sound port (card, motherboard, USB, etc.) peripheral in Ubuntu linux distribution, using (strong preference) C language I can compile (from source.)The ideal solution would be something that would accept the sound peripheral identifier (for recording/input or playback/output) and related parameters (sample rate, bits/sample, etc.) on command line, then output a continuous stream of bytes to stdout (from the recording input), or accept a stream of bytes on stdin (to go to the playback output.) I realize the sample rate of audio is quite fixed, so presumably there would be modest buffering in the program, and it would be the responsibility of the (software, etc.) linked to stdin/stdout to maintain the required data rate, or accept overruns/dropouts as appropriate.The important requirements are that the code is in source form so it can be recompiled, and that it just emit or accept (either, doesn't need to do both at the same time, as two instances would be used for simultaneous recording and playback) audio stream using (ideally) stdin/stdout, or alternatively, a named pipe or something like that.This isn't intended as a media player or recorder (no files need be read or written), it just needs to work with live audio stream at the physical port of the PC.Any pointers to whether this has been solved/done or otherwise where I might get started?Thanks!

author: FlyingDutch
author_rank: Regular Contributor
timestamp: January 21, 2022, 04:28:40 pm
content: Hello,see audio-codecs (and streaming audio) in "FFMPEG" source code; Here is link to it's WWWpage:https://www.ffmpeg.org/documentation.htmlBest Regards

author: wb0gaz
author_rank: Frequent Contributor
timestamp: January 21, 2022, 04:30:22 pm
content: Thank you, FlyingDutch!I also found this while searching some morehttps://freedesktop.org/software/pulseaudio/doxygen/simple.htmlhttps://freedesktop.org/software/pulseaudio/doxygen/https://freedesktop.org/software/pulseaudio/doxygen/examples.html

author: PKTKS
author_rank: Super Contributor
timestamp: January 21, 2022, 05:36:39 pm
content: Well..I am not sure what level of knowledge you need...Butbuntusarestillbounded to *NIX (Linux) at least..(and besides all efforts made w/pulseaudio by POTTERIX himself)(which BTW pulseaudio is a piece of crap.. as well )and.. you already know in *NIXeverything is a file..so it is a plain trivial matter to open the file (ANY FILE!) over a FIFOor even better a named pipe... and redirect elsewhere...likeCode:mkfifo audio.wav && cat audio.wav | <whatever DSP>Obviously audio.wav like any file can be theport/dev/audio as wellas long as you do not name the pipe as the device ...of course...all file operators apply trivial like cat/tee .. on your sound devices..trivial and used daily in any DAW... mostly combined with a REAL TIMEtransport stream like JACK to route multi-channel named pipes...in doubt man mkfifoPaul

author: ve7xen
author_rank: Super Contributor
timestamp: January 21, 2022, 06:49:45 pm
content: If you want to send the audio in C, which is totally different than your 'preferred' pipe solution, thenPulseAudiois probably the way to go on modern Linux, it's almost always the default audio server. The simple API is pretty straightforward:Code:pa_simple *s;pa_sample_spec ss;ss.format = PA_SAMPLE_S16NE;ss.channels = 2;ss.rate = 44100;s = pa_simple_new(NULL, // Use the default server."Fooapp", // Our application's name.PA_STREAM_PLAYBACK,NULL, // Use the default device."Music", // Description of our stream.&ss, // Our sample format.NULL, // Use default channel mapNULL, // Use default buffering attributes.NULL, // Ignore error code.);Then you just call blocking pa_simple_write to send data. There's an async API too if you prefer.If you just want to use pipelines and stdin/out, you can use the `pacat` command. Trying to do this with realtime audio is probably not going to go super well.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 21, 2022, 07:17:13 pm
content: If you want exclusive access to a peripheral - servers like PulseAudio will potentially mix stuff from various sources - you can use ALSA. It's the most commonly available on Linux. It's not that hard to use - take a look at examples.https://www.alsa-project.org/alsa-doc/alsa-lib/examples.html

author: wb0gaz
author_rank: Frequent Contributor
timestamp: January 21, 2022, 08:09:13 pm
content: Thanks for the helpful ideas!I wandered into pulse audio and "pacat" and associated small programs.The binary in my Ubuntu 20.04 distribution is somewhat larger (about 3x larger) than the binary I build from source from pacat-simple.c, but it seems like a reasonable start. No particular objection to using Ubuntu.I hadn't considered at all the idea of piping directly to/from a device node...Anyway, it seems like pacat_simple.c and parec_simple.c are very close to what I had in mind (I'd not heard of those before), so I'm going to play with them a little and see if I can just do the microphone-to-speaker transfer (chaining pacat_simple into parec_simple.Thanks again for the helpful ideas and pointers,Dave

author: PKTKS
author_rank: Super Contributor
timestamp: January 22, 2022, 08:59:11 am
content: Anything needing REAL TIME DSP at the moment needs JACK...boils down to interfacing the ring buffersPaul

author: wb0gaz
author_rank: Frequent Contributor
timestamp: January 22, 2022, 01:30:03 pm
content: Thanks Paul -Does one install JACK (daemon, I remember of it but haven't encountered it in some time) used in lieu of Pulse Audio (that came with Ubuntu linux) or alongside Pulse Audio?I expect to use ring buffers sufficient to prevent underruns, but I haven't investigated the length/depth of the buffers needed to accomplish that.

author: PKTKS
author_rank: Super Contributor
timestamp: January 22, 2022, 01:53:25 pm
content: Quote from: wb0gaz on January 22, 2022, 01:30:03 pm2 cents of jambo...PulseAudio has a solely unique purpose of serving systemd panacea...It is absolutely useless (as systemd is as well.. ) and against all real time applications ..reason being is systemd doing ad hocs things (it should not) in the backgroundBoth can/should be removed in full without loosing any type of functionality and with a great (much much great) improvement in security for a dedicated DIGITAL SIGNAL PROCESSING machine...As systemd is deeply buried in the install embracing several dozens tools and compilation options.. it is mostly IMPOSSIBLE to be removed... but PulseAudio is a tiny useless applet that can be removed safely...Reason being is that the very same EGOtrip author of systemd is also the author of PulseAudio and both serve nothing for real in a DSP machine... the PulseAudio just completes systemd...A single safe SystemV init coupled with vanilla ALSA works 100 times fold better in any way...JACK is a very optimized REAL TIME daemon which should be run with a considerable criteria setup.. done to integrate JACK alongside all the DSP pipes available via LADSPA...It can handle several threads safely with a real time schedule almost flawless with proper setupI have done an exercise some years ago trying to integrate my instrument widget set with SIGROK and JACK and I was deeply surprised how damn well the JACK signal processor can handle data I/O of any kind for INSTRUMENTATION as well...wondering how high can raise frequency these days...The setup requires in the very first place to ditch systemd because that thing is a REAL TIME PIG... it was not designed for real time applets or even DSP machines at all.. it serves other way different reasons.. the EGOtrip of the author...Screenshot of my INSTRUMENTATION widgets integrated with JACK and SIGROK using a FULLY CAPABLE LADSPA Plugin console... it can be raised to almost 500kHz without changing a bit...It took me about a week to write that thing... just a toy.. amazingly well how it works.The applet was written in plain GTK tripple buffered (all instruments..) each instrument with a separate thread and each DSP with own thread as well...It can interface ANYTYPE of JACK device available in the system..SCOPE + DMM + FUNCTION GENERATOR... with LADSPA support..Paul

author: ve7xen
author_rank: Super Contributor
timestamp: January 24, 2022, 06:32:30 pm
content: You get off my lawn folks are insufferable.QuotePulseAudio and systemd are unrelated.QuoteIt serves a useful purpose, and its analogue exists on every popular OS.If you really hate it so much because of its connection to FDO or its developer(s), use pipewire, which doesn't change anything for implementing a client.I agree that for a dedicated signal processing machine, JACK is more appropriate, being designed for that purpose, but is that the case here? It wasn't really described that way, especially since OP wants to use UNIX pipes to pass audio around. Using JACK will make that audio interface basically unusable for normal audio purposes.Your rant doesn't help OP at all. If they want to run Ubuntu, trying to remove SystemD and PulseAudio is just a wild goose chase that will frustrate them and offer no useful benefit. You're proposing they basically replace their entire operating system in response to a simple question about audio I/O...QuoteIf you want to use JACK you will need to install it, and then make sure nothing else is using the audio device you intend to assign to JACK, as it takes exclusive control. Then you run the JACK daemon and bind it to the audio interface, and connect your clients to it. A management client like QJackCtl will help.It depends on your ultimate goal which approach is more appropriate. If you want something that can integrate with your normal system, and maybe be usable by others in the same scenario, use PA. If you want to write some signal processing for live audio or professional musicians, use JACK... or write a LADSPA plugin, which would be even more flexible.

author: PKTKS
author_rank: Super Contributor
timestamp: January 24, 2022, 06:44:18 pm
content: Quote from: ve7xen on January 24, 2022, 06:32:30 pm... In 2011 Poettering, one of the main developers of PulseAudio, ..https://en.wikipedia.org/wiki/Lennart_PoetteringThis folk made the whoooole thingy...Tried that a couple times.. for serious use... no way.My 6y old nephew uses a POTTERIX machine I made for him...I like thathe likes that..it is vanilla POTTERIX made by me.. for him to play games...Nothing will change the fact that systemd + Pulse are crap...And any JACK patch bay will make your life easier reallyalthough not necessary..Me using a POTTERIX machine.. unlikelyPaul

author: wb0gaz
author_rank: Frequent Contributor
timestamp: January 24, 2022, 06:44:49 pm
content: Thanks - progress...I am from the era of /etc/inittab, so I've not dealt with systemd either way and would rather not try to re-engineer that subsystem.I *have* used jackd (long ago, when it happened to be part of a linux distribution I was experimenting with) and would be fine using it, but learning curve would be from zero as I didn't try to use it as an API/Library back then.My question is this - should I remove pulse audio (sudo apt remove "something") then install jackd (sudo apt install jackd?)? To narrow down the OS environment - Ubuntu 20.04.3 LTS running on 64-bit X86 type machine; the OS install has nothing beyond whatever constitutes a "minimum install" plus build-essential.My application doesn't have a latency or jitter requirement or specification (it is not for music or entertainment).I will use a ring buffer as long (large) as is needed to avoid underrun conditions (think "buffering..." as the buffer fills to some set point before processing ensues).The output (or processed) byte count will exactly match the input (unprocessed) byte count, so for example if 1000 bytes of audio samples arrive from the microphone/line in connector, 1000 bytes of audio samples will go back out to the speaker/line out connector. I will need to use stereo (left/right) so I'll actually have two concurrent (and equal rate/format) sample streams arriving then departing. Between the input (mic/line in) and output (spk/line out) API interfaces (however my "C" application would talk to jackd's library calls) would be some as-yet undefined processing (at a minimum, it would just echo each sample received back out, so audio arriving at the microphone would, after whatever processing delay, be delivered to the attached speaker.Hope this helps better define the problem!Thanks again for suggestions/ideas and/or pointers to reference/reading material or (ideally) sample source code.

author: PKTKS
author_rank: Super Contributor
timestamp: January 24, 2022, 06:48:02 pm
content: Quote from: wb0gaz on January 24, 2022, 06:44:49 pmBy making a very simple setup you can achieve very HIGH REAL TIME performance of JACK...Just ditch everything you do not need to have all resources to JACK daemon...Your machine will do DSP like real dedicated ones..Been there several times.. have a boot setup myself for that..I love that... looking my old widgets performing so wellPaul

author: PKTKS
author_rank: Super Contributor
timestamp: January 24, 2022, 06:51:38 pm
content: Quote from: wb0gaz on January 24, 2022, 06:44:49 pmWELCOME !!!Grab yourself the whole thing..https://www.ladspa.org/Very good examples you can easily understand how to interface things..Paul

author: ve7xen
author_rank: Super Contributor
timestamp: January 24, 2022, 08:11:22 pm
content: Quote from: wb0gaz on January 24, 2022, 06:44:49 pmIf you remove Pulse from an Ubuntu system, you will basically break audio entirely, all the system audio depends on it. I don't recommend doing that unless you want to go down that particular unprodcutive rabbit hole, or if this will be a machine dedicated to live audio processing and you don't care about normal system audio.If you want to use JACK, I suggest you just stop Pulse while you are using it. I don't recall off the top of my head how Ubuntu starts PA, but `systemctl --user stop pulseaudio.service pulseaudio.socket` is probably sufficient to control it manually. You could also look into using `pasuspender` to automatically suspend PA while running jackd and restart it when you are done, I'm not sure if this tool is included in Ubuntu or not.I'd suggest starting with the simplest case, which would be either PulseAudio or ALSA (or your original pipeline idea), and if you find you need/want better realtime performance, you can add JACK later. The complication will just make development more cumbersome, IMO.

author: PKTKS
author_rank: Super Contributor
timestamp: January 24, 2022, 09:04:49 pm
content: yeah.. the POTTERIX thing is made to put everything under that..It is a whole crippled thing from ground to topYou can not remove systemd..You can not just use the plain ALSA like it should..You can not just put JACK to run with all those things running...Change your system.. and put proper things in place..My nephew loves POTTERIX.. I like to see him happy..But no chance in hell I will use that ...The JACK code contains the best examples available..Code:/** @file simple_client.c** @brief This simple client demonstrates the basic features of JACK* as they would be used by many applications.*/#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <signal.h>#ifndef WIN32#include <unistd.h>#endif#include <jack/jack.h>jack_port_t *output_port1, *output_port2;jack_client_t *client;#ifndef M_PI#define M_PI (3.14159265)#endif#define TABLE_SIZE (200)typedef struct{float sine;int left_phase;int right_phase;}paTestData;static void signal_handler(int sig){jack_client_close(client);fprintf(stderr, "signal received, exiting ...\n");exit(0);}/*** The process callback for this JACK application is called in a* special realtime thread once for each audio cycle.** This client follows a simple rule: when the JACK transport is* running, copy the input port to the output. When it stops, exit.*/intprocess (jack_nframes_t nframes, void *arg){jack_default_audio_sample_t *out1, *out2;paTestData *data = (paTestData*)arg;int i;out1 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port1, nframes);out2 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port2, nframes);for( i=0; i<nframes; i++ ){out1 = data->sine[data->left_phase]; /* left */out2 = data->sine[data->right_phase]; /* right */data->left_phase += 1;if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;data->right_phase += 3; /* higher pitch so we can distinguish left and right. */if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;}return 0;}/*** JACK calls this shutdown_callback if the server ever shuts down or* decides to disconnect the client.*/voidjack_shutdown (void *arg){exit (1);}intmain (int argc, char *argv[]){const char **ports;const char *client_name;const char *server_name = NULL;jack_options_t options = JackNullOption;jack_status_t status;paTestData data;int i;if (argc >= 2) {/* client name specified? */client_name = argv;if (argc >= 3) {/* server name specified? */server_name = argv;int my_option = JackNullOption | JackServerName;options = (jack_options_t)my_option;}} else {/* use basename of argv */client_name = strrchr(argv, '/');if (client_name == 0) {client_name = argv;} else {client_name++;}}for( i=0; i<TABLE_SIZE; i++ ){data.sine = 0.2 * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );}data.left_phase = data.right_phase = 0;/* open a client connection to the JACK server */client = jack_client_open (client_name, options, &status, server_name);if (client == NULL) {fprintf (stderr, "jack_client_open() failed, ""status = 0x%2.0x\n", status);if (status & JackServerFailed) {fprintf (stderr, "Unable to connect to JACK server\n");}exit (1);}if (status & JackServerStarted) {fprintf (stderr, "JACK server started\n");}if (status & JackNameNotUnique) {client_name = jack_get_client_name(client);fprintf (stderr, "unique name `%s' assigned\n", client_name);}/* tell the JACK server to call `process()' wheneverthere is work to be done.*/jack_set_process_callback (client, process, &data);/* tell the JACK server to call `jack_shutdown()' ifit ever shuts down, either entirely, or if itjust decides to stop calling us.*/jack_on_shutdown (client, jack_shutdown, 0);/* create two ports */output_port1 = jack_port_register (client, "output1",JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput, 0);output_port2 = jack_port_register (client, "output2",JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput, 0);if ((output_port1 == NULL) || (output_port2 == NULL)) {fprintf(stderr, "no more JACK ports available\n");exit (1);}/* Tell the JACK server that we are ready to roll. Our* process() callback will start running now. */if (jack_activate (client)) {fprintf (stderr, "cannot activate client");exit (1);}/* Connect the ports. You can't do this before the client is* activated, because we can't make connections to clients* that aren't running. Note the confusing (but necessary)* orientation of the driver backend ports: playback ports are* "input" to the backend, and capture ports are "output" from* it.*/ports = jack_get_ports (client, NULL, NULL,JackPortIsPhysical|JackPortIsInput);if (ports == NULL) {fprintf(stderr, "no physical playback ports\n");exit (1);}if (jack_connect (client, jack_port_name (output_port1), ports)) {fprintf (stderr, "cannot connect output ports\n");}if (jack_connect (client, jack_port_name (output_port2), ports)) {fprintf (stderr, "cannot connect output ports\n");}jack_free (ports);/* install a signal handler to properly quits jack client */#ifdef WIN32signal(SIGINT, signal_handler);signal(SIGABRT, signal_handler);signal(SIGTERM, signal_handler);#elsesignal(SIGQUIT, signal_handler);signal(SIGTERM, signal_handler);signal(SIGHUP, signal_handler);signal(SIGINT, signal_handler);#endif/* keep running until the Ctrl+C */while (1) {#ifdef WIN32Sleep(1000);#elsesleep (1);#endif}jack_client_close (client);exit (0);}API athttp://jackaudio.orgIt is just another level of things..BUNTUs POTTERIX and today RedHat thingys are NICHES..If you want serious things... just move on..Paul

author: ve7xen
author_rank: Super Contributor
timestamp: January 24, 2022, 09:25:29 pm
content: Quote from: PKTKS on January 24, 2022, 09:04:49 pmYou mean just like how running jackd will take exclusive control of the audio device? Any audio server will do this, because that's how the kernel's hardware API works.Can you please take your misplaced ideological opposition to Pulse and Systemd elsewhere? It is not helpful to OP to have you suggesting the most convoluted path for their task, just because you don't like the way that modern Linux does things.PulseAudio is the default audio framework for Linux machines today. Deal with it.QuoteYou can, the ALSA API will work just fine on a (properly set up) PulseAudio system. So use that if you want, but since it's a wrapper, it doesn't really offer any advantages.QuoteYou can use JACK as a backend for PulseAudio if you want. But this is just adding complication and for 99% of users has no benefit and several drawbacks. And of course, requires configuration and setup that is not helping OP achieve their rather simple goal of audio I/O on their existing system.QuoteNo. Any alternative is a niche. Mainstream Linux is systemd and PulseAudio, period.

author: PKTKS
author_rank: Super Contributor
timestamp: January 25, 2022, 08:52:11 am
content: Quote from: ve7xen on January 24, 2022, 09:25:29 pmI have seen this slightly different..LikeNo more good alternatives.Mainstream POTTERIX is the thing...And MS is no longer that mainstream thingoPaul

author: Bassman59
author_rank: Super Contributor
timestamp: January 25, 2022, 08:00:04 pm
content: Quote from: PKTKS on January 25, 2022, 08:52:11 amYou keep using that word.Nobody knows what the fuck you're on about.

author: PKTKS
author_rank: Super Contributor
timestamp: January 26, 2022, 09:24:45 am
content: Quote from: Bassman59 on January 25, 2022, 08:00:04 pmVery simple..The folk cited above (see wiki) is the author of systemd and pulse...He obviously created a whole new thing which diverts more and more from *nix..Each month a new feature which nobody's ever asked for is pushed into that his system.. freakshowHas gone so far that this new system which can no longer be called *nix receives his name.. kinda...POTTERIXHas gone way too far... the folk created a new thing which obviously veered off trying to mimic MS mainstream look feel..Kinda hype of IT darlings.I have seen this new system name on other discussions related to the serious problems caused by all those changes.. not new at allPaulPS> another interesting comment i have read about it is that POTTERIX is like Arduino for IT.. a newbie thinks that is great.. fantastic magic..Anything above ground zero requires a proper MCU or system...So POTTERIX is like Arduino..My 6y old nephew loves it and Arduino