From 8d6cb61e5f9f3ffb06d541796b8d7cf30014c10e Mon Sep 17 00:00:00 2001
From: Stan Seibert <volsung@xiph.org>
Date: Mon, 14 Jul 2003 02:59:10 +0000
Subject: [PATCH] NAS plugin from Antoine Mathys <Antoine.Mathys@unifr.ch> (for
 real this time)

git-svn-id: http://svn.xiph.org/trunk/ao@5140 0101bb08-14d6-0310-b084-bc0e0c8e3800
---
 src/plugins/nas/.cvsignore  |   6 +
 src/plugins/nas/Makefile.am |  28 +++++
 src/plugins/nas/ao_nas.c    | 244 ++++++++++++++++++++++++++++++++++++
 3 files changed, 278 insertions(+)
 create mode 100644 src/plugins/nas/.cvsignore
 create mode 100644 src/plugins/nas/Makefile.am
 create mode 100644 src/plugins/nas/ao_nas.c

diff --git a/src/plugins/nas/.cvsignore b/src/plugins/nas/.cvsignore
new file mode 100644
index 0000000..165280f
--- /dev/null
+++ b/src/plugins/nas/.cvsignore
@@ -0,0 +1,6 @@
+Makefile.in
+Makefile
+*.la
+*.lo
+.deps
+.libs
diff --git a/src/plugins/nas/Makefile.am b/src/plugins/nas/Makefile.am
new file mode 100644
index 0000000..2fe1d64
--- /dev/null
+++ b/src/plugins/nas/Makefile.am
@@ -0,0 +1,28 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+if HAVE_NAS
+
+nasltlibs = libnas.la
+nasldflags = -export-dynamic -avoid-version
+nassources = ao_nas.c
+
+else
+
+nasltlibs =
+nasldflags =
+nassources =
+
+endif
+
+INCLUDES = -I$(top_builddir)/include/ao -I$(top_srcdir)/include @NAS_CFLAGS@
+
+libdir = $(plugindir)
+lib_LTLIBRARIES = $(nasltlibs)
+
+libnas_la_LDFLAGS = $(nasldflags)
+libnas_la_LIBADD = @NAS_LIBS@
+libnas_la_SOURCES = $(nassources)
+
+EXTRA_DIST = ao_nas.c
diff --git a/src/plugins/nas/ao_nas.c b/src/plugins/nas/ao_nas.c
new file mode 100644
index 0000000..f9543ce
--- /dev/null
+++ b/src/plugins/nas/ao_nas.c
@@ -0,0 +1,244 @@
+/*
+ *
+ *  ao_nas.c - Network Audio System output plugin for libao
+ *
+ *  Copyright (C) 2003 - Antoine Mathys <Antoine.Mathys@unifr.ch>
+ *
+ *  Based on the XMMS NAS plugin by Willem Monsuwe.
+ *
+ *  This file is part of libao, a cross-platform library.  See
+ *  README for a history of this source code.
+ *
+ *  libao is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  libao is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <audio/audiolib.h>
+#include <ao/ao.h>
+#include <ao/plugin.h>
+
+#define AO_NAS_BUF_SIZE 4096
+
+static char *ao_nas_options[] = {
+  "host",    /* NAS server. See nas(1) for format. */
+  "buf_size" /* Buffer size on server */
+};
+
+static ao_info ao_nas_info =
+{
+	AO_TYPE_LIVE,
+	"NAS output",
+	"nas",
+	"Antoine Mathys <Antoine.Mathys@unifr.ch>",
+	"Outputs to the Network Audio System.",
+	AO_FMT_NATIVE,
+	10,
+	ao_nas_options,
+	2
+};
+
+
+typedef struct ao_nas_internal
+{
+  AuServer* aud;
+  AuFlowID flow;
+  AuDeviceID dev;
+  char *host;
+  int buf_size;
+  int buf_free;
+} ao_nas_internal;
+
+int ao_plugin_test()
+{
+  AuServer* aud = 0;
+
+  aud = AuOpenServer(0, 0, 0, 0, 0, 0);
+  if (!aud)
+    return 0;
+  else {
+    AuCloseServer(aud);
+    return 1;
+  }
+}
+
+
+ao_info *ao_plugin_driver_info(void)
+{
+	return &ao_nas_info;
+}
+
+
+int ao_plugin_device_init(ao_device *device)
+{
+	ao_nas_internal *internal;
+
+	internal = (ao_nas_internal *) malloc(sizeof(ao_nas_internal));
+
+	if (internal == NULL)	
+		return 0; /* Could not initialize device memory */
+	
+	internal->host = NULL;
+	internal->buf_size = AO_NAS_BUF_SIZE;
+	internal->buf_free = -1;
+
+	device->internal = internal;
+	return 1; /* Memory alloc successful */
+}
+
+int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
+{
+	ao_nas_internal *internal = (ao_nas_internal *) device->internal;
+
+	if (!strcmp(key, "host")) {
+	  if (internal->host)
+	    free(internal->host);
+	  internal->host = strdup(value);
+	  if (!internal->host)
+	    return 0;
+	}
+	else if (!strcmp(key, "buf_size")) {
+	  internal->buf_size = atoi(value);
+	  if (internal->buf_size <= 2)
+	    return 0;
+	}
+		 
+	return 1;
+}
+
+
+int ao_plugin_open(ao_device *device, ao_sample_format *format)
+{
+	ao_nas_internal *internal = (ao_nas_internal *) device->internal;
+	unsigned char nas_format;
+	AuElement elms[2];
+
+	/* get format */
+	switch (format->bits)
+	{
+	case 8  :
+	  nas_format = AuFormatLinearUnsigned8;
+	  break;
+	case 16 :
+	  if (device->machine_byte_format == AO_FMT_BIG)
+	    nas_format = AuFormatLinearSigned16MSB;
+	  else
+	    nas_format = AuFormatLinearSigned16LSB;
+	  break;
+	default : return 0;
+	}
+
+	/* open server */
+	internal->aud = AuOpenServer(internal->host, 0, 0, 0, 0, 0);
+	if (!internal->aud)
+	  return 0; /* Could not contact NAS server */
+
+	/* find physical output device */
+	{
+	  int i;
+	  for (i = 0; i < AuServerNumDevices(internal->aud); i++)
+	    if ((AuDeviceKind(AuServerDevice(internal->aud, i)) ==
+		 AuComponentKindPhysicalOutput) &&
+		(AuDeviceNumTracks(AuServerDevice(internal->aud, i)) ==
+		 format->channels))
+	      break;
+	  
+	  if ((i == AuServerNumDevices(internal->aud)) || 
+	      (!(internal->flow = AuCreateFlow(internal->aud, 0)))) {
+	    /* No physical output device found or flow creation failed. */
+	    AuCloseServer(internal->aud);
+	    return 0;
+	  }
+	  internal->dev = AuDeviceIdentifier(AuServerDevice(internal->aud, i));
+	}
+
+	/* set up flow */
+	AuMakeElementImportClient(&elms[0], format->rate,
+				  nas_format, format->channels, AuTrue,
+				  internal->buf_size, internal->buf_size / 2,
+				  0, 0);
+	AuMakeElementExportDevice(&elms[1], 0, internal->dev,
+				  format->rate, AuUnlimitedSamples, 0, 0);
+	AuSetElements(internal->aud, internal->flow, AuTrue, 2, elms, 0);
+	AuStartFlow(internal->aud, internal->flow, 0);
+	
+	device->driver_byte_format = AO_FMT_NATIVE;
+	return 1;
+}
+
+int ao_plugin_play(ao_device *device, const char* output_samples, 
+		uint_32 num_bytes)
+{
+	ao_nas_internal *internal = (ao_nas_internal *) device->internal;
+
+	while (num_bytes > 0) {
+	  /* Wait for room in buffer */
+	  while (internal->buf_free <= 0) {
+	    AuEvent ev;
+	    AuNextEvent(internal->aud, AuTrue, &ev);
+	    if (ev.type == AuEventTypeElementNotify) {
+	      AuElementNotifyEvent* event = (AuElementNotifyEvent*)(&ev);
+	      if (event->kind == AuElementNotifyKindLowWater)
+		internal->buf_free = event->num_bytes;
+	      else if ((event->kind == AuElementNotifyKindState) &&
+		       (event->cur_state == AuStatePause) &&
+		       (event->reason != AuReasonUser))
+		internal->buf_free = event->num_bytes;
+	    }
+	  }
+	  
+	  /* Partial transfer */
+	  if (num_bytes > internal->buf_free) {
+	    AuWriteElement(internal->aud, internal->flow, 0, internal->buf_free,
+			   output_samples, AuFalse, 0);
+	    num_bytes -= internal->buf_free;
+	    output_samples += internal->buf_free;
+	    internal->buf_free = 0;
+	  }
+
+	  /* Final transfer */
+	  else {
+	    AuWriteElement(internal->aud, internal->flow, 0, num_bytes,
+			   output_samples, AuFalse, 0);
+	    internal->buf_free -= num_bytes;
+	    break;
+	  }
+	}
+	
+	return 1;
+}
+
+
+int ao_plugin_close(ao_device *device)
+{
+	ao_nas_internal *internal = (ao_nas_internal *) device->internal;
+
+	AuStopFlow(internal->aud, internal->flow, 0);
+	AuCloseServer(internal->aud);
+	return 1;
+}
+
+
+void ao_plugin_device_clear(ao_device *device)
+{
+	ao_nas_internal *internal = (ao_nas_internal *) device->internal;
+
+	free(internal->host);
+	free(internal);
+}
-- 
GitLab