Finding all the devices I can use to play PCM with ALSA - linux

I use ALSA to play PCM samples. I open the PCM stream with this function:
int snd_pcm_open(snd_pcm_t** pcmp,
const char* name,
snd_pcm_stream_t stream,
int mode);
I'm currently using "default" as the name parameter. I would like to be able to choose other devices. What I cannot understand is how I can determine what are the names of the other available devices.
I attached a USB microphone to my system and aplay and amixer seems to detect the new device. How do I determine the name of that device? Is there any ALSA function to get a list of available devices with their respective names?

I think you can use snd_device_name_hint for enumerating devices.
Here is an example. Beware that I haven't compiled it !
char **hints;
/* Enumerate sound devices */
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
if (err != 0)
return;//Error! Just return
char** n = hints;
while (*n != NULL) {
char *name = snd_device_name_get_hint(*n, "NAME");
if (name != NULL && 0 != strcmp("null", name)) {
//Copy name to another buffer and then free it
free(name);
}
n++;
}//End of while
//Free hint buffer too
snd_device_name_free_hint((void**)hints);

It was my first requirements to a linux/unix projects where I need to know about all of the available audio devices capability and name. Then I need to use these devices to capture and plaback the audio. What I have done is pretty simple. There is a linux/unix command which is used to find the devices through alsa utility in linux.
It is:
aplay -l
Now what I did is just make a programme to give the out as like as this by alsa.
For everyone's help I have made a (.so) library and a sample Application demonstrating the use of this library in c++.
The output of my library is like-
[root#~]# ./IdeaAudioEngineTest
HDA Intel plughw:0,0
HDA Intel plughw:0,2
USB Audio Device plughw:1,0
This library can also capture and playback the real-time audio data.
It is available with documentation in IdeaAudio library with Duplex Alsa Audio

Just for grins, your program reformatted:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
void listdev(char *devname)
{
char** hints;
int err;
char** n;
char* name;
char* desc;
char* ioid;
/* Enumerate sound devices */
err = snd_device_name_hint(-1, devname, (void***)&hints);
if (err != 0) {
fprintf(stderr, "*** Cannot get device names\n");
exit(1);
}
n = hints;
while (*n != NULL) {
name = snd_device_name_get_hint(*n, "NAME");
desc = snd_device_name_get_hint(*n, "DESC");
ioid = snd_device_name_get_hint(*n, "IOID");
printf("Name of device: %s\n", name);
printf("Description of device: %s\n", desc);
printf("I/O type of device: %s\n", ioid);
printf("\n");
if (name && strcmp("null", name)) free(name);
if (desc && strcmp("null", desc)) free(desc);
if (ioid && strcmp("null", ioid)) free(ioid);
n++;
}
//Free hint buffer too
snd_device_name_free_hint((void**)hints);
}
int main(void)
{
printf("PCM devices:\n");
printf("\n");
listdev("pcm");
printf("MIDI devices:\n");
printf("\n");
listdev("rawmidi");
return 0;
}

Related

I cannot send data to my Arduino through usb serial connection

So, I have an arduino uno R3 SMD edition and I want to send commands to it while it's running. It has an adafruit v2 motor shield connected to it, which is powered separately from the arduino. The arduino is connected to my laptop by a usb cable.
Now, the motor shield works and I can send code to the arduino to make it do things. I can't get the arduino to receive anything I send to it while it's running from the serial connection though. I can print to the monitor in the arduino ide from arduino code though. I'm on debian linux stretch btw. My arduino ide is from the debian repos.
Here is all the code I'm trying to use:
Arduino Code
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
void setup()
{
Serial.begin(115200);
AFMS.begin();
myMotor->setSpeed(300);
}
char input;
int dir;
void loop()
{
dir = 0;
if (Serial.available() > 0) {
input = Serial.read();
Serial.print(input);
if (input == 1) {
dir = FORWARD;
}
if (input == 2) {
dir = BACKWARD;
}
}
if (dir != 0) {
myMotor->step(360, dir, DOUBLE);
delay(1000);
}
}
Controller Code on Laptop
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
FILE *arduino;
int c;
arduino = fopen("/dev/ttyACM0", "w");
if (arduino == NULL) {
fprintf(stdout, "NOOOOOOOOOOOO\n");
}
while (1) {
c = fgetc(stdin);
if (c == 'f') {
fprintf(arduino, "%d", 1);
}
if (c == 'b') {
fprintf(arduino, "%d", 2);
}
fflush(arduino);
if (c == 'q') {
break;
}
}
return 0;
}
I'm pretty sure this isn't a permissions problem, I've run the controller code from root and the tty device opens fine. Also, I've tried both 9600 and 115200 for my baud rate, but no dice. Does anyone have an idea? From googling it really seems like this is all anyone else is doing.
Your controller is sending characters '1' and '2'. Your Arduino is checking for character codes 1 and 2 - in other words, the characters CtrlA and CtrlB. You can make the change at either end, they just need to match.

