obuffer.cc
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:11k
源码类别:

DVD

开发平台:

Unix_Linux

  1. /*
  2.    File: obuffer.cc
  3.    
  4.    Description:
  5.    Audio output buffer implementation
  6. */
  7. #ifdef __GNUG__
  8. #pragma implementation
  9. #endif
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <String.h>
  14. #include <unistd.h>
  15. #include <fcntl.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/types.h>
  18. #ifndef LINUX
  19. #include <stropts.h>
  20. #endif
  21. #include <fstream.h>
  22. #ifdef IRIX
  23. extern "C" {
  24. #include <dmedia/audio.h>
  25. }
  26. #endif
  27. #ifdef SOLARIS
  28. #include <sys/audioio.h>
  29. #endif
  30. #ifdef LINUX
  31. #include <sys/soundcard.h>
  32. #endif
  33. #include <memory.h>
  34. #include <sys/select.h>
  35. #include <sys/time.h>  // Time
  36. #ifndef LINUX
  37. extern "C" {
  38. int ioctl(int, int, ...);
  39. }
  40. #else
  41. #define IOCTL(a,b,c) ioctl(a,b,&c)
  42. #endif
  43. #include "athread.hh"
  44. #include <errno.h>
  45. #include "error.hh"
  46. #include "debug.hh"
  47. #include "util.hh"
  48. #include "sync.hh"
  49. #include "mpeg2const.hh"
  50. #include "mpeg2buff.hh"
  51. #include "astream.hh"
  52. #include "crc.hh"
  53. #include "header.hh"
  54. #include "obuffer.hh"
  55. ShortObuffer::ShortObuffer(uint32 number_of_channels){
  56. #ifdef DEBUG
  57.   if (!number_of_channels || number_of_channels > MAXCHANNELS){
  58.     String err("ShortObuffer: number of channels has to be in [1, ");
  59.     err+=itoa(MAXCHANNELS);
  60.     err+="]!";
  61.     error(err.chars());
  62.     athr_exit(0);
  63.   }
  64. #endif
  65.   channels = number_of_channels;
  66.   for (unsigned int i=0; i<number_of_channels; i++) bufferp[i]=buffer+i;
  67. }
  68. void ShortObuffer::append(uint32 channel, int16 value){
  69. #ifdef DEBUG
  70.   if (channel >= channels){
  71.     error("illegal channelnumber in ShortObuffer::append()!");
  72.     athr_exit(0);
  73.   }
  74.   if (bufferp[channel] - buffer >= OBUFFERSIZE){
  75.     error("ShortObuffer: buffer overflow!");
  76.     athr_exit(0);
  77.   }
  78. #endif
  79.   *bufferp[channel] = value;
  80.   bufferp[channel] += channels;
  81. }
  82. void ShortObuffer::write_buffer (int fd){
  83.   int length = (int)((char *)bufferp[0] - (char *)buffer);
  84.   if (write (fd, buffer, length) != length)
  85.     warning("couldn't write all samples");
  86.   for (unsigned int i=0; i<channels; i++) bufferp[i]=buffer+i;
  87. }
  88. #ifdef IRIX
  89.   
  90. IrixObuffer::IrixObuffer(uint32 number_of_channels, Header* header){
  91. #ifdef DEBUG
  92.   if (!number_of_channels || number_of_channels > MAXCHANNELS){
  93.     cerr << "IrixObuffer: number of channels has to be in [1, " <<  MAXCHANNELS << "] !n";
  94.     exit(1);
  95.   }
  96. #endif
  97.   channels = number_of_channels;
  98.   for (int i = 0; i < number_of_channels; ++i) bufferp[i] = buffer + i;
  99.   
  100.   // open an audio port and configure it:
  101.     ALconfig config;
  102.   if (!(config = ALnewconfig())){
  103.     error("ALnewconfig failed!");
  104.     exit(1);
  105.   }
  106.   ALsetwidth(config, AL_SAMPLE_16);
  107.   if (channels == 1)
  108.     ALsetchannels(config, AL_MONO);
  109.   else  ALsetchannels(config, AL_STEREO);
  110.   if (!(port = ALopenport("MPEG audio player", "w", config))){
  111.     error("can't allocate an audio port!");
  112.     exit (1);
  113.   }
  114.   
  115.   // set sample rate:
  116.   long pvbuffer[2] = { AL_OUTPUT_RATE, 0 };
  117.   pvbuffer[1] = header->frequency ();
  118.   ALsetparams(AL_DEFAULT_DEVICE, pvbuffer, 2);
  119.   ALfreeconfig(config);
  120. }
  121. IrixObuffer::~IrixObuffer(){
  122.   while (ALgetfilled(port) > 0) sleep (1);
  123.   ALcloseport(port);
  124. }
  125. // All inline to avoid linking problem!
  126. void IrixObuffer::append(uint32 channel, int16 value){
  127. #ifdef DEBUG
  128.   if (channel >= channels){
  129.     error("illegal channelnumber in IrixObuffer::append()!");
  130.     athr_exit(0);
  131.   }
  132.   if (bufferp[channel] - buffer >= OBUFFERSIZE){
  133.     error("IrixObuffer: buffer overflow!");
  134.     athr_exit(0);
  135.   }
  136. #endif
  137.   *bufferp[channel] = value;
  138.   bufferp[channel] += channels;
  139. }
  140. void IrixObuffer::write_buffer(int /* dummy */){
  141.   ALwritesamps(port, buffer, (long)(bufferp[0] - buffer));
  142.   for (int i = 0; i < channels; ++i) bufferp[i] = buffer + i;
  143. }
  144. #endif // IRIX
  145. #ifdef SOLARIS
  146. int SparcObuffer::audio_fd = -1;
  147. SparcObuffer::SparcObuffer (uint32 number_of_channels, Header *header,
  148.     bool use_speaker, bool use_headphone, bool use_line_out){
  149.   channels=number_of_channels;
  150. #ifdef DEBUG
  151.   if (!number_of_channels || number_of_channels > MAXCHANNELS){
  152.     cerr << "SparcObuffer: 0 < number of channels < " << MAXCHANNELS << "!n";
  153.     exit (1);
  154.   }
  155. #endif
  156.   for (unsigned int i=0; i<number_of_channels; i++) bufferp[i]=buffer+i;
  157.   if (audio_fd < 0){
  158.     error("SparcObuffer::audio_fd has to be initialized by SparcObuffer::class_suitable()!");
  159.     athr_exit(0);
  160.   }
  161.   // configure the device:
  162.   audio_info info;
  163.   AUDIO_INITINFO (&info);
  164.   info.output_muted = False;
  165.   info.play.sample_rate = header->frequency ();
  166.   info.play.channels = channels;
  167.   info.play.precision = 16;
  168.   info.play.encoding = AUDIO_ENCODING_LINEAR;
  169. //  info.play.gain=AUDIO_MAX_GAIN/3;
  170.   if (use_speaker)
  171.     info.play.port |= AUDIO_SPEAKER;
  172.   if (use_headphone)
  173.     info.play.port |= AUDIO_HEADPHONE;
  174.   if (use_line_out)
  175.     info.play.port |= AUDIO_LINE_OUT;
  176.   info.play.buffer_size=OBUFFERSIZE;
  177.   info.play.samples=0;
  178.   info.play.eof=0;
  179.   info.play.pause=0;
  180.   info.play.error=0;
  181.   info.play.waiting=0;
  182.   info.play.balance = AUDIO_MID_BALANCE;
  183.   if (ioctl(audio_fd, AUDIO_SETINFO, &info)){
  184.     error("configuration of /dev/audio failed");
  185.     athr_exit(0);
  186.   }
  187. }
  188. static int droppedframes=0;
  189. static timeval timeout;
  190. SparcObuffer::~SparcObuffer (void){
  191.   ioctl(audio_fd, AUDIO_DRAIN);
  192.   close (audio_fd);
  193.   msg("Number of interrupted frames: ");  message(itoa(droppedframes));
  194. }
  195. void SparcObuffer::append(uint32 channel, int16 value){
  196. #ifdef DEBUG
  197.   if (channel >= channels){
  198.     cerr << "illegal channelnumber in SparcObuffer::append()!n";
  199.     exit (1);
  200.   }
  201.   if (bufferp[channel] - buffer >= OBUFFERSIZE){
  202.     cerr << "buffer overflow!n";
  203.     exit (1);
  204.   }
  205. #endif
  206.   *bufferp[channel] = value;
  207.   bufferp[channel] += channels;
  208. }
  209. void SparcObuffer::write_buffer(int){
  210.   int length = (int)((char*) bufferp[0] - (char*) buffer);
  211. #ifdef SPARC5
  212.   // This stuff seems useful on a SUN Sparc 5 
  213.   static fd_set wfs;
  214.   FD_ZERO(&wfs);
  215.   FD_SET(audio_fd, &wfs);
  216.   if (select(FD_SETSIZE, 0, &wfs, 0, &timeout)>=0){
  217.     if (FD_ISSET(audio_fd, &wfs)){
  218. #endif
  219.       if (write(audio_fd, buffer, length) != length){
  220.         message("Warning: couldn't write all samples to /dev/audio");
  221.       }
  222. #ifdef SPARC5
  223.     }
  224.     else {
  225.       ioctl(audio_fd, I_FLUSH, FLUSHW);    // flush current stuff and replace by new
  226.       msg("flush audio");
  227.       droppedframes++;
  228.       if (write(audio_fd, buffer, length) != length){
  229.         message("Warning: couldn't write all samples to /dev/audio");
  230.       }
  231.     }
  232.   }
  233. #endif
  234.   for (unsigned int i=0; i<channels; i++) bufferp[i]=buffer+i;
  235. }
  236. int SparcObuffer::open_audio_device (void){
  237.   int fd=0;
  238.   // just check
  239.   if ((fd=open("/dev/audio", O_WRONLY | O_NDELAY)) < 0) // 
  240.     if (errno == EBUSY){
  241.       cerr << "Sorry, the audio device is busy!n";
  242.       exit (1);
  243.     }
  244.     else{
  245.       perror ("can't open /dev/audio for writing");
  246.       exit (1);
  247.     }
  248.   ioctl(fd, I_FLUSH, FLUSHRW);
  249.   close(fd);
  250.   /* now open (blocking) // | O_NDELAY)) */
  251.   if ((fd=open("/dev/audio", O_WRONLY))< 0){ 
  252.     if (errno == EBUSY){
  253.       error("Sorry, the audio device is busy!");
  254.       athr_exit(0);
  255.     }
  256.     else {
  257.       error("can't open /dev/audio for writing");
  258.       athr_exit(0);
  259.     }
  260.   }
  261.   ioctl(fd, I_FLUSH, FLUSHW);
  262.   // next time out
  263.   timeout.tv_sec=0;             // length/5513;  // length/5513=length*8 / 44100 (bps) 
  264.   timeout.tv_usec=752600;
  265.   // (long int) (length*181);   // length*181= length*8/ 44100 * 1000000
  266. }
  267. void SparcObuffer::get_device_type (int fd, audio_device *devtype){
  268.   if (ioctl (fd, AUDIO_GETDEV, devtype)){
  269.     error("ioctl on /dev/audio");
  270.     athr_exit(0);
  271.   }
  272. }
  273. bool SparcObuffer::class_suitable (void){
  274.   audio_fd=open_audio_device();      // check for the CS4231 or dbri audio device
  275.   audio_device devtype;
  276.   get_device_type(audio_fd, &devtype);
  277.   // Sparc 5: CS4321, Sparc 10: dbri
  278.   return (!strcmp (devtype.name, "SUNW,CS4231") || !strcmp (devtype.name, "SUNW,dbri")) ? True : False;
  279. }
  280. #endif // SOLARIS
  281. #ifdef LINUX
  282. int LinuxObuffer::audio_fd = -1;
  283. LinuxObuffer::LinuxObuffer (uint32 number_of_channels,Header *header) {
  284.   int abuf_size;
  285.   int sample_rate;
  286.   int sample_bits=16;
  287.   int chan = channels=number_of_channels;
  288.   
  289. #ifdef DEBUG
  290.   if (!number_of_channels || number_of_channels > MAXCHANNELS){
  291.     cerr << "LinuxObuffer: 0 < number of channels < " << MAXCHANNELS << "!n";
  292.     exit (1);
  293.   }
  294. #endif
  295.   for (unsigned int i=0; i<number_of_channels; i++) bufferp[i]=buffer+i;
  296.   if (audio_fd < 0){
  297.     error("LinuxObuffer::audio_fd has to be initialized by LinuxObuffer::class_suitable()!");
  298.     athr_exit(0);
  299.   }
  300.   IOCTL(audio_fd, SNDCTL_DSP_GETBLKSIZE, abuf_size);
  301.   if (abuf_size < 4096 || abuf_size > 65536) {
  302.     if (abuf_size == -1) {
  303.       error ("LinuxObuffer::abufsize failure");
  304.     } else {
  305.       error("Invalid audio buffers size n");
  306.     }
  307.     athr_exit (0);
  308.   }
  309.   // configure the device:
  310.   sample_rate = header->frequency ();
  311.   if (IOCTL(audio_fd, SNDCTL_DSP_SPEED, sample_rate) < 0) {
  312.     error("unable to set audio speed");
  313.     athr_exit (0);
  314.   }
  315.   if ( IOCTL(audio_fd, SNDCTL_DSP_CHANNELS, chan) < 0 ) {
  316.     printf("LinuxObuffer::amount of channels (%d) not supportedn",chan);
  317.     athr_exit(0);
  318.   }
  319.   chan--;
  320.   if ( IOCTL(audio_fd, SNDCTL_DSP_STEREO, chan) < 0 ) {
  321.     printf("LinuxObuffer::Error when setting stereon");
  322.     athr_exit(0);
  323.   }
  324.   IOCTL(audio_fd, SNDCTL_DSP_SAMPLESIZE, sample_bits);
  325. }
  326. static int droppedframes=0;
  327. static timeval timeout;
  328. LinuxObuffer::~LinuxObuffer (void){
  329.   ioctl(audio_fd, SNDCTL_DSP_SYNC,NULL);
  330.   close (audio_fd);
  331.   msg("Number of interrupted frames: ");  message(itoa(droppedframes));
  332. }
  333. void LinuxObuffer::append(uint32 channel, int16 value){
  334. #ifdef DEBUG
  335.   if (channel >= channels){
  336.     cerr << "illegal channelnumber in SparcObuffer::append()!n";
  337.     exit (1);
  338.   }
  339.   if (bufferp[channel] - buffer >= OBUFFERSIZE){
  340.     cerr << "buffer overflow!n";
  341.     exit (1);
  342.   }
  343. #endif
  344.   *bufferp[channel] = value;
  345.   bufferp[channel] += channels;
  346. }
  347. void LinuxObuffer::write_buffer(int){
  348.   int length = (int)((char*) bufferp[0] - (char*) buffer);
  349.       if (write(audio_fd, buffer, length) != length){
  350.         message("Warning: couldn't write all samples to /dev/audio");
  351.       }
  352.   for (unsigned int i=0; i<channels; i++) bufferp[i]=buffer+i;
  353. }
  354. int LinuxObuffer::open_audio_device (void){
  355.   int fd=0;
  356.   // just check
  357.   if ((fd=open("/dev/dsp", O_WRONLY | O_NDELAY)) < 0) // 
  358.     if (errno == EBUSY){
  359.       cerr << "Sorry, the audio device is busy!n";
  360.       exit (1);
  361.     }
  362.     else{
  363.       perror ("can't open /dev/audio for writing");
  364.       exit (1);
  365.     }
  366.   ioctl(fd, SNDCTL_DSP_SYNC,NULL);
  367.   close(fd);
  368.   /* now open (blocking) // | O_NDELAY)) */
  369.   if ((fd=open("/dev/dsp", O_WRONLY))< 0){ 
  370.     if (errno == EBUSY){
  371.       error("Sorry, the audio device is busy!");
  372.       athr_exit(0);
  373.     }
  374.     else {
  375.       error("can't open /dev/audio for writing");
  376.       athr_exit(0);
  377.     }
  378.   }
  379.   ioctl(fd, SNDCTL_DSP_SYNC,NULL);
  380.   // next time out
  381.   timeout.tv_sec=0;             // length/5513;  // length/5513=length*8 / 44100 (bps) 
  382.   timeout.tv_usec=752600;
  383.   // (long int) (length*181);   // length*181= length*8/ 44100 * 1000000
  384.   return fd;
  385. }
  386. bool LinuxObuffer::class_suitable (void){
  387.   audio_fd=open_audio_device();      // check for audio device
  388.   if (audio_fd == -1)
  389.     return False;
  390.   return True;
  391. }
  392. #endif // LINUX