qemu/audio/jackaudio.c
<<
>>
Prefs
   1/*
   2 * QEMU JACK Audio Connection Kit Client
   3 *
   4 * Copyright (c) 2020 Geoffrey McRae (gnif)
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qemu/module.h"
  27#include "qemu/atomic.h"
  28#include "qemu/main-loop.h"
  29#include "qemu-common.h"
  30#include "audio.h"
  31
  32#define AUDIO_CAP "jack"
  33#include "audio_int.h"
  34
  35#include <jack/jack.h>
  36#include <jack/thread.h>
  37
  38struct QJack;
  39
  40typedef enum QJackState {
  41    QJACK_STATE_DISCONNECTED,
  42    QJACK_STATE_RUNNING,
  43    QJACK_STATE_SHUTDOWN
  44}
  45QJackState;
  46
  47typedef struct QJackBuffer {
  48    int          channels;
  49    int          frames;
  50    uint32_t     used;
  51    int          rptr, wptr;
  52    float      **data;
  53}
  54QJackBuffer;
  55
  56typedef struct QJackClient {
  57    AudiodevJackPerDirectionOptions *opt;
  58
  59    bool out;
  60    bool enabled;
  61    bool connect_ports;
  62    int  packets;
  63
  64    QJackState      state;
  65    jack_client_t  *client;
  66    jack_nframes_t  freq;
  67    QEMUBH         *shutdown_bh;
  68
  69    struct QJack   *j;
  70    int             nchannels;
  71    int             buffersize;
  72    jack_port_t   **port;
  73    QJackBuffer     fifo;
  74}
  75QJackClient;
  76
  77typedef struct QJackOut {
  78    HWVoiceOut  hw;
  79    QJackClient c;
  80}
  81QJackOut;
  82
  83typedef struct QJackIn {
  84    HWVoiceIn   hw;
  85    QJackClient c;
  86}
  87QJackIn;
  88
  89static int qjack_client_init(QJackClient *c);
  90static void qjack_client_connect_ports(QJackClient *c);
  91static void qjack_client_fini(QJackClient *c);
  92static QemuMutex qjack_shutdown_lock;
  93
  94static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
  95{
  96    buffer->channels = channels;
  97    buffer->frames   = frames;
  98    buffer->used     = 0;
  99    buffer->rptr     = 0;
 100    buffer->wptr     = 0;
 101    buffer->data     = g_malloc(channels * sizeof(float *));
 102    for (int i = 0; i < channels; ++i) {
 103        buffer->data[i] = g_malloc(frames * sizeof(float));
 104    }
 105}
 106
 107static void qjack_buffer_clear(QJackBuffer *buffer)
 108{
 109    assert(buffer->data);
 110    qatomic_store_release(&buffer->used, 0);
 111    buffer->rptr = 0;
 112    buffer->wptr = 0;
 113}
 114
 115static void qjack_buffer_free(QJackBuffer *buffer)
 116{
 117    if (!buffer->data) {
 118        return;
 119    }
 120
 121    for (int i = 0; i < buffer->channels; ++i) {
 122        g_free(buffer->data[i]);
 123    }
 124
 125    g_free(buffer->data);
 126    buffer->data = NULL;
 127}
 128
 129/* write PCM interleaved */
 130static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
 131{
 132    assert(buffer->data);
 133    const int samples = size / sizeof(float);
 134    int frames        = samples / buffer->channels;
 135    const int avail   = buffer->frames - qatomic_load_acquire(&buffer->used);
 136
 137    if (frames > avail) {
 138        frames = avail;
 139    }
 140
 141    int copy = frames;
 142    int wptr = buffer->wptr;
 143
 144    while (copy) {
 145
 146        for (int c = 0; c < buffer->channels; ++c) {
 147            buffer->data[c][wptr] = *data++;
 148        }
 149
 150        if (++wptr == buffer->frames) {
 151            wptr = 0;
 152        }
 153
 154        --copy;
 155    }
 156
 157    buffer->wptr = wptr;
 158
 159    qatomic_add(&buffer->used, frames);
 160    return frames * buffer->channels * sizeof(float);
 161};
 162
 163/* write PCM linear */
 164static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
 165{
 166    assert(buffer->data);
 167    const int avail   = buffer->frames - qatomic_load_acquire(&buffer->used);
 168    int wptr = buffer->wptr;
 169
 170    if (frames > avail) {
 171        frames = avail;
 172    }
 173
 174    int right = buffer->frames - wptr;
 175    if (right > frames) {
 176        right = frames;
 177    }
 178
 179    const int left = frames - right;
 180    for (int c = 0; c < buffer->channels; ++c) {
 181        memcpy(buffer->data[c] + wptr, dest[c]        , right * sizeof(float));
 182        memcpy(buffer->data[c]       , dest[c] + right, left  * sizeof(float));
 183    }
 184
 185    wptr += frames;
 186    if (wptr >= buffer->frames) {
 187        wptr -= buffer->frames;
 188    }
 189    buffer->wptr = wptr;
 190
 191    qatomic_add(&buffer->used, frames);
 192    return frames;
 193}
 194
 195/* read PCM interleaved */
 196static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size)
 197{
 198    assert(buffer->data);
 199    const int samples = size / sizeof(float);
 200    int frames        = samples / buffer->channels;
 201    const int avail   = qatomic_load_acquire(&buffer->used);
 202
 203    if (frames > avail) {
 204        frames = avail;
 205    }
 206
 207    int copy = frames;
 208    int rptr = buffer->rptr;
 209
 210    while (copy) {
 211
 212        for (int c = 0; c < buffer->channels; ++c) {
 213            *dest++ = buffer->data[c][rptr];
 214        }
 215
 216        if (++rptr == buffer->frames) {
 217            rptr = 0;
 218        }
 219
 220        --copy;
 221    }
 222
 223    buffer->rptr = rptr;
 224
 225    qatomic_sub(&buffer->used, frames);
 226    return frames * buffer->channels * sizeof(float);
 227}
 228
 229/* read PCM linear */
 230static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames)
 231{
 232    assert(buffer->data);
 233    int copy       = frames;
 234    const int used = qatomic_load_acquire(&buffer->used);
 235    int rptr       = buffer->rptr;
 236
 237    if (copy > used) {
 238        copy = used;
 239    }
 240
 241    int right = buffer->frames - rptr;
 242    if (right > copy) {
 243        right = copy;
 244    }
 245
 246    const int left = copy - right;
 247    for (int c = 0; c < buffer->channels; ++c) {
 248        memcpy(dest[c]        , buffer->data[c] + rptr, right * sizeof(float));
 249        memcpy(dest[c] + right, buffer->data[c]       , left  * sizeof(float));
 250    }
 251
 252    rptr += copy;
 253    if (rptr >= buffer->frames) {
 254        rptr -= buffer->frames;
 255    }
 256    buffer->rptr = rptr;
 257
 258    qatomic_sub(&buffer->used, copy);
 259    return copy;
 260}
 261
 262static int qjack_process(jack_nframes_t nframes, void *arg)
 263{
 264    QJackClient *c = (QJackClient *)arg;
 265
 266    if (c->state != QJACK_STATE_RUNNING) {
 267        return 0;
 268    }
 269
 270    /* get the buffers for the ports */
 271    float *buffers[c->nchannels];
 272    for (int i = 0; i < c->nchannels; ++i) {
 273        buffers[i] = jack_port_get_buffer(c->port[i], nframes);
 274    }
 275
 276    if (c->out) {
 277        if (likely(c->enabled)) {
 278            qjack_buffer_read_l(&c->fifo, buffers, nframes);
 279        } else {
 280            for (int i = 0; i < c->nchannels; ++i) {
 281                memset(buffers[i], 0, nframes * sizeof(float));
 282            }
 283        }
 284    } else {
 285        if (likely(c->enabled)) {
 286            qjack_buffer_write_l(&c->fifo, buffers, nframes);
 287        }
 288    }
 289
 290    return 0;
 291}
 292
 293static void qjack_port_registration(jack_port_id_t port, int reg, void *arg)
 294{
 295    if (reg) {
 296        QJackClient *c = (QJackClient *)arg;
 297        c->connect_ports = true;
 298    }
 299}
 300
 301static int qjack_xrun(void *arg)
 302{
 303    QJackClient *c = (QJackClient *)arg;
 304    if (c->state != QJACK_STATE_RUNNING) {
 305        return 0;
 306    }
 307
 308    qjack_buffer_clear(&c->fifo);
 309    return 0;
 310}
 311
 312static void qjack_shutdown_bh(void *opaque)
 313{
 314    QJackClient *c = (QJackClient *)opaque;
 315    qjack_client_fini(c);
 316}
 317
 318static void qjack_shutdown(void *arg)
 319{
 320    QJackClient *c = (QJackClient *)arg;
 321    c->state = QJACK_STATE_SHUTDOWN;
 322    qemu_bh_schedule(c->shutdown_bh);
 323}
 324
 325static void qjack_client_recover(QJackClient *c)
 326{
 327    if (c->state != QJACK_STATE_DISCONNECTED) {
 328        return;
 329    }
 330
 331    /* packets is used simply to throttle this */
 332    if (c->packets % 100 == 0) {
 333
 334        /* if enabled then attempt to recover */
 335        if (c->enabled) {
 336            dolog("attempting to reconnect to server\n");
 337            qjack_client_init(c);
 338        }
 339    }
 340}
 341
 342static size_t qjack_write(HWVoiceOut *hw, void *buf, size_t len)
 343{
 344    QJackOut *jo = (QJackOut *)hw;
 345    ++jo->c.packets;
 346
 347    if (jo->c.state != QJACK_STATE_RUNNING) {
 348        qjack_client_recover(&jo->c);
 349        return len;
 350    }
 351
 352    qjack_client_connect_ports(&jo->c);
 353    return qjack_buffer_write(&jo->c.fifo, buf, len);
 354}
 355
 356static size_t qjack_read(HWVoiceIn *hw, void *buf, size_t len)
 357{
 358    QJackIn *ji = (QJackIn *)hw;
 359    ++ji->c.packets;
 360
 361    if (ji->c.state != QJACK_STATE_RUNNING) {
 362        qjack_client_recover(&ji->c);
 363        return len;
 364    }
 365
 366    qjack_client_connect_ports(&ji->c);
 367    return qjack_buffer_read(&ji->c.fifo, buf, len);
 368}
 369
 370static void qjack_client_connect_ports(QJackClient *c)
 371{
 372    if (!c->connect_ports || !c->opt->connect_ports) {
 373        return;
 374    }
 375
 376    c->connect_ports = false;
 377    const char **ports;
 378    ports = jack_get_ports(c->client, c->opt->connect_ports, NULL,
 379        c->out ? JackPortIsInput : JackPortIsOutput);
 380
 381    if (!ports) {
 382        return;
 383    }
 384
 385    for (int i = 0; i < c->nchannels && ports[i]; ++i) {
 386        const char *p = jack_port_name(c->port[i]);
 387        if (jack_port_connected_to(c->port[i], ports[i])) {
 388            continue;
 389        }
 390
 391        if (c->out) {
 392            dolog("connect %s -> %s\n", p, ports[i]);
 393            jack_connect(c->client, p, ports[i]);
 394        } else {
 395            dolog("connect %s -> %s\n", ports[i], p);
 396            jack_connect(c->client, ports[i], p);
 397        }
 398    }
 399}
 400
 401static int qjack_client_init(QJackClient *c)
 402{
 403    jack_status_t status;
 404    char client_name[jack_client_name_size()];
 405    jack_options_t options = JackNullOption;
 406
 407    if (c->state == QJACK_STATE_RUNNING) {
 408        return 0;
 409    }
 410
 411    c->connect_ports = true;
 412
 413    snprintf(client_name, sizeof(client_name), "%s-%s",
 414        c->out ? "out" : "in",
 415        c->opt->client_name ? c->opt->client_name : qemu_get_vm_name());
 416
 417    if (c->opt->exact_name) {
 418        options |= JackUseExactName;
 419    }
 420
 421    if (!c->opt->start_server) {
 422        options |= JackNoStartServer;
 423    }
 424
 425    if (c->opt->server_name) {
 426        options |= JackServerName;
 427    }
 428
 429    c->client = jack_client_open(client_name, options, &status,
 430      c->opt->server_name);
 431
 432    if (c->client == NULL) {
 433        dolog("jack_client_open failed: status = 0x%2.0x\n", status);
 434        if (status & JackServerFailed) {
 435            dolog("unable to connect to JACK server\n");
 436        }
 437        return -1;
 438    }
 439
 440    c->freq = jack_get_sample_rate(c->client);
 441
 442    if (status & JackServerStarted) {
 443        dolog("JACK server started\n");
 444    }
 445
 446    if (status & JackNameNotUnique) {
 447        dolog("JACK unique name assigned %s\n",
 448          jack_get_client_name(c->client));
 449    }
 450
 451    jack_set_process_callback(c->client, qjack_process , c);
 452    jack_set_port_registration_callback(c->client, qjack_port_registration, c);
 453    jack_set_xrun_callback(c->client, qjack_xrun, c);
 454    jack_on_shutdown(c->client, qjack_shutdown, c);
 455
 456    /* allocate and register the ports */
 457    c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels);
 458    for (int i = 0; i < c->nchannels; ++i) {
 459
 460        char port_name[16];
 461        snprintf(
 462            port_name,
 463            sizeof(port_name),
 464            c->out ? "output %d" : "input %d",
 465            i);
 466
 467        c->port[i] = jack_port_register(
 468            c->client,
 469            port_name,
 470            JACK_DEFAULT_AUDIO_TYPE,
 471            c->out ? JackPortIsOutput : JackPortIsInput,
 472            0);
 473    }
 474
 475    /* activate the session */
 476    jack_activate(c->client);
 477    c->buffersize = jack_get_buffer_size(c->client);
 478
 479    /*
 480     * ensure the buffersize is no smaller then 512 samples, some (all?) qemu
 481     * virtual devices do not work correctly otherwise
 482     */
 483    if (c->buffersize < 512) {
 484        c->buffersize = 512;
 485    }
 486
 487    /* create a 2 period buffer */
 488    qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2);
 489
 490    qjack_client_connect_ports(c);
 491    c->state = QJACK_STATE_RUNNING;
 492    return 0;
 493}
 494
 495static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as,
 496    void *drv_opaque)
 497{
 498    QJackOut *jo  = (QJackOut *)hw;
 499    Audiodev *dev = (Audiodev *)drv_opaque;
 500
 501    jo->c.out       = true;
 502    jo->c.enabled   = false;
 503    jo->c.nchannels = as->nchannels;
 504    jo->c.opt       = dev->u.jack.out;
 505
 506    jo->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &jo->c);
 507
 508    int ret = qjack_client_init(&jo->c);
 509    if (ret != 0) {
 510        qemu_bh_delete(jo->c.shutdown_bh);
 511        return ret;
 512    }
 513
 514    /* report the buffer size to qemu */
 515    hw->samples = jo->c.buffersize;
 516
 517    /* report the audio format we support */
 518    struct audsettings os = {
 519        .freq       = jo->c.freq,
 520        .nchannels  = jo->c.nchannels,
 521        .fmt        = AUDIO_FORMAT_F32,
 522        .endianness = 0
 523    };
 524    audio_pcm_init_info(&hw->info, &os);
 525
 526    dolog("JACK output configured for %dHz (%d samples)\n",
 527        jo->c.freq, jo->c.buffersize);
 528
 529    return 0;
 530}
 531
 532static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as,
 533    void *drv_opaque)
 534{
 535    QJackIn  *ji  = (QJackIn *)hw;
 536    Audiodev *dev = (Audiodev *)drv_opaque;
 537
 538    ji->c.out       = false;
 539    ji->c.enabled   = false;
 540    ji->c.nchannels = as->nchannels;
 541    ji->c.opt       = dev->u.jack.in;
 542
 543    ji->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &ji->c);
 544
 545    int ret = qjack_client_init(&ji->c);
 546    if (ret != 0) {
 547        qemu_bh_delete(ji->c.shutdown_bh);
 548        return ret;
 549    }
 550
 551    /* report the buffer size to qemu */
 552    hw->samples = ji->c.buffersize;
 553
 554    /* report the audio format we support */
 555    struct audsettings is = {
 556        .freq       = ji->c.freq,
 557        .nchannels  = ji->c.nchannels,
 558        .fmt        = AUDIO_FORMAT_F32,
 559        .endianness = 0
 560    };
 561    audio_pcm_init_info(&hw->info, &is);
 562
 563    dolog("JACK input configured for %dHz (%d samples)\n",
 564        ji->c.freq, ji->c.buffersize);
 565
 566    return 0;
 567}
 568
 569static void qjack_client_fini_locked(QJackClient *c)
 570{
 571    switch (c->state) {
 572    case QJACK_STATE_RUNNING:
 573        jack_deactivate(c->client);
 574        /* fallthrough */
 575
 576    case QJACK_STATE_SHUTDOWN:
 577        jack_client_close(c->client);
 578        c->client = NULL;
 579
 580        qjack_buffer_free(&c->fifo);
 581        g_free(c->port);
 582
 583        c->state = QJACK_STATE_DISCONNECTED;
 584        /* fallthrough */
 585
 586    case QJACK_STATE_DISCONNECTED:
 587        break;
 588    }
 589}
 590
 591static void qjack_client_fini(QJackClient *c)
 592{
 593    qemu_mutex_lock(&qjack_shutdown_lock);
 594    qjack_client_fini_locked(c);
 595    qemu_mutex_unlock(&qjack_shutdown_lock);
 596}
 597
 598static void qjack_fini_out(HWVoiceOut *hw)
 599{
 600    QJackOut *jo = (QJackOut *)hw;
 601    qjack_client_fini(&jo->c);
 602
 603    qemu_bh_delete(jo->c.shutdown_bh);
 604}
 605
 606static void qjack_fini_in(HWVoiceIn *hw)
 607{
 608    QJackIn *ji = (QJackIn *)hw;
 609    qjack_client_fini(&ji->c);
 610
 611    qemu_bh_delete(ji->c.shutdown_bh);
 612}
 613
 614static void qjack_enable_out(HWVoiceOut *hw, bool enable)
 615{
 616    QJackOut *jo = (QJackOut *)hw;
 617    jo->c.enabled = enable;
 618}
 619
 620static void qjack_enable_in(HWVoiceIn *hw, bool enable)
 621{
 622    QJackIn *ji = (QJackIn *)hw;
 623    ji->c.enabled = enable;
 624}
 625
 626static int qjack_thread_creator(jack_native_thread_t *thread,
 627    const pthread_attr_t *attr, void *(*function)(void *), void *arg)
 628{
 629    int ret = pthread_create(thread, attr, function, arg);
 630    if (ret != 0) {
 631        return ret;
 632    }
 633
 634    /* set the name of the thread */
 635    pthread_setname_np(*thread, "jack-client");
 636
 637    return ret;
 638}
 639
 640static void *qjack_init(Audiodev *dev)
 641{
 642    assert(dev->driver == AUDIODEV_DRIVER_JACK);
 643    return dev;
 644}
 645
 646static void qjack_fini(void *opaque)
 647{
 648}
 649
 650static struct audio_pcm_ops jack_pcm_ops = {
 651    .init_out       = qjack_init_out,
 652    .fini_out       = qjack_fini_out,
 653    .write          = qjack_write,
 654    .run_buffer_out = audio_generic_run_buffer_out,
 655    .enable_out     = qjack_enable_out,
 656
 657    .init_in        = qjack_init_in,
 658    .fini_in        = qjack_fini_in,
 659    .read           = qjack_read,
 660    .run_buffer_in  = audio_generic_run_buffer_in,
 661    .enable_in      = qjack_enable_in
 662};
 663
 664static struct audio_driver jack_driver = {
 665    .name           = "jack",
 666    .descr          = "JACK Audio Connection Kit Client",
 667    .init           = qjack_init,
 668    .fini           = qjack_fini,
 669    .pcm_ops        = &jack_pcm_ops,
 670    .can_be_default = 1,
 671    .max_voices_out = INT_MAX,
 672    .max_voices_in  = INT_MAX,
 673    .voice_size_out = sizeof(QJackOut),
 674    .voice_size_in  = sizeof(QJackIn)
 675};
 676
 677static void qjack_error(const char *msg)
 678{
 679    dolog("E: %s\n", msg);
 680}
 681
 682static void qjack_info(const char *msg)
 683{
 684    dolog("I: %s\n", msg);
 685}
 686
 687static void register_audio_jack(void)
 688{
 689    qemu_mutex_init(&qjack_shutdown_lock);
 690    audio_driver_register(&jack_driver);
 691    jack_set_thread_creator(qjack_thread_creator);
 692    jack_set_error_function(qjack_error);
 693    jack_set_info_function(qjack_info);
 694}
 695type_init(register_audio_jack);
 696