// 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;
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;
}
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;
*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
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;
}
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);
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 &);
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
--- /dev/null
+#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;
+ }
+};