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

sndconfig.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)sndconfig.c      1.17 04/08/03 Copyright 1998-2004 Heiko Eissfeldt */
/* os dependent functions */
#include "config.h"
#include <stdio.h>
#include <stdxlib.h>
#include <strdefs.h>
#include <fctldefs.h>
#include <unixstd.h>
#include <sys/ioctl.h>

#if   !defined __CYGWIN32__
# include <timedefs.h>
#endif
#include <schily.h>


/* soundcard setup */
#if defined (HAVE_SOUNDCARD_H) || defined (HAVE_LINUX_SOUNDCARD_H) || defined (HAVE_SYS_SOUNDCARD_H) || defined (HAVE_MACHINE_SOUNDCARD_H)
# if defined (HAVE_SOUNDCARD_H)
#  include <soundcard.h>
# else
#  if defined (HAVE_MACHINE_SOUNDCARD_H)
#   include <machine/soundcard.h>
#  else
#   if defined (HAVE_SYS_SOUNDCARD_H)
#    include <sys/soundcard.h>
#   else
#    if defined (HAVE_LINUX_SOUNDCARD_H)
#     include <linux/soundcard.h>
#    endif
#   endif
#  endif
# endif
#endif

#include "mytype.h"
#include "byteorder.h"
#include "lowlevel.h"
#include "global.h"
#include "sndconfig.h"

#ifdef      ECHO_TO_SOUNDCARD
#   if defined(__CYGWIN32__)
#      include <windows.h>
#      include "mmsystem.h"
#   endif

#   if      defined(__EMX__)
#      define     INCL_DOS
#      define     INCL_OS2MM
#      include    <os2.h>
#      define     PPFN  _PPFN
#      include    <os2me.h>
#      undef      PPFN
static unsigned long    DeviceID;

#      define     FRAGMENTS   2
/* playlist-structure */
typedef struct {
        ULONG ulCommand;
        ULONG ulOperand1, ulOperand2, ulOperand3;
} PLAYLISTSTRUCTURE;

static PLAYLISTSTRUCTURE PlayList[FRAGMENTS + 1];
static unsigned BufferInd;
#   endif /* defined __EMX__ */

static char snd_device[200] = SOUND_DEV;

int set_snd_device(const char *devicename)
{
      strncpy(snd_device, devicename, sizeof(snd_device));
      return 0;
}

#   if      defined __CYGWIN32__
static HWAVEOUT   DeviceID;
#      define WAVEHDRS  3
static WAVEHDR    wavehdr[WAVEHDRS];
static unsigned lastwav = 0;

static int check_winsound_caps(int bits, double rate, int channels);

static int check_winsound_caps(int bits, double rate, int channels)
{
  int result = 0;

  WAVEOUTCAPS caps;

  /* get caps */
  if (waveOutGetDevCaps(0, &caps, sizeof(caps))) {
     fprintf(stderr, "cannot get soundcard capabilities!\n");
     return 1;
  }

  /* check caps */
  if ((bits == 8 && !(caps.dwFormats & 0x333)) ||
      (bits == 16 && !(caps.dwFormats & 0xccc))) {
      fprintf(stderr, "%d bits sound are not supported\n", bits);
      result = 2;
  }

  if ((channels == 1 && !(caps.dwFormats & 0x555)) ||
      (channels == 2 && !(caps.dwFormats & 0xaaa))) {
      fprintf(stderr, "%d sound channels are not supported\n", channels);
      result = 3;
  }

  if ((rate == 44100.0 && !(caps.dwFormats & 0xf00)) ||
      (rate == 22050.0 && !(caps.dwFormats & 0xf0)) ||
      (rate == 11025.0 && !(caps.dwFormats & 0xf))) {
      fprintf(stderr, "%d sample rate is not supported\n", (int)rate);
      result = 4;
  }

  return result;
}
#   endif /* defined CYGWIN */
#endif /* defined ECHO_TO_SOUNDCARD */

#ifdef      HAVE_SUN_AUDIOIO_H
# include <sun/audioio.h>
#endif
#ifdef      HAVE_SYS_AUDIOIO_H
# include <sys/audioio.h>
#endif

