You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
18 KiB
575 lines
18 KiB
/*
|
|
The mediastreamer library aims at providing modular media processing and I/O
|
|
for linphone, but also for any telephony application.
|
|
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
JACK support
|
|
Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
|
|
*/
|
|
|
|
#include "jackcard.h"
|
|
|
|
#ifdef __JACK_ENABLED__
|
|
|
|
#include "msossread.h"
|
|
#include "msosswrite.h"
|
|
|
|
#include <signal.h>
|
|
|
|
#define READBUFFERSIZE 524288
|
|
#define WRITEBUFFERSIZE 524288
|
|
#define BSIZE 512
|
|
|
|
/**
|
|
* jack_shutdown:
|
|
* @arg:
|
|
*
|
|
* This is the shutdown callback for this JACK application.
|
|
* It is called by JACK if the server ever shuts down or
|
|
* decides to disconnect the client.
|
|
*
|
|
*/
|
|
void
|
|
jack_shutdown (void *arg)
|
|
{
|
|
JackCard* obj = (JackCard*) arg;
|
|
|
|
obj->jack_running = FALSE;
|
|
obj->jack_active = FALSE;
|
|
obj->read.port = NULL;
|
|
if (obj->read.open)
|
|
obj->read.init = TRUE;
|
|
obj->write.port = NULL;
|
|
if (obj->write.open)
|
|
obj->write.init = TRUE;
|
|
}
|
|
|
|
int samplerate(jack_nframes_t rate, void *arg)
|
|
{
|
|
JackCard* obj = (JackCard*) arg;
|
|
int error;
|
|
|
|
obj->rate = rate;
|
|
if (obj->read.open) {
|
|
obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate;
|
|
obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
|
|
g_free(obj->read.data.data_in);
|
|
obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
|
|
if (obj->read.src_state)
|
|
if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0)
|
|
g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
|
|
}
|
|
if (obj->write.open) {
|
|
obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate;
|
|
obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
|
|
g_free(obj->write.data.data_out);
|
|
obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
|
|
if (obj->write.src_state)
|
|
if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0)
|
|
g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The process callback for this JACK application.
|
|
* It is called by JACK at the appropriate times.
|
|
* @nframes :
|
|
* @arg :
|
|
*/
|
|
int
|
|
process (jack_nframes_t nframes, void *arg)
|
|
{
|
|
JackCard* obj = (JackCard*) arg;
|
|
sample_t *out;
|
|
sample_t *in;
|
|
|
|
if (obj->clear && !obj->write.can_process) {
|
|
out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
|
|
memset (out, 0, nframes * sizeof(sample_t));
|
|
obj->clear = FALSE;
|
|
}
|
|
|
|
if (!obj->can_process)
|
|
return 0;
|
|
|
|
if(obj->read.can_process) {
|
|
in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes);
|
|
jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes);
|
|
}
|
|
|
|
if (obj->write.can_process) {
|
|
out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
|
|
memset (out, 0, nframes * sizeof(sample_t));
|
|
if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) {
|
|
obj->write.can_process = FALSE;
|
|
if (!obj->read.open)
|
|
obj->can_process = FALSE;
|
|
obj->clear = FALSE;
|
|
return 0;
|
|
}
|
|
jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int jack_init(JackCard* obj)
|
|
{
|
|
char* client_name;
|
|
int error;
|
|
|
|
if (!obj->jack_running) {
|
|
obj->client = NULL;
|
|
client_name = g_strdup_printf("linphone-%u", g_random_int());
|
|
if ((obj->client = jack_client_new (client_name)) == NULL) {
|
|
g_warning("cannot create jack client");
|
|
g_free(client_name);
|
|
return -1;
|
|
}
|
|
g_message("Found Jack Daemon");
|
|
g_free(client_name);
|
|
|
|
/* tell the JACK server to call `process()' whenever
|
|
there is work to be done.
|
|
*/
|
|
jack_set_process_callback (obj->client, process, obj);
|
|
|
|
/* tell the JACK server to call `jack_shutdown()' if
|
|
it ever shuts down, either entirely, or if it
|
|
just decides to stop calling us.
|
|
*/
|
|
jack_on_shutdown (obj->client, jack_shutdown, obj);
|
|
jack_set_sample_rate_callback (obj->client, samplerate, obj);
|
|
obj->rate = jack_get_sample_rate (obj->client);
|
|
if (obj->rate == 0) {
|
|
g_warning ("rate is 0???");
|
|
if (jack_client_close(obj->client) != 0)
|
|
g_warning("could not close client");
|
|
return -1;
|
|
}
|
|
obj->buffer_size = jack_get_buffer_size(obj->client);
|
|
obj->jack_running = TRUE;
|
|
}
|
|
|
|
if (!obj->jack_active) {
|
|
if (jack_activate (obj->client)) {
|
|
g_warning("cannot activate jack client");
|
|
return -1;
|
|
} else obj->jack_active = TRUE;
|
|
}
|
|
|
|
if (obj->read.init) {
|
|
if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) {
|
|
g_warning("error while trying to register input port");
|
|
return -1;
|
|
}
|
|
if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
|
|
g_warning("Cannot find any physical capture ports\n");
|
|
jack_port_unregister(obj->client, obj->read.port);
|
|
obj->read.port = NULL;
|
|
return -1;
|
|
}
|
|
if (!jack_port_connected(obj->read.port))
|
|
if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) {
|
|
g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]);
|
|
if (error == EEXIST) g_warning("connection already made");
|
|
else {
|
|
jack_port_unregister(obj->client, obj->read.port);
|
|
obj->read.port = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
obj->read.init = FALSE;
|
|
}
|
|
|
|
if (obj->write.init) {
|
|
if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) {
|
|
g_warning("error while trying to register output port");
|
|
return -1;
|
|
}
|
|
if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
|
|
g_warning("Cannot find any physical playback ports\n");
|
|
jack_port_unregister(obj->client, obj->write.port);
|
|
obj->write.port = NULL;
|
|
return -1;
|
|
}
|
|
if (!jack_port_connected(obj->write.port)) {
|
|
if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) {
|
|
g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]);
|
|
if (error == EEXIST) g_warning("connection already made");
|
|
else {
|
|
jack_port_unregister(obj->client, obj->write.port);
|
|
obj->write.port = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) {
|
|
g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]);
|
|
if (error == EEXIST) g_warning("connection already made");
|
|
else {
|
|
jack_port_unregister(obj->client, obj->write.port);
|
|
obj->write.port = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
obj->write.init = FALSE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
int channels = stereo + 1, bsize, error;
|
|
obj->read.init = TRUE;
|
|
if (jack_init(obj) != 0) return -1;
|
|
|
|
obj->read.rate = rate;
|
|
obj->sample_size = bits / 8;
|
|
obj->frame_size = channels * obj->sample_size;
|
|
bsize = BSIZE;
|
|
obj->read.frames = bsize / 2;
|
|
SND_CARD(obj)->bsize = bsize;
|
|
SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
|
|
obj->read.channels = channels;
|
|
if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL)
|
|
g_warning("Error while initializing the samplerate converter: %s", src_strerror(error));
|
|
obj->read.data.src_ratio = (double)rate / (double)obj->rate;
|
|
obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
|
|
obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
|
|
obj->read.data.data_out = malloc(obj->read.frames*sizeof(float));
|
|
obj->read.data.end_of_input = 0;
|
|
if (!obj->read.buffer)
|
|
obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE);
|
|
obj->read.can_process = TRUE;
|
|
obj->can_process = TRUE;
|
|
obj->read.open = TRUE;
|
|
obj->read.init = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
int channels = stereo + 1, bsize, err;
|
|
obj->write.init = TRUE;
|
|
if (jack_init(obj) != 0) return -1;
|
|
|
|
obj->write.rate = rate;
|
|
obj->sample_size = bits / 8;
|
|
obj->frame_size = channels * obj->sample_size;
|
|
bsize = BSIZE;
|
|
obj->write.frames = bsize / 2;
|
|
SND_CARD(obj)->bsize = bsize;
|
|
SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
|
|
obj->write.channels = channels;
|
|
if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL)
|
|
g_warning("Error while initializing the samplerate converter: %s", src_strerror(err));
|
|
obj->write.data.src_ratio = (double)obj->rate / (double)rate;
|
|
obj->write.data.data_in = malloc(obj->write.frames*sizeof(float));
|
|
obj->write.data.end_of_input = 0;
|
|
obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
|
|
obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
|
|
if (!obj->write.buffer)
|
|
obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE);
|
|
obj->write.can_process = TRUE;
|
|
obj->can_process = TRUE;
|
|
obj->write.open = TRUE;
|
|
obj->write.init = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno)
|
|
{
|
|
}
|
|
|
|
void jack_card_close_r(JackCard *obj)
|
|
{
|
|
obj->read.open = FALSE;
|
|
obj->read.init = FALSE;
|
|
obj->read.can_process = FALSE;
|
|
if (!obj->write.open)
|
|
obj->can_process = FALSE;
|
|
if (obj->read.src_state)
|
|
obj->read.src_state = src_delete (obj->read.src_state);
|
|
g_free(obj->read.data.data_in);
|
|
g_free(obj->read.data.data_out);
|
|
}
|
|
|
|
void jack_card_close_w(JackCard *obj)
|
|
{
|
|
obj->write.open = FALSE;
|
|
obj->write.init = FALSE;
|
|
obj->clear = TRUE;
|
|
if (!obj->jack_running) {
|
|
obj->write.can_process = FALSE;
|
|
obj->can_process = FALSE;
|
|
}
|
|
if (obj->write.src_state)
|
|
obj->write.src_state = src_delete (obj->write.src_state);
|
|
g_free(obj->write.data.data_in);
|
|
g_free(obj->write.data.data_out);
|
|
}
|
|
|
|
int jack_card_probe(JackCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
if (obj->jack_running) return BSIZE;
|
|
else if (jack_init(obj) == 0) return BSIZE;
|
|
else return -1;
|
|
}
|
|
|
|
void jack_card_destroy(JackCard *obj)
|
|
{
|
|
if (obj->jack_running) jack_client_close (obj->client);
|
|
snd_card_uninit(SND_CARD(obj));
|
|
if (obj->read.buffer) {
|
|
jack_ringbuffer_free(obj->read.buffer);
|
|
obj->read.buffer = NULL;
|
|
}
|
|
if (obj->write.buffer) {
|
|
jack_ringbuffer_free(obj->write.buffer);
|
|
obj->write.buffer = NULL;
|
|
}
|
|
if (obj->read.phys_ports) {
|
|
g_free(obj->read.phys_ports);
|
|
obj->read.phys_ports = NULL;
|
|
}
|
|
if (obj->write.phys_ports) {
|
|
g_free(obj->write.phys_ports);
|
|
obj->write.phys_ports = NULL;
|
|
}
|
|
}
|
|
|
|
gboolean jack_card_can_read(JackCard *obj)
|
|
{
|
|
g_return_val_if_fail(obj->read.buffer!=NULL,0);
|
|
if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE;
|
|
else return FALSE;
|
|
}
|
|
|
|
int jack_card_read(JackCard *obj,char *buf,int size)
|
|
{
|
|
size_t bytes, can_read, i;
|
|
int error;
|
|
float norm, value;
|
|
|
|
g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1);
|
|
if (jack_init(obj) != 0) return -1;
|
|
size /= 2;
|
|
can_read = MIN(size, obj->read.frames);
|
|
// can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer));
|
|
can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t);
|
|
obj->read.can_process = FALSE;
|
|
bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read);
|
|
obj->read.can_process = TRUE;
|
|
obj->read.data.input_frames = bytes / sizeof(sample_t);
|
|
can_read = MIN(size, obj->read.frames);
|
|
obj->read.data.output_frames = can_read;
|
|
if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0)
|
|
g_warning("error while samplerate conversion. error: %s", src_strerror(error));
|
|
norm = obj->read.level*obj->level*(float)0x8000;
|
|
for (i=0; i < obj->read.data.output_frames_gen; i++) {
|
|
value = obj->read.data.data_out[i]*norm;
|
|
if (value >= 32767.0)
|
|
((short*)buf)[i] = 32767;
|
|
else if (value <= -32768.0)
|
|
((short*)buf)[i] = -32768;
|
|
else
|
|
((short*)buf)[i] = (short)value;
|
|
}
|
|
bytes = obj->read.data.output_frames_gen * 2;
|
|
return bytes;
|
|
}
|
|
|
|
int jack_card_write(JackCard *obj,char *buf,int size)
|
|
{
|
|
size_t bytes, can_write, i;
|
|
int error;
|
|
float norm;
|
|
|
|
g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1);
|
|
if (jack_init(obj) != 0) return -1;
|
|
size /= 2;
|
|
can_write = MIN(size, obj->write.frames);
|
|
norm = obj->write.level*obj->level/(float)0x8000;
|
|
for (i=0; i<can_write; i++) {
|
|
obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm;
|
|
}
|
|
obj->write.data.input_frames = can_write;
|
|
if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0)
|
|
g_warning("error while samplerate conversion. error: %s", src_strerror(error));
|
|
obj->write.can_process = FALSE;
|
|
bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen);
|
|
obj->write.can_process = TRUE;
|
|
return bytes;
|
|
}
|
|
|
|
void jack_card_set_level(JackCard *obj,gint way,gint a)
|
|
{
|
|
switch(way){
|
|
case SND_CARD_LEVEL_GENERAL:
|
|
obj->level = (float)a / 100.0;
|
|
break;
|
|
case SND_CARD_LEVEL_INPUT:
|
|
obj->read.level = (float)a / 100.0;
|
|
break;
|
|
case SND_CARD_LEVEL_OUTPUT:
|
|
obj->write.level = (float)a / 100.0;
|
|
break;
|
|
default:
|
|
g_warning("jack_card_set_level: unsupported command.");
|
|
}
|
|
}
|
|
|
|
gint jack_card_get_level(JackCard *obj,gint way)
|
|
{
|
|
gint value = 0;
|
|
|
|
switch(way){
|
|
case SND_CARD_LEVEL_GENERAL:
|
|
value = (gint)(obj->level*100.0);
|
|
break;
|
|
case SND_CARD_LEVEL_INPUT:
|
|
value = (gint)(obj->read.level*100.0);
|
|
break;
|
|
case SND_CARD_LEVEL_OUTPUT:
|
|
value = (gint)(obj->write.level*100.0);
|
|
break;
|
|
default:
|
|
g_warning("jack_card_get_level: unsupported command.");
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void jack_card_set_source(JackCard *obj,int source)
|
|
{
|
|
}
|
|
|
|
MSFilter *jack_card_create_read_filter(JackCard *card)
|
|
{
|
|
MSFilter *f=ms_oss_read_new();
|
|
ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
|
|
return f;
|
|
}
|
|
|
|
MSFilter *jack_card_create_write_filter(JackCard *card)
|
|
{
|
|
MSFilter *f=ms_oss_write_new();
|
|
ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
|
|
return f;
|
|
}
|
|
SndCard * jack_card_new(jack_client_t *client)
|
|
{
|
|
JackCard * obj;
|
|
SndCard *base;
|
|
|
|
obj= g_new0(JackCard,1);
|
|
|
|
if (!client) return NULL;
|
|
obj->client = client;
|
|
obj->jack_running = TRUE;
|
|
obj->jack_active = FALSE;
|
|
obj->can_process = FALSE;
|
|
obj->clear = TRUE;
|
|
obj->write.can_process = FALSE;
|
|
obj->write.open = FALSE;
|
|
obj->write.init = TRUE;
|
|
obj->write.port = NULL;
|
|
obj->write.phys_ports = NULL;
|
|
obj->write.buffer = NULL;
|
|
obj->read.can_process = FALSE;
|
|
obj->read.open = FALSE;
|
|
obj->read.init = TRUE;
|
|
obj->read.port = NULL;
|
|
obj->read.phys_ports = NULL;
|
|
obj->read.buffer = NULL;
|
|
|
|
/* tell the JACK server to call `process()' whenever
|
|
there is work to be done.
|
|
*/
|
|
jack_set_process_callback (client, process, obj);
|
|
|
|
/* tell the JACK server to call `jack_shutdown()' if
|
|
it ever shuts down, either entirely, or if it
|
|
just decides to stop calling us.
|
|
*/
|
|
jack_on_shutdown (client, jack_shutdown, obj);
|
|
|
|
jack_set_sample_rate_callback (client, samplerate, obj);
|
|
|
|
obj->rate = jack_get_sample_rate (client);
|
|
obj->buffer_size = jack_get_buffer_size(obj->client);
|
|
|
|
jack_init(obj);
|
|
|
|
base= SND_CARD(obj);
|
|
snd_card_init(base);
|
|
|
|
#ifdef HAVE_GLIB
|
|
base->card_name=g_strdup_printf("JACK client");
|
|
#else
|
|
base->card_name=malloc(100);
|
|
snprintf(base->card_name, 100, "JACK client");
|
|
#endif
|
|
|
|
base->_probe=(SndCardOpenFunc)jack_card_probe;
|
|
base->_open_r=(SndCardOpenFunc)jack_card_open_r;
|
|
base->_open_w=(SndCardOpenFunc)jack_card_open_w;
|
|
base->_can_read=(SndCardPollFunc)jack_card_can_read;
|
|
base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode;
|
|
base->_read=(SndCardIOFunc)jack_card_read;
|
|
base->_write=(SndCardIOFunc)jack_card_write;
|
|
base->_close_r=(SndCardCloseFunc)jack_card_close_r;
|
|
base->_close_w=(SndCardCloseFunc)jack_card_close_w;
|
|
base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source;
|
|
base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level;
|
|
base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level;
|
|
base->_destroy=(SndCardDestroyFunc)jack_card_destroy;
|
|
base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter;
|
|
base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter;
|
|
|
|
obj->read.buffer=NULL;
|
|
obj->write.buffer=NULL;
|
|
obj->buffer_size = 0;
|
|
obj->level = 1.0;
|
|
obj->write.level = 1.0;
|
|
obj->read.level = 1.0;
|
|
|
|
return base;
|
|
}
|
|
|
|
|
|
gint jack_card_manager_init(SndCardManager *m, gint index)
|
|
{
|
|
jack_client_t *client = NULL;
|
|
char* client_name;
|
|
|
|
client_name=g_strdup_printf("linphone-%u", g_random_int());
|
|
if ((client = jack_client_new (client_name))!= NULL)
|
|
{
|
|
g_message("Found Jack Daemon");
|
|
g_free(client_name);
|
|
m->cards[index]=jack_card_new(client);
|
|
m->cards[index]->index=index;
|
|
return 1;
|
|
} else {
|
|
g_free(client_name);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endif
|