Re: [PATCH v3] audio/jack: add JACK client audiodev

2020-04-29 Thread Geoffrey McRae




On 2020-04-29 22:59, Eric Blake wrote:

On 4/29/20 12:53 AM, Geoffrey McRae wrote:

This commit adds a new audiodev backend to allow QEMU to use JACK as
both an audio sink and source.

Signed-off-by: Geoffrey McRae 
---
  audio/Makefile.objs|   5 +
  audio/audio.c  |   1 +
  audio/audio_template.h |   2 +
  audio/jackaudio.c  | 615 
+

  configure  |  17 ++
  qapi/audio.json|  50 +++-


Focusing just on UI:


+++ b/qapi/audio.json
@@ -152,6 +152,51 @@
  '*out': 'AudiodevPerDirectionOptions',
  '*latency': 'uint32' } }
  +##
+# @AudiodevJackPerDirectionOptions:
+#
+# Options of the JACK backend that are used for both playback and
+# recording.
+#
+# @server_name: select from among several possible concurrent server 
instances.
+# If unspecified, use "default" unless $JACK_DEFAULT_SERVER is 
defined in the

+# process environment.


Our convention is to prefer '-' over '_' except in cases of
pre-existing consistency.  This should be 'server-name' unless you
have an example of what we have to be consistent with.


No reason at all just didn't think about it, I will correct it :)




+#
+# @client_name: the client name to use. The server will modify this 
name to

+# create a unique variant, if needed unless @exact_name is true.
+#
+# @start_server: set to true to start a jack server instance if one 
is not

+# present.
+#
+# @exact_name: use the exact name requested otherwise JACK 
automatically

+# generates a unique one, if needed.


Ditto for these three.


+#
+# Since: 4.0


The earliest this will be added is 5.1, not 4.0.


Yup, copy & paste error :)




+##
+{ 'struct': 'AudiodevJackPerDirectionOptions',
+  'base': 'AudiodevPerDirectionOptions',
+  'data': {
+'*server_name':  'str',
+'*client_name':  'str',
+'*start_server': 'bool',
+'*exact_name':   'bool' } }
+
+##
+# @AudiodevJackOptions:
+#
+# Options of the JACK audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# Since: 4.0


5.1


+##
+{ 'struct': 'AudiodevJackOptions',
+  'data': {
+'*in':  'AudiodevJackPerDirectionOptions',
+'*out': 'AudiodevJackPerDirectionOptions' } }
+
  ##
  # @AudiodevOssPerDirectionOptions:
  #
@@ -300,8 +345,8 @@
  # Since: 4.0
  ##
  { 'enum': 'AudiodevDriver',
-  'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'oss', 'pa', 
'sdl',

-'spice', 'wav' ] }
+  'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'jack', 'oss', 
'pa',

+'sdl', 'spice', 'wav' ] }


It's worth adding a doc comment that @jack was added in 5.1 (I didn't
check if audio.json has an example of adding to an enum, but other
.json files do)


No worries, I will see if I can figure this out.

-Geoff



Re: [PATCH v3] audio/jack: add JACK client audiodev

2020-04-29 Thread Eric Blake

On 4/29/20 12:53 AM, Geoffrey McRae wrote:

This commit adds a new audiodev backend to allow QEMU to use JACK as
both an audio sink and source.

Signed-off-by: Geoffrey McRae 
---
  audio/Makefile.objs|   5 +
  audio/audio.c  |   1 +
  audio/audio_template.h |   2 +
  audio/jackaudio.c  | 615 +
  configure  |  17 ++
  qapi/audio.json|  50 +++-


Focusing just on UI:


+++ b/qapi/audio.json
@@ -152,6 +152,51 @@
  '*out': 'AudiodevPerDirectionOptions',
  '*latency': 'uint32' } }
  
+##

+# @AudiodevJackPerDirectionOptions:
+#
+# Options of the JACK backend that are used for both playback and
+# recording.
+#
+# @server_name: select from among several possible concurrent server instances.
+# If unspecified, use "default" unless $JACK_DEFAULT_SERVER is defined in the
+# process environment.


Our convention is to prefer '-' over '_' except in cases of pre-existing 
consistency.  This should be 'server-name' unless you have an example of 
what we have to be consistent with.



+#
+# @client_name: the client name to use. The server will modify this name to
+# create a unique variant, if needed unless @exact_name is true.
+#
+# @start_server: set to true to start a jack server instance if one is not
+# present.
+#
+# @exact_name: use the exact name requested otherwise JACK automatically
+# generates a unique one, if needed.


Ditto for these three.


+#
+# Since: 4.0


The earliest this will be added is 5.1, not 4.0.


+##
+{ 'struct': 'AudiodevJackPerDirectionOptions',
+  'base': 'AudiodevPerDirectionOptions',
+  'data': {
+'*server_name':  'str',
+'*client_name':  'str',
+'*start_server': 'bool',
+'*exact_name':   'bool' } }
+
+##
+# @AudiodevJackOptions:
+#
+# Options of the JACK audio backend.
+#
+# @in: options of the capture stream
+#
+# @out: options of the playback stream
+#
+# Since: 4.0


5.1