#ifdef      HAVE_SYS_ASOUNDLIB_H
# include <sys/asoundlib.h>
snd_pcm_t   *pcm_handle;
#endif

#if   defined     HAVE_OSS && defined SNDCTL_DSP_GETOSPACE
audio_buf_info abinfo;
#endif

int init_soundcard(double rate, int bits)
{
#ifdef      ECHO_TO_SOUNDCARD
  if (global.echo) {
# if  defined(HAVE_OSS) && HAVE_OSS == 1
    if (open_snd_device() != 0) {
        errmsg("Cannot open sound device '%s'\n", snd_device);
        global.echo = 0;
    } else { 
      /* This the sound device initialisation for 4front Open sound drivers */

      int dummy;
      int garbled_rate = rate;
      int stereo = (global.channels == 2);
      int myformat = bits == 8 ? AFMT_U8 :
            (MY_LITTLE_ENDIAN ? AFMT_S16_LE : AFMT_S16_BE);
      int mask;

      if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETBLKSIZE, &dummy) == -1) {
          fprintf(stderr, "Cannot get blocksize for %s\n", snd_device);
          global.echo = 0;
      }
      if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SYNC, NULL) == -1) {
          fprintf(stderr, "Cannot sync for %s\n", snd_device);
          global.echo = 0;
      }

#if   defined SNDCTL_DSP_GETOSPACE
      if (ioctl(global.soundcard_fd, SNDCTL_DSP_GETOSPACE, &abinfo) == -1) {
            fprintf(stderr, "Cannot get input buffersize for %s\n", snd_device);
            abinfo.fragments  = 0;
      }
#endif

      /* check, if the sound device can do the requested format */
      if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETFMTS, &mask) == -1) {
            perror("fatal error:");
            return -1;
      }
      if ((mask & myformat) == 0) {
            fprintf(stderr, "sound format (%d bits signed) is not available\n", bits);
            if ((mask & AFMT_U8) != 0) {
                  bits = 8;
                  myformat = AFMT_U8;
            }
      }
      if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SETFMT, &myformat) == -1) {
          fprintf(stderr, "Cannot set %d bits/sample for %s\n",bits, snd_device);
          global.echo = 0;
      }

      /* limited sound devices may not support stereo */
      if (stereo
          && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) {
          fprintf(stderr, "Cannot set stereo mode for %s\n", snd_device);
          stereo = 0;
      }
      if (!stereo
            && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) {
          fprintf(stderr, "Cannot set mono mode for %s\n", snd_device);
          global.echo = 0;
      }

      /* set the sample rate */
      if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SPEED, &garbled_rate) == -1) {
          fprintf(stderr, "Cannot set rate %d.%2d Hz for %s\n",
            (int)rate, (int)(rate*100)%100, snd_device);
          global.echo = 0;
      }
      if ( abs((long)rate - garbled_rate) > rate / 20) {
          fprintf(stderr, "sound device: next best sample rate is %d\n",garbled_rate);
      }
    }

# else /* HAVE_OSS */

#  if defined     HAVE_SYS_AUDIOIO_H || defined HAVE_SUN_AUDIOIO_H
      /* This is the SunOS / Solaris and compatibles sound initialisation */

    if ((global.soundcard_fd = open(snd_device, O_WRONLY, 0)) == EOF) {
      perror("");
        fprintf(stderr, "Cannot open %s\n",snd_device);
        global.echo = 0;
    } else { 

        audio_info_t            info;

#   if      defined     (AUDIO_INITINFO) && defined (AUDIO_ENCODING_LINEAR)
        AUDIO_INITINFO(&info);
        info.play.sample_rate = rate;
        info.play.channels = global.channels;
        info.play.precision = bits;
        info.play.encoding = AUDIO_ENCODING_LINEAR;
        info.play.pause = 0;
        info.record.pause = 0;
        info.monitor_gain = 0;
        if (ioctl(global.soundcard_fd, AUDIO_SETINFO, &info) < 0) {
          fprintf(stderr, "Cannot init %s (sun)\n", snd_device);
          global.echo = 0;
      }
#   else
      fprintf(stderr, "Cannot init sound device with 44.1 KHz sample rate on %s (sun compatible)\n", snd_device);
      global.echo = 0;
#   endif
    }
