~ubuntu-branches/ubuntu/raring/freerdp/raring

« back to all changes in this revision

Viewing changes to channels/rdpsnd/rdpsnd_alsa.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2010-06-23 21:39:09 UTC
  • Revision ID: james.westby@ubuntu.com-20100623213909-bb9pvvv03913tdv6
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (c) 2009-2010 Jay Sorg
 
3
 
 
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:
 
10
 
 
11
   The above copyright notice and this permission notice shall be included
 
12
   in all copies or substantial portions of the Software.
 
13
 
 
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.
 
21
 
 
22
*/
 
23
 
 
24
// libasound2-dev
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <alsa/asoundlib.h>
 
30
#include <freerdp/types_ui.h>
 
31
#include "chan_stream.h"
 
32
 
 
33
#define LOG_LEVEL 1
 
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)
 
38
 
 
39
struct alsa_device_data
 
40
{
 
41
        snd_pcm_t * out_handle;
 
42
        uint32 rrate;
 
43
        snd_pcm_format_t format;
 
44
        int num_channels;
 
45
        int bytes_per_channel;
 
46
};
 
47
 
 
48
static int
 
49
set_params(struct alsa_device_data * alsa_data)
 
50
{
 
51
        snd_pcm_hw_params_t * hw_params;
 
52
        int error;
 
53
 
 
54
        error = snd_pcm_hw_params_malloc(&hw_params);
 
55
        if (error < 0)
 
56
        {
 
57
                LLOGLN(0, ("set_params: snd_pcm_hw_params_malloc failed"));
 
58
                return 1;
 
59
        }
 
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,
 
64
                alsa_data->format);
 
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);
 
71
        return 0;
 
72
}
 
73
 
 
74
void *
 
75
wave_out_new(void)
 
76
{
 
77
        struct alsa_device_data * alsa_data;
 
78
 
 
79
        alsa_data = (struct alsa_device_data *) malloc(sizeof(struct alsa_device_data));
 
80
        memset(alsa_data, 0, sizeof(struct alsa_device_data));
 
81
 
 
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;
 
87
 
 
88
        return (void *) alsa_data;
 
89
}
 
90
 
 
91
void
 
92
wave_out_free(void * device_data)
 
93
{
 
94
        free(device_data);
 
95
}
 
96
 
 
97
int
 
98
wave_out_open(void * device_data)
 
99
{
 
100
        struct alsa_device_data * alsa_data;
 
101
        int error;
 
102
 
 
103
        alsa_data = (struct alsa_device_data *) device_data;
 
104
 
 
105
        if (alsa_data->out_handle != 0)
 
106
        {
 
107
                return 0;
 
108
        }
 
109
        LLOGLN(10, ("wave_out_open:"));
 
110
        error = snd_pcm_open(&alsa_data->out_handle, "default",
 
111
                SND_PCM_STREAM_PLAYBACK, 0);
 
112
        if (error < 0)
 
113
        {
 
114
                LLOGLN(0, ("wave_out_open: snd_pcm_open failed"));
 
115
                return 1;
 
116
        }
 
117
        set_params(alsa_data);
 
118
        return 0;
 
119
}
 
120
 
 
121
int
 
122
wave_out_close(void * device_data)
 
123
{
 
124
        struct alsa_device_data * alsa_data;
 
125
 
 
126
        alsa_data = (struct alsa_device_data *) device_data;
 
127
        if (alsa_data->out_handle != 0)
 
128
        {
 
129
                LLOGLN(10, ("wave_out_close:"));
 
130
                snd_pcm_close(alsa_data->out_handle);
 
131
                alsa_data->out_handle = 0;
 
132
        }
 
133
        return 0;
 
134
}
 
135
 
 
136
/*
 
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
 
145
*/
 
146
 
 
147
/* returns boolean */
 
148
int
 
149
wave_out_format_supported(void * device_data, char * snd_format, int size)
 
150
{
 
151
        struct alsa_device_data * alsa_data;
 
152
        int nChannels;
 
153
        int wBitsPerSample;
 
154
        int nSamplesPerSec;
 
155
        int cbSize;
 
156
        int wFormatTag;
 
157
 
 
158
        alsa_data = (struct alsa_device_data *) device_data;
 
159
 
 
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);
 
