Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

oss.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

/*
#if HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
*/

/* TODO autotools */
#include "context.h"

#if HAVE_SOUNDCARD_H /* defined(__NetBSD__) */
#include <soundcard.h>
#endif
#if HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#endif

#define FREQUENCY 4410
/* #define FREQUENCY 44100 */
/* #define FREQUENCY 11025 */
/* #define FREQUENCY 8000 */
/* #define FREQUENCY 22050 */

/* #define ABUF_SIZE 8192 */
/* #define ABUF_SIZE 4096 */
#define ABUF_SIZE 512
/* #define ABUF_SIZE 256 */

u_long id = 945287538;
u_long options = BEQ_THREAD;

#define OSS  "/dev/audio"

static int fd;                  /* file descriptor for device */

/* XXX test avec un tableau pour bug freebsd */
static struct pollfd pfd[1];       /* to poll the fd */

static int abuf_size;           /* audio buffer size */
/* audio buffer */
static short         *abuf;

/* utility function for displaying boolean status */
static const char *
yes_no(int condition)
{
  return (condition) ? "yes" : "no";
}


/*
 * Set sound device parameters to given values. Return -1 if
 * values not valid. Sampling rate is returned.
 */
static int
set_dsp_params(int fd, int channels, int bits, int *rate)
{
  int status, val = channels;

  status= ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &val);
  if (status == -1)
    perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
  if (val != channels) /* not valid, so return */
    return -1;
  val = bits;
  status= ioctl(fd, SOUND_PCM_WRITE_BITS, &val);
  if (status == -1)
    perror("SOUND_PCM_WRITE_BITS ioctl failed");
  if (val != bits)
    return -1;
  status= ioctl(fd, SOUND_PCM_WRITE_RATE, rate);
  if (status == -1)
    perror("SOUND_PCM_WRITE_RATE ioctl failed");
  return 0;
}


static void
init()
{
  int format=AFMT_S16_LE, sample_size=16, stereo=1, frequency=FREQUENCY, status;

  status = ioctl(fd, SOUND_PCM_SETFMT, &format);
  if (status ==  -1)
    xperror("SOUND_PCM_SETFMT ioctl failed");
  if (format != AFMT_S16_LE)
    xerror("Could not choose S16_LE mode\n");

  if (ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &sample_size) == -1)
    xperror("ioctl");
  if (sample_size != 16)
    xerror("Could not choose 16bits sample size\n");
  
  if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) == -1)
    xperror("ioctl");
  if (stereo != 1)
    xerror("Unable to choose stereo\n");

  if (ioctl(fd, SNDCTL_DSP_SPEED, &frequency) == -1)
    xperror("ioctl");
  printf("[i] sampling at %dHz\n", frequency);

  if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &abuf_size) == -1)
    xperror("ioctl");
  if (abuf_size < 1)
    xerror("fatal: GETBLKSIZE\n");
  printf("[i] abuf_size= %d\n", abuf_size);

  abuf = xcalloc(abuf_size*2, sizeof(short));

  pfd[0].fd = fd;
  pfd[0].events = POLLIN;

  okdone("DSP initialized");
}


void
create(Context_t *ctx)
{
  int rate;
  int channels;            /* number of channels */
  int bits;                /* sample size */
  int blocksize;           /* block size */
  int formats;             /* data formats */
  int caps;                /* capabilities */
  int deffmt;              /* default format */
  int min_rate, max_rate;  /* min and max sampling rates */
  int status;              /* return value from ioctl */
  int frag_size;           /* fragment size */

  /* try to open OSS audio device */
  fd = open(OSS, O_RDONLY);
  if (fd == -1)
    printf("[dsp] Unable to open OSS device '%s'\n", OSS);

  frag_size = 0x7fff0008; /* try to get a fragment of 256 bytes */
  /* printf("FRAG_SIZE = %d\n", frag_size); */
      
  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) == -1)
    xperror("ioctl");

#if 1 /* TODO: 0 when ok */
  status= ioctl(fd, SOUND_PCM_READ_RATE, &rate);
  if (status ==  -1)
    perror("SOUND_PCM_READ_RATE ioctl failed");
  status= ioctl(fd, SOUND_PCM_READ_CHANNELS, &channels);
  if (status ==  -1)
    perror("SOUND_PCM_READ_CHANNELS ioctl failed");
  status= ioctl(fd, SOUND_PCM_READ_BITS, &bits);
  if (status ==  -1)
    perror("SOUND_PCM_READ_BITS ioctl failed");
  status= ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
  if (status ==  -1)
    perror("SNFCTL_DSP_GETBLKSIZE ioctl failed");
  
  printf(
       "[i] Information on soundcard:\n"
       "[i] Defaults:\n"
       "[i]  sampling rate: %d Hz\n"
       "[i]  channels: %d\n"
       "[i]  sample size: %d bits\n"
       "[i]  block size: %d bytes\n",
       rate, channels, bits, blocksize
       );

  /* this requires a more recent version of the sound driver */
