]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Initial support for libsoundio 433/head
authorshtirlic <serg@podtynnyi.com>
Sat, 3 Dec 2016 22:03:23 +0000 (00:03 +0200)
committershtirlic <serg@podtynnyi.com>
Sat, 3 Dec 2016 22:03:23 +0000 (00:03 +0200)
Makefile.am
audio.c
audio_soundio.c [new file with mode: 0644]
configure.ac
shairport.c

index 1be55de514ab248f9bb8deac82fb9028245dd0e1..c6e4d5e7c8f22d6a9b41bf42a09d2da79d9e20a8 100644 (file)
@@ -47,6 +47,10 @@ if USE_AO
 shairport_sync_SOURCES += audio_ao.c
 endif
 
+if USE_SOUNDIO
+shairport_sync_SOURCES += audio_soundio.c
+endif
+
 if USE_PULSE
 shairport_sync_SOURCES += audio_pulse.c
 endif
diff --git a/audio.c b/audio.c
index e40006c4dbcbf32a5ed531a7b67297e190a7c56a..915cb8023ec1c1dc90604c849111d9c0147dc879 100644 (file)
--- a/audio.c
+++ b/audio.c
@@ -35,6 +35,9 @@ extern audio_output audio_sndio;
 #ifdef CONFIG_AO
 extern audio_output audio_ao;
 #endif
+#ifdef CONFIG_SOUNDIO
+extern audio_output audio_soundio;
+#endif
 #ifdef CONFIG_PULSE
 extern audio_output audio_pulse;
 #endif
