/[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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 491 by stargo, Mon Oct 13 16:09:45 2003 UTC revision 1346 by ossman_, Thu Dec 7 15:23:45 2006 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions     Sound Channel Process Functions
4       Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
5     Copyright (C) Matthew Chapman 2003     Copyright (C) Matthew Chapman 2003
6     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
7    
# Line 19  Line 20 
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */  */
22    
23    #include <assert.h>
24    
25  #include "rdesktop.h"  #include "rdesktop.h"
26    #include "rdpsnd.h"
27    #include "rdpsnd_dsp.h"
28    
29  #define RDPSND_CLOSE            1  #define RDPSND_CLOSE            1
30  #define RDPSND_WRITE            2  #define RDPSND_WRITE            2
31  #define RDPSND_SET_VOLUME       3  #define RDPSND_SET_VOLUME       3
32  #define RDPSND_UNKNOWN4         4  #define RDPSND_UNKNOWN4         4
33  #define RDPSND_COMPLETION       5  #define RDPSND_COMPLETION       5
34  #define RDPSND_UNKNOWN6         6  #define RDPSND_PING                     6
35  #define RDPSND_NEGOTIATE        7  #define RDPSND_NEGOTIATE        7
36    
37  #define MAX_FORMATS             10  #define MAX_FORMATS             10
38    #define MAX_QUEUE               10
39    
40  static VCHANNEL *rdpsnd_channel;  static VCHANNEL *rdpsnd_channel;
41    static struct audio_driver *drivers = NULL;
42    struct audio_driver *current_driver = NULL;
43    
44  static BOOL device_open;  static BOOL device_open;
45  static WAVEFORMATEX formats[MAX_FORMATS];  static WAVEFORMATEX formats[MAX_FORMATS];
46  static unsigned int format_count;  static unsigned int format_count;
47  static unsigned int current_format;  static unsigned int current_format;
48    unsigned int queue_hi, queue_lo, queue_pending;
49    struct audio_packet packet_queue[MAX_QUEUE];
50    
51    static uint8 packet_opcode;
52    static struct stream packet;
53    
54    void (*wave_out_play) (void);
55    
56  STREAM  static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index);
57    static void rdpsnd_queue_init(void);
58    static void rdpsnd_queue_complete_pending(void);
59    static long rdpsnd_queue_next_completion(void);
60    
61    static STREAM
62  rdpsnd_init_packet(uint16 type, uint16 size)  rdpsnd_init_packet(uint16 type, uint16 size)
63  {  {
64          STREAM s;          STREAM s;
65    
66          s = channel_init(rdpsnd_channel, size+4);          s = channel_init(rdpsnd_channel, size + 4);
67          out_uint16_le(s, type);          out_uint16_le(s, type);
68          out_uint16_le(s, size);          out_uint16_le(s, size);
69          return s;          return s;
70  }  }
71    
72  void  static void
73  rdpsnd_send(STREAM s)  rdpsnd_send(STREAM s)
74  {  {
 #ifdef RDPSND_DEBUG  
         printf("RDPSND send:\n");  
         hexdump(s->channel_hdr+8, s->end-s->channel_hdr-8);  
 #endif  
   
75          channel_send(s, rdpsnd_channel);          channel_send(s, rdpsnd_channel);
76  }  }
77    
78  void rdpsnd_send_completion(uint16 tick, uint8 packet_index)  static void
79    rdpsnd_send_completion(uint16 tick, uint8 packet_index)
80  {  {
81          STREAM s;          STREAM s;
82    
83          s = rdpsnd_init_packet(RDPSND_COMPLETION, 4);          s = rdpsnd_init_packet(RDPSND_COMPLETION, 4);
84          out_uint16_le(s, tick+50);          out_uint16_le(s, tick);
85          out_uint8(s, packet_index);          out_uint8(s, packet_index);
86          out_uint8(s, 0);          out_uint8(s, 0);
87          s_mark_end(s);          s_mark_end(s);
88          rdpsnd_send(s);          rdpsnd_send(s);
89    
90            DEBUG_SOUND(("RDPSND: -> RDPSND_COMPLETION(tick: %u, index: %u)\n",
91                         (unsigned) tick, (unsigned) packet_index));
92  }  }
93    
94  void  
95    static BOOL
96    rdpsnd_auto_select(void)
97    {
98            static BOOL failed = False;
99    
100            if (!failed)
101            {
102                    current_driver = drivers;
103                    while (current_driver != NULL)
104                    {
105                            DEBUG(("trying %s...\n", current_driver->name));
106                            if (current_driver->wave_out_open())
107                            {
108                                    DEBUG(("selected %s\n", current_driver->name));
109                                    return True;
110                            }
111                            current_driver = current_driver->next;
112                    }
113    
114                    warning("no working audio-driver found\n");
115                    failed = True;
116                    current_driver = NULL;
117            }
118    
119            return False;
120    }
121    
122    static void
123  rdpsnd_process_negotiate(STREAM in)  rdpsnd_process_negotiate(STREAM in)
124  {  {
125          unsigned int in_format_count, i;          uint16 in_format_count, i;
126            uint8 pad;
127            uint16 version;
128          WAVEFORMATEX *format;          WAVEFORMATEX *format;
129          STREAM out;          STREAM out;
130          BOOL device_available = False;          BOOL device_available = False;
131            int readcnt;
132            int discardcnt;
133    
134          in_uint8s(in, 14);      /* flags, volume, pitch, UDP port */          in_uint8s(in, 14);      /* initial bytes not valid from server */
135          in_uint16_le(in, in_format_count);          in_uint16_le(in, in_format_count);
136          in_uint8s(in, 4);       /* pad, status, pad */          in_uint8(in, pad);
137            in_uint16_le(in, version);
138            in_uint8s(in, 1);       /* padding */
139    
140          if (wave_out_open())          DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n",
141                         (int) in_format_count, (unsigned) pad, (unsigned) version));
142    
143            if (!current_driver)
144                    rdpsnd_auto_select();
145    
146            if (current_driver && current_driver->wave_out_open())
147          {          {
148                  wave_out_close();                  current_driver->wave_out_close();
149                  device_available = True;                  device_available = True;
150          }          }
151    
152          format_count = 0;          format_count = 0;
153          if (s_check_rem(in, 18*in_format_count))          if (s_check_rem(in, 18 * in_format_count))
154          {          {
155                  for (i = 0; i < in_format_count; i++)                  for (i = 0; i < in_format_count; i++)
156                  {                  {
# Line 104  rdpsnd_process_negotiate(STREAM in) Line 163  rdpsnd_process_negotiate(STREAM in)
163                          in_uint16_le(in, format->wBitsPerSample);                          in_uint16_le(in, format->wBitsPerSample);
164                          in_uint16_le(in, format->cbSize);                          in_uint16_le(in, format->cbSize);
165    
166                          if (device_available && wave_out_format_supported(format))                          /* read in the buffer of unknown use */
167                            readcnt = format->cbSize;
168                            discardcnt = 0;
169                            if (format->cbSize > MAX_CBSIZE)
170                            {
171                                    fprintf(stderr, "cbSize too large for buffer: %d\n",
172                                            format->cbSize);
173                                    readcnt = MAX_CBSIZE;
174                                    discardcnt = format->cbSize - MAX_CBSIZE;
175                            }
176                            in_uint8a(in, format->cb, readcnt);
177                            in_uint8s(in, discardcnt);
178    
179                            if (device_available && current_driver->wave_out_format_supported(format))
180                          {                          {
181                                  format_count++;                                  format_count++;
182                                  if (format_count == MAX_FORMATS)                                  if (format_count == MAX_FORMATS)
# Line 113  rdpsnd_process_negotiate(STREAM in) Line 185  rdpsnd_process_negotiate(STREAM in)
185                  }                  }
186          }          }
187    
188          out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18*format_count);          out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
189          out_uint32_le(out, 3);          /* flags */          out_uint32_le(out, 3);  /* flags */
190          out_uint32(out, 0xffffffff);    /* volume */          out_uint32(out, 0xffffffff);    /* volume */
191          out_uint32(out, 0);             /* pitch */          out_uint32(out, 0);     /* pitch */
192          out_uint16(out, 0);             /* UDP port */          out_uint16(out, 0);     /* UDP port */
193    
194          out_uint16_le(out, format_count);          out_uint16_le(out, format_count);
195          out_uint8(out, 0x95);           /* pad? */          out_uint8(out, 0);      /* padding */
196          out_uint16_le(out, 2);          /* status */          out_uint16_le(out, 2);  /* version */
197          out_uint8(out, 0x77);           /* pad? */          out_uint8(out, 0);      /* padding */
198    
199          for (i = 0; i < format_count; i++)          for (i = 0; i < format_count; i++)
200          {          {
# Line 133  rdpsnd_process_negotiate(STREAM in) Line 205  rdpsnd_process_negotiate(STREAM in)
205                  out_uint32_le(out, format->nAvgBytesPerSec);                  out_uint32_le(out, format->nAvgBytesPerSec);
206                  out_uint16_le(out, format->nBlockAlign);                  out_uint16_le(out, format->nBlockAlign);
207                  out_uint16_le(out, format->wBitsPerSample);                  out_uint16_le(out, format->wBitsPerSample);
208                  out_uint16(out, 0); /* cbSize */                  out_uint16(out, 0);     /* cbSize */
209          }          }
210    
211          s_mark_end(out);          s_mark_end(out);
212    
213            DEBUG_SOUND(("RDPSND: -> RDPSND_NEGOTIATE(formats: %d)\n", (int) format_count));
214    
215          rdpsnd_send(out);          rdpsnd_send(out);
216  }  }
217    
218  void  static void
219  rdpsnd_process_unknown6(STREAM in)  rdpsnd_process_ping(STREAM in)
220  {  {
221          uint16 unknown1, unknown2;          uint16 tick;
222          STREAM out;          STREAM out;
223    
224          /* in_uint8s(in, 4); unknown */          in_uint16_le(in, tick);
225          in_uint16_le(in, unknown1);  
226          in_uint16_le(in, unknown2);          DEBUG_SOUND(("RDPSND: RDPSND_PING(tick: 0x%04x)\n", (unsigned) tick));
227    
228          out = rdpsnd_init_packet(RDPSND_UNKNOWN6 | 0x2300, 4);          out = rdpsnd_init_packet(RDPSND_PING | 0x2300, 4);
229          out_uint16_le(out, unknown1);          out_uint16_le(out, tick);
230          out_uint16_le(out, unknown2);          out_uint16_le(out, 0);
231          s_mark_end(out);          s_mark_end(out);
232          rdpsnd_send(out);          rdpsnd_send(out);
233    
234            DEBUG_SOUND(("RDPSND: -> (tick: 0x%04x)\n", (unsigned) tick));
235  }  }
236    
237  void  static void
238  rdpsnd_process(STREAM s)  rdpsnd_process_packet(uint8 opcode, STREAM s)
239  {  {
240          uint8 type;          uint16 vol_left, vol_right;
         uint16 datalen;  
         uint32 volume;  
241          static uint16 tick, format;          static uint16 tick, format;
242          static uint8 packet_index;          static uint8 packet_index;
         static BOOL awaiting_data_packet;  
   
 #ifdef RDPSND_DEBUG  
         printf("RDPSND recv:\n");  
         hexdump(s->p, s->end-s->p);  
 #endif  
243    
244          if (awaiting_data_packet)          switch (opcode)
245          {          {
246                  if (format >= MAX_FORMATS)                  case RDPSND_WRITE:
247                  {                          in_uint16_le(s, tick);
248                          error("RDPSND: Invalid format index\n");                          in_uint16_le(s, format);
249                            in_uint8(s, packet_index);
250                            in_uint8s(s, 3);
251                            DEBUG_SOUND(("RDPSND: RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", (unsigned) tick, (unsigned) format, (unsigned) packet_index, (unsigned) s->size - 8));
252    
253                            if (format >= MAX_FORMATS)
254                            {
255                                    error("RDPSND: Invalid format index\n");
256                                    break;
257                            }
258    
259                            if (!device_open || (format != current_format))
260                            {
261                                    /*
262                                     * If we haven't selected a device by now, then either
263                                     * we've failed to find a working device, or the server
264                                     * is sending bogus RDPSND_WRITE.
265                                     */
266                                    if (!current_driver)
267                                    {
268                                            rdpsnd_send_completion(tick, packet_index);
269                                            break;
270                                    }
271                                    if (!device_open && !current_driver->wave_out_open())
272                                    {
273                                            rdpsnd_send_completion(tick, packet_index);
274                                            break;
275                                    }
276                                    if (!current_driver->wave_out_set_format(&formats[format]))
277                                    {
278                                            rdpsnd_send_completion(tick, packet_index);
279                                            current_driver->wave_out_close();
280                                            device_open = False;
281                                            break;
282                                    }
283                                    device_open = True;
284                                    current_format = format;
285                            }
286    
287                            rdpsnd_queue_write(rdpsnd_dsp_process
288                                               (s->p, s->end - s->p, current_driver,
289                                                &formats[current_format]), tick, packet_index);
290                          return;                          return;
291                  }                          break;
292                    case RDPSND_CLOSE:
293                            DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n"));
294                            if (device_open)
295                                    current_driver->wave_out_close();
296                            device_open = False;
297                            break;
298                    case RDPSND_NEGOTIATE:
299                            rdpsnd_process_negotiate(s);
300                            break;
301                    case RDPSND_PING:
302                            rdpsnd_process_ping(s);
303                            break;
304                    case RDPSND_SET_VOLUME:
305                            in_uint16_le(s, vol_left);
306                            in_uint16_le(s, vol_right);
307                            DEBUG_SOUND(("RDPSND: RDPSND_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655));
308                            if (device_open)
309                                    current_driver->wave_out_volume(vol_left, vol_right);
310                            break;
311                    default:
312                            unimpl("RDPSND packet type %x\n", opcode);
313                            break;
314            }
315    }
316    
317                  if (!device_open || (format != current_format))  static void
318    rdpsnd_process(STREAM s)
319    {
320            uint16 len;
321    
322            while (!s_check_end(s))
323            {
324                    /* New packet */
325                    if (packet.size == 0)
326                  {                  {
327                          if (!device_open && !wave_out_open())                          if ((s->end - s->p) < 4)
328                          {                          {
329                                  rdpsnd_send_completion(tick, packet_index);                                  error("RDPSND: Split at packet header. Things will go south from here...\n");
330                                  return;                                  return;
331                          }                          }
332                          if (!wave_out_set_format(&formats[format]))                          in_uint8(s, packet_opcode);
333                            in_uint8s(s, 1);        /* Padding */
334                            in_uint16_le(s, len);
335    
336                            DEBUG_SOUND(("RDPSND: == Opcode %x Length: %d ==\n",
337                                         (int) packet_opcode, (int) len));
338    
339                            packet.p = packet.data;
340                            packet.end = packet.data + len;
341                            packet.size = len;
342                    }
343                    else
344                    {
345                            len = MIN(s->end - s->p, packet.end - packet.p);
346    
347                            /* Microsoft's server is so broken it's not even funny... */
348                            if (packet_opcode == RDPSND_WRITE)
349                          {                          {
350                                  rdpsnd_send_completion(tick, packet_index);                                  if ((packet.p - packet.data) < 12)
351                                  wave_out_close();                                          len = MIN(len, 12 - (packet.p - packet.data));
352                                  device_open = False;                                  else if ((packet.p - packet.data) == 12)
353                                  return;                                  {
354                                            DEBUG_SOUND(("RDPSND: Eating 4 bytes of %d bytes...\n",
355                                                         len));
356                                            in_uint8s(s, 4);
357                                            len -= 4;
358                                    }
359                          }                          }
360                          device_open = True;  
361                          current_format = format;                          in_uint8a(s, packet.p, len);
362                            packet.p += len;
363                  }                  }
364    
365                  wave_out_write(s, tick, packet_index);                  /* Packet fully assembled */
366                  awaiting_data_packet = False;                  if (packet.p == packet.end)
367                  return;                  {
368                            packet.p = packet.data;
369                            rdpsnd_process_packet(packet_opcode, &packet);
370                            packet.size = 0;
371                    }
372          }          }
373    }
374    
375          in_uint8(s, type);  static void
376          in_uint8s(s, 1); /* unknown? */  rdpsnd_register_drivers(char *options)
377          in_uint16_le(s, datalen);  {
378            struct audio_driver **reg;
379          switch (type)  
380          {          /* The order of registrations define the probe-order
381          case RDPSND_WRITE:             when opening the device for the first time */
382                  in_uint16_le(s, tick);          reg = &drivers;
383                  in_uint16_le(s, format);  #if defined(RDPSND_ALSA)
384                  in_uint8(s, packet_index);          *reg = alsa_register(options);
385                  awaiting_data_packet = True;          assert(*reg);
386                  break;          reg = &((*reg)->next);
387          case RDPSND_CLOSE:  #endif
388                  wave_out_close();  #if defined(RDPSND_SUN)
389                  device_open = False;          *reg = sun_register(options);
390                  break;          assert(*reg);
391          case RDPSND_NEGOTIATE:          reg = &((*reg)->next);
392                  rdpsnd_process_negotiate(s);  #endif
393                  break;  #if defined(RDPSND_OSS)
394          case RDPSND_UNKNOWN6:          *reg = oss_register(options);
395                  rdpsnd_process_unknown6(s);          assert(*reg);
396                  break;          reg = &((*reg)->next);
397          case RDPSND_SET_VOLUME:  #endif
398                  in_uint32(s, volume);  #if defined(RDPSND_SGI)
399                  if ( device_open )          *reg = sgi_register(options);
400                  {          assert(*reg);
401                          wave_out_volume((volume & 0xffff), (volume & 0xffff0000) >> 16);          reg = &((*reg)->next);
402                  }  #endif
403                  break;  #if defined(RDPSND_LIBAO)
404          default:          *reg = libao_register(options);
405                  unimpl("RDPSND packet type %d\n", type);          assert(*reg);
406                  break;          reg = &((*reg)->next);
407          }  #endif
408            *reg = NULL;
409  }  }
410    
411  BOOL  BOOL
412  rdpsnd_init(void)  rdpsnd_init(char *optarg)
413  {  {
414            struct audio_driver *pos;
415            char *driver = NULL, *options = NULL;
416    
417            drivers = NULL;
418    
419            packet.data = xmalloc(65536);
420            packet.p = packet.end = packet.data;
421            packet.size = 0;
422    
423          rdpsnd_channel =          rdpsnd_channel =
424                  channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,                  channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
425                                   rdpsnd_process);                                   rdpsnd_process);
426          return (rdpsnd_channel != NULL);  
427            if (rdpsnd_channel == NULL)
428            {
429                    error("channel_register\n");
430                    return False;
431            }
432    
433            rdpsnd_queue_init();
434    
435            if (optarg != NULL && strlen(optarg) > 0)
436            {
437                    driver = options = optarg;
438    
439                    while (*options != '\0' && *options != ':')
440                            options++;
441    
442                    if (*options == ':')
443                    {
444                            *options = '\0';
445                            options++;
446                    }
447    
448                    if (*options == '\0')
449                            options = NULL;
450            }
451    
452            rdpsnd_register_drivers(options);
453    
454            if (!driver)
455                    return True;
456    
457            pos = drivers;
458            while (pos != NULL)
459            {
460                    if (!strcmp(pos->name, driver))
461                    {
462                            DEBUG(("selected %s\n", pos->name));
463                            current_driver = pos;
464                            return True;
465                    }
466                    pos = pos->next;
467            }
468            return False;
469    }
470    
471    void
472    rdpsnd_show_help(void)
473    {
474            struct audio_driver *pos;
475    
476            rdpsnd_register_drivers(NULL);
477    
478            pos = drivers;
479            while (pos != NULL)
480            {
481                    fprintf(stderr, "                     %s:\t%s\n", pos->name, pos->description);
482                    pos = pos->next;
483            }
484    }
485    
486    void
487    rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
488    {
489            long next_pending;
490    
491            if (device_open)
492                    current_driver->add_fds(n, rfds, wfds, tv);
493    
494            next_pending = rdpsnd_queue_next_completion();
495            if (next_pending >= 0)
496            {
497                    long cur_timeout;
498    
499                    cur_timeout = tv->tv_sec * 1000000 + tv->tv_usec;
500                    if (cur_timeout > next_pending)
501                    {
502                            tv->tv_sec = next_pending / 1000000;
503                            tv->tv_usec = next_pending % 1000000;
504                    }
505            }
506    }
507    
508    void
509    rdpsnd_check_fds(fd_set * rfds, fd_set * wfds)
510    {
511            rdpsnd_queue_complete_pending();
512    
513            if (device_open)
514                    current_driver->check_fds(rfds, wfds);
515    }
516    
517    static void
518    rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
519    {
520            struct audio_packet *packet = &packet_queue[queue_hi];
521            unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
522    
523            if (next_hi == queue_pending)
524            {
525                    error("No space to queue audio packet\n");
526                    return;
527            }
528    
529            queue_hi = next_hi;
530    
531            packet->s = *s;
532            packet->tick = tick;
533            packet->index = index;
534    
535            gettimeofday(&packet->arrive_tv, NULL);
536    }
537    
538    struct audio_packet *
539    rdpsnd_queue_current_packet(void)
540    {
541            return &packet_queue[queue_lo];
542    }
543    
544    BOOL
545    rdpsnd_queue_empty(void)
546    {
547            return (queue_lo == queue_hi);
548    }
549    
550    static void
551    rdpsnd_queue_init(void)
552    {
553            queue_pending = queue_lo = queue_hi = 0;
554    }
555    
556    void
557    rdpsnd_queue_next(unsigned long completed_in_us)
558    {
559            struct audio_packet *packet;
560    
561            assert(!rdpsnd_queue_empty());
562    
563            packet = &packet_queue[queue_lo];
564    
565            gettimeofday(&packet->completion_tv, NULL);
566    
567            packet->completion_tv.tv_usec += completed_in_us;
568            packet->completion_tv.tv_sec += packet->completion_tv.tv_usec / 1000000;
569            packet->completion_tv.tv_usec %= 1000000;
570    
571            queue_lo = (queue_lo + 1) % MAX_QUEUE;
572    
573            rdpsnd_queue_complete_pending();
574    }
575    
576    int
577    rdpsnd_queue_next_tick(void)
578    {
579            if (((queue_lo + 1) % MAX_QUEUE) != queue_hi)
580            {
581                    return packet_queue[(queue_lo + 1) % MAX_QUEUE].tick;
582            }
583            else
584            {
585                    return (packet_queue[queue_lo].tick + 65535) % 65536;
586            }
587    }
588    
589    static void
590    rdpsnd_queue_complete_pending(void)
591    {
592            struct timeval now;
593            long elapsed;
594            struct audio_packet *packet;
595    
596            gettimeofday(&now, NULL);
597    
598            while (queue_pending != queue_lo)
599            {
600                    packet = &packet_queue[queue_pending];
601    
602                    if (now.tv_sec < packet->completion_tv.tv_sec)
603                            break;
604    
605                    if ((now.tv_sec == packet->completion_tv.tv_sec) &&
606                        (now.tv_usec < packet->completion_tv.tv_usec))
607                            break;
608    
609                    elapsed = (packet->completion_tv.tv_sec - packet->arrive_tv.tv_sec) * 1000000 +
610                            (packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec);
611                    elapsed /= 1000;
612    
613                    xfree(packet->s.data);
614                    rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index);
615                    queue_pending = (queue_pending + 1) % MAX_QUEUE;
616            }
617    }
618    
619    static long
620    rdpsnd_queue_next_completion(void)
621    {
622            struct audio_packet *packet;
623            long remaining;
624            struct timeval now;
625    
626            if (queue_pending == queue_lo)
627                    return -1;
628    
629            gettimeofday(&now, NULL);
630    
631            packet = &packet_queue[queue_pending];
632    
633            remaining = (packet->completion_tv.tv_sec - now.tv_sec) * 1000000 +
634                    (packet->completion_tv.tv_usec - now.tv_usec);
635    
636            if (remaining < 0)
637                    return 0;
638    
639            return remaining;
640  }  }

Legend:
Removed from v.491  
changed lines
  Added in v.1346

  ViewVC Help
Powered by ViewVC 1.1.26