Transmitting binary data throught ttyACM

Good afternoon,
I have a peripheral device which communicates over usb over virtual serial port. Everything works well under Windows with generic ACM serial driver, for example with: https://www.kernel.org/doc/Documentation/usb/linux-cdc-acm.inf
Under Linux, it uses CDC ACM drivers. Everything in sys logs seems to work ok, but communication is behaving strangely. When I connect the device, about 10 bytes at the begining of communication are lost. Next, just each second command is received ok.
My questions are:
1) Communication protocol of this device doesn't use ASCII, it is binary (it can randomly contain control characters etc...). Should I use stty for configuring just speed, data bits, stop bits and parity, or something more is necessary to be set up for binary communication? (To ignore control bits in kernel and transmit every byte - raw data.)
2) Any idea, how to test if linux ACM drivers works properly, or which another drivers should i try for my CDC ACM device?
Thanks for any idea!
Linux will often mangle things like line-ending characters (0x0A and 0x0D) when you try to send them over a serial port, which can cause issues if they are actually binary data and not intended as line-ending characters.
Here is a snippet from Pololu that shows how to configure your serial port correctly and then send and receive a few bytes. Pay attention to the part that calls tcsetattr in particular.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#ifdef _WIN32
#define O_NOCTTY 0
#else
#include <termios.h>
#endif
// Gets the position of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
int maestroGetPosition(int fd, unsigned char channel)
{
unsigned char command[] = {0x90, channel};
if(write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
unsigned char response[2];
if(read(fd,response,2) != 2)
{
perror("error reading");
return -1;
}
return response[0] + 256*response[1];
}
// Sets the target of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
// The units of 'target' are quarter-microseconds.
int maestroSetTarget(int fd, unsigned char channel, unsigned short target)
{
unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F};
if (write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
return 0;
}
int main()
{
const char * device = "/dev/ttyACM0"; // Linux
int fd = open(device, O_RDWR | O_NOCTTY);
if (fd == -1)
{
perror(device);
return 1;
}
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#else
struct termios options;
tcgetattr(fd, &options);
options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tcsetattr(fd, TCSANOW, &options);
#endif
int position = maestroGetPosition(fd, 0);
printf("Current position is %d.\n", position);
int target = (position < 6000) ? 7000 : 5000;
printf("Setting target to %d (%d us).\n", target, target/4);
maestroSetTarget(fd, 0, target);
close(fd);
return 0;
}
You might be able to do the same thing with the stty command line utility.

Headphone or mic detection connected via 3.5 mm jack linux

I have written a small program that informs when any headphone or mic is connected or not.
I provide a file path to identify, is there any way to know through a C program which file path is for mic or headphone?
Here is the program:
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
int fd = -1;
char name[256]= {'\0'};
struct input_event event;
/*On my system
/dev/input/event6 for headphone
/dev/input/event5 for mic
*/
if ((fd = open("/dev/input/event6", O_RDONLY)) < 0) {
perror("evdev open");
exit(1);
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
perror("evdev ioctl");
}
printf("The device name on path %s is === %s\n Now Plug in or Plug out the device\n",
argv[1],name);
// while(1)
{
read(fd, &event, sizeof(struct input_event));
printf("Event type is %d\n", event.type);
printf("Event code is %d\n", event.code);
printf("Event value is %d\n", event.value);
}
close(fd);
return 0;
}
Here i need to provide path in open, I want my program should identify the path of the mic or headphone. Is there anyway to do this?
It would be great to have some help.
thanks,

USB device detection - Windows & Linux (FT232R)

How can I enumerate and identify (get pid, vid and serial) FT232R chips in windows and linux. I need to:
1. at start of program enumerate already plugged devices
2. detect plugging of usb device
3. get PID, VID, Serial
And I need to do that in windows and linux. I know there is libusb for windows as well as for linux, but I don't have that much experience with USB. Code example would be best.
You should use SetupAPIs in Windows for getting device information like hardware id(contains vid and pid both) and to detect the plugging/unplugging see example in this link
Registering for Device Notification
To use SetupAPI you can use below code as reference and add/modify according to your requirement.
#include "stdafx.h"
#include <stdlib.h>
#include <Windows.h>
// Link to setapi.lib
#include <setupapi.h>
void GetDeviceInfo()
{
GUID gUSBGuid;
DWORD ClassGuidListSize = 1;
DWORD RequiredSize = NULL;
//if device shown under "USB" node in Devmgr, else see inf for classname
BOOL bres = SetupDiClassGuidsFromName((PCTSTR)"USB",
&gUSBGuid,//GUID will get populated
ClassGuidListSize,
&RequiredSize);
HDEVINFO hDevInfo = SetupDiGetClassDevs(&gUSBGuid,NULL,NULL,DIGCF_PRESENT);
if (INVALID_HANDLE_VALUE != hDevInfo)
{
BOOL bResult = FALSE;
SP_DEVICE_INTERFACE_DATA tDeviceInterfaceData;
tDeviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
for (int nMemberIndex = 0; TRUE ; nMemberIndex++)
{
SP_DEVINFO_DATA tSpDevInfoData;
tSpDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
//Get the tSpDevInfoData for the instance ID
bResult = SetupDiEnumDeviceInfo(hDevInfo,nMemberIndex,&tSpDevInfoData);
if(bResult)
{
TCHAR *szHardwareId = new TCHAR[128] ;
DWORD dwtype = REG_SZ;
SetupDiGetDeviceRegistryProperty(hDevInfo,&tSpDevInfoData,SPDRP_HARDWAREID
,&dwtype,(PBYTE szHardwareId,256,NULL);
//code to process szHardwareId
delete szHardwareId;
break;
}
}
}
}
I dont have idea for Linux..:(
Hope this helps..

get graphic card info in linux ( /proc file system )

I can create proc file.what I want to learn graphic card info using proc read function.How can I do this?
I do not mean to learn that info in terminal( by writing lspci vs).
do you know the path of which file stores the graphic card info in /proc directory?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
// read proc function
int read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) {
/* file to be read? */
return 1;
}
// Module loading..
static int start(void){
create_proc_read_entry("myproc", 0, NULL, read_proc, NULL);
return 0;
}
static void fin(void) {
remove_proc_entry("myproc", NULL);
}
module_init(start);
module_exit(fin);
I am not completely sure if I understand what your question is actually about. But in case you're asking where you can read information about your graphics card(s), here are my 0.01€.
PCI device information is available under /sys/bus/pci/devices.
Use lspci to find out the device number(s) for your graphics card(s). For example: lspci |grep -i graphics|awk '{ print $1 }'.
Then see appropriate subdirectories in /sys/bus/pci/devices.

Resources