#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/atomic.h"
+#include "qemu/main-loop.h"
#include "qemu-common.h"
#include "audio.h"
QJackState state;
jack_client_t *client;
jack_nframes_t freq;
+ QEMUBH *shutdown_bh;
struct QJack *j;
int nchannels;
static int qjack_client_init(QJackClient *c);
static void qjack_client_connect_ports(QJackClient *c);
static void qjack_client_fini(QJackClient *c);
+static QemuMutex qjack_shutdown_lock;
static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
{
static void qjack_buffer_clear(QJackBuffer *buffer)
{
assert(buffer->data);
- atomic_store_release(&buffer->used, 0);
+ qatomic_store_release(&buffer->used, 0);
buffer->rptr = 0;
buffer->wptr = 0;
}
assert(buffer->data);
const int samples = size / sizeof(float);
int frames = samples / buffer->channels;
- const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
+ const int avail = buffer->frames - qatomic_load_acquire(&buffer->used);
if (frames > avail) {
frames = avail;
buffer->wptr = wptr;
- atomic_add(&buffer->used, frames);
+ qatomic_add(&buffer->used, frames);
return frames * buffer->channels * sizeof(float);
};
static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
{
assert(buffer->data);
- const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
+ const int avail = buffer->frames - qatomic_load_acquire(&buffer->used);
int wptr = buffer->wptr;
if (frames > avail) {
}
buffer->wptr = wptr;
- atomic_add(&buffer->used, frames);
+ qatomic_add(&buffer->used, frames);
return frames;
}
assert(buffer->data);
const int samples = size / sizeof(float);
int frames = samples / buffer->channels;
- const int avail = atomic_load_acquire(&buffer->used);
+ const int avail = qatomic_load_acquire(&buffer->used);
if (frames > avail) {
frames = avail;
buffer->rptr = rptr;
- atomic_sub(&buffer->used, frames);
+ qatomic_sub(&buffer->used, frames);
return frames * buffer->channels * sizeof(float);
}
{
assert(buffer->data);
int copy = frames;
- const int used = atomic_load_acquire(&buffer->used);
+ const int used = qatomic_load_acquire(&buffer->used);
int rptr = buffer->rptr;
if (copy > used) {
}
buffer->rptr = rptr;
- atomic_sub(&buffer->used, copy);
+ qatomic_sub(&buffer->used, copy);
return copy;
}
return 0;
}
+static void qjack_shutdown_bh(void *opaque)
+{
+ QJackClient *c = (QJackClient *)opaque;
+ qjack_client_fini(c);
+}
+
static void qjack_shutdown(void *arg)
{
QJackClient *c = (QJackClient *)arg;
c->state = QJACK_STATE_SHUTDOWN;
+ qemu_bh_schedule(c->shutdown_bh);
}
static void qjack_client_recover(QJackClient *c)
{
- if (c->state == QJACK_STATE_SHUTDOWN) {
- qjack_client_fini(c);
+ if (c->state != QJACK_STATE_DISCONNECTED) {
+ return;
}
/* packets is used simply to throttle this */
- if (c->state == QJACK_STATE_DISCONNECTED &&
- c->packets % 100 == 0) {
+ if (c->packets % 100 == 0) {
/* if enabled then attempt to recover */
if (c->enabled) {
QJackOut *jo = (QJackOut *)hw;
Audiodev *dev = (Audiodev *)drv_opaque;
- qjack_client_fini(&jo->c);
-
jo->c.out = true;
jo->c.enabled = false;
jo->c.nchannels = as->nchannels;
jo->c.opt = dev->u.jack.out;
+ jo->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &jo->c);
+
int ret = qjack_client_init(&jo->c);
if (ret != 0) {
+ qemu_bh_delete(jo->c.shutdown_bh);
return ret;
}
QJackIn *ji = (QJackIn *)hw;
Audiodev *dev = (Audiodev *)drv_opaque;
- qjack_client_fini(&ji->c);
-
ji->c.out = false;
ji->c.enabled = false;
ji->c.nchannels = as->nchannels;
ji->c.opt = dev->u.jack.in;
+ ji->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &ji->c);
+
int ret = qjack_client_init(&ji->c);
if (ret != 0) {
+ qemu_bh_delete(ji->c.shutdown_bh);
return ret;
}
return 0;
}
-static void qjack_client_fini(QJackClient *c)
+static void qjack_client_fini_locked(QJackClient *c)
{
switch (c->state) {
case QJACK_STATE_RUNNING:
case QJACK_STATE_SHUTDOWN:
jack_client_close(c->client);
+ c->client = NULL;
+
+ qjack_buffer_free(&c->fifo);
+ g_free(c->port);
+
+ c->state = QJACK_STATE_DISCONNECTED;
/* fallthrough */
case QJACK_STATE_DISCONNECTED:
break;
}
+}
- qjack_buffer_free(&c->fifo);
- g_free(c->port);
-
- c->state = QJACK_STATE_DISCONNECTED;
+static void qjack_client_fini(QJackClient *c)
+{
+ qemu_mutex_lock(&qjack_shutdown_lock);
+ qjack_client_fini_locked(c);
+ qemu_mutex_unlock(&qjack_shutdown_lock);
}
static void qjack_fini_out(HWVoiceOut *hw)
{
QJackOut *jo = (QJackOut *)hw;
qjack_client_fini(&jo->c);
+
+ qemu_bh_delete(jo->c.shutdown_bh);
}
static void qjack_fini_in(HWVoiceIn *hw)
{
QJackIn *ji = (QJackIn *)hw;
qjack_client_fini(&ji->c);
+
+ qemu_bh_delete(ji->c.shutdown_bh);
}
static void qjack_enable_out(HWVoiceOut *hw, bool enable)
static void register_audio_jack(void)
{
+ qemu_mutex_init(&qjack_shutdown_lock);
audio_driver_register(&jack_driver);
jack_set_thread_creator(qjack_thread_creator);
jack_set_error_function(qjack_error);