#  else /* SUN audio */
#   if defined(__CYGWIN32__)
    /* Windows sound info */

    MMRESULT mmres;
    WAVEFORMATEX wavform;

    if (waveOutGetNumDevs() < 1) {
      fprintf( stderr, "no sound devices available!\n");
      global.echo = 0;
      return 1;
    }

    /* check capabilities */
    if (check_winsound_caps(bits, rate, global.channels) != 0) {
      fprintf( stderr, "soundcard capabilities are not sufficient!\n");
      global.echo = 0;
      return 1;
    }

    wavform.wFormatTag = WAVE_FORMAT_PCM;
    wavform.nChannels = global.channels;
    wavform.nSamplesPerSec = (int)rate;
    wavform.wBitsPerSample = bits;
    wavform.cbSize = sizeof(wavform);
    wavform.nAvgBytesPerSec = (int)rate * global.channels *
                        (wavform.wBitsPerSample / 8);
    wavform.nBlockAlign = global.channels * (wavform.wBitsPerSample / 8);
  
    DeviceID = 0;
    mmres = waveOutOpen(&DeviceID, WAVE_MAPPER, &wavform, (unsigned long)WIN_CallBack, 0, CALLBACK_FUNCTION);
    if (mmres) {
      char erstr[329];

      waveOutGetErrorText(mmres, erstr, sizeof(erstr));
      fprintf( stderr, "soundcard open error: %s!\n", erstr);
      global.echo = 0;
      return 1;
    }

    global.soundcard_fd = 0;

    /* init all wavehdrs */
    { int i;
      for (i=0; i < WAVEHDRS; i++) {
          wavehdr[i].dwBufferLength = (global.channels*(bits/ 8)*(int)rate*
                        global.nsectors)/75;
          wavehdr[i].lpData = malloc(wavehdr[i].dwBufferLength);
          if (wavehdr[i].lpData == NULL) {
                fprintf(stderr, "no memory for sound buffers available\n");
                waveOutReset(0);
                waveOutClose(DeviceID);
                return 1;
          }
          
          mmres = waveOutPrepareHeader(DeviceID, &wavehdr[i], sizeof(WAVEHDR));
          if (mmres) {
            char erstr[129];

            waveOutGetErrorText(mmres, erstr, sizeof(erstr));
            fprintf( stderr, "soundcard prepare error: %s!\n", erstr);
            return 1;
          }

          wavehdr[i].dwLoops = 0;
          wavehdr[i].dwFlags = WHDR_DONE;
          wavehdr[i].dwBufferLength = 0;
      }
    }

#   else
#    if defined(__EMX__)
#     if defined (HAVE_MMPM)
    /* OS/2 MMPM/2 MCI sound info */

    MCI_OPEN_PARMS mciOpenParms;
    int i;

    /* create playlist */
    for (i = 0; i < FRAGMENTS; i++) {
        PlayList[i].ulCommand = DATA_OPERATION; /* play data */
        PlayList[i].ulOperand1 = 0; /* address */
        PlayList[i].ulOperand2 = 0; /* size */
        PlayList[i].ulOperand3 = 0;     /* offset */
    }
    PlayList[FRAGMENTS].ulCommand = BRANCH_OPERATION;       /* jump */
    PlayList[FRAGMENTS].ulOperand1 = 0;
    PlayList[FRAGMENTS].ulOperand2 = 0;     /* destination */
    PlayList[FRAGMENTS].ulOperand3 = 0;

    memset(&mciOpenParms, 0, sizeof(mciOpenParms));
    mciOpenParms.pszDeviceType = (PSZ) (((unsigned long) MCI_DEVTYPE_WAVEFORM_AUDIO << 16) | (unsigned short) DeviceIndex);
    mciOpenParms.pszElementName = (PSZ) & PlayList;

    /* try to open the sound device */
    if (mciSendCommand(0, MCI_OPEN,
       MCI_WAIT | MCI_OPEN_SHAREABLE | MCIOPEN_Type_ID, &mciOpenParms, 0)
       != MCIERR_SUCCESS) {
      /* no sound */
      fprintf( stderr, "no sound devices available!\n");
      global.echo = 0;
      return 1;
    }
    /* try to set the parameters */
    DeviceID = mciOpenParms.usDeviceID;

    {
      MCI_WAVE_SET_PARMS mciWaveSetParms;

      memset(&mciWaveSetParms, 0, sizeof(mciWaveSetParms));
      mciWaveSetParms.ulSamplesPerSec = rate;
      mciWaveSetParms.usBitsPerSample = bits;
      mciWaveSetParms.usChannels = global.channels;
      mciWaveSetParms.ulAudio = MCI_SET_AUDIO_ALL;

      /* set play-parameters */
      if (mciSendCommand(DeviceID, MCI_SET,
                  MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC |
                  MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_CHANNELS,
                  (PVOID) & mciWaveSetParms, 0)) {
            MCI_GENERIC_PARMS mciGenericParms;
            fprintf( stderr, "soundcard capabilities are not sufficient!\n");
            global.echo = 0;
            /* close */
            mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0);
            return 1;
      }
    }

