chiark / gitweb /
Merge branch 'master' of git.distorted.org.uk:~mdw/publish/public-git/disorder
[disorder] / lib / uaudio.c
index aa00f6619002f05aed80b4298da037a99ffe05df..a9ac103cd485bbb0a1570aecf2ae598b2ebb7ad9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2009 Richard Kettlewell
+ * Copyright (C) 2009, 2013 Richard Kettlewell
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -11,7 +11,7 @@
  * 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.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include "uaudio.h"
 #include "hash.h"
 #include "mem.h"
+#include "log.h"
 
 /** @brief Options for chosen uaudio API */
 static hash *uaudio_options;
 
+/** @brief Sample rate (Hz) */
+int uaudio_rate;
+
+/** @brief Bits per channel */
+int uaudio_bits;
+
+/** @brief Number of channels */
+int uaudio_channels;
+
+/** @brief Whether samples are signed or unsigned */
+int uaudio_signed;
+
+/** @brief Frames of buffer to tolerate inside chosen API */
+int uaudio_buffer;
+
+/** @brief Sample size in bytes
+ *
+ * NB one sample is a single point sample; up to @c uaudio_channels samples may
+ * play at the same time through different speakers.  Thus this value is
+ * independent of @ref uaudio_channels.
+ */
+size_t uaudio_sample_size;
+
 /** @brief Set a uaudio option */
 void uaudio_set(const char *name, const char *value) {
+  if(!value) {
+    if(uaudio_options)
+      hash_remove(uaudio_options, name);
+    return;
+  }
   if(!uaudio_options)
     uaudio_options = hash_new(sizeof(char *));
   value = xstrdup(value);
   hash_add(uaudio_options, name, &value, HASH_INSERT_OR_REPLACE);
 }
 
-/** @brief Set a uaudio option */
-const char *uaudio_get(const char *name) {
-  const char *value = (uaudio_options ?
-                       *(char **)hash_find(uaudio_options, name)
-                       : NULL);
-  return value ? xstrdup(value) : NULL;
+/** @brief Get a uaudio option */
+char *uaudio_get(const char *name, const char *default_value) {
+  if(!uaudio_options)
+    return default_value ? xstrdup(default_value) : 0;
+  char **valuep = hash_find(uaudio_options, name);
+  if(!valuep)
+    return default_value ? xstrdup(default_value) : 0;
+  return xstrdup(*valuep);
 }
 
-/** @brief List of known APIs
+/** @brief Set sample format
+ * @param rate Sample rate in KHz
+ * @param channels Number of channels (i.e. 2 for stereo)
+ * @param bits Number of bits per channel (typically 8 or 16)
+ * @param signed_ True for signed samples, false for unsigned
+ *
+ * Sets @ref uaudio_rate, @ref uaudio_channels, @ref uaudio_bits, @ref
+ * uaudio_signed and @ref uaudio_sample_size.
  *
- * Terminated by a null pointer.
+ * Currently there is no way to specify non-native endian formats even if the
+ * underlying API can conveniently handle them.  Actually this would be quite
+ * convenient for playrtp, so it might be added at some point.
  *
- * The first one will be used as a default, so putting ALSA before OSS
- * constitutes a policy decision.
+ * Not all APIs can support all sample formats.  Generally the @c start
+ * function will do some error checking but some may be deferred to the point
+ * the device is opened (which might be @c activate).
  */
-const struct uaudio *uaudio_apis[] = {
-#if HAVE_COREAUDIO_AUDIOHARDWARE_H
-  &uaudio_coreaudio,
-#endif  
-#if HAVE_ALSA_ASOUNDLIB_H
-  &uaudio_alsa,
-#endif
-#if HAVE_SYS_SOUNDCARD_H || EMPEG_HOST
-  &uaudio_oss,
-#endif
-  &uaudio_rtp,
-  NULL,
-};
+void uaudio_set_format(int rate, int channels, int bits, int signed_) {
+  uaudio_rate = rate;
+  uaudio_channels = channels;
+  uaudio_bits = bits;
+  uaudio_signed = signed_;
+  uaudio_sample_size = bits / CHAR_BIT;
+}
+
+/** @brief Choose the default audio API by context
+ * @param apis Table of APIs or a null pointer
+ * @param context @ref UAUDIO_API_SERVER or @ref UAUDIO_API_CLIENT
+ * @return Default API or a null pointer
+ */
+const struct uaudio *uaudio_default(const struct uaudio *const *apis,
+                                    unsigned context) {
+  if(apis) {
+    for(int n = 0; apis[n]; ++n)
+      if(apis[n]->flags & context)
+        return apis[n];
+  }
+  return 0;
+}
 
 /*
 Local Variables: