| Open Sound System |
| Do you have problems with sound/audio application development? Don't panic! Click here for help! |
Copyright (C) 4Front Technologies, 2002-2004. Released under GPLv2/CDDL.
This program demonstrates use of the SNDCTL_DSP_READCTL call. It's actually a low cost digital (S/PDIF) input analyzer.
This program will work just with a bunch of sound cards because most devices are not able to return this information. AT this moment the only card that is verified is M Audio Audiophile 2496. It's possible that some other M Audio Delta models work too. It's almost certain that "ordinary" sound cards will never have a digital receiver chip capable to return this information.
Please read the "Digital audio interface status and setup" section of the OSS Developer's manual for more info.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <time.h>
#include <soundcard.h>
#undef SHOW_DATA
#define SHOW_STATUS
#define RATE 48000
#define CHANNELS 2
#define BUFSZ (CHANNELS*RATE)
#ifdef SHOW_STATUS
static int
xbits (unsigned char b, int first, int last)
{
int v, i;
v = 0;
for (i = first; i <= last; i++)
{
v <<= 1;
if (b & (1 << i))
v |= 1;
}
return v;
}
static void
decode_pro_mode (unsigned char *bits)
{
printf ("Professional mode (PRO=1)\n");
}
static void
decode_consumer_mode (unsigned char *bits)
{
int tmp, tmp2, tmp3;
printf ("Consumer mode (PRO=0)\n");
printf ("Byte 00=%02x: ", bits[0]);
if (bits[0] & 0x02)
printf ("Data (not audio) ");
else
printf ("Audio (not data) ");
if (bits[0] & 0x04)
printf ("Copy permitted ");
else
printf ("Copy inhibited ");
tmp = xbits (bits[0], 3, 5);
if (bits[0] & 0x02)
printf ("Non-audio=0x%x ", tmp);
else
printf ("Pre-emph=0x%x ", tmp);
tmp = xbits (bits[0], 6, 7);
printf ("Mode=0x%x ", tmp);
printf ("\n");
printf ("Byte 01=%02x: ", bits[1]);
tmp = xbits (bits[1], 0, 2);
tmp2 = xbits (bits[1], 3, 6);
tmp3 = xbits (bits[1], 7, 7);
printf ("Category code = %x:%x, L=%d ", tmp, tmp2, tmp3);
printf ("\n");
printf ("Byte 02=%02x: ", bits[2]);
tmp = xbits (bits[2], 0, 3);
tmp2 = xbits (bits[2], 4, 7);
printf ("Source number=0x%x Channel number=0x%x ", tmp, tmp2);
printf ("\n");
printf ("Byte 03=%02x: ", bits[3]);
tmp = xbits (bits[3], 0, 3);
tmp2 = xbits (bits[3], 4, 5);
printf ("Sample rate=0x%x Clock accuracy=0x%x ", tmp, tmp2);
printf ("\n");
}
#endif
int
main (int argc, char *argv[])
{
char *devname = "/dev/dsp";
unsigned short buf[BUFSZ], expected = 0;
int fd, parm, l, i;
int bcount = 0;
if (argc > 1)
devname = argv[1];
if ((fd = open (devname, O_RDONLY, 0)) == -1)
{
perror (devname);
exit (-1);
}
parm = AFMT_S16_NE;
if (ioctl (fd, SNDCTL_DSP_SETFMT, &parm) == -1)
{
perror ("SETFMT");
close (fd);
exit (-1);
}
if (parm != AFMT_S16_NE)
{
printf
("Error: 16 bit sample format is not supported by the device\n");
printf ("%08x/%08x\n", parm, AFMT_S16_LE);
close (fd);
exit (-1);
}
parm = CHANNELS;
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &parm) == -1)
{
perror ("CHANNELS");
close (fd);
exit (-1);
}
parm = RATE;
if (ioctl (fd, SNDCTL_DSP_SPEED, &parm) == -1)
{
perror ("SPEED");
close (fd);
exit (-1);
}
if (parm != RATE)
{
printf
("Warning: %d Hz sampling rate is not supported by the device. Will use %d)\n",
RATE, parm);
}
#ifdef SHOW_DATA
while ((l = read (fd, buf, sizeof (buf))) > 0)
#else
while (1)
#endif
{
#ifdef SHOW_STATUS
time_t t;
oss_digital_control c;
c.valid = VAL_CBITIN | VAL_ISTATUS;
if (ioctl (fd, SNDCTL_DSP_READCTL, &c) == -1)
{
perror ("SNDCTL_DSP_READCTL");
exit (-1);
}
time (&t);
printf ("\n%s\n", ctime (&t));
if (c.valid & VAL_ISTATUS)
{
switch (c.in_locked)
{
case LOCK_NOT_INDICATED:
printf ("Receiver locked: Status unknown\n");
break;
case LOCK_UNLOCKED:
printf ("receiver locked: *** NOT LOCKED ***\n");
break;
case LOCK_LOCKED:
printf ("receiver locked: Locked OK\n");
break;
}
switch (c.in_quality)
{
case IN_QUAL_NOT_INDICATED:
printf ("Signal quality: Unknown\n");
break;
case IN_QUAL_POOR:
printf ("Signal quality: *** POOR ***\n");
break;
case IN_QUAL_GOOD:
printf ("Signal quality: Good\n");
break;
}
switch (c.in_vbit)
{
case VBIT_NOT_INDICATED:
printf ("V-bit: Unknown\n");
break;
case VBIT_ON:
printf ("V-bit: On (not valid audio)\n");
break;
case VBIT_OFF:
printf ("V-bit: Off (valid audio signal)\n");
break;
}
switch (c.in_data)
{
case IND_UNKNOWN:
printf ("Audio/data: Unknown\n");
break;
case IND_AUDIO:
printf ("Audio/data: Audio\n");
break;
case IND_DATA:
printf ("Audio/data: Data\n");
break;
}
printf ("Errors: ");
if (c.in_errors & INERR_CRC)
printf ("CRC ");
if (c.in_errors & INERR_QCODE_CRC)
printf ("QCODE_CRC ");
if (c.in_errors & INERR_PARITY)
printf ("PARITY ");
if (c.in_errors & INERR_BIPHASE)
printf ("BIPHASE ");
printf ("\n");
}
else
printf ("No input status information available\n");
if (c.valid & VAL_CBITIN && c.in_locked != LOCK_UNLOCKED)
{
printf ("\n");
printf ("Control bits: ");
for (i = 0; i < 24; i++)
printf ("%02x ", c.cbitin[i]);
printf ("\n");
if (c.cbitin[0] & 0x01)
decode_pro_mode (c.cbitin);
else
decode_consumer_mode (c.cbitin);
}
else
printf ("No incoming control bit information available\n");
#endif
#ifdef SHOW_DATA
# ifdef SHOW_STATUS
if (c.in_locked != LOCK_UNLOCKED)
# endif
{
for (i = 0; i < l / 2; i++)
{
if (buf[i] == expected)
{
printf ("%04x\n", buf[i]);
}
else
{
printf ("Error %04x != %04x (%4x), c=%d/%x\n", buf[i],
expected, buf[i] ^ expected, bcount, bcount);
}
expected = buf[i] + 1;
bcount++;
}
}
#else
sleep (1);
#endif
}
perror (devname);
exit (-1);
}