#       endif /* EMX MMPM OS2 sound */
#    else
#      if defined(__QNX__)

      int   card = -1;
      int   dev = 0;
      int   rtn;
      snd_pcm_channel_info_t  pi;
      snd_pcm_channel_params_t      pp;

      if (card == -1) {
            rtn = snd_pcm_open_preferred(&pcm_handle, 
                  &card, &dev, SND_PCM_OPEN_PLAYBACK);
            if (rtn < 0) {
                  perror("sound device open");
                  return 1;
            }
      } else {
            rtn = snd_pcm_open(&pcm_handle, 
                  card, dev, SND_PCM_OPEN_PLAYBACK);
            if (rtn < 0) {
                  perror("sound device open");
                  return 1;
            }
      }

      memset(&pi, 0, sizeof(pi));
      pi.channel = SND_PCM_CHANNEL_PLAYBACK;
      rtn = snd_pcm_plugin_info(pcm_handle, &pi);
      if (rtn < 0) {
            fprintf(stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror(rtn));
            return 1;
      }

      memset(&pp, 0, sizeof(pp));
      pp.mode = SND_PCM_MODE_BLOCK;
      pp.channel = SND_PCM_CHANNEL_PLAYBACK;
      pp.start_mode = SND_PCM_START_FULL;
      pp.stop_mode = SND_PCM_STOP_STOP;

      pp.buf.block.frag_size = pi.max_fragment_size;
      pp.buf.block.frags_max = 1;
      pp.buf.block.frags_min = 1;

      pp.format.interleave = 1;
      pp.format.rate = rate;
      pp.format.voices = global.channels;
      if (bits == 8) {
            pp.format.format = SND_PCM_SFMT_U8;
      } else {
            pp.format.format = SND_PCM_SFMT_S16_LE;
      }

      rtn = snd_pcm_plugin_params(pcm_handle, &pp);
      if (rtn < 0) {
            fprintf(stderr, "snd_pcm_plugin_params failed: %s\n", snd_strerror(rtn));
            return 1;
      }

      rtn = snd_pcm_plugin_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
      if (rtn < 0) {
            fprintf(stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rtn));
            return 1;
      }

      global.soundcard_fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);

#      endif /* QNX sound */
#    endif /* EMX OS2 sound */
#   endif /* CYGWIN Windows sound */
#  endif /* else SUN audio */
# endif /* else HAVE_OSS */
  }
#endif /* ifdef ECHO_TO_SOUNDCARD */
  return 0;
}

int open_snd_device()
{
#if   defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK)
      int   fl;
#endif

#if   defined ECHO_TO_SOUNDCARD && !defined __CYGWIN32__ && !defined __EMX__
      global.soundcard_fd = open(snd_device, O_WRONLY
#ifdef      linux
            /* Linux BUG: the sound driver open() blocks, if the device is in use. */
             | O_NONBLOCK
#endif
            , 0);

#if   defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK)
      fl = fcntl(global.soundcard_fd, F_GETFL, 0);
      fl &= ~O_NONBLOCK;
      fcntl(global.soundcard_fd, F_SETFL, fl);
#endif

      return (global.soundcard_fd < 0);
#else
      return 0;
#endif
}

