By default, Bugzilla does not search the list of RESOLVED bugs.
You can force it to do so by putting the upper-case word ALL in front of your search query, e.g.: ALL tdelibs
We recommend searching for bugs this way, as you may discover that your bug has already been resolved and fixed in a later release. View | Details | Raw Unified | Return to bug 2108
Collapse All | Expand All

(-) (+310 lines)
Added Link Here
1
/*
2
 * Copyright (c) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
6
 * copyright notice and this permission notice appear in all copies.
7
 *
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
 */
16
17
#ifdef HAVE_CONFIG_H
18
	#include <config.h>
19
#endif
20
21
#ifdef HAVE_LIBSNDIO
22
23
#include <sys/types.h>
24
#include <errno.h>
25
#include <math.h>
26
27
#include <sndio.h>
28
#include <poll.h>
29
30
#include "debug.h"
31
#include "audioio.h"
32
#include "audiosubsys.h"
33
#include "iomanager.h"
34
#include "dispatcher.h"
35
36
#include <cstdlib>
37
#include <cstring>
38
39
int bps, chans;
40
long long realpos, playpos, recpos;
41
42
void movecb(void *addr, int delta)
43
{
44
	realpos += delta * (int)(bps * chans);
45
}
46
47
namespace Arts {
48
49
class AudioIOSNDIO : public AudioIO, public TimeNotify {
50
51
protected:
52
	struct sio_hdl *hdl;
53
	struct sio_par par;
54
	int bufsz;
55
	int bufused;
56
	int duplex;
57
58
public:
59
	AudioIOSNDIO();
60
61
	void notifyTime();
62
63
	void setParam(AudioParam param, int& value);
64
	int getParam(AudioParam param);
65
66
	bool open();
67
	void close();
68
	int read(void *buffer, int size);
69
	int write(void *buffer, int size);
70
};
71
72
REGISTER_AUDIO_IO(AudioIOSNDIO,"sndio","libsndio");
73
}
74
75
using namespace std;
76
using namespace Arts;
77
78
AudioIOSNDIO::AudioIOSNDIO()
79
{
80
	/* default parameters */
81
	param(samplingRate) = 48000;
82
	paramStr(deviceName) = "";
83
	param(fragmentSize) = 4096;
84
	param(fragmentCount) = 4;
85
	param(format) = 16;
86
	param(channels) = 2;
87
	param(direction) = directionWrite;
88
}
89
90
bool AudioIOSNDIO::open()
91
{
92
	string& _error = paramStr(lastError);
93
	string& _deviceName = paramStr(deviceName);
94
	int& _channels = param(channels);
95
	int& _fragmentSize = param(fragmentSize);
96
	int& _fragmentCount = param(fragmentCount);
97
	int& _samplingRate = param(samplingRate);
98
	int& _format = param(format);
99
100
	struct sio_par testpar;
101
	char dev[PATH_MAX];
102
	int mode, bpf;
103
104
	duplex = 0;
105
	if (param(direction) == (directionRead | directionWrite)) {
106
		mode = SIO_PLAY | SIO_REC;
107
		duplex = 1;
108
	} else if (param(direction) == directionWrite) {
109
		mode = SIO_PLAY;
110
	} else {
111
		_error = "invalid direction";
112
		return false;
113
	}
114
115
	strlcpy(dev, _deviceName.c_str(), PATH_MAX);
116
117
	if (strcmp(dev, "") == 0)
118
		hdl = sio_open(NULL, mode, 0);
119
	else
120
		hdl = sio_open(dev, mode, 0);
121
122
	if (hdl == NULL) {
123
		_error = "device ";
124
		if (strcmp(_deviceName.c_str(), "") == 0)
125
			_error += "(default sndio device)";
126
		else
127
			_error += _deviceName.c_str();
128
		_error += " can't be opened";
129
		return false;
130
	}
131
132
	sio_initpar(&par);
133
134
	if (_format == 8) {
135
		par.bits = 8;
136
		par.sig = 0;
137
	} else {
138
		par.bits = 16;
139
		par.sig = 1;
140
		par.le = 1;
141
	}
142
143
	if (duplex)
144
		par.pchan = par.rchan = _channels;
145
	else
146
		par.pchan = _channels;
147
148
	par.rate = _samplingRate;
149
150
	/* limit the buffer size for hardware constraints */
151
152
	if (_fragmentSize > 1024*16)
153
		_fragmentSize = 1024*16;
154
155
	while (_fragmentSize * _fragmentCount > 1024*32)
156
		_fragmentCount--;
157
158
	bpf = ((par.bits / NBBY) * par.pchan);
159
	par.round = _fragmentSize / bpf;
160
	par.appbufsz = _fragmentSize * _fragmentCount / bpf;
161
162
	testpar = par;
163
164
	char details[128];
165
166
	snprintf(details, 128, " rate=%d pchan=%d bits=%d le=%d sig=%d sz=%d",
167
	    par.rate, par.pchan, par.bits, par.le, par.sig, par.appbufsz);
168
169
	if (!sio_setpar(hdl, &par)) {
170
		_error = "sio_setpar failed:";
171
		_error += details;
172
173
		close();
174
		return false;
175
	}
176
177
	if (!sio_getpar(hdl, &par)) {
178
		_error = "sio_getpar failed";
179
180
		close();
181
		return false;
182
	}
183
184
	if (testpar.bits != par.bits ||
185
	    testpar.sig != par.sig ||
186
	    testpar.le != par.le ||
187
	    testpar.pchan != par.pchan ||
188
	    fabs((testpar.rate - par.rate)/testpar.rate) > 0.05) {
189
		_error = "returned params do not match requested params";
190
191
		close();
192
		return false;
193
	}
194
195
	bpf = par.pchan * par.bps;
196
	bufsz = par.bufsz * bpf;
197
198
	::bps = par.bps;
199
	::chans = par.pchan;
200
	::realpos = ::playpos = ::recpos = 0;
201
202
	sio_onmove(hdl, ::movecb, NULL);
203
204
	if (!sio_start(hdl)) {
205
		_error = "sio_start failed";
206
207
		close();
208
		return false;
209
	}
210
211
	/* use a timer instead of select() */
212
	Dispatcher::the()->ioManager()->addTimer(10, this);
213
214
	return true;
215
}
216
217
void AudioIOSNDIO::close()
218
{
219
	if (hdl != NULL) {
220
		sio_close(hdl);
221
		hdl = NULL;
222
	}
223
}
224
225
void AudioIOSNDIO::setParam(AudioParam p, int& value)
226
{
227
	param(p) = value;
228
}
229
230
int AudioIOSNDIO::getParam(AudioParam p)
231
{
232
	struct pollfd gpfd;
233
	int n, events;
234
235
	/* update ::realpos */
236
	if ((p == canRead || p == canWrite) && hdl != NULL) {
237
		events = POLLOUT;
238
		if (duplex)
239
			events |= POLLIN;
240
		n = sio_pollfd(hdl, &gpfd, events);
241
		while (poll(&gpfd, n, 0) < 0 && errno == EINTR)
242
			;
243
		sio_revents(hdl, &gpfd);
244
	}
245
246
	switch(p) {
247
	case canRead:
248
		bufused = (::realpos - ::recpos < 0) ? 0 : ::realpos - ::recpos;
249
		return bufused;
250
		break;
251
	case canWrite:
252
		bufused = (::realpos < 0) ? ::playpos : ::playpos - ::realpos;
253
		return bufsz - bufused;
254
		break;
255
	case autoDetect:
256
		return 15;
257
		break;
258
	default:
259
		return param(p);
260
		break;
261
	}
262
}
263
264
int AudioIOSNDIO::read(void *buffer, int size)
265
{
266
	arts_assert(hdl != NULL);
267
268
	size_t result;
269
270
	result = sio_read(hdl, buffer, size);
271
272
	::recpos += result;
273
274
	return (int)result;
275
}
276
277
int AudioIOSNDIO::write(void *buffer, int size)
278
{
279
	arts_assert(hdl != NULL);
280
281
	size_t result;
282
283
	result = sio_write(hdl, buffer, size);
284
285
	::playpos += result;
286
287
	return (int)result;
288
}
289
290
void AudioIOSNDIO::notifyTime()
291
{
292
	int& _direction = param(direction);
293
294
	for (;;) {
295
		int todo = 0;
296
297
		if ((_direction & directionRead) && (getParam(canRead) > 0))
298
			todo |= AudioSubSystem::ioRead;
299
300
		if ((_direction & directionWrite) && (getParam(canWrite) > 0))
301
			todo |= AudioSubSystem::ioWrite;
302
303
		if (todo == 0)
304
			return;
305
306
		AudioSubSystem::the()->handleIO(todo);
307
	}
308
}
309
310
#endif

Return to bug 2108