/[rdesktop]/sourceforge.net/rdesktop/trunk/rdpsnd.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/rdesktop/trunk/rdpsnd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1302 - (hide annotations)
Thu Oct 26 09:47:17 2006 UTC (17 years, 7 months ago) by ossman_
Original Path: sourceforge.net/trunk/rdesktop/rdpsnd.c
File MIME type: text/plain
File size: 12580 byte(s)
Rewrite the queue management a bit so that blocks are not completed until
they have finished playing. This also makes the queue system mandatory for
all backends.

1 astrand 963 /* -*- c-basic-offset: 8 -*-
2 matthewc 474 rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions
4     Copyright (C) Matthew Chapman 2003
5     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20     */
21    
22 ossman_ 1298 #include <assert.h>
23    
24 matthewc 432 #include "rdesktop.h"
25 stargo 1254 #include "rdpsnd.h"
26 stargo 1258 #include "rdpsnd_dsp.h"
27 matthewc 432
28 matthewc 474 #define RDPSND_CLOSE 1
29     #define RDPSND_WRITE 2
30     #define RDPSND_SET_VOLUME 3
31     #define RDPSND_UNKNOWN4 4
32     #define RDPSND_COMPLETION 5
33 stargo 1044 #define RDPSND_SERVERTICK 6
34 matthewc 474 #define RDPSND_NEGOTIATE 7
35    
36     #define MAX_FORMATS 10
37 stargo 1254 #define MAX_QUEUE 10
38 matthewc 474
39 stargo 1254 BOOL g_dsp_busy = False;
40     int g_dsp_fd;
41    
42 matthewc 432 static VCHANNEL *rdpsnd_channel;
43 stargo 1255 static struct audio_driver *drivers = NULL;
44 stargo 1256 struct audio_driver *current_driver = NULL;
45 matthewc 432
46 matthewc 474 static BOOL device_open;
47     static WAVEFORMATEX formats[MAX_FORMATS];
48     static unsigned int format_count;
49     static unsigned int current_format;
50 ossman_ 1302 unsigned int queue_hi, queue_lo, queue_pending;
51 stargo 1256 struct audio_packet packet_queue[MAX_QUEUE];
52 matthewc 474
53 stargo 1255 void (*wave_out_play) (void);
54    
55 ossman_ 1302 static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index);
56     static void rdpsnd_queue_init(void);
57     static void rdpsnd_queue_complete_pending(void);
58     static long rdpsnd_queue_next_completion(void);
59    
60 astrand 665 static STREAM
61 matthewc 474 rdpsnd_init_packet(uint16 type, uint16 size)
62     {
63     STREAM s;
64    
65 astrand 499 s = channel_init(rdpsnd_channel, size + 4);
66 matthewc 474 out_uint16_le(s, type);
67     out_uint16_le(s, size);
68     return s;
69     }
70    
71 astrand 665 static void
72 matthewc 474 rdpsnd_send(STREAM s)
73     {
74     #ifdef RDPSND_DEBUG
75     printf("RDPSND send:\n");
76 astrand 499 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
77 matthewc 474 #endif
78    
79     channel_send(s, rdpsnd_channel);
80     }
81    
82 ossman_ 1302 static void
83 astrand 499 rdpsnd_send_completion(uint16 tick, uint8 packet_index)
84 matthewc 474 {
85     STREAM s;
86    
87     s = rdpsnd_init_packet(RDPSND_COMPLETION, 4);
88 stargo 1254 out_uint16_le(s, tick);
89 matthewc 474 out_uint8(s, packet_index);
90     out_uint8(s, 0);
91     s_mark_end(s);
92     rdpsnd_send(s);
93     }
94    
95 astrand 665 static void
96 matthewc 474 rdpsnd_process_negotiate(STREAM in)
97     {
98     unsigned int in_format_count, i;
99     WAVEFORMATEX *format;
100     STREAM out;
101 stargo 491 BOOL device_available = False;
102 stargo 493 int readcnt;
103     int discardcnt;
104 matthewc 474
105     in_uint8s(in, 14); /* flags, volume, pitch, UDP port */
106     in_uint16_le(in, in_format_count);
107     in_uint8s(in, 4); /* pad, status, pad */
108    
109 stargo 1255 if (current_driver->wave_out_open())
110 stargo 491 {
111 stargo 1255 current_driver->wave_out_close();
112 stargo 491 device_available = True;
113     }
114    
115 matthewc 474 format_count = 0;
116 astrand 499 if (s_check_rem(in, 18 * in_format_count))
117 matthewc 474 {
118     for (i = 0; i < in_format_count; i++)
119     {
120     format = &formats[format_count];
121     in_uint16_le(in, format->wFormatTag);
122     in_uint16_le(in, format->nChannels);
123     in_uint32_le(in, format->nSamplesPerSec);
124     in_uint32_le(in, format->nAvgBytesPerSec);
125     in_uint16_le(in, format->nBlockAlign);
126     in_uint16_le(in, format->wBitsPerSample);
127     in_uint16_le(in, format->cbSize);
128    
129 stargo 492 /* read in the buffer of unknown use */
130 stargo 493 readcnt = format->cbSize;
131     discardcnt = 0;
132 stargo 492 if (format->cbSize > MAX_CBSIZE)
133     {
134 astrand 499 fprintf(stderr, "cbSize too large for buffer: %d\n",
135     format->cbSize);
136 stargo 492 readcnt = MAX_CBSIZE;
137     discardcnt = format->cbSize - MAX_CBSIZE;
138     }
139     in_uint8a(in, format->cb, readcnt);
140     in_uint8s(in, discardcnt);
141    
142 stargo 1255 if (device_available && current_driver->wave_out_format_supported(format))
143 matthewc 474 {
144     format_count++;
145     if (format_count == MAX_FORMATS)
146     break;
147     }
148     }
149     }
150    
151 astrand 499 out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
152     out_uint32_le(out, 3); /* flags */
153 matthewc 474 out_uint32(out, 0xffffffff); /* volume */
154 astrand 499 out_uint32(out, 0); /* pitch */
155     out_uint16(out, 0); /* UDP port */
156 matthewc 474
157     out_uint16_le(out, format_count);
158 astrand 499 out_uint8(out, 0x95); /* pad? */
159     out_uint16_le(out, 2); /* status */
160     out_uint8(out, 0x77); /* pad? */
161 matthewc 474
162     for (i = 0; i < format_count; i++)
163     {
164     format = &formats[i];
165     out_uint16_le(out, format->wFormatTag);
166     out_uint16_le(out, format->nChannels);
167     out_uint32_le(out, format->nSamplesPerSec);
168     out_uint32_le(out, format->nAvgBytesPerSec);
169     out_uint16_le(out, format->nBlockAlign);
170     out_uint16_le(out, format->wBitsPerSample);
171 astrand 499 out_uint16(out, 0); /* cbSize */
172 matthewc 474 }
173    
174     s_mark_end(out);
175     rdpsnd_send(out);
176     }
177    
178 astrand 665 static void
179 stargo 1044 rdpsnd_process_servertick(STREAM in)
180 matthewc 474 {
181 stargo 1044 uint16 tick1, tick2;
182 matthewc 474 STREAM out;
183    
184     /* in_uint8s(in, 4); unknown */
185 stargo 1044 in_uint16_le(in, tick1);
186     in_uint16_le(in, tick2);
187 matthewc 474
188 stargo 1044 out = rdpsnd_init_packet(RDPSND_SERVERTICK | 0x2300, 4);
189     out_uint16_le(out, tick1);
190     out_uint16_le(out, tick2);
191 matthewc 474 s_mark_end(out);
192     rdpsnd_send(out);
193     }
194    
195 astrand 665 static void
196 matthewc 432 rdpsnd_process(STREAM s)
197     {
198 matthewc 474 uint8 type;
199     uint16 datalen;
200 stargo 491 uint32 volume;
201 matthewc 474 static uint16 tick, format;
202     static uint8 packet_index;
203     static BOOL awaiting_data_packet;
204 stargo 1265 static unsigned char missing_bytes[4] = { 0, 0, 0, 0 };
205 matthewc 474
206     #ifdef RDPSND_DEBUG
207     printf("RDPSND recv:\n");
208 astrand 499 hexdump(s->p, s->end - s->p);
209 matthewc 474 #endif
210    
211     if (awaiting_data_packet)
212     {
213     if (format >= MAX_FORMATS)
214     {
215     error("RDPSND: Invalid format index\n");
216     return;
217     }
218    
219     if (!device_open || (format != current_format))
220     {
221 stargo 1255 if (!device_open && !current_driver->wave_out_open())
222 matthewc 474 {
223     rdpsnd_send_completion(tick, packet_index);
224     return;
225     }
226 stargo 1255 if (!current_driver->wave_out_set_format(&formats[format]))
227 matthewc 474 {
228     rdpsnd_send_completion(tick, packet_index);
229 stargo 1255 current_driver->wave_out_close();
230 matthewc 474 device_open = False;
231     return;
232     }
233     device_open = True;
234     current_format = format;
235     }
236    
237 stargo 1265 /* Insert the 4 missing bytes retrieved from last RDPSND_WRITE */
238     memcpy(s->data, missing_bytes, 4);
239    
240 ossman_ 1302 rdpsnd_queue_write(rdpsnd_dsp_process
241     (s, current_driver, &formats[current_format]), tick,
242     packet_index);
243 matthewc 474 awaiting_data_packet = False;
244     return;
245     }
246    
247     in_uint8(s, type);
248 astrand 499 in_uint8s(s, 1); /* unknown? */
249 matthewc 474 in_uint16_le(s, datalen);
250    
251     switch (type)
252     {
253 astrand 499 case RDPSND_WRITE:
254     in_uint16_le(s, tick);
255     in_uint16_le(s, format);
256     in_uint8(s, packet_index);
257 stargo 1265 /* Here are our lost bytes, but why? */
258     memcpy(missing_bytes, s->end - 4, 4);
259 astrand 499 awaiting_data_packet = True;
260     break;
261     case RDPSND_CLOSE:
262 stargo 1255 current_driver->wave_out_close();
263 astrand 499 device_open = False;
264     break;
265     case RDPSND_NEGOTIATE:
266     rdpsnd_process_negotiate(s);
267     break;
268 stargo 1044 case RDPSND_SERVERTICK:
269     rdpsnd_process_servertick(s);
270 astrand 499 break;
271     case RDPSND_SET_VOLUME:
272     in_uint32(s, volume);
273     if (device_open)
274     {
275 stargo 1255 current_driver->wave_out_volume((volume & 0xffff),
276     (volume & 0xffff0000) >> 16);
277 astrand 499 }
278     break;
279     default:
280     unimpl("RDPSND packet type %d\n", type);
281     break;
282 matthewc 474 }
283 matthewc 432 }
284    
285 stargo 1274 static BOOL
286 stargo 1255 rdpsnd_auto_open(void)
287     {
288 stargo 1271 static BOOL failed = False;
289    
290     if (!failed)
291 stargo 1255 {
292 stargo 1271 struct audio_driver *auto_driver = current_driver;
293    
294     current_driver = drivers;
295     while (current_driver != NULL)
296 stargo 1255 {
297 stargo 1271 DEBUG(("trying %s...\n", current_driver->name));
298     if (current_driver->wave_out_open())
299     {
300     DEBUG(("selected %s\n", current_driver->name));
301     return True;
302     }
303     g_dsp_fd = 0;
304     current_driver = current_driver->next;
305 stargo 1255 }
306 stargo 1271
307     warning("no working audio-driver found\n");
308     failed = True;
309     current_driver = auto_driver;
310 stargo 1255 }
311    
312     return False;
313     }
314    
315 stargo 1274 static void
316 stargo 1255 rdpsnd_register_drivers(char *options)
317     {
318     struct audio_driver **reg;
319    
320     /* The order of registrations define the probe-order
321     when opening the device for the first time */
322     reg = &drivers;
323     #if defined(RDPSND_ALSA)
324     *reg = alsa_register(options);
325 ossman_ 1298 assert(*reg);
326 stargo 1255 reg = &((*reg)->next);
327     #endif
328 stargo 1264 #if defined(RDPSND_SUN)
329     *reg = sun_register(options);
330 ossman_ 1298 assert(*reg);
331 stargo 1264 reg = &((*reg)->next);
332     #endif
333 stargo 1255 #if defined(RDPSND_OSS)
334     *reg = oss_register(options);
335 ossman_ 1298 assert(*reg);
336 stargo 1255 reg = &((*reg)->next);
337     #endif
338     #if defined(RDPSND_SGI)
339     *reg = sgi_register(options);
340 ossman_ 1298 assert(*reg);
341 stargo 1255 reg = &((*reg)->next);
342     #endif
343     #if defined(RDPSND_LIBAO)
344     *reg = libao_register(options);
345 ossman_ 1302 assert(*reg);
346 stargo 1255 reg = &((*reg)->next);
347     #endif
348     }
349    
350     BOOL
351 stargo 1272 rdpsnd_init(char *optarg)
352 stargo 1255 {
353     static struct audio_driver auto_driver;
354     struct audio_driver *pos;
355 stargo 1272 char *driver = NULL, *options = NULL;
356 stargo 1255
357     drivers = NULL;
358 stargo 1272
359     rdpsnd_channel =
360     channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
361     rdpsnd_process);
362    
363     if (rdpsnd_channel == NULL)
364     {
365     error("channel_register\n");
366     return False;
367     }
368    
369 ossman_ 1302 rdpsnd_queue_init();
370    
371 stargo 1272 if (optarg != NULL && strlen(optarg) > 0)
372     {
373     driver = options = optarg;
374    
375     while (*options != '\0' && *options != ':')
376     options++;
377    
378     if (*options == ':')
379     {
380     *options = '\0';
381     options++;
382     }
383    
384     if (*options == '\0')
385     options = NULL;
386     }
387    
388 stargo 1255 rdpsnd_register_drivers(options);
389    
390     if (!driver)
391     {
392     auto_driver.wave_out_open = &rdpsnd_auto_open;
393     current_driver = &auto_driver;
394     return True;
395     }
396    
397     pos = drivers;
398     while (pos != NULL)
399     {
400     if (!strcmp(pos->name, driver))
401     {
402     DEBUG(("selected %s\n", pos->name));
403     current_driver = pos;
404     return True;
405     }
406     pos = pos->next;
407     }
408     return False;
409     }
410    
411     void
412     rdpsnd_show_help(void)
413     {
414     struct audio_driver *pos;
415    
416     rdpsnd_register_drivers(NULL);
417    
418     pos = drivers;
419     while (pos != NULL)
420     {
421     fprintf(stderr, " %s:\t%s\n", pos->name, pos->description);
422     pos = pos->next;
423     }
424     }
425    
426 stargo 1273 void
427 stargo 1255 rdpsnd_play(void)
428     {
429     current_driver->wave_out_play();
430     }
431    
432 ossman_ 1299 void
433 ossman_ 1302 rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
434     {
435     long next_pending;
436    
437     if (g_dsp_busy)
438     {
439     FD_SET(g_dsp_fd, wfds);
440     *n = (g_dsp_fd > *n) ? g_dsp_fd : *n;
441     }
442    
443     next_pending = rdpsnd_queue_next_completion();
444     if (next_pending >= 0)
445     {
446     long cur_timeout;
447    
448     cur_timeout = tv->tv_sec * 1000000 + tv->tv_usec;
449     if (cur_timeout > next_pending)
450     {
451     tv->tv_sec = next_pending / 1000000;
452     tv->tv_usec = next_pending % 1000000;
453     }
454     }
455     }
456    
457     void
458     rdpsnd_check_fds(fd_set * rfds, fd_set * wfds)
459     {
460     rdpsnd_queue_complete_pending();
461    
462     if (g_dsp_busy && FD_ISSET(g_dsp_fd, wfds))
463     rdpsnd_play();
464     }
465    
466     static void
467 stargo 1254 rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
468     {
469     struct audio_packet *packet = &packet_queue[queue_hi];
470     unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
471    
472 ossman_ 1302 if (next_hi == queue_pending)
473 stargo 1254 {
474     error("No space to queue audio packet\n");
475     return;
476     }
477    
478     queue_hi = next_hi;
479    
480     packet->s = *s;
481     packet->tick = tick;
482     packet->index = index;
483    
484 ossman_ 1302 gettimeofday(&packet->arrive_tv, NULL);
485    
486 stargo 1254 if (!g_dsp_busy)
487 stargo 1255 current_driver->wave_out_play();
488 stargo 1254 }
489    
490 ossman_ 1299 struct audio_packet *
491 stargo 1254 rdpsnd_queue_current_packet(void)
492     {
493     return &packet_queue[queue_lo];
494     }
495    
496 ossman_ 1299 BOOL
497 stargo 1254 rdpsnd_queue_empty(void)
498     {
499     return (queue_lo == queue_hi);
500     }
501    
502 ossman_ 1302 static void
503 stargo 1254 rdpsnd_queue_init(void)
504     {
505 ossman_ 1302 queue_pending = queue_lo = queue_hi = 0;
506 stargo 1254 }
507    
508 ossman_ 1299 void
509 ossman_ 1302 rdpsnd_queue_next(unsigned long completed_in_us)
510 stargo 1254 {
511 ossman_ 1302 struct audio_packet *packet;
512    
513     assert(!rdpsnd_queue_empty());
514    
515     packet = &packet_queue[queue_lo];
516    
517     gettimeofday(&packet->completion_tv, NULL);
518    
519     packet->completion_tv.tv_usec += completed_in_us;
520     packet->completion_tv.tv_sec += packet->completion_tv.tv_usec / 1000000;
521     packet->completion_tv.tv_usec %= 1000000;
522    
523 stargo 1254 queue_lo = (queue_lo + 1) % MAX_QUEUE;
524 ossman_ 1302
525     rdpsnd_queue_complete_pending();
526 stargo 1254 }
527    
528 ossman_ 1299 int
529 stargo 1254 rdpsnd_queue_next_tick(void)
530     {
531     if (((queue_lo + 1) % MAX_QUEUE) != queue_hi)
532     {
533     return packet_queue[(queue_lo + 1) % MAX_QUEUE].tick;
534     }
535     else
536     {
537     return (packet_queue[queue_lo].tick + 65535) % 65536;
538     }
539     }
540 ossman_ 1302
541     static void
542     rdpsnd_queue_complete_pending(void)
543     {
544     struct timeval now;
545     long elapsed;
546     struct audio_packet *packet;
547    
548     gettimeofday(&now, NULL);
549    
550     while (queue_pending != queue_lo)
551     {
552     packet = &packet_queue[queue_pending];
553    
554     if (now.tv_sec < packet->completion_tv.tv_sec)
555     break;
556    
557     if ((now.tv_sec == packet->completion_tv.tv_sec) &&
558     (now.tv_usec < packet->completion_tv.tv_usec))
559     break;
560    
561     elapsed = (packet->completion_tv.tv_sec - packet->arrive_tv.tv_sec) * 1000000 +
562     (packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec);
563    
564     xfree(packet->s.data);
565     rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index);
566     queue_pending = (queue_pending + 1) % MAX_QUEUE;
567     }
568     }
569    
570     static long
571     rdpsnd_queue_next_completion(void)
572     {
573     struct audio_packet *packet;
574     long remaining;
575     struct timeval now;
576    
577     if (queue_pending == queue_lo)
578     return -1;
579    
580     gettimeofday(&now, NULL);
581    
582     packet = &packet_queue[queue_pending];
583    
584     remaining = (packet->completion_tv.tv_sec - now.tv_sec) * 1000000 +
585     (packet->completion_tv.tv_usec - now.tv_usec);
586    
587     if (remaining < 0)
588     return 0;
589    
590     return remaining;
591     }

  ViewVC Help
Powered by ViewVC 1.1.26