+##
+{ 'struct': 'AudiodevJackOptions',
+  'data': {
+'*in':  'AudiodevJackPerDirectionOptions',
+'*out': 'AudiodevJackPerDirectionOptions' } }
+
  ##
  # @AudiodevOssPerDirectionOptions:
  #
@@ -300,8 +345,8 @@
  # Since: 4.0
  ##
  { 'enum': 'AudiodevDriver',
-  'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'oss', 'pa', 'sdl',
-'spice', 'wav' ] }
+  'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'jack', 'oss', 'pa',
+'sdl', 'spice', 'wav' ] }


It's worth adding a doc comment that @jack was added in 5.1 (I didn't 
check if audio.json has an example of adding to an enum, but other .json 
files do)


--
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




[PATCH v3] audio/jack: add JACK client audiodev

2020-04-29 Thread Geoffrey McRae
This commit adds a new audiodev backend to allow QEMU to use JACK as
both an audio sink and source.

Signed-off-by: Geoffrey McRae 
---
 audio/Makefile.objs|   5 +
 audio/audio.c  |   1 +
 audio/audio_template.h |   2 +
 audio/jackaudio.c  | 615 +
 configure  |  17 ++
 qapi/audio.json|  50 +++-
 6 files changed, 688 insertions(+), 2 deletions(-)
 create mode 100644 audio/jackaudio.c

diff --git a/audio/Makefile.objs b/audio/Makefile.objs
index d7490a379f..b4a4c11f31 100644
--- a/audio/Makefile.objs
+++ b/audio/Makefile.objs
@@ -28,3 +28,8 @@ common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo
 sdl.mo-objs = sdlaudio.o
 sdl.mo-cflags := $(SDL_CFLAGS)
 sdl.mo-libs := $(SDL_LIBS)
+
+# jack module
+common-obj-$(CONFIG_AUDIO_JACK) += jack.mo
+jack.mo-objs = jackaudio.o
+jack.mo-libs := $(JACK_LIBS)
diff --git a/audio/audio.c b/audio/audio.c
index 7a9e680355..95d9fb16ca 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1969,6 +1969,7 @@ void audio_create_pdos(Audiodev *dev)
 CASE(ALSA, alsa, Alsa);
 CASE(COREAUDIO, coreaudio, Coreaudio);
 CASE(DSOUND, dsound, );
+CASE(JACK, jack, Jack);
 CASE(OSS, oss, Oss);
 CASE(PA, pa, Pa);
 CASE(SDL, sdl, );
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7013d3041f..8dd48ce14e 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -330,6 +330,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, 
TYPE)(Audiodev *dev)
 dev->u.coreaudio.TYPE);
 case AUDIODEV_DRIVER_DSOUND:
 return dev->u.dsound.TYPE;
+case AUDIODEV_DRIVER_JACK:
+return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
 case AUDIODEV_DRIVER_OSS:
 return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
 case AUDIODEV_DRIVER_PA:
diff --git a/audio/jackaudio.c b/audio/jackaudio.c
new file mode 100644
index 00..a93d361ac4
--- /dev/null
+++ b/audio/jackaudio.c
@@ -0,0 +1,615 @@
+/*
+ * QEMU JACK Audio Connection Kit Client
+ *
+ * Copyright (c) 2020 Geoffrey McRae (gnif)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/fifo8.h"
+#include "qemu-common.h"
+#include "audio.h"
+
+#define AUDIO_CAP "jack"
+#include "audio_int.h"
+
+#include 
+#include 
+#include 
+
+struct QJack;
+
+typedef enum QJackState {
+  QJACK_STATE_DISCONNECTED,
+  QJACK_STATE_CONNECTED,
+  QJACK_STATE_IDLE,
+  QJACK_STATE_RUNNING,
+  QJACK_STATE_STOPPING,
+  QJACK_STATE_STOPPED,
+}
+QJackState;
+
+typedef struct QJackBuffer {
+  int  channels;
+  int  frames;
+  _Atomic(int) used;
+  int  rptr, wptr;
+  float  **data;
+}
+QJackBuffer;
+
+typedef struct QJackClient {
+  boolout;
+  QJackState  state;
+  jack_client_t  *client;
+  jack_nframes_t  freq;
+
+  struct QJack   *j;
+  int nchannels;
+  int buffersize;
+  jack_port_t   **port;
+  QJackBuffer fifo;
+}
+QJackClient;
+
+typedef struct QJackOut {
+HWVoiceOut  hw;
+QJackClient c;
+}
+QJackOut;
+
+typedef struct QJackIn {
+HWVoiceIn   hw;
+QJackClient c;
+}
+QJackIn;
+
+static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
+{
+buffer->channels = channels;
+buffer->frames   = frames;
+buffer->used = 0;
+buffer->rptr = 0;
+buffer->wptr = 0;
+buffer->data = g_malloc(channels * sizeof(float *));
+for (int i = 0; i < channels; ++i) {
+buffer->data[i] = g_malloc(frames * sizeof(float));
+}
+}
+
+static void qjack_buffer_clear(QJackBuffer *buffer)
+{
+atomic_store_explicit(>used, 0, memory_order_relaxed);
+buffer->rptr = 0;
+buffer->wptr = 0;
+}
+
+static void qjack_buffer_free(QJackBuffer *buffer)
+{
+for (int i = 0; i < buffer->channels; ++i) {
+g_free(buffer->data[i]);
+}