@@ -64,6 +67,9 @@ static audio_output *outputs[] = {
 #ifdef CONFIG_AO
     &audio_ao,
 #endif
+#ifdef CONFIG_SOUNDIO
+    &audio_soundio,
+#endif
 #ifdef CONFIG_DUMMY
     &audio_dummy,
 #endif
diff --git a/audio_soundio.c b/audio_soundio.c
new file mode 100644 (file)
index 0000000..b76a4ca
--- /dev/null
@@ -0,0 +1,215 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include "common.h"
+#include "audio.h"
+
+#include <soundio/soundio.h>
+
+int Fs;
+long long starttime, samples_played;
+
+struct SoundIoOutStream *outstream;
+struct SoundIo *soundio;
+struct SoundIoDevice *device;
+struct SoundIoRingBuffer *ring_buffer = NULL;
+
+static int min_int(int a, int b) {
+    return (a < b) ? a : b;
+}
+
+static void write_callback(struct SoundIoOutStream *outstream,
+        int frame_count_min, int frame_count_max)
+{
+  struct SoundIoChannelArea *areas;
+     int frame_count;
+     int err;
+
+     char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
+     int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
+     int fill_count = fill_bytes / outstream->bytes_per_frame;
+
+     debug(3, "[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , outstream->bytes_per_frame: %d", frame_count_min, frame_count_max, fill_bytes, fill_count, outstream->bytes_per_frame );
+
+     if (frame_count_min > fill_count) {
+          int frame_count = frame_count_min;
+             if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))){
+               debug(0, "[--->>] begin write error: %s", soundio_strerror(err));
+             }
+             for (int frame = 0; frame < frame_count; frame += 1) {
+                 for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
+                     memset(areas[ch].ptr, 0, outstream->bytes_per_sample);
+                     areas[ch].ptr += areas[ch].step;
+                 }
+             }
+             if ((err = soundio_outstream_end_write(outstream)))
+                 debug(0,"[--->>] end write error: %s", soundio_strerror(err));
+        return;
+     }
+
+     int read_count = min_int(frame_count_max, fill_count);
+     int frames_left = read_count;
+
+     while (frames_left > 0) {
+         int frame_count = frames_left;
+
+         if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
+             debug(0, "[--->>] begin write error: %s", soundio_strerror(err));
+
+         if (frame_count <= 0)
+             break;
+
+         for (int frame = 0; frame < frame_count; frame += 1) {
+             for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
+                 memcpy(areas[ch].ptr, read_ptr, outstream->bytes_per_sample);
+                 areas[ch].ptr += areas[ch].step;
+                 read_ptr += outstream->bytes_per_sample;
+             }
+         }
+
+         if ((err = soundio_outstream_end_write(outstream)))
+             debug(0, "[--->>] end write error: %s", soundio_strerror(err));
+
+         frames_left -= frame_count;
+     }
+
+     debug(3,"[--->>]  Wrote: %d", read_count * outstream->bytes_per_frame);
+     soundio_ring_buffer_advance_read_ptr(ring_buffer, read_count * outstream->bytes_per_frame);
+}
+
+static void underflow_callback(struct SoundIoOutStream *outstream) {
+    static int count = 0;
+    debug(0, "underflow %d\n", ++count);
+}
+
+static int init(int argc, char **argv) {
+  int err;
+  config.audio_backend_buffer_desired_length = 2.0;
+
+  soundio = soundio_create();
+  if (!soundio) {
+      debug(0, "out of memory\n");
+      return 1;
+  }
+  if ((err = soundio_connect_backend(soundio, SoundIoBackendCoreAudio))) {
+      debug(0, "error connecting: %s", soundio_strerror(err));
+      return 1;
+  }
+  soundio_flush_events(soundio);
+
+  int default_out_device_index = soundio_default_output_device_index(soundio);
+  if (default_out_device_index < 0) {
+      debug(0, "no output device found");
+      return 1;
+  }
+
+  device = soundio_get_output_device(soundio, default_out_device_index);
+  if (!device) {
+      debug(0, "out of memory");
+      return 1;
+  }
+  debug(0, "Output device: %s\n", device->name);
+  return 0;
+}
+
+static void deinit(void) {
+  soundio_ring_buffer_destroy(ring_buffer);
+  soundio_device_unref(device);
+  soundio_destroy(soundio);
+  debug(0, "soundio audio deinit\n");
+}
+
+static void start(int sample_rate, int sample_format) {
+  Fs = sample_rate;
+  starttime = 0;
+  samples_played = 0;
+  int err;
+
+  debug(1, "soundion rate: %d, format: %d", sample_rate, sample_format);
+
+  // soundio_device_sort_channel_layouts(device);
+
+  outstream = soundio_outstream_create(device);
+  outstream->format = SoundIoFormatS16NE;
+  outstream->sample_rate = sample_rate;
+  outstream->layout.channel_count = 2;
+  outstream->write_callback = write_callback;
+  outstream->underflow_callback = underflow_callback;
+  // outstream->software_latency = 0;
+
+  if ((err = soundio_outstream_open(outstream))) {
+      debug(0, "unable to open device: %s", soundio_strerror(err));
+  }
+  if (outstream->layout_error)
+      debug(0, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
+
+  int capacity = outstream->sample_rate * outstream->bytes_per_frame;
+  ring_buffer = soundio_ring_buffer_create(soundio, capacity);
+  if (!ring_buffer)
+       debug(0, "unable to create ring buffer: out of memory");
+  char *buf = soundio_ring_buffer_write_ptr(ring_buffer);
+  memset(buf, 0, capacity);
+  soundio_ring_buffer_advance_write_ptr(ring_buffer, capacity);
+
+  if ((err = soundio_outstream_start(outstream))) {
+      debug(0, "unable to start outstream: %s", soundio_strerror(err));
+  }
+
+  debug(1, "libsoundio output started\n");
+}
+
+static void play(short buf[], int samples) {
+  int err;
+  int free_bytes = soundio_ring_buffer_free_count(ring_buffer);
+  int written_bytes = 0;
+  int write_bytes = 0;
+  int left_bytes = samples * outstream->bytes_per_frame;
+  char *write_ptr = soundio_ring_buffer_write_ptr(ring_buffer);
+
+  debug(3, "[<<---] samples: %d , size: %d", samples, left_bytes );
+  write_bytes = min_int(left_bytes, free_bytes);
+  debug(3, "[<<---] left_bytes: %d, write_bytes: %d, free_bytes: %d\n", left_bytes, write_bytes, free_bytes);
+
+  if (write_bytes){
+    memcpy(write_ptr, (char*) buf, write_bytes);
+    written_bytes += write_bytes;
+    soundio_ring_buffer_advance_write_ptr(ring_buffer, write_bytes);
+    debug(3, "[<<---] Written to buffer : %d\n", written_bytes);
+  }
+}
+
+static void parameters(audio_parameters *info) {
+  info->minimum_volume_dB = -30.0;
+  info->maximum_volume_dB = 0.0;
+debug(2, "Parameters\n");
+debug(2, "Current Volume dB: %f\n", info->current_volume_dB);
+debug(2, "Minimum Volume dB: %d\n", info->minimum_volume_dB);
+debug(2, "Maximum Volume dB: %d\n", info->maximum_volume_dB);
+}
+
+static void stop(void) {
+  soundio_outstream_destroy(outstream);
+  soundio_ring_buffer_clear(ring_buffer);
+  debug(1, "libsoundio output stopped\n");
+ }
+
+static void flush(void) {
+  soundio_ring_buffer_clear(ring_buffer);
+  debug(1, "libsoundio output flushed\n");
+}
+
+static void help(void) { printf(" There are no options for libsoundio.\n"); }
+
+audio_output audio_soundio = {.name = "soundio",
+                            .help = &help,
+                            .init = &init,
+                            .deinit = &deinit,
+                            .start = &start,
+                            .stop = &stop,
+                            .flush = &flush,
+                            .delay = NULL,
+                            .play = &play,
+                            .volume = NULL,
+                            .parameters = &parameters,
+                            .mute = NULL};
index bf3b25f7efd27823d5a360a4cb594f182e2db9c6..d2d1c0fb290570da7f9e482ab51a88c938158baf 100644 (file)
@@ -214,6 +214,14 @@ AC_ARG_WITH(ao, [  --with-ao = choose AO (Audio Output?) API support. N.B. no sy
   AC_CHECK_LIB([ao], [ao_initialize], , AC_MSG_ERROR(AO support requires the ao library -- libao-dev suggested))], )
 AM_CONDITIONAL([USE_AO], [test "x$HAS_AO" = "x1"])
 
+# Look for Soundio flag
+AC_ARG_WITH(soundio, [  --with-soundio = choose soundio API support.], [
+  AC_MSG_RESULT(>>Including an soundio back end)
+  HAS_SOUNDIO=1
+  AC_DEFINE([CONFIG_SOUNDIO], 1, [Needed by the compiler.])
+  AC_CHECK_LIB([soundio], [soundio_create], , AC_MSG_ERROR(soundio support requires the soundio library!))], )
+AM_CONDITIONAL([USE_SOUNDIO], [test "x$HAS_SOUNDIO" = "x1"])
+
 # Look for pulseaudio flag
 AC_ARG_WITH(pulseaudio, [  --with-pulseaudio = choose PulseAudio API support. N.B. no synchronisation -- so underflow or overflow is inevitable!], [
   AC_MSG_RESULT(>>Including a PulseAudio back end. N.B. no synchronisation -- so underflow or overflow is inevitable!)
index fd2cd965931c0eee733f7d1a430dfb1bcc1b5511..6d37f96cf82412eb4b069a138108fb49f217abe0 100644 (file)
@@ -136,6 +136,9 @@ char *get_version_string() {
 #ifdef CONFIG_PULSE
     strcat(version_string, "-pulse");
 #endif
+#ifdef CONFIG_SOUNDIO
+    strcat(version_string, "-soundio");
+#endif
 #ifdef CONFIG_DUMMY
     strcat(version_string, "-dummy");
 #endif