12024
|
1 /*
|
|
2 The mediastreamer library aims at providing modular media processing and I/O
|
|
3 for linphone, but also for any telephony application.
|
|
4 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
5
|
|
6 This library is free software; you can redistribute it and/or
|
|
7 modify it under the terms of the GNU Lesser General Public
|
|
8 License as published by the Free Software Foundation; either
|
|
9 version 2.1 of the License, or (at your option) any later version.
|
|
10
|
|
11 This library is distributed in the hope that it will be useful,
|
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14 Lesser General Public License for more details.
|
|
15
|
|
16 You should have received a copy of the GNU Lesser General Public
|
|
17 License along with this library; if not, write to the Free Software
|
|
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19
|
|
20 JACK support
|
|
21 Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
|
|
22 */
|
|
23
|
|
24 #include "jackcard.h"
|
|
25
|
|
26 #ifdef __JACK_ENABLED__
|
|
27
|
|
28 #include "msossread.h"
|
|
29 #include "msosswrite.h"
|
|
30
|
|
31 #include <signal.h>
|
|
32
|
|
33 #define READBUFFERSIZE 524288
|
|
34 #define WRITEBUFFERSIZE 524288
|
|
35 #define BSIZE 512
|
|
36
|
|
37 /**
|
|
38 * jack_shutdown:
|
|
39 * @arg:
|
|
40 *
|
|
41 * This is the shutdown callback for this JACK application.
|
|
42 * It is called by JACK if the server ever shuts down or
|
|
43 * decides to disconnect the client.
|
|
44 *
|
|
45 */
|
|
46 void
|
|
47 jack_shutdown (void *arg)
|
|
48 {
|
|
49 JackCard* obj = (JackCard*) arg;
|
|
50
|
|
51 obj->jack_running = FALSE;
|
|
52 obj->jack_active = FALSE;
|
|
53 obj->read.port = NULL;
|
|
54 if (obj->read.open)
|
|
55 obj->read.init = TRUE;
|
|
56 obj->write.port = NULL;
|
|
57 if (obj->write.open)
|
|
58 obj->write.init = TRUE;
|
|
59 }
|
|
60
|
|
61 int samplerate(jack_nframes_t rate, void *arg)
|
|
62 {
|
|
63 JackCard* obj = (JackCard*) arg;
|
|
64 int error;
|
|
65
|
|
66 obj->rate = rate;
|
|
67 if (obj->read.open) {
|
|
68 obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate;
|
|
69 obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
|
|
70 g_free(obj->read.data.data_in);
|
|
71 obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
|
|
72 if (obj->read.src_state)
|
|
73 if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0)
|
|
74 g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
|
|
75 }
|
|
76 if (obj->write.open) {
|
|
77 obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate;
|
|
78 obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
|
|
79 g_free(obj->write.data.data_out);
|
|
80 obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
|
|
81 if (obj->write.src_state)
|
|
82 if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0)
|
|
83 g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
|
|
84 }
|
|
85 return 0;
|
|
86 }
|
|
87
|
|
88 /*
|
|
89 * The process callback for this JACK application.
|
|
90 * It is called by JACK at the appropriate times.
|
|
91 * @nframes :
|
|
92 * @arg :
|
|
93 */
|
|
94 int
|
|
95 process (jack_nframes_t nframes, void *arg)
|
|
96 {
|
|
97 JackCard* obj = (JackCard*) arg;
|
|
98 sample_t *out;
|
|
99 sample_t *in;
|
|
100
|
|
101 if (obj->clear && !obj->write.can_process) {
|
|
102 out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
|
|
103 memset (out, 0, nframes * sizeof(sample_t));
|
|
104 obj->clear = FALSE;
|
|
105 }
|
|
106
|
|
107 if (!obj->can_process)
|
|
108 return 0;
|
|
109
|
|
110 if(obj->read.can_process) {
|
|
111 in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes);
|
|
112 jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes);
|
|
113 }
|
|
114
|
|
115 if (obj->write.can_process) {
|
|
116 out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
|
|
117 memset (out, 0, nframes * sizeof(sample_t));
|
|
118 if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) {
|
|
119 obj->write.can_process = FALSE;
|
|
120 if (!obj->read.open)
|
|
121 obj->can_process = FALSE;
|
|
122 obj->clear = FALSE;
|
|
123 return 0;
|
|
124 }
|
|
125 jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes);
|
|
126 }
|
|
127 return 0;
|
|
128 }
|
|
129
|
|
130 int jack_init(JackCard* obj)
|
|
131 {
|
|
132 char* client_name;
|
|
133 int error;
|
|
134
|
|
135 if (!obj->jack_running) {
|
|
136 obj->client = NULL;
|
|
137 client_name = g_strdup_printf("linphone-%u", g_random_int());
|
|
138 if ((obj->client = jack_client_new (client_name)) == NULL) {
|
|
139 g_warning("cannot create jack client");
|
|
140 g_free(client_name);
|
|
141 return -1;
|
|
142 }
|
|
143 g_message("Found Jack Daemon");
|
|
144 g_free(client_name);
|
|
145
|
|
146 /* tell the JACK server to call `process()' whenever
|
|
147 there is work to be done.
|
|
148 */
|
|
149 jack_set_process_callback (obj->client, process, obj);
|
|
150
|
|
151 /* tell the JACK server to call `jack_shutdown()' if
|
|
152 it ever shuts down, either entirely, or if it
|
|
153 just decides to stop calling us.
|
|
154 */
|
|
155 jack_on_shutdown (obj->client, jack_shutdown, obj);
|
|
156 jack_set_sample_rate_callback (obj->client, samplerate, obj);
|
|
157 obj->rate = jack_get_sample_rate (obj->client);
|
|
158 if (obj->rate == 0) {
|
|
159 g_warning ("rate is 0???");
|
|
160 if (jack_client_close(obj->client) != 0)
|
|
161 g_warning("could not close client");
|
|
162 return -1;
|
|
163 }
|
|
164 obj->buffer_size = jack_get_buffer_size(obj->client);
|
|
165 obj->jack_running = TRUE;
|
|
166 }
|
|
167
|
|
168 if (!obj->jack_active) {
|
|
169 if (jack_activate (obj->client)) {
|
|
170 g_warning("cannot activate jack client");
|
|
171 return -1;
|
|
172 } else obj->jack_active = TRUE;
|
|
173 }
|
|
174
|
|
175 if (obj->read.init) {
|
|
176 if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) {
|
|
177 g_warning("error while trying to register input port");
|
|
178 return -1;
|
|
179 }
|
|
180 if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
|
|
181 g_warning("Cannot find any physical capture ports\n");
|
|
182 jack_port_unregister(obj->client, obj->read.port);
|
|
183 obj->read.port = NULL;
|
|
184 return -1;
|
|
185 }
|
|
186 if (!jack_port_connected(obj->read.port))
|
|
187 if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) {
|
|
188 g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]);
|
|
189 if (error == EEXIST) g_warning("connection already made");
|
|
190 else {
|
|
191 jack_port_unregister(obj->client, obj->read.port);
|
|
192 obj->read.port = NULL;
|
|
193 return -1;
|
|
194 }
|
|
195 }
|
|
196 obj->read.init = FALSE;
|
|
197 }
|
|
198
|
|
199 if (obj->write.init) {
|
|
200 if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) {
|
|
201 g_warning("error while trying to register output port");
|
|
202 return -1;
|
|
203 }
|
|
204 if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
|
|
205 g_warning("Cannot find any physical playback ports\n");
|
|
206 jack_port_unregister(obj->client, obj->write.port);
|
|
207 obj->write.port = NULL;
|
|
208 return -1;
|
|
209 }
|
|
210 if (!jack_port_connected(obj->write.port)) {
|
|
211 if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) {
|
|
212 g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]);
|
|
213 if (error == EEXIST) g_warning("connection already made");
|
|
214 else {
|
|
215 jack_port_unregister(obj->client, obj->write.port);
|
|
216 obj->write.port = NULL;
|
|
217 return -1;
|
|
218 }
|
|
219 }
|
|
220 if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) {
|
|
221 g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]);
|
|
222 if (error == EEXIST) g_warning("connection already made");
|
|
223 else {
|
|
224 jack_port_unregister(obj->client, obj->write.port);
|
|
225 obj->write.port = NULL;
|
|
226 return -1;
|
|
227 }
|
|
228 }
|
|
229 }
|
|
230 obj->write.init = FALSE;
|
|
231 }
|
|
232 return 0;
|
|
233 }
|
|
234
|
|
235 int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate)
|
|
236 {
|
|
237 int channels = stereo + 1, bsize, error;
|
|
238 obj->read.init = TRUE;
|
|
239 if (jack_init(obj) != 0) return -1;
|
|
240
|
|
241 obj->read.rate = rate;
|
|
242 obj->sample_size = bits / 8;
|
|
243 obj->frame_size = channels * obj->sample_size;
|
|
244 bsize = BSIZE;
|
|
245 obj->read.frames = bsize / 2;
|
|
246 SND_CARD(obj)->bsize = bsize;
|
|
247 SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
|
|
248 obj->read.channels = channels;
|
|
249 if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL)
|
|
250 g_warning("Error while initializing the samplerate converter: %s", src_strerror(error));
|
|
251 obj->read.data.src_ratio = (double)rate / (double)obj->rate;
|
|
252 obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
|
|
253 obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
|
|
254 obj->read.data.data_out = malloc(obj->read.frames*sizeof(float));
|
|
255 obj->read.data.end_of_input = 0;
|
|
256 if (!obj->read.buffer)
|
|
257 obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE);
|
|
258 obj->read.can_process = TRUE;
|
|
259 obj->can_process = TRUE;
|
|
260 obj->read.open = TRUE;
|
|
261 obj->read.init = FALSE;
|
|
262 return 0;
|
|
263 }
|
|
264
|
|
265 int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate)
|
|
266 {
|
|
267 int channels = stereo + 1, bsize, err;
|
|
268 obj->write.init = TRUE;
|
|
269 if (jack_init(obj) != 0) return -1;
|
|
270
|
|
271 obj->write.rate = rate;
|
|
272 obj->sample_size = bits / 8;
|
|
273 obj->frame_size = channels * obj->sample_size;
|
|
274 bsize = BSIZE;
|
|
275 obj->write.frames = bsize / 2;
|
|
276 SND_CARD(obj)->bsize = bsize;
|
|
277 SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
|
|
278 obj->write.channels = channels;
|
|
279 if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL)
|
|
280 g_warning("Error while initializing the samplerate converter: %s", src_strerror(err));
|
|
281 obj->write.data.src_ratio = (double)obj->rate / (double)rate;
|
|
282 obj->write.data.data_in = malloc(obj->write.frames*sizeof(float));
|
|
283 obj->write.data.end_of_input = 0;
|
|
284 obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
|
|
285 obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
|
|
286 if (!obj->write.buffer)
|
|
287 obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE);
|
|
288 obj->write.can_process = TRUE;
|
|
289 obj->can_process = TRUE;
|
|
290 obj->write.open = TRUE;
|
|
291 obj->write.init = FALSE;
|
|
292 return 0;
|
|
293 }
|
|
294
|
|
295 void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno)
|
|
296 {
|
|
297 }
|
|
298
|
|
299 void jack_card_close_r(JackCard *obj)
|
|
300 {
|
|
301 obj->read.open = FALSE;
|
|
302 obj->read.init = FALSE;
|
|
303 obj->read.can_process = FALSE;
|
|
304 if (!obj->write.open)
|
|
305 obj->can_process = FALSE;
|
|
306 if (obj->read.src_state)
|
|
307 obj->read.src_state = src_delete (obj->read.src_state);
|
|
308 g_free(obj->read.data.data_in);
|
|
309 g_free(obj->read.data.data_out);
|
|
310 }
|
|
311
|
|
312 void jack_card_close_w(JackCard *obj)
|
|
313 {
|
|
314 obj->write.open = FALSE;
|
|
315 obj->write.init = FALSE;
|
|
316 obj->clear = TRUE;
|
|
317 if (!obj->jack_running) {
|
|
318 obj->write.can_process = FALSE;
|
|
319 obj->can_process = FALSE;
|
|
320 }
|
|
321 if (obj->write.src_state)
|
|
322 obj->write.src_state = src_delete (obj->write.src_state);
|
|
323 g_free(obj->write.data.data_in);
|
|
324 g_free(obj->write.data.data_out);
|
|
325 }
|
|
326
|
|
327 int jack_card_probe(JackCard *obj,int bits,int stereo,int rate)
|
|
328 {
|
|
329 if (obj->jack_running) return BSIZE;
|
|
330 else if (jack_init(obj) == 0) return BSIZE;
|
|
331 else return -1;
|
|
332 }
|
|
333
|
|
334 void jack_card_destroy(JackCard *obj)
|
|
335 {
|
|
336 if (obj->jack_running) jack_client_close (obj->client);
|
|
337 snd_card_uninit(SND_CARD(obj));
|
|
338 if (obj->read.buffer) {
|
|
339 jack_ringbuffer_free(obj->read.buffer);
|
|
340 obj->read.buffer = NULL;
|
|
341 }
|
|
342 if (obj->write.buffer) {
|
|
343 jack_ringbuffer_free(obj->write.buffer);
|
|
344 obj->write.buffer = NULL;
|
|
345 }
|
|
346 if (obj->read.phys_ports) {
|
|
347 g_free(obj->read.phys_ports);
|
|
348 obj->read.phys_ports = NULL;
|
|
349 }
|
|
350 if (obj->write.phys_ports) {
|
|
351 g_free(obj->write.phys_ports);
|
|
352 obj->write.phys_ports = NULL;
|
|
353 }
|
|
354 }
|
|
355
|
|
356 gboolean jack_card_can_read(JackCard *obj)
|
|
357 {
|
|
358 g_return_val_if_fail(obj->read.buffer!=NULL,0);
|
|
359 if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE;
|
|
360 else return FALSE;
|
|
361 }
|
|
362
|
|
363 int jack_card_read(JackCard *obj,char *buf,int size)
|
|
364 {
|
|
365 size_t bytes, can_read, i;
|
|
366 int error;
|
|
367 float norm, value;
|
|
368
|
|
369 g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1);
|
|
370 if (jack_init(obj) != 0) return -1;
|
|
371 size /= 2;
|
|
372 can_read = MIN(size, obj->read.frames);
|
|
373 // can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer));
|
|
374 can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t);
|
|
375 obj->read.can_process = FALSE;
|
|
376 bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read);
|
|
377 obj->read.can_process = TRUE;
|
|
378 obj->read.data.input_frames = bytes / sizeof(sample_t);
|
|
379 can_read = MIN(size, obj->read.frames);
|
|
380 obj->read.data.output_frames = can_read;
|
|
381 if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0)
|
|
382 g_warning("error while samplerate conversion. error: %s", src_strerror(error));
|
|
383 norm = obj->read.level*obj->level*(float)0x8000;
|
|
384 for (i=0; i < obj->read.data.output_frames_gen; i++) {
|
|
385 value = obj->read.data.data_out[i]*norm;
|
|
386 if (value >= 32767.0)
|
|
387 ((short*)buf)[i] = 32767;
|
|
388 else if (value <= -32768.0)
|
|
389 ((short*)buf)[i] = -32768;
|
|
390 else
|
|
391 ((short*)buf)[i] = (short)value;
|
|
392 }
|
|
393 bytes = obj->read.data.output_frames_gen * 2;
|
|
394 return bytes;
|
|
395 }
|
|
396
|
|
397 int jack_card_write(JackCard *obj,char *buf,int size)
|
|
398 {
|
|
399 size_t bytes, can_write, i;
|
|
400 int error;
|
|
401 float norm;
|
|
402
|
|
403 g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1);
|
|
404 if (jack_init(obj) != 0) return -1;
|
|
405 size /= 2;
|
|
406 can_write = MIN(size, obj->write.frames);
|
|
407 norm = obj->write.level*obj->level/(float)0x8000;
|
|
408 for (i=0; i<can_write; i++) {
|
|
409 obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm;
|
|
410 }
|
|
411 obj->write.data.input_frames = can_write;
|
|
412 if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0)
|
|
413 g_warning("error while samplerate conversion. error: %s", src_strerror(error));
|
|
414 obj->write.can_process = FALSE;
|
|
415 bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen);
|
|
416 obj->write.can_process = TRUE;
|
|
417 return bytes;
|
|
418 }
|
|
419
|
|
420 void jack_card_set_level(JackCard *obj,gint way,gint a)
|
|
421 {
|
|
422 switch(way){
|
|
423 case SND_CARD_LEVEL_GENERAL:
|
|
424 obj->level = (float)a / 100.0;
|
|
425 break;
|
|
426 case SND_CARD_LEVEL_INPUT:
|
|
427 obj->read.level = (float)a / 100.0;
|
|
428 break;
|
|
429 case SND_CARD_LEVEL_OUTPUT:
|
|
430 obj->write.level = (float)a / 100.0;
|
|
431 break;
|
|
432 default:
|
|
433 g_warning("jack_card_set_level: unsupported command.");
|
|
434 }
|
|
435 }
|
|
436
|
|
437 gint jack_card_get_level(JackCard *obj,gint way)
|
|
438 {
|
|
439 gint value = 0;
|
|
440
|
|
441 switch(way){
|
|
442 case SND_CARD_LEVEL_GENERAL:
|
|
443 value = (gint)(obj->level*100.0);
|
|
444 break;
|
|
445 case SND_CARD_LEVEL_INPUT:
|
|
446 value = (gint)(obj->read.level*100.0);
|
|
447 break;
|
|
448 case SND_CARD_LEVEL_OUTPUT:
|
|
449 value = (gint)(obj->write.level*100.0);
|
|
450 break;
|
|
451 default:
|
|
452 g_warning("jack_card_get_level: unsupported command.");
|
|
453 }
|
|
454 return value;
|
|
455 }
|
|
456
|
|
457 void jack_card_set_source(JackCard *obj,int source)
|
|
458 {
|
|
459 }
|
|
460
|
|
461 MSFilter *jack_card_create_read_filter(JackCard *card)
|
|
462 {
|
|
463 MSFilter *f=ms_oss_read_new();
|
|
464 ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
|
|
465 return f;
|
|
466 }
|
|
467
|
|
468 MSFilter *jack_card_create_write_filter(JackCard *card)
|
|
469 {
|
|
470 MSFilter *f=ms_oss_write_new();
|
|
471 ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
|
|
472 return f;
|
|
473 }
|
|
474 SndCard * jack_card_new(jack_client_t *client)
|
|
475 {
|
|
476 JackCard * obj;
|
|
477 SndCard *base;
|
|
478
|
|
479 obj= g_new0(JackCard,1);
|
|
480
|
|
481 if (!client) return NULL;
|
|
482 obj->client = client;
|
|
483 obj->jack_running = TRUE;
|
|
484 obj->jack_active = FALSE;
|
|
485 obj->can_process = FALSE;
|
|
486 obj->clear = TRUE;
|
|
487 obj->write.can_process = FALSE;
|
|
488 obj->write.open = FALSE;
|
|
489 obj->write.init = TRUE;
|
|
490 obj->write.port = NULL;
|
|
491 obj->write.phys_ports = NULL;
|
|
492 obj->write.buffer = NULL;
|
|
493 obj->read.can_process = FALSE;
|
|
494 obj->read.open = FALSE;
|
|
495 obj->read.init = TRUE;
|
|
496 obj->read.port = NULL;
|
|
497 obj->read.phys_ports = NULL;
|
|
498 obj->read.buffer = NULL;
|
|
499
|
|
500 /* tell the JACK server to call `process()' whenever
|
|
501 there is work to be done.
|
|
502 */
|
|
503 jack_set_process_callback (client, process, obj);
|
|
504
|
|
505 /* tell the JACK server to call `jack_shutdown()' if
|
|
506 it ever shuts down, either entirely, or if it
|
|
507 just decides to stop calling us.
|
|
508 */
|
|
509 jack_on_shutdown (client, jack_shutdown, obj);
|
|
510
|
|
511 jack_set_sample_rate_callback (client, samplerate, obj);
|
|
512
|
|
513 obj->rate = jack_get_sample_rate (client);
|
|
514 obj->buffer_size = jack_get_buffer_size(obj->client);
|
|
515
|
|
516 jack_init(obj);
|
|
517
|
|
518 base= SND_CARD(obj);
|
|
519 snd_card_init(base);
|
|
520
|
|
521 #ifdef HAVE_GLIB
|
|
522 base->card_name=g_strdup_printf("JACK client");
|
|
523 #else
|
|
524 base->card_name=malloc(100);
|
|
525 snprintf(base->card_name, 100, "JACK client");
|
|
526 #endif
|
|
527
|
|
528 base->_probe=(SndCardOpenFunc)jack_card_probe;
|
|
529 base->_open_r=(SndCardOpenFunc)jack_card_open_r;
|
|
530 base->_open_w=(SndCardOpenFunc)jack_card_open_w;
|
|
531 base->_can_read=(SndCardPollFunc)jack_card_can_read;
|
|
532 base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode;
|
|
533 base->_read=(SndCardIOFunc)jack_card_read;
|
|
534 base->_write=(SndCardIOFunc)jack_card_write;
|
|
535 base->_close_r=(SndCardCloseFunc)jack_card_close_r;
|
|
536 base->_close_w=(SndCardCloseFunc)jack_card_close_w;
|
|
537 base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source;
|
|
538 base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level;
|
|
539 base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level;
|
|
540 base->_destroy=(SndCardDestroyFunc)jack_card_destroy;
|
|
541 base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter;
|
|
542 base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter;
|
|
543
|
|
544 obj->read.buffer=NULL;
|
|
545 obj->write.buffer=NULL;
|
|
546 obj->buffer_size = 0;
|
|
547 obj->level = 1.0;
|
|
548 obj->write.level = 1.0;
|
|
549 obj->read.level = 1.0;
|
|
550
|
|
551 return base;
|
|
552 }
|
|
553
|
|
554
|
|
555 gint jack_card_manager_init(SndCardManager *m, gint index)
|
|
556 {
|
|
557 jack_client_t *client = NULL;
|
|
558 char* client_name;
|
|
559
|
|
560 client_name=g_strdup_printf("linphone-%u", g_random_int());
|
|
561 if ((client = jack_client_new (client_name))!= NULL)
|
|
562 {
|
|
563 g_message("Found Jack Daemon");
|
|
564 g_free(client_name);
|
|
565 m->cards[index]=jack_card_new(client);
|
|
566 m->cards[index]->index=index;
|
|
567 return 1;
|
|
568 } else {
|
|
569 g_free(client_name);
|
|
570 return 0;
|
|
571 }
|
|
572 }
|
|
573
|
|
574 #endif
|