ReactOS  0.4.14-dev-98-gb0d4763
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 
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
GLintptr offset
Definition: glext.h:5920
static unsigned int queue_hi
Definition: rdpsnd_libao.c:48
int g_samplerate
Definition: rdpsnd_libao.c:36
static unsigned int queue_lo
Definition: rdpsnd_libao.c:48
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define WAVE_FORMAT_PCM
Definition: constants.h:425
unsigned int BOOL
Definition: ntddk_ex.h:94
int default_driver
Definition: rdpsnd_libao.c:35
WORD wBitsPerSample
Definition: audioclient.idl:45
smooth NULL
Definition: ftsmooth.c:416
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
void wave_out_play(void)
Definition: rdpsnd_libao.c:174
static BOOL g_reopened
Definition: rdpsnd_libao.c:39
static FILE * out
Definition: regtests2xml.c:44
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
Definition: parse.h:22
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
void rdpsnd_send_completion(RDPCLIENT *This, uint16 tick, uint8 packet_index)
Definition: rdpsnd.c:55
unsigned short uint16
Definition: types.h:30
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
char data[MTU]
Definition: ipreceive.c:8
#define warning(s)
Definition: debug.h:71