ReactOS  r76032
rdpsnd_libao.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 8 -*-
2  rdesktop: A Remote Desktop Protocol client.
3  Sound Channel Process Functions - libao-driver
4  Copyright (C) Matthew Chapman 2003
5  Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6  Copyright (C) Michael Gernoth mike@zerfleddert.de 2005
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License along
19  with this program; if not, write to the Free Software Foundation, Inc.,
20  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 
23 #include "rdesktop.h"
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <ao/ao.h>
28 #include <sys/time.h>
29 
30 #define MAX_QUEUE 10
31 #define WAVEOUTBUF 16
32 
33 int This->dsp_;
34 ao_device *o_device = NULL;
37 int This->channels;
38 BOOL This->dsp_bu = False;
40 static short g_samplewidth;
41 
42 static struct audio_packet
43 {
44  struct stream s;
48 static unsigned int queue_hi, queue_lo;
49 
50 BOOL
52 {
53  ao_sample_format format;
54 
55  ao_initialize();
56  default_driver = ao_default_driver_id();
57 
58  format.bits = 16;
59  format.channels = 2;
60  This->channels = 2;
61  format.rate = 44100;
62  g_samplerate = 44100;
63  format.byte_format = AO_FMT_LITTLE;
64 
65  o_device = ao_open_live(default_driver, &format, NULL);
66  if (o_device == NULL)
67  {
68  return False;
69  }
70 
71  This->dsp_ = 0;
72  queue_lo = queue_hi = 0;
73 
74  g_reopened = True;
75 
76  return True;
77 }
78 
79 void
81 {
82  /* Ack all remaining packets */
83  while (queue_lo != queue_hi)
84  {
86  free(packet_queue[queue_lo].s.data);
87  queue_lo = (queue_lo + 1) % MAX_QUEUE;
88  }
89 
90  if (o_device != NULL)
91  ao_close(o_device);
92 
93  ao_shutdown();
94 }
95 
96 BOOL
98 {
99  if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
100  return False;
101  if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
102  return False;
103  if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
104  return False;
105  /* The only common denominator between libao output drivers is a sample-rate of
106  44100, we need to upsample 22050 to it */
107  if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
108  return False;
109 
110  return True;
111 }
112 
113 BOOL
115 {
116  ao_sample_format format;
117 
118  format.bits = pwfx->wBitsPerSample;
119  format.channels = pwfx->nChannels;
120  This->channels = pwfx->nChannels;
121  format.rate = 44100;
123  format.byte_format = AO_FMT_LITTLE;
124 
125  g_samplewidth = pwfx->wBitsPerSample / 8;
126 
127  if (o_device != NULL)
128  ao_close(o_device);
129 
130  o_device = ao_open_live(default_driver, &format, NULL);
131  if (o_device == NULL)
132  {
133  return False;
134  }
135 
136  g_reopened = True;
137 
138  return True;
139 }
140 
141 void
143 {
144  warning("volume changes not supported with libao-output\n");
145 }
146 
147 void
149 {
151  unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
152 
153  if (next_hi == queue_lo)
154  {
155  error("No space to queue audio packet\n");
156  return;
157  }
158 
159  queue_hi = next_hi;
160 
161  packet->s = *s;
162  packet->tick = tick;
163  packet->index = index;
164  packet->s.p += 4;
165 
166  /* we steal the data buffer from s, give it a new one */
167  s->data = malloc(s->size);
168 
169  if (!This->dsp_bu)
170  wave_out_play();
171 }
172 
173 void
175 {
176  struct audio_packet *packet;
177  STREAM out;
178  char outbuf[WAVEOUTBUF];
179  int offset, len, i;
180  static long prev_s, prev_us;
181  unsigned int duration;
182  struct timeval tv;
183  int next_tick;
184 
185  if (g_reopened)
186  {
187  g_reopened = False;
188  gettimeofday(&tv, NULL);
189  prev_s = tv.tv_sec;
190  prev_us = tv.tv_usec;
191  }
192 
193  if (queue_lo == queue_hi)
194  {
195  This->dsp_bu = 0;
196  return;
197  }
198 
199  packet = &packet_queue[queue_lo];
200  out = &packet->s;
201 
202  if (((queue_lo + 1) % MAX_QUEUE) != queue_hi)
203  {
204  next_tick = packet_queue[(queue_lo + 1) % MAX_QUEUE].tick;
205  }
206  else
207  {
208  next_tick = (packet->tick + 65535) % 65536;
209  }
210 
211  len = 0;
212 
213  if (g_samplerate == 22050)
214  {
215  /* Resample to 44100 */
216  for (i = 0; (i < ((WAVEOUTBUF / 4) * (3 - g_samplewidth))) && (out->p < out->end);
217  i++)
218  {
219  /* On a stereo-channel we must make sure that left and right
220  does not get mixed up, so we need to expand the sample-
221  data with channels in mind: 1234 -> 12123434
222  If we have a mono-channel, we can expand the data by simply
223  doubling the sample-data: 1234 -> 11223344 */
224  if (This->channels == 2)
225  offset = ((i * 2) - (i & 1)) * g_samplewidth;
226  else
227  offset = (i * 2) * g_samplewidth;
228 
229  memcpy(&outbuf[offset], out->p, g_samplewidth);
230  memcpy(&outbuf[This->channels * g_samplewidth + offset], out->p, g_samplewidth);
231 
232  out->p += g_samplewidth;
233  len += 2 * g_samplewidth;
234  }
235  }
236  else
237  {
238  len = (WAVEOUTBUF > (out->end - out->p)) ? (out->end - out->p) : WAVEOUTBUF;
239  memcpy(outbuf, out->p, len);
240  out->p += len;
241  }
242 
243  ao_play(o_device, outbuf, len);
244 
245  gettimeofday(&tv, NULL);
246 
247  duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000;
248 
249  if (packet->tick > next_tick)
250  next_tick += 65536;
251 
252  if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
253  {
254  prev_s = tv.tv_sec;
255  prev_us = tv.tv_usec;
256 
257  if (abs((next_tick - packet->tick) - duration) > 20)
258  {
259  DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick));
260  DEBUG(("last: %d, is: %d, should: %d\n", packet->tick,
261  (packet->tick + duration) % 65536, next_tick % 65536));
262  }
263 
264  /* Until all drivers are using the windows sound-ticks, we need to
265  substract the 50 ticks added later by rdpsnd.c */
266  rdpsnd_send_completion(((packet->tick + duration) % 65536) - 50, packet->index);
267  free(out->data);
268  queue_lo = (queue_lo + 1) % MAX_QUEUE;
269  }
270 
271  This->dsp_bu = 1;
272  return;
273 }
#define MAX_QUEUE
Definition: rdpsnd_libao.c:30
#define abs(i)
Definition: fconv.c:206
#define WAVEOUTBUF
Definition: rdpsnd_libao.c:31
void wave_out_close(void)
Definition: rdpsnd_libao.c:80
static struct audio_packet packet_queue[MAX_QUEUE]
#define error(str)
Definition: mkdosfs.c:1605
UCHAR packet[_PAGE_SIZE]
Definition: serial.c:53
#define free
Definition: debug_ros.c:5
void wave_out_volume(uint16 left, uint16 right)
Definition: rdpsnd_libao.c:142
unsigned long tv_sec
Definition: linux.h:1738
struct stream s
Definition: rdpsnd_libao.c:44
static unsigned int queue_hi
Definition: rdpsnd_libao.c:48
unsigned char * data
Definition: parse.h:26
int g_samplerate
Definition: rdpsnd_libao.c:36
static unsigned int queue_lo
Definition: rdpsnd_libao.c:48
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define WAVE_FORMAT_PCM
Definition: constants.h:425
int default_driver
Definition: rdpsnd_libao.c:35
WORD wBitsPerSample
Definition: audioclient.idl:45
smooth NULL
Definition: ftsmooth.c:557
unsigned long tv_usec
Definition: linux.h:1739
GLuint index
Definition: glext.h:6031
void wave_out_write(STREAM s, uint16 tick, uint8 index)
Definition: rdpsnd_libao.c:148
BOOL wave_out_open(void)
Definition: rdpsnd_libao.c:51
BOOL wave_out_format_supported(WAVEFORMATEX *pwfx)
Definition: rdpsnd_libao.c:97
DWORD nSamplesPerSec
Definition: audioclient.idl:42
Definition: dhcpd.h:135
#define True
Definition: types.h:24
#define False
Definition: types.h:25
unsigned int BOOL
Definition: ntddk_ex.h:94
void wave_out_play(void)
Definition: rdpsnd_libao.c:174
static BOOL g_reopened
Definition: rdpsnd_libao.c:39
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
static FILE * out
Definition: regtests2xml.c:44
unsigned char * end
Definition: parse.h:25
GLint left
Definition: glext.h:7726
unsigned char uint8
Definition: types.h:28
GLdouble GLdouble right
Definition: glext.h:10859
#define index(s, c)
Definition: various.h:29
unsigned int size
Definition: parse.h:27
Definition: parse.h:22
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLdouble s
Definition: gl.h:2039
GLenum GLsizei len
Definition: glext.h:6722
void rdpsnd_send_completion(RDPCLIENT *This, uint16 tick, uint8 packet_index)
Definition: rdpsnd.c:55
unsigned short uint16
Definition: types.h:30
unsigned char * p
Definition: parse.h:24
BOOL wave_out_set_format(WAVEFORMATEX *pwfx)
Definition: rdpsnd_libao.c:114
ao_device * o_device
Definition: rdpsnd_libao.c:34
#define malloc
Definition: debug_ros.c:4
#define DEBUG(args)
Definition: rdesktop.h:129
static short g_samplewidth
Definition: rdpsnd_libao.c:40
#define warning(s)
Definition: debug.h:71
GLintptr offset
Definition: glext.h:5920
uchar outbuf[M_BLOCK_OUT]
Definition: unzcrash.c:41