166
        if (cbSize == 0 &&
 
167
                (nSamplesPerSec == 22050 || nSamplesPerSec == 44100) &&
 
168
                (wBitsPerSample == 8 || wBitsPerSample == 16) &&
 
169
                (nChannels == 1 || nChannels == 2) &&
 
170
                wFormatTag == 1) /* WAVE_FORMAT_PCM */
 
171
        {
 
172
                LLOGLN(0, ("wave_out_format_supported: ok"));
 
173
                return 1;
 
174
        }
 
175
        return 0;
 
176
}
 
177
 
 
178
int
 
179
wave_out_set_format(void * device_data, char * snd_format, int size)
 
180
{
 
181
        struct alsa_device_data * alsa_data;
 
182
        int nChannels;
 
183
        int wBitsPerSample;
 
184
        int nSamplesPerSec;
 
185
 
 
186
        alsa_data = (struct alsa_device_data *) device_data;
 
187
 
 
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)
 
197
        {
 
198
                case 8:
 
199
                        alsa_data->format = SND_PCM_FORMAT_S8;
 
200
                        alsa_data->bytes_per_channel = 1;
 
201
                        break;
 
202
                case 16:
 
203
                        alsa_data->format = SND_PCM_FORMAT_S16_LE;
 
204
                        alsa_data->bytes_per_channel = 2;
 
205
                        break;
 
206
        }
 
207
        set_params(alsa_data);
 
208
        return 0;
 
209
}
 
210
 
 
211
int
 
212
wave_out_set_volume(void * device_data, uint32 value)
 
213
{
 
214
        LLOGLN(0, ("wave_out_set_volume: %8.8x", value));
 
215
        return 0;
 
216
}
 
217
 
 
218
int
 
219
wave_out_play(void * device_data, char * data, int size, int * delay_ms)
 
220
{
 
221
        struct alsa_device_data * alsa_data;
 
222
        int len;
 
223
        int error;
 
224
        int frames;
 
225
        int bytes_per_frame;
 
226
        char * pindex;
 
227
        char * end;
 
228
        snd_pcm_sframes_t delay_frames = 0;
 
229
 
 
230
        alsa_data = (struct alsa_device_data *) device_data;
 
231
 
 
232
        LLOGLN(10, ("wave_out_play: size %d", size));
 
233
 
 
234
        bytes_per_frame = alsa_data->num_channels * alsa_data->bytes_per_channel;
 
235
        if ((size % bytes_per_frame) != 0)
 
236
        {
 
237
                LLOGLN(0, ("wave_out_play: error len mod"));
 
238
                return 1;
 
239
        }
 
240
 
 
241
        pindex = data;
 
242
        end = pindex + size;
 
243
        while (pindex < end)
 
244
        {
 
245
                len = end - pindex;
 
246
                frames = len / bytes_per_frame;
 
247
                error = snd_pcm_writei(alsa_data->out_handle, pindex, frames);
 
248
                if (error == -EPIPE)
 
249
                {
 
250
                        LLOGLN(0, ("wave_out_play: underrun occurred"));
 
251
                        snd_pcm_recover(alsa_data->out_handle, error, 0);
 
252
                        error = 0;
 
253
                }
 
254
                else if (error < 0)
 
255
                {
 
256
                        LLOGLN(0, ("wave_out_play: error len %d", error));
 
257
                        break;
 
258
                }
 
259
                pindex += error * bytes_per_frame;
 
260
        }
 
261
 
 
262
        if (snd_pcm_delay(alsa_data->out_handle, &delay_frames) < 0)
 
263
        {
 
264
                delay_frames = size / bytes_per_frame;
 
265
        }
 
266
        if (delay_frames < 0)
 
267
        {
 
268
                delay_frames = 0;
 
269
        }
 
270
        *delay_ms = delay_frames * (1000000 / alsa_data->rrate) / 1000;
 
271
 
 
272
        return 0;
 
273
}