alsadevice.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // alsadevice.cpp
  2. #ifdef __linux
  3. #include "freeaudio.h"
  4. #include <sys/ioctl.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <sys/soundcard.h>
  8. #include <pthread.h>
  9. //#include <alsa/asoundlib.h>
  10. extern "C" audiodevice *OpenALSADevice();
  11. void *audiothread(void *dev);
  12. #define LINUXFRAG 2048
  13. struct alsaaudio:audiodevice{
  14. pthread_t audiothread;
  15. int threadid;
  16. int running,playing;
  17. short *buffer;
  18. int buffersize; //in bytes
  19. int reset(){
  20. running=1;
  21. playing=0;
  22. mix=new mixer(LINUXFRAG);
  23. mix->freq=44100;
  24. mix->channels=2;
  25. buffer=new short[LINUXFRAG];
  26. buffersize=LINUXFRAG*2;
  27. pthread_attr_t attr;
  28. pthread_attr_init(&attr);
  29. threadid=pthread_create(&audiothread,&attr,audiothread,(void*)this);
  30. return 0;
  31. }
  32. int close(){
  33. int timeout;
  34. running=0;
  35. timeout=5;
  36. while (timeout-- && playing) sleep(1);
  37. return 0;
  38. }
  39. };
  40. void *audiothread(void *v){
  41. int policy;
  42. sched_param sched;
  43. int err;
  44. alsaaudio *dev;
  45. pthread_getschedparam(pthread_self(),&policy,&sched);
  46. sched.sched_priority++;//policy=SCHED_RR;
  47. pthread_setschedparam(pthread_self(),policy,&sched);
  48. dev=(alsaaudio*)v;
  49. unsigned int val;
  50. snd_pcm_t *fd;
  51. snd_pcm_uframes_t periodsize;
  52. snd_pcm_hw_params_t *hwparams;
  53. snd_pcm_hw_params_alloca(&hwparams);
  54. int output_rate;
  55. int channels;
  56. int fragment_size;
  57. int fragment_count;
  58. err=snd_pcm_open(&fd, strdup("default"), SND_PCM_STREAM_PLAYBACK, 0);
  59. if (err<0) return -1;
  60. fragment_size=LINUXFRAG; //overall buffer size
  61. fragment_count=2; //2 - 16 fragment count - 2 minimum, the lower it is potentially the lower the latency
  62. //configure device
  63. if (snd_pcm_hw_params_any(fd, hwparams) < 0) {
  64. //printf("linuxaudio failed at params any\n");
  65. return -1;
  66. }
  67. if (snd_pcm_hw_params_set_access(fd, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
  68. //printf("linuxaudio failed at set access\n");
  69. return -1;
  70. }
  71. if (snd_pcm_hw_params_set_format(fd, hwparams,SND_PCM_FORMAT_S16_LE) < 0) {
  72. //printf("linuxaudio failed at set format\n");
  73. return -1;
  74. }
  75. val = 44100;
  76. if (snd_pcm_hw_params_set_rate_near(fd, hwparams,&val, 0) < 0) {
  77. // Try 48KHZ too
  78. //printf("linuxaudio - %d HZ not available, trying 48000HZ\n", output_rate);
  79. val = 48000;
  80. if (snd_pcm_hw_params_set_rate_near(fd, hwparams,&val, 0) < 0) {
  81. //printf("linuxaudio failed at setting output rate (%d)\n", output_rate);
  82. return -1;
  83. }
  84. dev->mix->freq=val;
  85. }
  86. channels=2;
  87. if (snd_pcm_hw_params_set_channels(fd, hwparams, channels) < 0) {
  88. //printf("linuxaudio failed at set channels (%d)\n", channels);
  89. return -1;
  90. }
  91. periodsize = (fragment_size) / 4; // bytes -> frames for 16-bit,stereo - should be a minimum of 512
  92. if (snd_pcm_hw_params_set_period_size_near(fd, hwparams,&periodsize, 0) < 0) {
  93. //printf("linuxaudio failed at set period size (%d)\n", (int)periodsize);
  94. return -1;
  95. }
  96. val = fragment_count;
  97. if (snd_pcm_hw_params_set_periods_near(fd, hwparams,&val, 0) < 0) {
  98. //printf("linuxaudio failed at set periods (%d)\n", val);
  99. //should attempt a one by one period increase up to 16?
  100. return -1;
  101. }
  102. if (snd_pcm_hw_params(fd, hwparams) < 0) {
  103. //printf("linuxaudio failed at installing hw params\n");
  104. return -1;
  105. }
  106. //loop while playing sound
  107. dev->playing=1;
  108. while (dev->playing)
  109. {
  110. dev->mix->mix16(dev->buffer);
  111. if ((snd_pcm_writei (fd, dev->buffer,LINUXFRAG/2)) < 0) { //Half buffer for two channels?
  112. //printf ("linuxaudio warning: buffer underrun occurred\n");
  113. if (snd_pcm_prepare(fd) < 0) {
  114. //printf ("linuxaudio failed at preparing pcm\n");
  115. dev->playing=0; //die gracefully
  116. }
  117. }
  118. }
  119. snd_pcm_drop(fd);
  120. snd_pcm_close (fd);
  121. return 0;
  122. }
  123. audiodevice *OpenALSADevice(){
  124. return new alsaaudio();
  125. }
  126. #endif