12e445703SGeoffrey McRae /* 22e445703SGeoffrey McRae * QEMU JACK Audio Connection Kit Client 32e445703SGeoffrey McRae * 42e445703SGeoffrey McRae * Copyright (c) 2020 Geoffrey McRae (gnif) 52e445703SGeoffrey McRae * 62e445703SGeoffrey McRae * Permission is hereby granted, free of charge, to any person obtaining a copy 72e445703SGeoffrey McRae * of this software and associated documentation files (the "Software"), to deal 82e445703SGeoffrey McRae * in the Software without restriction, including without limitation the rights 92e445703SGeoffrey McRae * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 102e445703SGeoffrey McRae * copies of the Software, and to permit persons to whom the Software is 112e445703SGeoffrey McRae * furnished to do so, subject to the following conditions: 122e445703SGeoffrey McRae * 132e445703SGeoffrey McRae * The above copyright notice and this permission notice shall be included in 142e445703SGeoffrey McRae * all copies or substantial portions of the Software. 152e445703SGeoffrey McRae * 162e445703SGeoffrey McRae * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 172e445703SGeoffrey McRae * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 182e445703SGeoffrey McRae * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 192e445703SGeoffrey McRae * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 202e445703SGeoffrey McRae * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 212e445703SGeoffrey McRae * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 222e445703SGeoffrey McRae * THE SOFTWARE. 232e445703SGeoffrey McRae */ 242e445703SGeoffrey McRae 252e445703SGeoffrey McRae #include "qemu/osdep.h" 262e445703SGeoffrey McRae #include "qemu/module.h" 272e445703SGeoffrey McRae #include "qemu/atomic.h" 282e445703SGeoffrey McRae #include "qemu-common.h" 292e445703SGeoffrey McRae #include "audio.h" 302e445703SGeoffrey McRae 312e445703SGeoffrey McRae #define AUDIO_CAP "jack" 322e445703SGeoffrey McRae #include "audio_int.h" 332e445703SGeoffrey McRae 342e445703SGeoffrey McRae #include <jack/jack.h> 352e445703SGeoffrey McRae #include <jack/thread.h> 362e445703SGeoffrey McRae 372e445703SGeoffrey McRae struct QJack; 382e445703SGeoffrey McRae 392e445703SGeoffrey McRae typedef enum QJackState { 402e445703SGeoffrey McRae QJACK_STATE_DISCONNECTED, 412e445703SGeoffrey McRae QJACK_STATE_RUNNING, 422e445703SGeoffrey McRae QJACK_STATE_SHUTDOWN 432e445703SGeoffrey McRae } 442e445703SGeoffrey McRae QJackState; 452e445703SGeoffrey McRae 462e445703SGeoffrey McRae typedef struct QJackBuffer { 472e445703SGeoffrey McRae int channels; 482e445703SGeoffrey McRae int frames; 492e445703SGeoffrey McRae uint32_t used; 502e445703SGeoffrey McRae int rptr, wptr; 512e445703SGeoffrey McRae float **data; 522e445703SGeoffrey McRae } 532e445703SGeoffrey McRae QJackBuffer; 542e445703SGeoffrey McRae 552e445703SGeoffrey McRae typedef struct QJackClient { 562e445703SGeoffrey McRae AudiodevJackPerDirectionOptions *opt; 572e445703SGeoffrey McRae 582e445703SGeoffrey McRae bool out; 59*81e0efb2SGeoffrey McRae bool enabled; 602e445703SGeoffrey McRae bool connect_ports; 612e445703SGeoffrey McRae int packets; 622e445703SGeoffrey McRae 632e445703SGeoffrey McRae QJackState state; 642e445703SGeoffrey McRae jack_client_t *client; 652e445703SGeoffrey McRae jack_nframes_t freq; 662e445703SGeoffrey McRae 672e445703SGeoffrey McRae struct QJack *j; 682e445703SGeoffrey McRae int nchannels; 692e445703SGeoffrey McRae int buffersize; 702e445703SGeoffrey McRae jack_port_t **port; 712e445703SGeoffrey McRae QJackBuffer fifo; 722e445703SGeoffrey McRae } 732e445703SGeoffrey McRae QJackClient; 742e445703SGeoffrey McRae 752e445703SGeoffrey McRae typedef struct QJackOut { 762e445703SGeoffrey McRae HWVoiceOut hw; 772e445703SGeoffrey McRae QJackClient c; 782e445703SGeoffrey McRae } 792e445703SGeoffrey McRae QJackOut; 802e445703SGeoffrey McRae 812e445703SGeoffrey McRae typedef struct QJackIn { 822e445703SGeoffrey McRae HWVoiceIn hw; 832e445703SGeoffrey McRae QJackClient c; 842e445703SGeoffrey McRae } 852e445703SGeoffrey McRae QJackIn; 862e445703SGeoffrey McRae 872e445703SGeoffrey McRae static int qjack_client_init(QJackClient *c); 882e445703SGeoffrey McRae static void qjack_client_connect_ports(QJackClient *c); 892e445703SGeoffrey McRae static void qjack_client_fini(QJackClient *c); 902e445703SGeoffrey McRae 912e445703SGeoffrey McRae static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames) 922e445703SGeoffrey McRae { 932e445703SGeoffrey McRae buffer->channels = channels; 942e445703SGeoffrey McRae buffer->frames = frames; 952e445703SGeoffrey McRae buffer->used = 0; 962e445703SGeoffrey McRae buffer->rptr = 0; 972e445703SGeoffrey McRae buffer->wptr = 0; 982e445703SGeoffrey McRae buffer->data = g_malloc(channels * sizeof(float *)); 992e445703SGeoffrey McRae for (int i = 0; i < channels; ++i) { 1002e445703SGeoffrey McRae buffer->data[i] = g_malloc(frames * sizeof(float)); 1012e445703SGeoffrey McRae } 1022e445703SGeoffrey McRae } 1032e445703SGeoffrey McRae 1042e445703SGeoffrey McRae static void qjack_buffer_clear(QJackBuffer *buffer) 1052e445703SGeoffrey McRae { 1062e445703SGeoffrey McRae assert(buffer->data); 1072e445703SGeoffrey McRae atomic_store_release(&buffer->used, 0); 1082e445703SGeoffrey McRae buffer->rptr = 0; 1092e445703SGeoffrey McRae buffer->wptr = 0; 1102e445703SGeoffrey McRae } 1112e445703SGeoffrey McRae 1122e445703SGeoffrey McRae static void qjack_buffer_free(QJackBuffer *buffer) 1132e445703SGeoffrey McRae { 1142e445703SGeoffrey McRae if (!buffer->data) { 1152e445703SGeoffrey McRae return; 1162e445703SGeoffrey McRae } 1172e445703SGeoffrey McRae 1182e445703SGeoffrey McRae for (int i = 0; i < buffer->channels; ++i) { 1192e445703SGeoffrey McRae g_free(buffer->data[i]); 1202e445703SGeoffrey McRae } 1212e445703SGeoffrey McRae 1222e445703SGeoffrey McRae g_free(buffer->data); 1232e445703SGeoffrey McRae buffer->data = NULL; 1242e445703SGeoffrey McRae } 1252e445703SGeoffrey McRae 1262e445703SGeoffrey McRae /* write PCM interleaved */ 1272e445703SGeoffrey McRae static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size) 1282e445703SGeoffrey McRae { 1292e445703SGeoffrey McRae assert(buffer->data); 1302e445703SGeoffrey McRae const int samples = size / sizeof(float); 1312e445703SGeoffrey McRae int frames = samples / buffer->channels; 1322e445703SGeoffrey McRae const int avail = buffer->frames - atomic_load_acquire(&buffer->used); 1332e445703SGeoffrey McRae 1342e445703SGeoffrey McRae if (frames > avail) { 1352e445703SGeoffrey McRae frames = avail; 1362e445703SGeoffrey McRae } 1372e445703SGeoffrey McRae 1382e445703SGeoffrey McRae int copy = frames; 1392e445703SGeoffrey McRae int wptr = buffer->wptr; 1402e445703SGeoffrey McRae 1412e445703SGeoffrey McRae while (copy) { 1422e445703SGeoffrey McRae 1432e445703SGeoffrey McRae for (int c = 0; c < buffer->channels; ++c) { 1442e445703SGeoffrey McRae buffer->data[c][wptr] = *data++; 1452e445703SGeoffrey McRae } 1462e445703SGeoffrey McRae 1472e445703SGeoffrey McRae if (++wptr == buffer->frames) { 1482e445703SGeoffrey McRae wptr = 0; 1492e445703SGeoffrey McRae } 1502e445703SGeoffrey McRae 1512e445703SGeoffrey McRae --copy; 1522e445703SGeoffrey McRae } 1532e445703SGeoffrey McRae 1542e445703SGeoffrey McRae buffer->wptr = wptr; 1552e445703SGeoffrey McRae 1562e445703SGeoffrey McRae atomic_add(&buffer->used, frames); 1572e445703SGeoffrey McRae return frames * buffer->channels * sizeof(float); 1582e445703SGeoffrey McRae }; 1592e445703SGeoffrey McRae 1602e445703SGeoffrey McRae /* write PCM linear */ 1612e445703SGeoffrey McRae static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames) 1622e445703SGeoffrey McRae { 1632e445703SGeoffrey McRae assert(buffer->data); 1642e445703SGeoffrey McRae const int avail = buffer->frames - atomic_load_acquire(&buffer->used); 1652e445703SGeoffrey McRae int wptr = buffer->wptr; 1662e445703SGeoffrey McRae 1672e445703SGeoffrey McRae if (frames > avail) { 1682e445703SGeoffrey McRae frames = avail; 1692e445703SGeoffrey McRae } 1702e445703SGeoffrey McRae 1712e445703SGeoffrey McRae int right = buffer->frames - wptr; 1722e445703SGeoffrey McRae if (right > frames) { 1732e445703SGeoffrey McRae right = frames; 1742e445703SGeoffrey McRae } 1752e445703SGeoffrey McRae 1762e445703SGeoffrey McRae const int left = frames - right; 1772e445703SGeoffrey McRae for (int c = 0; c < buffer->channels; ++c) { 1782e445703SGeoffrey McRae memcpy(buffer->data[c] + wptr, dest[c] , right * sizeof(float)); 1792e445703SGeoffrey McRae memcpy(buffer->data[c] , dest[c] + right, left * sizeof(float)); 1802e445703SGeoffrey McRae } 1812e445703SGeoffrey McRae 1822e445703SGeoffrey McRae wptr += frames; 1832e445703SGeoffrey McRae if (wptr >= buffer->frames) { 1842e445703SGeoffrey McRae wptr -= buffer->frames; 1852e445703SGeoffrey McRae } 1862e445703SGeoffrey McRae buffer->wptr = wptr; 1872e445703SGeoffrey McRae 1882e445703SGeoffrey McRae atomic_add(&buffer->used, frames); 1892e445703SGeoffrey McRae return frames; 1902e445703SGeoffrey McRae } 1912e445703SGeoffrey McRae 1922e445703SGeoffrey McRae /* read PCM interleaved */ 1932e445703SGeoffrey McRae static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size) 1942e445703SGeoffrey McRae { 1952e445703SGeoffrey McRae assert(buffer->data); 1962e445703SGeoffrey McRae const int samples = size / sizeof(float); 1972e445703SGeoffrey McRae int frames = samples / buffer->channels; 1982e445703SGeoffrey McRae const int avail = atomic_load_acquire(&buffer->used); 1992e445703SGeoffrey McRae 2002e445703SGeoffrey McRae if (frames > avail) { 2012e445703SGeoffrey McRae frames = avail; 2022e445703SGeoffrey McRae } 2032e445703SGeoffrey McRae 2042e445703SGeoffrey McRae int copy = frames; 2052e445703SGeoffrey McRae int rptr = buffer->rptr; 2062e445703SGeoffrey McRae 2072e445703SGeoffrey McRae while (copy) { 2082e445703SGeoffrey McRae 2092e445703SGeoffrey McRae for (int c = 0; c < buffer->channels; ++c) { 2102e445703SGeoffrey McRae *dest++ = buffer->data[c][rptr]; 2112e445703SGeoffrey McRae } 2122e445703SGeoffrey McRae 2132e445703SGeoffrey McRae if (++rptr == buffer->frames) { 2142e445703SGeoffrey McRae rptr = 0; 2152e445703SGeoffrey McRae } 2162e445703SGeoffrey McRae 2172e445703SGeoffrey McRae --copy; 2182e445703SGeoffrey McRae } 2192e445703SGeoffrey McRae 2202e445703SGeoffrey McRae buffer->rptr = rptr; 2212e445703SGeoffrey McRae 2222e445703SGeoffrey McRae atomic_sub(&buffer->used, frames); 2232e445703SGeoffrey McRae return frames * buffer->channels * sizeof(float); 2242e445703SGeoffrey McRae } 2252e445703SGeoffrey McRae 2262e445703SGeoffrey McRae /* read PCM linear */ 2272e445703SGeoffrey McRae static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames) 2282e445703SGeoffrey McRae { 2292e445703SGeoffrey McRae assert(buffer->data); 2302e445703SGeoffrey McRae int copy = frames; 2312e445703SGeoffrey McRae const int used = atomic_load_acquire(&buffer->used); 2322e445703SGeoffrey McRae int rptr = buffer->rptr; 2332e445703SGeoffrey McRae 2342e445703SGeoffrey McRae if (copy > used) { 2352e445703SGeoffrey McRae copy = used; 2362e445703SGeoffrey McRae } 2372e445703SGeoffrey McRae 2382e445703SGeoffrey McRae int right = buffer->frames - rptr; 2392e445703SGeoffrey McRae if (right > copy) { 2402e445703SGeoffrey McRae right = copy; 2412e445703SGeoffrey McRae } 2422e445703SGeoffrey McRae 2432e445703SGeoffrey McRae const int left = copy - right; 2442e445703SGeoffrey McRae for (int c = 0; c < buffer->channels; ++c) { 2452e445703SGeoffrey McRae memcpy(dest[c] , buffer->data[c] + rptr, right * sizeof(float)); 2462e445703SGeoffrey McRae memcpy(dest[c] + right, buffer->data[c] , left * sizeof(float)); 2472e445703SGeoffrey McRae } 2482e445703SGeoffrey McRae 2492e445703SGeoffrey McRae rptr += copy; 2502e445703SGeoffrey McRae if (rptr >= buffer->frames) { 2512e445703SGeoffrey McRae rptr -= buffer->frames; 2522e445703SGeoffrey McRae } 2532e445703SGeoffrey McRae buffer->rptr = rptr; 2542e445703SGeoffrey McRae 2552e445703SGeoffrey McRae atomic_sub(&buffer->used, copy); 2562e445703SGeoffrey McRae return copy; 2572e445703SGeoffrey McRae } 2582e445703SGeoffrey McRae 2592e445703SGeoffrey McRae static int qjack_process(jack_nframes_t nframes, void *arg) 2602e445703SGeoffrey McRae { 2612e445703SGeoffrey McRae QJackClient *c = (QJackClient *)arg; 2622e445703SGeoffrey McRae 2632e445703SGeoffrey McRae if (c->state != QJACK_STATE_RUNNING) { 2642e445703SGeoffrey McRae return 0; 2652e445703SGeoffrey McRae } 2662e445703SGeoffrey McRae 2672e445703SGeoffrey McRae /* get the buffers for the ports */ 2682e445703SGeoffrey McRae float *buffers[c->nchannels]; 2692e445703SGeoffrey McRae for (int i = 0; i < c->nchannels; ++i) { 2702e445703SGeoffrey McRae buffers[i] = jack_port_get_buffer(c->port[i], nframes); 2712e445703SGeoffrey McRae } 2722e445703SGeoffrey McRae 2732e445703SGeoffrey McRae if (c->out) { 274*81e0efb2SGeoffrey McRae if (likely(c->enabled)) { 2752e445703SGeoffrey McRae qjack_buffer_read_l(&c->fifo, buffers, nframes); 2762e445703SGeoffrey McRae } else { 277*81e0efb2SGeoffrey McRae for(int i = 0; i < c->nchannels; ++i) { 278*81e0efb2SGeoffrey McRae memset(buffers[i], 0, nframes * sizeof(float)); 279*81e0efb2SGeoffrey McRae } 280*81e0efb2SGeoffrey McRae } 281*81e0efb2SGeoffrey McRae } else { 282*81e0efb2SGeoffrey McRae if (likely(c->enabled)) { 2832e445703SGeoffrey McRae qjack_buffer_write_l(&c->fifo, buffers, nframes); 2842e445703SGeoffrey McRae } 285*81e0efb2SGeoffrey McRae } 2862e445703SGeoffrey McRae 2872e445703SGeoffrey McRae return 0; 2882e445703SGeoffrey McRae } 2892e445703SGeoffrey McRae 2902e445703SGeoffrey McRae static void qjack_port_registration(jack_port_id_t port, int reg, void *arg) 2912e445703SGeoffrey McRae { 2922e445703SGeoffrey McRae if (reg) { 2932e445703SGeoffrey McRae QJackClient *c = (QJackClient *)arg; 2942e445703SGeoffrey McRae c->connect_ports = true; 2952e445703SGeoffrey McRae } 2962e445703SGeoffrey McRae } 2972e445703SGeoffrey McRae 2982e445703SGeoffrey McRae static int qjack_xrun(void *arg) 2992e445703SGeoffrey McRae { 3002e445703SGeoffrey McRae QJackClient *c = (QJackClient *)arg; 3012e445703SGeoffrey McRae if (c->state != QJACK_STATE_RUNNING) { 3022e445703SGeoffrey McRae return 0; 3032e445703SGeoffrey McRae } 3042e445703SGeoffrey McRae 3052e445703SGeoffrey McRae qjack_buffer_clear(&c->fifo); 3062e445703SGeoffrey McRae return 0; 3072e445703SGeoffrey McRae } 3082e445703SGeoffrey McRae 3092e445703SGeoffrey McRae static void qjack_shutdown(void *arg) 3102e445703SGeoffrey McRae { 3112e445703SGeoffrey McRae QJackClient *c = (QJackClient *)arg; 3122e445703SGeoffrey McRae c->state = QJACK_STATE_SHUTDOWN; 3132e445703SGeoffrey McRae } 3142e445703SGeoffrey McRae 3152e445703SGeoffrey McRae static void qjack_client_recover(QJackClient *c) 3162e445703SGeoffrey McRae { 3172e445703SGeoffrey McRae if (c->state == QJACK_STATE_SHUTDOWN) { 3182e445703SGeoffrey McRae qjack_client_fini(c); 3192e445703SGeoffrey McRae } 3202e445703SGeoffrey McRae 3212e445703SGeoffrey McRae /* packets is used simply to throttle this */ 3222e445703SGeoffrey McRae if (c->state == QJACK_STATE_DISCONNECTED && 3232e445703SGeoffrey McRae c->packets % 100 == 0) { 3242e445703SGeoffrey McRae 325*81e0efb2SGeoffrey McRae /* if enabled then attempt to recover */ 326*81e0efb2SGeoffrey McRae if (c->enabled) { 3272e445703SGeoffrey McRae dolog("attempting to reconnect to server\n"); 3282e445703SGeoffrey McRae qjack_client_init(c); 3292e445703SGeoffrey McRae } 3302e445703SGeoffrey McRae } 3312e445703SGeoffrey McRae } 3322e445703SGeoffrey McRae 3332e445703SGeoffrey McRae static size_t qjack_write(HWVoiceOut *hw, void *buf, size_t len) 3342e445703SGeoffrey McRae { 3352e445703SGeoffrey McRae QJackOut *jo = (QJackOut *)hw; 3362e445703SGeoffrey McRae ++jo->c.packets; 3372e445703SGeoffrey McRae 3382e445703SGeoffrey McRae if (jo->c.state != QJACK_STATE_RUNNING) { 3392e445703SGeoffrey McRae qjack_client_recover(&jo->c); 3402e445703SGeoffrey McRae return len; 3412e445703SGeoffrey McRae } 3422e445703SGeoffrey McRae 3432e445703SGeoffrey McRae qjack_client_connect_ports(&jo->c); 3442e445703SGeoffrey McRae return qjack_buffer_write(&jo->c.fifo, buf, len); 3452e445703SGeoffrey McRae } 3462e445703SGeoffrey McRae 3472e445703SGeoffrey McRae static size_t qjack_read(HWVoiceIn *hw, void *buf, size_t len) 3482e445703SGeoffrey McRae { 3492e445703SGeoffrey McRae QJackIn *ji = (QJackIn *)hw; 3502e445703SGeoffrey McRae ++ji->c.packets; 3512e445703SGeoffrey McRae 3522e445703SGeoffrey McRae if (ji->c.state != QJACK_STATE_RUNNING) { 3532e445703SGeoffrey McRae qjack_client_recover(&ji->c); 3542e445703SGeoffrey McRae return len; 3552e445703SGeoffrey McRae } 3562e445703SGeoffrey McRae 3572e445703SGeoffrey McRae qjack_client_connect_ports(&ji->c); 3582e445703SGeoffrey McRae return qjack_buffer_read(&ji->c.fifo, buf, len); 3592e445703SGeoffrey McRae } 3602e445703SGeoffrey McRae 3612e445703SGeoffrey McRae static void qjack_client_connect_ports(QJackClient *c) 3622e445703SGeoffrey McRae { 3632e445703SGeoffrey McRae if (!c->connect_ports || !c->opt->connect_ports) { 3642e445703SGeoffrey McRae return; 3652e445703SGeoffrey McRae } 3662e445703SGeoffrey McRae 3672e445703SGeoffrey McRae c->connect_ports = false; 3682e445703SGeoffrey McRae const char **ports; 3692e445703SGeoffrey McRae ports = jack_get_ports(c->client, c->opt->connect_ports, NULL, 3702e445703SGeoffrey McRae c->out ? JackPortIsInput : JackPortIsOutput); 3712e445703SGeoffrey McRae 3722e445703SGeoffrey McRae if (!ports) { 3732e445703SGeoffrey McRae return; 3742e445703SGeoffrey McRae } 3752e445703SGeoffrey McRae 3762e445703SGeoffrey McRae for (int i = 0; i < c->nchannels && ports[i]; ++i) { 3772e445703SGeoffrey McRae const char *p = jack_port_name(c->port[i]); 3782e445703SGeoffrey McRae if (jack_port_connected_to(c->port[i], ports[i])) { 3792e445703SGeoffrey McRae continue; 3802e445703SGeoffrey McRae } 3812e445703SGeoffrey McRae 3822e445703SGeoffrey McRae if (c->out) { 3832e445703SGeoffrey McRae dolog("connect %s -> %s\n", p, ports[i]); 3842e445703SGeoffrey McRae jack_connect(c->client, p, ports[i]); 3852e445703SGeoffrey McRae } else { 3862e445703SGeoffrey McRae dolog("connect %s -> %s\n", ports[i], p); 3872e445703SGeoffrey McRae jack_connect(c->client, ports[i], p); 3882e445703SGeoffrey McRae } 3892e445703SGeoffrey McRae } 3902e445703SGeoffrey McRae } 3912e445703SGeoffrey McRae 3922e445703SGeoffrey McRae static int qjack_client_init(QJackClient *c) 3932e445703SGeoffrey McRae { 3942e445703SGeoffrey McRae jack_status_t status; 3952e445703SGeoffrey McRae char client_name[jack_client_name_size()]; 3962e445703SGeoffrey McRae jack_options_t options = JackNullOption; 3972e445703SGeoffrey McRae 3982e445703SGeoffrey McRae c->connect_ports = true; 3992e445703SGeoffrey McRae 4002e445703SGeoffrey McRae snprintf(client_name, sizeof(client_name), "%s-%s", 4012e445703SGeoffrey McRae c->out ? "out" : "in", 4022e445703SGeoffrey McRae c->opt->client_name ? c->opt->client_name : qemu_get_vm_name()); 4032e445703SGeoffrey McRae 4042e445703SGeoffrey McRae if (c->opt->exact_name) { 4052e445703SGeoffrey McRae options |= JackUseExactName; 4062e445703SGeoffrey McRae } 4072e445703SGeoffrey McRae 4082e445703SGeoffrey McRae if (!c->opt->start_server) { 4092e445703SGeoffrey McRae options |= JackNoStartServer; 4102e445703SGeoffrey McRae } 4112e445703SGeoffrey McRae 4122e445703SGeoffrey McRae if (c->opt->server_name) { 4132e445703SGeoffrey McRae options |= JackServerName; 4142e445703SGeoffrey McRae } 4152e445703SGeoffrey McRae 4162e445703SGeoffrey McRae c->client = jack_client_open(client_name, options, &status, 4172e445703SGeoffrey McRae c->opt->server_name); 4182e445703SGeoffrey McRae 4192e445703SGeoffrey McRae if (c->client == NULL) { 4202e445703SGeoffrey McRae dolog("jack_client_open failed: status = 0x%2.0x\n", status); 4212e445703SGeoffrey McRae if (status & JackServerFailed) { 4222e445703SGeoffrey McRae dolog("unable to connect to JACK server\n"); 4232e445703SGeoffrey McRae } 4242e445703SGeoffrey McRae return -1; 4252e445703SGeoffrey McRae } 4262e445703SGeoffrey McRae 4272e445703SGeoffrey McRae c->freq = jack_get_sample_rate(c->client); 4282e445703SGeoffrey McRae 4292e445703SGeoffrey McRae if (status & JackServerStarted) { 4302e445703SGeoffrey McRae dolog("JACK server started\n"); 4312e445703SGeoffrey McRae } 4322e445703SGeoffrey McRae 4332e445703SGeoffrey McRae if (status & JackNameNotUnique) { 4342e445703SGeoffrey McRae dolog("JACK unique name assigned %s\n", 4352e445703SGeoffrey McRae jack_get_client_name(c->client)); 4362e445703SGeoffrey McRae } 4372e445703SGeoffrey McRae 4382e445703SGeoffrey McRae jack_set_process_callback(c->client, qjack_process , c); 4392e445703SGeoffrey McRae jack_set_port_registration_callback(c->client, qjack_port_registration, c); 4402e445703SGeoffrey McRae jack_set_xrun_callback(c->client, qjack_xrun, c); 4412e445703SGeoffrey McRae jack_on_shutdown(c->client, qjack_shutdown, c); 4422e445703SGeoffrey McRae 4432e445703SGeoffrey McRae /* allocate and register the ports */ 4442e445703SGeoffrey McRae c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels); 4452e445703SGeoffrey McRae for (int i = 0; i < c->nchannels; ++i) { 4462e445703SGeoffrey McRae 4472e445703SGeoffrey McRae char port_name[16]; 4482e445703SGeoffrey McRae snprintf( 4492e445703SGeoffrey McRae port_name, 4502e445703SGeoffrey McRae sizeof(port_name), 4512e445703SGeoffrey McRae c->out ? "output %d" : "input %d", 4522e445703SGeoffrey McRae i); 4532e445703SGeoffrey McRae 4542e445703SGeoffrey McRae c->port[i] = jack_port_register( 4552e445703SGeoffrey McRae c->client, 4562e445703SGeoffrey McRae port_name, 4572e445703SGeoffrey McRae JACK_DEFAULT_AUDIO_TYPE, 4582e445703SGeoffrey McRae c->out ? JackPortIsOutput : JackPortIsInput, 4592e445703SGeoffrey McRae 0); 4602e445703SGeoffrey McRae } 4612e445703SGeoffrey McRae 4622e445703SGeoffrey McRae /* activate the session */ 4632e445703SGeoffrey McRae jack_activate(c->client); 4642e445703SGeoffrey McRae c->buffersize = jack_get_buffer_size(c->client); 4652e445703SGeoffrey McRae 46636963ed1SGeoffrey McRae /* 46736963ed1SGeoffrey McRae * ensure the buffersize is no smaller then 512 samples, some (all?) qemu 46836963ed1SGeoffrey McRae * virtual devices do not work correctly otherwise 46936963ed1SGeoffrey McRae */ 47036963ed1SGeoffrey McRae if (c->buffersize < 512) { 47136963ed1SGeoffrey McRae c->buffersize = 512; 47236963ed1SGeoffrey McRae } 47336963ed1SGeoffrey McRae 47436963ed1SGeoffrey McRae /* create a 2 period buffer */ 47536963ed1SGeoffrey McRae qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); 47636963ed1SGeoffrey McRae 4772e445703SGeoffrey McRae qjack_client_connect_ports(c); 4782e445703SGeoffrey McRae c->state = QJACK_STATE_RUNNING; 4792e445703SGeoffrey McRae return 0; 4802e445703SGeoffrey McRae } 4812e445703SGeoffrey McRae 4822e445703SGeoffrey McRae static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, 4832e445703SGeoffrey McRae void *drv_opaque) 4842e445703SGeoffrey McRae { 4852e445703SGeoffrey McRae QJackOut *jo = (QJackOut *)hw; 4862e445703SGeoffrey McRae Audiodev *dev = (Audiodev *)drv_opaque; 4872e445703SGeoffrey McRae 4882e445703SGeoffrey McRae if (jo->c.state != QJACK_STATE_DISCONNECTED) { 4892e445703SGeoffrey McRae return 0; 4902e445703SGeoffrey McRae } 4912e445703SGeoffrey McRae 4922e445703SGeoffrey McRae jo->c.out = true; 493*81e0efb2SGeoffrey McRae jo->c.enabled = false; 4942e445703SGeoffrey McRae jo->c.nchannels = as->nchannels; 4952e445703SGeoffrey McRae jo->c.opt = dev->u.jack.out; 496*81e0efb2SGeoffrey McRae 4972e445703SGeoffrey McRae int ret = qjack_client_init(&jo->c); 4982e445703SGeoffrey McRae if (ret != 0) { 4992e445703SGeoffrey McRae return ret; 5002e445703SGeoffrey McRae } 5012e445703SGeoffrey McRae 5022e445703SGeoffrey McRae /* report the buffer size to qemu */ 5032e445703SGeoffrey McRae hw->samples = jo->c.buffersize; 5042e445703SGeoffrey McRae 5052e445703SGeoffrey McRae /* report the audio format we support */ 5062e445703SGeoffrey McRae struct audsettings os = { 5072e445703SGeoffrey McRae .freq = jo->c.freq, 5082e445703SGeoffrey McRae .nchannels = jo->c.nchannels, 5092e445703SGeoffrey McRae .fmt = AUDIO_FORMAT_F32, 5102e445703SGeoffrey McRae .endianness = 0 5112e445703SGeoffrey McRae }; 5122e445703SGeoffrey McRae audio_pcm_init_info(&hw->info, &os); 5132e445703SGeoffrey McRae 5142e445703SGeoffrey McRae dolog("JACK output configured for %dHz (%d samples)\n", 5152e445703SGeoffrey McRae jo->c.freq, jo->c.buffersize); 5162e445703SGeoffrey McRae 5172e445703SGeoffrey McRae return 0; 5182e445703SGeoffrey McRae } 5192e445703SGeoffrey McRae 5202e445703SGeoffrey McRae static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, 5212e445703SGeoffrey McRae void *drv_opaque) 5222e445703SGeoffrey McRae { 5232e445703SGeoffrey McRae QJackIn *ji = (QJackIn *)hw; 5242e445703SGeoffrey McRae Audiodev *dev = (Audiodev *)drv_opaque; 5252e445703SGeoffrey McRae 5262e445703SGeoffrey McRae if (ji->c.state != QJACK_STATE_DISCONNECTED) { 5272e445703SGeoffrey McRae return 0; 5282e445703SGeoffrey McRae } 5292e445703SGeoffrey McRae 5302e445703SGeoffrey McRae ji->c.out = false; 531*81e0efb2SGeoffrey McRae ji->c.enabled = false; 5322e445703SGeoffrey McRae ji->c.nchannels = as->nchannels; 5332e445703SGeoffrey McRae ji->c.opt = dev->u.jack.in; 534*81e0efb2SGeoffrey McRae 5352e445703SGeoffrey McRae int ret = qjack_client_init(&ji->c); 5362e445703SGeoffrey McRae if (ret != 0) { 5372e445703SGeoffrey McRae return ret; 5382e445703SGeoffrey McRae } 5392e445703SGeoffrey McRae 5402e445703SGeoffrey McRae /* report the buffer size to qemu */ 5412e445703SGeoffrey McRae hw->samples = ji->c.buffersize; 5422e445703SGeoffrey McRae 5432e445703SGeoffrey McRae /* report the audio format we support */ 5442e445703SGeoffrey McRae struct audsettings is = { 5452e445703SGeoffrey McRae .freq = ji->c.freq, 5462e445703SGeoffrey McRae .nchannels = ji->c.nchannels, 5472e445703SGeoffrey McRae .fmt = AUDIO_FORMAT_F32, 5482e445703SGeoffrey McRae .endianness = 0 5492e445703SGeoffrey McRae }; 5502e445703SGeoffrey McRae audio_pcm_init_info(&hw->info, &is); 5512e445703SGeoffrey McRae 5522e445703SGeoffrey McRae dolog("JACK input configured for %dHz (%d samples)\n", 5532e445703SGeoffrey McRae ji->c.freq, ji->c.buffersize); 5542e445703SGeoffrey McRae 5552e445703SGeoffrey McRae return 0; 5562e445703SGeoffrey McRae } 5572e445703SGeoffrey McRae 5582e445703SGeoffrey McRae static void qjack_client_fini(QJackClient *c) 5592e445703SGeoffrey McRae { 5602e445703SGeoffrey McRae switch (c->state) { 5612e445703SGeoffrey McRae case QJACK_STATE_RUNNING: 5622e445703SGeoffrey McRae jack_deactivate(c->client); 5632e445703SGeoffrey McRae /* fallthrough */ 5642e445703SGeoffrey McRae 5652e445703SGeoffrey McRae case QJACK_STATE_SHUTDOWN: 5662e445703SGeoffrey McRae jack_client_close(c->client); 5672e445703SGeoffrey McRae /* fallthrough */ 5682e445703SGeoffrey McRae 5692e445703SGeoffrey McRae case QJACK_STATE_DISCONNECTED: 5702e445703SGeoffrey McRae break; 5712e445703SGeoffrey McRae } 5722e445703SGeoffrey McRae 5732e445703SGeoffrey McRae qjack_buffer_free(&c->fifo); 5742e445703SGeoffrey McRae g_free(c->port); 5752e445703SGeoffrey McRae 5762e445703SGeoffrey McRae c->state = QJACK_STATE_DISCONNECTED; 5772e445703SGeoffrey McRae } 5782e445703SGeoffrey McRae 5792e445703SGeoffrey McRae static void qjack_fini_out(HWVoiceOut *hw) 5802e445703SGeoffrey McRae { 5812e445703SGeoffrey McRae QJackOut *jo = (QJackOut *)hw; 5822e445703SGeoffrey McRae qjack_client_fini(&jo->c); 5832e445703SGeoffrey McRae } 5842e445703SGeoffrey McRae 5852e445703SGeoffrey McRae static void qjack_fini_in(HWVoiceIn *hw) 5862e445703SGeoffrey McRae { 5872e445703SGeoffrey McRae QJackIn *ji = (QJackIn *)hw; 5882e445703SGeoffrey McRae qjack_client_fini(&ji->c); 5892e445703SGeoffrey McRae } 5902e445703SGeoffrey McRae 5912e445703SGeoffrey McRae static void qjack_enable_out(HWVoiceOut *hw, bool enable) 5922e445703SGeoffrey McRae { 593*81e0efb2SGeoffrey McRae QJackOut *jo = (QJackOut *)hw; 594*81e0efb2SGeoffrey McRae jo->c.enabled = enable; 5952e445703SGeoffrey McRae } 5962e445703SGeoffrey McRae 5972e445703SGeoffrey McRae static void qjack_enable_in(HWVoiceIn *hw, bool enable) 5982e445703SGeoffrey McRae { 599*81e0efb2SGeoffrey McRae QJackIn *ji = (QJackIn *)hw; 600*81e0efb2SGeoffrey McRae ji->c.enabled = enable; 6012e445703SGeoffrey McRae } 6022e445703SGeoffrey McRae 6032e445703SGeoffrey McRae static int qjack_thread_creator(jack_native_thread_t *thread, 6042e445703SGeoffrey McRae const pthread_attr_t *attr, void *(*function)(void *), void *arg) 6052e445703SGeoffrey McRae { 6062e445703SGeoffrey McRae int ret = pthread_create(thread, attr, function, arg); 6072e445703SGeoffrey McRae if (ret != 0) { 6082e445703SGeoffrey McRae return ret; 6092e445703SGeoffrey McRae } 6102e445703SGeoffrey McRae 6112e445703SGeoffrey McRae /* set the name of the thread */ 6122e445703SGeoffrey McRae pthread_setname_np(*thread, "jack-client"); 6132e445703SGeoffrey McRae 6142e445703SGeoffrey McRae return ret; 6152e445703SGeoffrey McRae } 6162e445703SGeoffrey McRae 6172e445703SGeoffrey McRae static void *qjack_init(Audiodev *dev) 6182e445703SGeoffrey McRae { 6192e445703SGeoffrey McRae assert(dev->driver == AUDIODEV_DRIVER_JACK); 6202e445703SGeoffrey McRae return dev; 6212e445703SGeoffrey McRae } 6222e445703SGeoffrey McRae 6232e445703SGeoffrey McRae static void qjack_fini(void *opaque) 6242e445703SGeoffrey McRae { 6252e445703SGeoffrey McRae } 6262e445703SGeoffrey McRae 6272e445703SGeoffrey McRae static struct audio_pcm_ops jack_pcm_ops = { 6282e445703SGeoffrey McRae .init_out = qjack_init_out, 6292e445703SGeoffrey McRae .fini_out = qjack_fini_out, 6302e445703SGeoffrey McRae .write = qjack_write, 6312e445703SGeoffrey McRae .run_buffer_out = audio_generic_run_buffer_out, 6322e445703SGeoffrey McRae .enable_out = qjack_enable_out, 6332e445703SGeoffrey McRae 6342e445703SGeoffrey McRae .init_in = qjack_init_in, 6352e445703SGeoffrey McRae .fini_in = qjack_fini_in, 6362e445703SGeoffrey McRae .read = qjack_read, 6372e445703SGeoffrey McRae .enable_in = qjack_enable_in 6382e445703SGeoffrey McRae }; 6392e445703SGeoffrey McRae 6402e445703SGeoffrey McRae static struct audio_driver jack_driver = { 6412e445703SGeoffrey McRae .name = "jack", 6422e445703SGeoffrey McRae .descr = "JACK Audio Connection Kit Client", 6432e445703SGeoffrey McRae .init = qjack_init, 6442e445703SGeoffrey McRae .fini = qjack_fini, 6452e445703SGeoffrey McRae .pcm_ops = &jack_pcm_ops, 6462e445703SGeoffrey McRae .can_be_default = 1, 6472e445703SGeoffrey McRae .max_voices_out = INT_MAX, 6482e445703SGeoffrey McRae .max_voices_in = INT_MAX, 6492e445703SGeoffrey McRae .voice_size_out = sizeof(QJackOut), 6502e445703SGeoffrey McRae .voice_size_in = sizeof(QJackIn) 6512e445703SGeoffrey McRae }; 6522e445703SGeoffrey McRae 6532e445703SGeoffrey McRae static void qjack_error(const char *msg) 6542e445703SGeoffrey McRae { 6552e445703SGeoffrey McRae dolog("E: %s\n", msg); 6562e445703SGeoffrey McRae } 6572e445703SGeoffrey McRae 6582e445703SGeoffrey McRae static void qjack_info(const char *msg) 6592e445703SGeoffrey McRae { 6602e445703SGeoffrey McRae dolog("I: %s\n", msg); 6612e445703SGeoffrey McRae } 6622e445703SGeoffrey McRae 6632e445703SGeoffrey McRae static void register_audio_jack(void) 6642e445703SGeoffrey McRae { 6652e445703SGeoffrey McRae audio_driver_register(&jack_driver); 6662e445703SGeoffrey McRae jack_set_thread_creator(qjack_thread_creator); 6672e445703SGeoffrey McRae jack_set_error_function(qjack_error); 6682e445703SGeoffrey McRae jack_set_info_function(qjack_info); 6692e445703SGeoffrey McRae } 6702e445703SGeoffrey McRae type_init(register_audio_jack); 671