"Fossies" - the Fresh Open Source Software archive 
Member "xanalyser-1.32/src/pcm-oss.cc" of archive xanalyser-1.32.tar.gz:
/*
* Author: Arvin Schnell
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef __NetBSD__
# include <soundcard.h>
#else
# include <sys/soundcard.h>
#endif
#include <math.h>
#include <errno.h>
#include <string.h>
#include <iostream>
using std::cerr;
#include "pcm-oss.h"
PCMOSS::PCMOSS (const char* name, pcm_type_t type, pcm_mode_t mode,
pcm_format_t format, int channels, int rate, int buffer_size)
: PCM (name, type, mode, format, channels, rate, buffer_size),
fd (-1)
{
if (channels != 1 && channels != 2) {
cerr << "error: Illegal number of channels\n";
return;
}
if (format != S8 && format != S16) {
cerr << "error: Illegal format (resolution)\n";
return;
}
int openmode = mode == WRITE ? O_WRONLY : O_RDONLY;
fd = open (name, openmode, 0);
if (fd == -1) {
cerr << "error: Can't open " << name << ": "
<< strerror (errno) << '\n';
return;
}
const int want_buffer_size = get_bytes_per_frame () * buffer_size;
int s = (int) (floor (log (want_buffer_size) / log (2.0) + 0.5));
if ((1L << s) != want_buffer_size) {
cerr << "error: Invalid requested buffer size\n";
return;
}
int arg = 0x00020000 + s;
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
cerr << "error: Can't set fragment size: "
<< strerror (errno) << '\n';
return;
}
const int want_format = format == S8 ? AFMT_S8 : AFMT_S16_NE;
int tmp_format = want_format;
if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp_format) == -1) {
cerr << "error: " << strerror (errno) << '\n';
return;
}
if (want_format != tmp_format) {
cerr << "error: Can't set requested format (resolution)\n";
return;
}
const int want_stereo = channels == 1 ? 0 : 1;
int tmp_stereo = want_stereo;
if (ioctl (fd, SNDCTL_DSP_STEREO, &tmp_stereo) == -1) {
cerr << "error: " << strerror (errno) << '\n';
return;
}
if (want_stereo != tmp_stereo) {
cerr << "error: Can't set mono/stereo\n";
return;
}
int tmp_rate = rate;
if (ioctl (fd, SNDCTL_DSP_SPEED, &tmp_rate) == -1) {
cerr << "error: " << strerror (errno) << '\n';
return;
}
if (abs (rate - tmp_rate) > 1) { // we can tolerate 1 Hz difference
cerr << "error: Can't set requested rate\n"
<< "requested rate: " << rate << " Hz, actual rate: "
<< tmp_rate << " Hz\n";
return;
}
int tmp_buffer_size = want_buffer_size;
if (ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &tmp_buffer_size) == -1) {
cerr << "error " << strerror (errno) << '\n';
return;
}
if (want_buffer_size != tmp_buffer_size) {
cerr << "error: Can't set requested buffer size\n"
<< "requested size: " << want_buffer_size << " bytes, actual size: "
<< tmp_buffer_size << " bytes\n";
return;
}
ok = true;
}
PCMOSS::~PCMOSS ()
{
if (fd > 0)
close (fd);
}
void
PCMOSS::info () const
{
cerr << "driver: oss\n";
PCM::info ();
}
size_t
PCMOSS::size ()
{
return (size_t)(-1);
}
off_t
PCMOSS::seek (off_t, int)
{
return (off_t)(-1);
}
size_t
PCMOSS::read (void* buffer, size_t frames)
{
int i = get_bytes_per_frame () * frames;
if (::read (fd, buffer, i) != i) {
cerr << "error: " << strerror (errno) << '\n';
return (size_t)(-1);
}
return frames;
}
size_t
PCMOSS::write (void* buffer, size_t frames)
{
int i = get_bytes_per_frame () * frames;
if (::write (fd, buffer, i) != i) {
cerr << "error: " << strerror (errno) << '\n';
return (size_t)(-1);
}
return frames;
}