Enumerate devices, works for ALSA now.
authorbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 9 Mar 2014 06:53:02 +0000 (06:53 +0000)
committerbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 9 Mar 2014 06:53:02 +0000 (06:53 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1419 01035d8c-6547-0410-b346-abe4f91aad63

freedv-server/source/driver_manager.cpp
freedv-server/source/drivers.h
freedv-server/source/platform/linux/alsa.cpp [new file with mode: 0644]
freedv-server/source/platform/linux/audio_out_alsa.cpp

index b0cb1cf75a375a4baf021de97ca2ef607524b3f5..6dea58a11afedafaa6ecfc042bf5d98b0bdaf308 100644 (file)
@@ -14,13 +14,15 @@ namespace FreeDV {
   // embedded, it's worth some extra effort to avoid STL containers.
 
   static std::ostream &
-  enumerate(std::ostream & stream, const DriverList * list)
+  enumerate(std::ostream & stream, const char * name, const DriverList * list)
   {
     if ( list == 0 )
       return stream;
 
+    stream << "# " << name << std::endl;
+
     while ( list->key ) {
-      stream << list->key << ' ';
+      (*(list->enumerator))(stream);
       list++;
     }
     return stream;
@@ -32,7 +34,7 @@ namespace FreeDV {
     while ( list->key ) {
       if ( strcmp(key, list->key) == 0 ) {
        try {
-          return (*(list->value))(parameters);
+          return (*(list->creator))(parameters);
         }
         catch(std::exception & e) {
           std::cerr << "Open " << type << " \"" << key << "\": " << e.what() << std::endl;
@@ -46,7 +48,11 @@ namespace FreeDV {
   }
 
   static void
-  place(const char * const key, FreeDV::Base * (*value)(const char *), std::ostream & (*enumerator)(std::ostream &), DriverList * * const list)
+  place(
+   const char * const key,
+   FreeDV::Base * (*creator)(const char *),
+   std::ostream & (*enumerator)(std::ostream &),
+   DriverList * * const list)
   {
     DriverList * next;
 
@@ -67,10 +73,12 @@ namespace FreeDV {
       *list = next = new DriverList[2];
 
     next->key = strdup(key);
-    next->value = value;
+    next->creator = creator;
+    next->enumerator = enumerator;
     ++next;
     next->key = 0;
-    next->value = 0;
+    next->creator = 0;
+    next->enumerator = 0;
   }
 
   // Global instance of the driver manager used to register
@@ -86,32 +94,15 @@ namespace FreeDV {
   std::ostream &
   DriverManager::print(std::ostream & s) const
   {
-    s << "Audio Input: ";
-    enumerate(s, audio_input_drivers) << std::endl;
-
-    s << "Audio Output: ";
-    enumerate(s, audio_output_drivers) << std::endl;
-
-    s << "Codec: ";
-    enumerate(s, codecs) << std::endl;
-
-    s << "Framer: ";
-    enumerate(s, framers) << std::endl;
-
-    s << "Keying Output: ";
-    enumerate(s, keying_output_drivers) << std::endl;
-
-    s << "Modem: ";
-    enumerate(s, modems) << std::endl;
-
-    s << "PTT Input: ";
-    enumerate(s, ptt_input_drivers) << std::endl;
-
-    s << "Text Input: ";
-    enumerate(s, text_input_drivers) << std::endl;
-
-    s << "User Interface: ";
-    enumerate(s, user_interface_drivers) << std::endl;
+    enumerate(s, "Audio Input", audio_input_drivers) << std::endl;
+    enumerate(s, "Audio Output", audio_output_drivers) << std::endl;
+    enumerate(s, "Codec", codecs) << std::endl;
+    enumerate(s, "Protocol Framer", framers) << std::endl;
+    enumerate(s, "Keying Output", keying_output_drivers) << std::endl;
+    enumerate(s, "Modem", modems) << std::endl;
+    enumerate(s, "PTT Input", ptt_input_drivers) << std::endl;
+    enumerate(s, "Text Input", text_input_drivers) << std::endl;
+    enumerate(s, "User Interface", user_interface_drivers) << std::endl;
 
     return s;
   }
index 13fae2d448129e2f36968ce29e9060e2e8c34629..fc3e37d3fadc63501d825b6caeb9ef3c4e498829 100644 (file)
@@ -703,6 +703,7 @@ namespace FreeDV {
   namespace Driver {
     AudioInput *       Tone(const char * parameter);
     AudioOutput *      AudioSink(const char * parameter);
+    AudioOutput *      AudioOutALSA(const char * parameter);
     Codec *            CodecNoOp(const char * parameter);
     Framer *           FramerNoOp(const char * parameter);
     KeyingOutput *     KeyingSink(const char * parameter);
@@ -716,6 +717,7 @@ namespace FreeDV {
   namespace Enumerator {
     std::ostream &     Tone(std::ostream &);
     std::ostream &     AudioSink(std::ostream &);
+    std::ostream &     AudioOutALSA(std::ostream &);
     std::ostream &     CodecNoOp(std::ostream &);
     std::ostream &     FramerNoOp(std::ostream &);
     std::ostream &     KeyingSink(std::ostream &);
@@ -740,7 +742,8 @@ namespace FreeDV {
 
   struct DriverList {
     const char *       key;
-    FreeDV::Base *     (*value)(const char *);
+    FreeDV::Base *     (*creator)(const char *);
+    std::ostream &     (*enumerator)(std::ostream &);
   };
 
   /// Device driver manager. Allows for registration and enumeration of device
diff --git a/freedv-server/source/platform/linux/alsa.cpp b/freedv-server/source/platform/linux/alsa.cpp
new file mode 100644 (file)
index 0000000..792c3d4
--- /dev/null
@@ -0,0 +1,73 @@
+#include <iostream>
+#include <alsa/asoundlib.h>
+#include <sstream>
+
+namespace FreeDV {
+  static std::ostream &
+  error_message(std::ostream & stream, int error) {
+    switch ( error ) {
+    case 0:
+      break;
+    case -ENOENT:
+      stream << " (Not connected)";
+      break;
+    case -EBUSY:
+      stream << " (In use by another program)";
+      break;
+    case -EACCES:
+      stream << " (Access denied)";
+      break;
+    default:
+      stream << " (" << snd_strerror(error) << ')';
+    }
+    return stream;
+  }
+  
+  std::ostream &
+  ALSAEnumerate(std::ostream & stream, snd_pcm_stream_t mode)
+  {
+    int                        card_index = -1;
+    snd_pcm_t *                pcm_handle;
+    snd_ctl_card_info_t *      info = 0;
+  
+    const int error = snd_pcm_open(
+     &pcm_handle,
+     "default",
+     SND_PCM_STREAM_PLAYBACK,
+     0);
+  
+    stream << "\"alsa:default\"";
+    error_message(stream, error);
+    stream << std::endl;
+  
+    while ( snd_card_next(&card_index) == 0 && card_index >= 0 ) {
+      char             device_name[20];
+      snd_ctl_t *              ctl_handle = 0;
+      int                      pcm_error = 0;
+      char *           longname = 0;
+  
+      if ( snd_card_get_longname(card_index, &longname) == 0 ) {
+        sprintf(device_name, "hw:%d", card_index);
+        
+        const int ctl_error = snd_ctl_open(&ctl_handle, device_name, 0);
+        if ( ctl_error == 0 ) {
+          pcm_error = snd_pcm_open(&pcm_handle, device_name, mode, 0);
+        }
+          
+        const int error = ctl_error ? ctl_error : pcm_error;
+    
+        stream << "\"alsa:" << longname << '"';
+        error_message(stream, error);
+        stream << std::endl;
+  
+        if ( ctl_error == 0 ) {
+          snd_ctl_close(ctl_handle);
+       if ( pcm_error == 0 )
+            snd_pcm_close(pcm_handle);
+        }
+      }
+    }
+  
+    return stream;
+  }
+};
index 345b4ef38319c63b6a11e9c0fe87f6772052bf35..af12e0c0f06524b552120b7d8252113b4fe09784 100644 (file)
@@ -6,6 +6,8 @@
 #include <stdexcept>
 
 namespace FreeDV {
+  std::ostream & ALSAEnumerate(std::ostream & stream, snd_pcm_stream_t mode);
+
   /// Audio output "sink", discards the audio, for testing.
   class AudioOutALSA : public AudioOutput {
   private:
@@ -61,10 +63,10 @@ namespace FreeDV {
     return new ::FreeDV::AudioOutALSA(parameter);
   }
 
-  ostream &
-  Enumerator::AudioOutALSA(ostream & stream)
+  std::ostream &
+  Enumerator::AudioOutALSA(std::ostream & stream)
   {
-    return stream;
+    return ALSAEnumerate(stream, SND_PCM_STREAM_PLAYBACK);
   }
 
   std::size_t