int close_snd_device ()
{
#if   !defined ECHO_TO_SOUNDCARD
      return 0;
#else

# if  defined __CYGWIN32__
      waveOutReset(0);
      return waveOutClose(DeviceID);
# else /* !Cygwin32 */

#  if defined __EMX__
#   if      defined HAVE_MMPM
      /* close the sound device */
      MCI_GENERIC_PARMS mciGenericParms;
      mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0);
#   else /* HAVE_MMPM */
      return 0;
#   endif /* HAVE_MMPM */
#  else /* !EMX */
#   if      defined     __QNX__
      snd_pcm_plugin_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
      return snd_pcm_close(pcm_handle);
#   else /* !QNX */
      return close(global.soundcard_fd);
#   endif /* !QNX */
#  endif /* !EMX */
# endif /* !Cygwin32 */
#endif /* ifdef ECHO_TO_SOUNDCARD */
}

int write_snd_device(char *buffer, unsigned todo)
{
      int result = 0;
#ifdef      ECHO_TO_SOUNDCARD
#if   defined __CYGWIN32__
      MMRESULT mmres;

      wavehdr[lastwav].dwBufferLength = todo;
      memcpy(wavehdr[lastwav].lpData, buffer, todo);

      mmres = waveOutWrite(DeviceID, &wavehdr[lastwav], sizeof(WAVEHDR));
      if (mmres) {
            char erstr[129];

            waveOutGetErrorText(mmres, erstr, sizeof(erstr));
            fprintf( stderr, "soundcard write error: %s!\n", erstr);
            return 1;
      }
      if (++lastwav >= WAVEHDRS)
             lastwav -= WAVEHDRS;
      result = mmres;
#else
#if   defined __EMX__
      Playlist[BufferInd].ulOperand1 = buffer;
      Playlist[BufferInd].ulOperand2 = todo;
      Playlist[BufferInd].ulOperand3 = 0;
      if (++BufferInd >= FRAGMENTS)
            BufferInd -= FRAGMENTS;

      /* no MCI_WAIT here, because application program has to continue */
      memset(&mciPlayParms, 0, sizeof(mciPlayParms));
      if (mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM, &mciPlayParms, 0)) {
            fprintf( stderr, "soundcard write error: %s!\n", erstr);
            return 1;
      }
      result = 0;
#else
      int retval2;
      int towrite;

#if   defined     HAVE_OSS && defined SNDCTL_DSP_GETOSPACE
      towrite = abinfo.fragments * abinfo.fragsize;
      if (towrite == 0)
#endif
      towrite = todo;
      do {
            fd_set writefds[1];
            struct timeval timeout2;
            int wrote;

            timeout2.tv_sec = 0;
            timeout2.tv_usec = 4*120000;

            FD_ZERO(writefds);
            FD_SET(global.soundcard_fd, writefds);
            retval2 = select(global.soundcard_fd + 1,
                         NULL, writefds, NULL, &timeout2);
            switch (retval2) {
                  default:
                  case -1: perror ("select failed");
                  /* fall through */
                  case 0: /* timeout */
                        result = 2;
                        goto outside_loop;
                  case 1: break;
            }
            if (towrite > todo) {
                  towrite = todo;
            }
#if         defined __QNX__ && defined HAVE_SYS_ASOUNDLIB_H
            wrote = snd_pcm_plugin_write(pcm_handle, buffer, towrite);
#else
            wrote = write(global.soundcard_fd, buffer, towrite);
#endif
            if (wrote <= 0) {
                  perror( "cant write audio");
                  result = 1;
                  goto outside_loop;
            } else {
                  todo -= wrote;
                  buffer += wrote;
            }
      } while (todo > 0);
outside_loop:
      ;
#endif      /* !defined __EMX__ */
#endif      /* !defined __CYGWIN32__ */
#endif      /* ECHO_TO_SOUNDCARD */
      return result;
}


Generated by  Doxygen 1.6.0   Back to index