#if SOUND_VERSION >= 301
  printf("[i] Supported Formats:\n");
  deffmt = AFMT_QUERY;
  status= ioctl(fd, SOUND_PCM_SETFMT, &deffmt);
  if (status ==  -1)
    perror("SOUND_PCM_SETFMT ioctl failed");
  status= ioctl(fd, SOUND_PCM_GETFMTS, &formats);
  if (status ==  -1)
    perror("SOUND_PCM_GETFMTS ioctl failed");
  if (formats & AFMT_MU_LAW) {
    printf("[i]   mu-law");
    (deffmt == AFMT_MU_LAW) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_A_LAW) {
    printf("[i]   A-law");
    (deffmt == AFMT_A_LAW) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_IMA_ADPCM) {
    printf("[i]   IMA ADPCM");
    (deffmt == AFMT_IMA_ADPCM) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_U8) {
    printf("[i]   unsigned 8-bit");
    (deffmt == AFMT_U8) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_S16_LE) {
    printf("[i]   signed 16-bit little-endian");
    (deffmt == AFMT_S16_LE) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_S16_BE) {
    printf("[i]   signed 16-bit big-endian");
    (deffmt == AFMT_S16_BE) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_S8) {
    printf("[i]   signed 8-bit");
    (deffmt == AFMT_S8) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_U16_LE) {
    printf("[i]   unsigned 16-bit little-endian");
    (deffmt == AFMT_U16_LE) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_U16_BE) {
    printf("[i]   unsigned 16-bit big-endian");
    (deffmt == AFMT_U16_BE) ? printf(" (default)\n") : printf("\n");
  }
  if (formats & AFMT_MPEG) {
    printf("[i]   MPEG 2");
    (deffmt == AFMT_MPEG) ? printf(" (default)\n") : printf("\n");
  }
  
  printf("[i] Capabilities:\n");
  status= ioctl(fd, SNDCTL_DSP_GETCAPS, &caps);
  if (status ==  -1)
    perror("SNDCTL_DSP_GETCAPS ioctl failed");
  printf(
       "[i]   revision: %d\n"
       "[i]   full duplex: %s\n"
       "[i]   real-time: %s\n"
       "[i]   batch: %s\n"
       "[i]   coprocessor: %s\n" 
       "[i]   trigger: %s\n"
       "[i]   mmap: %s\n",
       caps & DSP_CAP_REVISION,
       yes_no(caps & DSP_CAP_DUPLEX),
       yes_no(caps & DSP_CAP_REALTIME),
       yes_no(caps & DSP_CAP_BATCH),
       yes_no(caps & DSP_CAP_COPROC),
       yes_no(caps & DSP_CAP_TRIGGER),
       yes_no(caps & DSP_CAP_MMAP));

#endif /* SOUND_VERSION >= 301 */
  
  /* display table heading */
  printf("[i] Modes and Limits:\n"
       "[i] Device    Sample    Minimum   Maximum\n"
       "[i] Channels  Size      Rate      Rate\n"
       "[i] --------  --------  --------  --------\n");
      
  /* do mono and stereo */  
  for (channels = 1; channels <= 2 ; channels++) {
    /* do 8 and 16 bits */
    for (bits = 8; bits <= 16 ; bits += 8) {
      /* To find the minimum and maximum sampling rates we rely on
       the fact that the kernel sound driver will round them to
       the closest legal value. */
      min_rate = 1;
      if (set_dsp_params(fd, channels, bits, &min_rate) == -1)
      continue;
      max_rate = 100000;
      if (set_dsp_params(fd, channels, bits, &max_rate) == -1)
      continue;
      /* display the results */
      printf("[i] %8d  %8d  %8d  %8d\n", channels, bits, min_rate, max_rate);
    }
  }
#endif

  init();
  ctx->input = Input_new(ABUF_SIZE);
}


void *
jthread(void *args)
{
  Context_t *ctx = (Context_t *)args;

  while (ctx->running) {
    pfd[0].revents = 0;
    /* printf("[+] Polling /dev/dsp...\n"); */
    poll(pfd, 1, 100);

    /* printf("polled: %d (&POLLIN: %d)\n", pfd[0].revents, pfd[0].revents&POLLIN); */
    if (pfd[0].revents & POLLIN) {
      int n, howmuch;

      fflush(stdout);
      howmuch = abuf_size * 2 * sizeof(short);
      n = read(fd, (void *)abuf, howmuch);

      if (n != howmuch)
       xperror("read");

      if ((ctx->input != NULL) && !ctx->input->mute) {
      int n2 = 0, idx;

      for (idx = 0; idx < ABUF_SIZE-abuf_size; idx++) {
        ctx->input->data[A_LEFT][idx] = ctx->input->data[A_LEFT][idx+abuf_size];
        ctx->input->data[A_RIGHT][idx] = ctx->input->data[A_RIGHT][idx+abuf_size];
      }

      for ( ; idx < ABUF_SIZE; idx++) {
        ctx->input->data[A_LEFT][idx] = 
          (float)(((float)(abuf[n2])) / (float)-SHRT_MIN);
        n2++;
        ctx->input->data[A_RIGHT][idx] = 
          (float)(((float)(abuf[n2])) / (float)-SHRT_MIN);
        n2++;
        /*
        printf("[+] Read %f %f\n",
             ctx->input->data[A_LEFT][idx],
             ctx->input->data[A_RIGHT][idx]);
        */
      }

      /* Input_set() handles the thread locking */
      Input_set(ctx->input, A_STEREO);
      }
    }
  }

  return NULL;
}


void
destroy(Context_t *ctx)
{
  Input_delete(ctx->input);
  close(fd);
  xfree(abuf);
}

Generated by  Doxygen 1.6.0   Back to index