--- sourceforge.net/trunk/rdesktop/rdpsnd.c 2006/09/17 18:08:51 1263 +++ sourceforge.net/trunk/rdesktop/rdpsnd.c 2006/12/06 12:31:58 1337 @@ -19,6 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" @@ -45,11 +47,16 @@ static WAVEFORMATEX formats[MAX_FORMATS]; static unsigned int format_count; static unsigned int current_format; -unsigned int queue_hi, queue_lo; +unsigned int queue_hi, queue_lo, queue_pending; struct audio_packet packet_queue[MAX_QUEUE]; void (*wave_out_play) (void); +static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index); +static void rdpsnd_queue_init(void); +static void rdpsnd_queue_complete_pending(void); +static long rdpsnd_queue_next_completion(void); + static STREAM rdpsnd_init_packet(uint16 type, uint16 size) { @@ -72,7 +79,7 @@ channel_send(s, rdpsnd_channel); } -void +static void rdpsnd_send_completion(uint16 tick, uint8 packet_index) { STREAM s; @@ -194,6 +201,7 @@ static uint16 tick, format; static uint8 packet_index; static BOOL awaiting_data_packet; + static unsigned char missing_bytes[4] = { 0, 0, 0, 0 }; #ifdef RDPSND_DEBUG printf("RDPSND recv:\n"); @@ -226,10 +234,12 @@ current_format = format; } - current_driver-> - wave_out_write(rdpsnd_dsp_process - (s, current_driver, &formats[current_format]), tick, - packet_index); + /* Insert the 4 missing bytes retrieved from last RDPSND_WRITE */ + memcpy(s->data, missing_bytes, 4); + + rdpsnd_queue_write(rdpsnd_dsp_process + (s, current_driver, &formats[current_format]), tick, + packet_index); awaiting_data_packet = False; return; } @@ -244,6 +254,8 @@ in_uint16_le(s, tick); in_uint16_le(s, format); in_uint8(s, packet_index); + /* Here are our lost bytes, but why? */ + memcpy(missing_bytes, s->end - 4, 4); awaiting_data_packet = True; break; case RDPSND_CLOSE: @@ -270,38 +282,37 @@ } } -BOOL -rdpsnd_init(void) -{ - rdpsnd_channel = - channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, - rdpsnd_process); - - return (rdpsnd_channel != NULL); -} - -BOOL +static BOOL rdpsnd_auto_open(void) { - current_driver = drivers; - while (current_driver != NULL) + static BOOL failed = False; + + if (!failed) { - DEBUG(("trying %s...\n", current_driver->name)); - if (current_driver->wave_out_open()) + struct audio_driver *auto_driver = current_driver; + + current_driver = drivers; + while (current_driver != NULL) { - DEBUG(("selected %s\n", current_driver->name)); - return True; + DEBUG(("trying %s...\n", current_driver->name)); + if (current_driver->wave_out_open()) + { + DEBUG(("selected %s\n", current_driver->name)); + return True; + } + g_dsp_fd = 0; + current_driver = current_driver->next; } - g_dsp_fd = 0; - current_driver = current_driver->next; - } - warning("no working audio-driver found\n"); + warning("no working audio-driver found\n"); + failed = True; + current_driver = auto_driver; + } return False; } -void +static void rdpsnd_register_drivers(char *options) { struct audio_driver **reg; @@ -311,33 +322,70 @@ reg = &drivers; #if defined(RDPSND_ALSA) *reg = alsa_register(options); - reg = &((*reg)->next); -#endif -#if defined(RDPSND_OSS) - *reg = oss_register(options); + assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_SUN) *reg = sun_register(options); + assert(*reg); + reg = &((*reg)->next); +#endif +#if defined(RDPSND_OSS) + *reg = oss_register(options); + assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_SGI) *reg = sgi_register(options); + assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_LIBAO) *reg = libao_register(options); + assert(*reg); reg = &((*reg)->next); #endif + *reg = NULL; } BOOL -rdpsnd_select_driver(char *driver, char *options) +rdpsnd_init(char *optarg) { static struct audio_driver auto_driver; struct audio_driver *pos; + char *driver = NULL, *options = NULL; drivers = NULL; + + rdpsnd_channel = + channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, + rdpsnd_process); + + if (rdpsnd_channel == NULL) + { + error("channel_register\n"); + return False; + } + + rdpsnd_queue_init(); + + if (optarg != NULL && strlen(optarg) > 0) + { + driver = options = optarg; + + while (*options != '\0' && *options != ':') + options++; + + if (*options == ':') + { + *options = '\0'; + options++; + } + + if (*options == '\0') + options = NULL; + } + rdpsnd_register_drivers(options); if (!driver) @@ -376,19 +424,53 @@ } } -inline void +void rdpsnd_play(void) { current_driver->wave_out_play(); } void +rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) +{ + long next_pending; + + if (g_dsp_busy) + { + FD_SET(g_dsp_fd, wfds); + *n = (g_dsp_fd > *n) ? g_dsp_fd : *n; + } + + next_pending = rdpsnd_queue_next_completion(); + if (next_pending >= 0) + { + long cur_timeout; + + cur_timeout = tv->tv_sec * 1000000 + tv->tv_usec; + if (cur_timeout > next_pending) + { + tv->tv_sec = next_pending / 1000000; + tv->tv_usec = next_pending % 1000000; + } + } +} + +void +rdpsnd_check_fds(fd_set * rfds, fd_set * wfds) +{ + rdpsnd_queue_complete_pending(); + + if (g_dsp_busy && FD_ISSET(g_dsp_fd, wfds)) + rdpsnd_play(); +} + +static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index) { struct audio_packet *packet = &packet_queue[queue_hi]; unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE; - if (next_hi == queue_lo) + if (next_hi == queue_pending) { error("No space to queue audio packet\n"); return; @@ -400,36 +482,51 @@ packet->tick = tick; packet->index = index; + gettimeofday(&packet->arrive_tv, NULL); + if (!g_dsp_busy) current_driver->wave_out_play(); } -inline struct audio_packet * +struct audio_packet * rdpsnd_queue_current_packet(void) { return &packet_queue[queue_lo]; } -inline BOOL +BOOL rdpsnd_queue_empty(void) { return (queue_lo == queue_hi); } -inline void +static void rdpsnd_queue_init(void) { - queue_lo = queue_hi = 0; + queue_pending = queue_lo = queue_hi = 0; } -inline void -rdpsnd_queue_next(void) +void +rdpsnd_queue_next(unsigned long completed_in_us) { - xfree(packet_queue[queue_lo].s.data); + struct audio_packet *packet; + + assert(!rdpsnd_queue_empty()); + + packet = &packet_queue[queue_lo]; + + gettimeofday(&packet->completion_tv, NULL); + + packet->completion_tv.tv_usec += completed_in_us; + packet->completion_tv.tv_sec += packet->completion_tv.tv_usec / 1000000; + packet->completion_tv.tv_usec %= 1000000; + queue_lo = (queue_lo + 1) % MAX_QUEUE; + + rdpsnd_queue_complete_pending(); } -inline int +int rdpsnd_queue_next_tick(void) { if (((queue_lo + 1) % MAX_QUEUE) != queue_hi) @@ -441,3 +538,56 @@ return (packet_queue[queue_lo].tick + 65535) % 65536; } } + +static void +rdpsnd_queue_complete_pending(void) +{ + struct timeval now; + long elapsed; + struct audio_packet *packet; + + gettimeofday(&now, NULL); + + while (queue_pending != queue_lo) + { + packet = &packet_queue[queue_pending]; + + if (now.tv_sec < packet->completion_tv.tv_sec) + break; + + if ((now.tv_sec == packet->completion_tv.tv_sec) && + (now.tv_usec < packet->completion_tv.tv_usec)) + break; + + elapsed = (packet->completion_tv.tv_sec - packet->arrive_tv.tv_sec) * 1000000 + + (packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec); + elapsed /= 1000; + + xfree(packet->s.data); + rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index); + queue_pending = (queue_pending + 1) % MAX_QUEUE; + } +} + +static long +rdpsnd_queue_next_completion(void) +{ + struct audio_packet *packet; + long remaining; + struct timeval now; + + if (queue_pending == queue_lo) + return -1; + + gettimeofday(&now, NULL); + + packet = &packet_queue[queue_pending]; + + remaining = (packet->completion_tv.tv_sec - now.tv_sec) * 1000000 + + (packet->completion_tv.tv_usec - now.tv_usec); + + if (remaining < 0) + return 0; + + return remaining; +}