2
Copyright (c) 2009-2010 Jay Sorg
4
Permission is hereby granted, free of charge, to any person obtaining a
5
copy of this software and associated documentation files (the "Software"),
6
to deal in the Software without restriction, including without limitation
7
the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
and/or sell copies of the Software, and to permit persons to whom the
9
Software is furnished to do so, subject to the following conditions:
11
The above copyright notice and this permission notice shall be included
12
in all copies or substantial portions of the Software.
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
DEALINGS IN THE SOFTWARE.
29
#include <alsa/asoundlib.h>
30
#include <freerdp/types_ui.h>
31
#include "chan_stream.h"
34
#define LLOG(_level, _args) \
35
do { if (_level < LOG_LEVEL) { printf _args ; } } while (0)
36
#define LLOGLN(_level, _args) \
37
do { if (_level < LOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
39
struct alsa_device_data
41
snd_pcm_t * out_handle;
43
snd_pcm_format_t format;
45
int bytes_per_channel;
49
set_params(struct alsa_device_data * alsa_data)
51
snd_pcm_hw_params_t * hw_params;
54
error = snd_pcm_hw_params_malloc(&hw_params);
57
LLOGLN(0, ("set_params: snd_pcm_hw_params_malloc failed"));
60
snd_pcm_hw_params_any(alsa_data->out_handle, hw_params);
61
snd_pcm_hw_params_set_access(alsa_data->out_handle, hw_params,
62
SND_PCM_ACCESS_RW_INTERLEAVED);
63
snd_pcm_hw_params_set_format(alsa_data->out_handle, hw_params,
65
snd_pcm_hw_params_set_rate_near(alsa_data->out_handle, hw_params,
66
&alsa_data->rrate, NULL);
67
snd_pcm_hw_params_set_channels(alsa_data->out_handle, hw_params, alsa_data->num_channels);
68
snd_pcm_hw_params(alsa_data->out_handle, hw_params);
69
snd_pcm_hw_params_free(hw_params);
70
snd_pcm_prepare(alsa_data->out_handle);
77
struct alsa_device_data * alsa_data;
79
alsa_data = (struct alsa_device_data *) malloc(sizeof(struct alsa_device_data));
80
memset(alsa_data, 0, sizeof(struct alsa_device_data));
82
alsa_data->out_handle = 0;
83
alsa_data->rrate = 22050;
84
alsa_data->format = SND_PCM_FORMAT_S16_LE;
85
alsa_data->num_channels = 2;
86
alsa_data->bytes_per_channel = 2;
88
return (void *) alsa_data;
92
wave_out_free(void * device_data)
98
wave_out_open(void * device_data)
100
struct alsa_device_data * alsa_data;
103
alsa_data = (struct alsa_device_data *) device_data;
105
if (alsa_data->out_handle != 0)
109
LLOGLN(10, ("wave_out_open:"));
110
error = snd_pcm_open(&alsa_data->out_handle, "default",
111
SND_PCM_STREAM_PLAYBACK, 0);
114
LLOGLN(0, ("wave_out_open: snd_pcm_open failed"));
117
set_params(alsa_data);
122
wave_out_close(void * device_data)
124
struct alsa_device_data * alsa_data;
126
alsa_data = (struct alsa_device_data *) device_data;
127
if (alsa_data->out_handle != 0)
129
LLOGLN(10, ("wave_out_close:"));
130
snd_pcm_close(alsa_data->out_handle);
131
alsa_data->out_handle = 0;
137
wFormatTag 2 byte offset 0
138
nChannels 2 byte offset 2
139
nSamplesPerSec 4 byte offset 4
140
nAvgBytesPerSec 4 byte offset 8
141
nBlockAlign 2 byte offset 12
142
wBitsPerSample 2 byte offset 14
143
cbSize 2 byte offset 16
144
data variable offset 18
147
/* returns boolean */
149
wave_out_format_supported(void * device_data, char * snd_format, int size)
151
struct alsa_device_data * alsa_data;
158
alsa_data = (struct alsa_device_data *) device_data;
160
LLOGLN(10, ("wave_out_format_supported: size %d", size));
161
wFormatTag = GET_UINT16(snd_format, 0);
162
nChannels = GET_UINT16(snd_format, 2);
163
nSamplesPerSec = GET_UINT32(snd_format, 4);
164
wBitsPerSample = GET_UINT16(snd_format, 14);
165
cbSize = GET_UINT16(snd_format, 16);
167
(nSamplesPerSec == 22050 || nSamplesPerSec == 44100) &&
168
(wBitsPerSample == 8 || wBitsPerSample == 16) &&
169
(nChannels == 1 || nChannels == 2) &&
170
wFormatTag == 1) /* WAVE_FORMAT_PCM */
172
LLOGLN(0, ("wave_out_format_supported: ok"));
179
wave_out_set_format(void * device_data, char * snd_format, int size)
181
struct alsa_device_data * alsa_data;
186
alsa_data = (struct alsa_device_data *) device_data;
188
nChannels = GET_UINT16(snd_format, 2);
189
nSamplesPerSec = GET_UINT32(snd_format, 4);
190
wBitsPerSample = GET_UINT16(snd_format, 14);
191
LLOGLN(0, ("wave_out_set_format: nChannels %d "
192
"nSamplesPerSec %d wBitsPerSample %d",
193
nChannels, nSamplesPerSec, wBitsPerSample));
194
alsa_data->rrate = nSamplesPerSec;
195
alsa_data->num_channels = nChannels;
196
switch (wBitsPerSample)
199
alsa_data->format = SND_PCM_FORMAT_S8;
200
alsa_data->bytes_per_channel = 1;
203
alsa_data->format = SND_PCM_FORMAT_S16_LE;
204
alsa_data->bytes_per_channel = 2;
207
set_params(alsa_data);
212
wave_out_set_volume(void * device_data, uint32 value)
214
LLOGLN(0, ("wave_out_set_volume: %8.8x", value));
219
wave_out_play(void * device_data, char * data, int size, int * delay_ms)
221
struct alsa_device_data * alsa_data;
228
snd_pcm_sframes_t delay_frames = 0;
230
alsa_data = (struct alsa_device_data *) device_data;
232
LLOGLN(10, ("wave_out_play: size %d", size));
234
bytes_per_frame = alsa_data->num_channels * alsa_data->bytes_per_channel;
235
if ((size % bytes_per_frame) != 0)
237
LLOGLN(0, ("wave_out_play: error len mod"));
246
frames = len / bytes_per_frame;
247
error = snd_pcm_writei(alsa_data->out_handle, pindex, frames);
250
LLOGLN(0, ("wave_out_play: underrun occurred"));
251
snd_pcm_recover(alsa_data->out_handle, error, 0);
256
LLOGLN(0, ("wave_out_play: error len %d", error));
259
pindex += error * bytes_per_frame;
262
if (snd_pcm_delay(alsa_data->out_handle, &delay_frames) < 0)
264
delay_frames = size / bytes_per_frame;
266
if (delay_frames < 0)
270
*delay_ms = delay_frames * (1000000 / alsa_data->rrate) / 1000;