Mercurial > mplayer.hg
annotate libao2/ao_nas.c @ 3639:64ee21b3bd09
Modified the sync code once again, commented out hardware pts sync (I'll likely burn in hell before understanding how to get this bastard to sync well)
Added automagic setup of aspect ratio, will remove the "aspect-bug" (I hope). As well as please you rich 16:9 doods ;)
author | mswitch |
---|---|
date | Thu, 20 Dec 2001 20:50:35 +0000 |
parents | 8818c12743a8 |
children | 080cf3df3e4e |
rev | line source |
---|---|
3336
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
1 /* |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
2 * NAS output plugin for mplayer |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
3 * |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
4 * based on the libaudiooss parts rewritten by me, which were |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
5 * originally based on the NAS output plugin for xmms. |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
6 * |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
7 * xmms plugin by Willem Monsuwe |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
8 * adapted for libaudiooss by Jon Trulson |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
9 * further modified by Erik Inge Bolsų |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
10 * largely rewritten and used for this |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
11 * plugin by Tobias Diedrich |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
12 * |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
13 */ |
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
14 |
3276 | 15 #include <stdio.h> |
16 #include <stdlib.h> | |
17 #include <pthread.h> | |
18 #include <audio/audiolib.h> | |
19 | |
20 #include "audio_out.h" | |
21 #include "audio_out_internal.h" | |
22 #include "afmt.h" | |
23 | |
24 #define FRAG_SIZE 4096 | |
25 #define FRAG_COUNT 8 | |
26 #define BUFFER_SIZE FRAG_SIZE * FRAG_COUNT | |
27 | |
28 #define NAS_DEBUG 0 | |
29 | |
30 #if NAS_DEBUG == 1 | |
31 #define DPRINTF(format, args...) fprintf(stderr, format, ## args); \ | |
32 fflush(stderr) | |
33 #else | |
34 #define DPRINTF(format, args...) | |
35 #endif | |
36 | |
37 static ao_info_t info = | |
38 { | |
39 "NAS audio output", | |
40 "nas", | |
41 "Tobias Diedrich", | |
42 "" | |
43 }; | |
44 | |
45 static AuServer* aud; | |
46 static AuFlowID flow; | |
47 static AuDeviceID dev; | |
48 | |
49 static void *client_buffer; | |
50 static int client_buffer_size = BUFFER_SIZE; | |
51 static int client_buffer_used; | |
52 static int server_buffer_size = BUFFER_SIZE; | |
53 static int server_buffer_used; | |
54 static pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER; | |
55 | |
56 pthread_t event_thread; | |
57 static int stop_thread; | |
58 | |
59 LIBAO_EXTERN(nas) | |
60 | |
61 static void wait_for_event() | |
62 { | |
63 AuEvent ev; | |
64 | |
65 AuNextEvent(aud, AuTrue, &ev); | |
66 AuDispatchEvent(aud, &ev); | |
67 } | |
68 | |
69 static int readBuffer(int num) | |
70 { | |
71 pthread_mutex_lock(&buffer_mutex); | |
72 DPRINTF("readBuffer(): num=%d client=%d/%d server=%d/%d\n", | |
73 num, | |
74 client_buffer_used, client_buffer_size, | |
75 server_buffer_used, server_buffer_size); | |
76 | |
77 if (client_buffer_used == 0) { | |
78 DPRINTF("buffer is empty, nothing read.\n"); | |
79 pthread_mutex_unlock(&buffer_mutex); | |
80 return 0; | |
81 } | |
82 if (client_buffer_used < num) | |
83 num = client_buffer_used; | |
84 | |
85 AuWriteElement(aud, flow, 0, num, client_buffer, AuFalse, NULL); | |
86 client_buffer_used -= num; | |
87 server_buffer_used += num; | |
88 memmove(client_buffer, client_buffer + num, client_buffer_used); | |
89 pthread_mutex_unlock(&buffer_mutex); | |
90 | |
91 return num; | |
92 } | |
93 | |
94 static void writeBuffer(void *data, int len) | |
95 { | |
96 pthread_mutex_lock(&buffer_mutex); | |
97 DPRINTF("writeBuffer(): len=%d client=%d/%d server=%d/%d\n", | |
98 len, client_buffer_used, client_buffer_size, | |
99 server_buffer_used, server_buffer_size); | |
100 | |
101 memcpy(client_buffer + client_buffer_used, data, len); | |
102 client_buffer_used += len; | |
103 | |
104 pthread_mutex_unlock(&buffer_mutex); | |
105 if (server_buffer_used < server_buffer_size) | |
106 readBuffer(server_buffer_size - server_buffer_used); | |
107 } | |
108 | |
109 | |
110 static void *event_thread_start(void *data) | |
111 { | |
112 while (!stop_thread) { | |
113 wait_for_event(); | |
114 } | |
115 } | |
116 | |
117 static AuBool event_handler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *hnd) | |
118 { | |
119 switch (ev->type) { | |
120 case AuEventTypeElementNotify: { | |
121 AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; | |
122 DPRINTF("event_handler(): kind %d state %d->%d reason %d numbytes %d\n", | |
123 event->kind, | |
124 event->prev_state, | |
125 event->cur_state, | |
126 event->reason, | |
127 event->num_bytes); | |
128 | |
129 switch (event->kind) { | |
130 case AuElementNotifyKindLowWater: | |
131 server_buffer_used -= event->num_bytes; | |
132 readBuffer(event->num_bytes); | |
133 break; | |
134 case AuElementNotifyKindState: | |
135 if ((event->cur_state == AuStatePause) && | |
136 (event->reason != AuReasonUser)) { | |
137 // buffer underrun -> refill buffer | |
138 server_buffer_used = 0; | |
139 readBuffer(server_buffer_size - server_buffer_used); | |
140 } | |
141 } | |
142 } | |
143 } | |
144 return AuTrue; | |
145 } | |
146 | |
147 static AuBool error_handler(AuServer* aud, AuErrorEvent* ev) | |
148 { | |
149 char s[100]; | |
150 AuGetErrorText(aud, ev->error_code, s, 100); | |
3336
8818c12743a8
patch by Tobias Diedrich <td@informatik.uni-hannover.de>
pl
parents:
3276
diff
changeset
|
151 fprintf(stderr,"ao_nas: error [%s]\n" |
3276 | 152 "error_code: %d\n" |
153 "request_code: %d\n" | |
154 "minor_code: %d\n", | |
155 s, | |
156 ev->error_code, | |
157 ev->request_code, | |
158 ev->minor_code); | |
159 fflush(stderr); | |
160 | |
161 return AuTrue; | |
162 } | |
163 | |
164 static AuDeviceID find_device(int nch) | |
165 { | |
166 int i; | |
167 for (i = 0; i < AuServerNumDevices(aud); i++) { | |
168 AuDeviceAttributes *dev = AuServerDevice(aud, i); | |
169 if ((AuDeviceKind(dev) == AuComponentKindPhysicalOutput) && | |
170 AuDeviceNumTracks(dev) == nch) { | |
171 return AuDeviceIdentifier(dev); | |
172 } | |
173 } | |
174 return AuNone; | |
175 } | |
176 | |
177 static unsigned char aformat_to_auformat(unsigned int format) | |
178 { | |
179 switch (format) { | |
180 case AFMT_U8: return AuFormatLinearUnsigned8; | |
181 case AFMT_S8: return AuFormatLinearSigned8; | |
182 case AFMT_U16_LE: return AuFormatLinearUnsigned16LSB; | |
183 case AFMT_U16_BE: return AuFormatLinearUnsigned16MSB; | |
184 case AFMT_S16_LE: return AuFormatLinearSigned16LSB; | |
185 case AFMT_S16_BE: return AuFormatLinearSigned16MSB; | |
186 case AFMT_MU_LAW: return AuFormatULAW8; | |
187 default: return 0; | |
188 } | |
189 } | |
190 | |
191 // to set/get/query special features/parameters | |
192 static int control(int cmd,int arg){ | |
193 return -1; | |
194 } | |
195 | |
196 // open & setup audio device | |
197 // return: 1=success 0=fail | |
198 static int init(int rate,int channels,int format,int flags) | |
199 { | |
200 AuElement elms[3]; | |
201 AuStatus as; | |
202 unsigned char auformat = aformat_to_auformat(format); | |
203 int bytes_per_sample; | |
204 char *server; | |
205 | |
206 printf("ao2: %d Hz %d chans %s\n",rate,channels, | |
207 audio_out_format_name(format)); | |
208 | |
209 if (!auformat) { | |
210 printf("Unsupported format -> nosound\n"); | |
211 return 0; | |
212 } | |
213 | |
214 client_buffer = malloc(BUFFER_SIZE); | |
215 bytes_per_sample = channels * AuSizeofFormat(auformat); | |
216 | |
217 ao_data.samplerate = rate; | |
218 ao_data.channels = channels; | |
219 ao_data.buffersize = BUFFER_SIZE * 2; | |
220 ao_data.outburst = FRAG_SIZE; | |
221 ao_data.bps = rate * bytes_per_sample; | |
222 | |
223 if (!bytes_per_sample) { | |
224 printf("Zero bytes per sample -> nosound\n"); | |
225 return 0; | |
226 } | |
227 | |
228 if (!(server = getenv("AUDIOSERVER"))) | |
229 server = getenv("DISPLAY"); | |
230 | |
231 if (!server) // default to tcp/localhost:8000 | |
232 server = "tcp/localhost:8000"; | |
233 | |
234 printf("Using audioserver %s\n", server); | |
235 | |
236 aud = AuOpenServer(server, 0, NULL, 0, NULL, NULL); | |
237 if (!aud){ | |
238 printf("Can't open nas audio server -> nosound\n"); | |
239 return 0; | |
240 } | |
241 | |
242 dev = find_device(channels); | |
243 if ((dev == AuNone) || (!(flow = AuCreateFlow(aud, NULL)))) { | |
244 printf("Can't find a device serving that many channels -> nosound\n"); | |
245 AuCloseServer(aud); | |
246 aud = 0; | |
247 return 0; | |
248 } | |
249 | |
250 AuMakeElementImportClient(elms, rate, auformat, channels, AuTrue, | |
251 BUFFER_SIZE / bytes_per_sample, | |
252 (BUFFER_SIZE - FRAG_SIZE) / bytes_per_sample, | |
253 0, NULL); | |
254 AuMakeElementExportDevice(elms+1, 0, dev, rate, | |
255 AuUnlimitedSamples, 0, NULL); | |
256 AuSetElements(aud, flow, AuTrue, 2, elms, &as); | |
257 if (as != AuSuccess) | |
258 printf("AuSetElements returned status %d!\n", as); | |
259 AuRegisterEventHandler(aud, AuEventHandlerIDMask | | |
260 AuEventHandlerTypeMask, | |
261 AuEventTypeElementNotify, flow, | |
262 event_handler, (AuPointer) NULL); | |
263 AuSetErrorHandler(aud, error_handler); | |
264 AuStartFlow(aud, flow, &as); | |
265 if (as != AuSuccess) | |
266 printf("AuSetElements returned status %d!\n", as); | |
267 | |
268 /* | |
269 * Wait for first buffer underrun event | |
270 * | |
271 * For some weird reason we get a buffer underrun event if we | |
272 * don't fill the server buffer fast enough after staring the | |
273 * flow. So we just wait for it to happen to be in a sane state. | |
274 */ | |
275 wait_for_event(); | |
276 | |
277 pthread_create(&event_thread, NULL, &event_thread_start, NULL); | |
278 | |
279 return 1; | |
280 } | |
281 | |
282 // close audio device | |
283 static void uninit(){ | |
284 stop_thread = 1; | |
285 pthread_join(event_thread, NULL); | |
286 AuStopFlow(aud, flow, NULL); | |
287 AuCloseServer(aud); | |
288 aud = 0; | |
289 free(client_buffer); | |
290 } | |
291 | |
292 // stop playing and empty buffers (for seeking/pause) | |
293 static void reset(){ | |
294 pthread_mutex_lock(&buffer_mutex); | |
295 client_buffer_used = 0; | |
296 pthread_mutex_unlock(&buffer_mutex); | |
297 while (server_buffer_used > 0) { | |
298 usleep(1000); | |
299 // DPRINTF("used=%d\n", server_buffer_used); | |
300 } | |
301 } | |
302 | |
303 // stop playing, keep buffers (for pause) | |
304 static void audio_pause() | |
305 { | |
306 // for now, just call reset(); | |
307 reset(); | |
308 } | |
309 | |
310 // resume playing, after audio_pause() | |
311 static void audio_resume() | |
312 { | |
313 } | |
314 | |
315 // return: how many bytes can be played without blocking | |
316 static int get_space() | |
317 { | |
318 int result; | |
319 | |
320 pthread_mutex_lock(&buffer_mutex); | |
321 result = client_buffer_size - client_buffer_used; | |
322 pthread_mutex_unlock(&buffer_mutex); | |
323 | |
324 return result; | |
325 } | |
326 | |
327 // plays 'len' bytes of 'data' | |
328 // it should round it down to outburst*n | |
329 // return: number of bytes played | |
330 static int play(void* data,int len,int flags){ | |
331 writeBuffer(data, len); | |
332 // printf("ao_nas: wrote %d bytes of audio data\n", len); | |
333 return len; | |
334 } | |
335 | |
336 // return: delay in seconds between first and last sample in buffer | |
337 static float get_delay() | |
338 { | |
339 float result; | |
340 | |
341 pthread_mutex_lock(&buffer_mutex); | |
342 result = ((float)(client_buffer_used + server_buffer_used)) / | |
343 (float)ao_data.bps; | |
344 pthread_mutex_unlock(&buffer_mutex); | |
345 | |
346 return result; | |
347 } |