1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 
6 #include <SDL.h>
7 
8 #include "../sexyal.h"
9 #include "../md5.h"
10 #include "../smallc.h"
11 
12 typedef struct
13 {
14 	void *Buffer;
15 	int32_t BufferSize;
16 	int32_t BufferRead;
17 	int32_t BufferWrite;
18 	int32_t BufferIn;
19 	int32_t BufferGranularity;
20 
21 	int StartPaused;
22 	int ProgPaused;
23 } SDLWrap;
24 
fillaudio(void * udata,uint8_t * stream,int len)25 static void fillaudio(void *udata, uint8_t *stream, int len)
26 {
27  SDLWrap *sw = udata;
28  int tocopy = len;
29 
30  if(tocopy > sw->BufferIn) tocopy = sw->BufferIn;
31 
32  if(tocopy < len)
33  {
34   //puts("Start pause");
35   SDL_PauseAudio(1);
36   sw->StartPaused = 1;
37  }
38 
39  while(tocopy)
40  {
41   int maxcopy = tocopy;
42 
43   if((maxcopy + sw->BufferRead) > sw->BufferSize)
44    maxcopy = sw->BufferSize - sw->BufferRead;
45 
46   memcpy(stream, (char *)sw->Buffer + sw->BufferRead, maxcopy);
47 
48   sw->BufferRead = (sw->BufferRead + maxcopy) % sw->BufferSize;
49 
50   sw->BufferIn -= maxcopy;
51 
52   stream += maxcopy;
53   tocopy -= maxcopy;
54   //printf("TOC: %d %d %d %d\n",tocopy, maxcopy,sw->BufferIn,sw->BufferSize);
55  }
56 }
57 
RawCanWrite(SexyAL_device * device)58 static uint32_t RawCanWrite(SexyAL_device *device)
59 {
60  SDLWrap *sw = device->private;
61  uint32_t ret;
62 
63  SDL_LockAudio();
64  ret = sw->BufferSize - sw->BufferIn;
65  SDL_UnlockAudio();
66  return(ret);
67 }
68 
RawWrite(SexyAL_device * device,void * data,uint32_t len)69 static uint32_t RawWrite(SexyAL_device *device, void *data, uint32_t len)
70 {
71  SDLWrap *sw = device->private;
72  uint32_t olen = len;
73 
74  while(len)
75  {
76   SDL_LockAudio();
77   int tocopy = len;
78 
79   if((tocopy + sw->BufferIn) > sw->BufferSize) tocopy = sw->BufferSize - sw->BufferIn;
80 
81   while(tocopy)
82   {
83    int maxcopy = tocopy;
84 
85    if((maxcopy + sw->BufferWrite) > sw->BufferSize)
86     maxcopy = sw->BufferSize - sw->BufferWrite;
87 
88    memcpy((char*)sw->Buffer + sw->BufferWrite, data, maxcopy);
89    sw->BufferWrite = (sw->BufferWrite + maxcopy) % sw->BufferSize;
90 
91    sw->BufferIn += maxcopy;
92 
93    data += maxcopy;
94    tocopy -= maxcopy;
95    len -= maxcopy;
96   }
97   SDL_UnlockAudio();
98   if(len)
99   {
100    if(sw->StartPaused)
101    {
102     sw->StartPaused = 0;
103     SDL_PauseAudio(sw->ProgPaused);
104    }
105    SDL_Delay(1);
106   }
107   //else
108   // puts("nodelay");
109  }
110  return(olen);
111 }
112 
Pause(SexyAL_device * device,int state)113 static int Pause(SexyAL_device *device, int state)
114 {
115  SDLWrap *sw = device->private;
116 
117  sw->ProgPaused = state?1:0;
118  SDL_PauseAudio(sw->ProgPaused | sw->StartPaused);
119 
120  return(sw->ProgPaused);
121 }
122 
Clear(SexyAL_device * device)123 static int Clear(SexyAL_device *device)
124 {
125  SDLWrap *sw = device->private;
126  SDL_LockAudio();
127 
128  SDL_PauseAudio(1);
129  sw->StartPaused = 1;
130  sw->BufferRead = sw->BufferWrite = sw->BufferIn = 0;
131 
132  SDL_UnlockAudio();
133  return(1);
134 }
135 
RawClose(SexyAL_device * device)136 static int RawClose(SexyAL_device *device)
137 {
138  if(device)
139  {
140   if(device->private)
141   {
142    SDLWrap *sw = device->private;
143    if(sw->Buffer)
144     free(sw->Buffer);
145    SDL_CloseAudio();
146    free(device->private);
147    SDL_Quit();
148   }
149   free(device);
150   return(1);
151  }
152  return(0);
153 }
154 
SexyALI_SDL_Open(char * id,SexyAL_format * format,SexyAL_buffering * buffering)155 SexyAL_device *SexyALI_SDL_Open(char *id, SexyAL_format *format, SexyAL_buffering *buffering)
156 {
157  SexyAL_device *device;
158  SDLWrap *sw;
159  SDL_AudioSpec desired, obtained;
160  int iflags;
161 
162  iflags = SDL_INIT_AUDIO | SDL_INIT_TIMER;
163 
164  #ifdef SDL_INIT_EVENTTHREAD
165  iflags |= SDL_INIT_EVENTTHREAD;
166  #endif
167  //iflags = SDL_INIT_EVERYTHING;
168  SDL_Init(iflags);
169 
170  sw = malloc(sizeof(SDLWrap));
171  memset(sw, 0, sizeof(SDLWrap));
172 
173  device = malloc(sizeof(SexyAL_device));
174  memset(device, 0, sizeof(SexyAL_device));
175  device->private = sw;
176 
177 
178  memset(&desired, 0, sizeof(SDL_AudioSpec));
179  memset(&obtained, 0, sizeof(SDL_AudioSpec));
180 
181  desired.freq = format->rate;
182  desired.format = AUDIO_S16;
183  desired.channels = format->channels;
184  desired.callback = fillaudio;
185  desired.userdata = sw;
186  desired.samples = 256;	// FIXME
187 
188  if(SDL_OpenAudio(&desired, &obtained) < 0)
189  {
190   puts(SDL_GetError());
191   RawClose(device);
192   return(0);
193  }
194 
195  format->channels = obtained.channels;
196  format->rate = obtained.freq;
197 
198  if(obtained.format == AUDIO_U8)
199   format->sampformat = SEXYAL_FMT_PCMU8;
200  else if(obtained.format == AUDIO_S8)
201   format->sampformat = SEXYAL_FMT_PCMS8;
202  else if(obtained.format == AUDIO_S16LSB || obtained.format == AUDIO_S16MSB)
203  {
204   format->sampformat = SEXYAL_FMT_PCMS16;
205   if(AUDIO_S16 != AUDIO_S16SYS)
206    format->byteorder = 1;
207  }
208  else if(obtained.format == AUDIO_U16LSB || obtained.format == AUDIO_U16MSB)
209  {
210   format->sampformat = SEXYAL_FMT_PCMU16;
211   if(AUDIO_S16 != AUDIO_U16SYS)
212    format->byteorder = 1;
213  }
214 
215  if(!buffering->ms)
216   buffering->ms = 100;
217 
218  sw->BufferSize = (format->rate * buffering->ms / 1000) - obtained.samples * 2;
219  if(sw->BufferSize < obtained.samples) sw->BufferSize = obtained.samples;
220 
221  sw->BufferIn = sw->BufferRead = sw->BufferWrite = 0;
222 
223  buffering->totalsize = sw->BufferSize;
224 
225  buffering->latency = (obtained.samples * 2 + sw->BufferSize);
226  //printf("%d\n", buffering->latency);
227  sw->BufferSize *= format->channels * (format->sampformat >> 4);
228  sw->Buffer = malloc(sw->BufferSize);
229 
230  memcpy(&device->format,format,sizeof(SexyAL_format));
231  memcpy(&device->buffering,buffering,sizeof(SexyAL_buffering));
232 
233  device->RawCanWrite = RawCanWrite;
234  device->RawWrite = RawWrite;
235  device->RawClose = RawClose;
236  device->Clear = Clear;
237  device->Pause = Pause;
238 
239  sw->StartPaused = 1;
240  //SDL_PauseAudio(0);
241  return(device);
242 }
243 
244