--- Makefile.am.orig 2004-10-17 10:44:02.000000000 +0930 +++ Makefile.am 2004-10-17 10:45:06.000000000 +0930 @@ -54,11 +54,13 @@ _audio_oss_la_SOURCES = \ audio_oss.cc \ + audio_oss_dev.cc \ audio_oss_sink.cc \ audio_oss_source.cc grinclude_HEADERS = \ + audio_oss_dev.h \ audio_oss_sink.h \ audio_oss_source.h --- /dev/null 2004-10-17 11:18:48.000000000 +0930 +++ audio_oss_dev.cc 2004-10-17 11:01:23.000000000 +0930 @@ -0,0 +1,137 @@ +#include +#include +#include + +#include "audio_oss_dev.h" + +// A vector to manage the active devices +static std::vector device_list; + +/* + * If not already open, open device of requested type, + * add it to the vector list, increment corresponding sink + * or source counter by one, store and return its file descriptor. + * The device can be opened multiple times as an audio source + * but only once as an audio sink. On success, the cached + * file descriptor stored for the device is returned to the + * application. + */ +int +audio_oss_dev::open(const std::string device, audio_oss_dev_type_t type) +{ + int fd; + std::vector::iterator vi; + + // Check if device is already open + vi = get(device); + + if(vi != device_list.end()) { + // Ensure that audio sink is only opened once + if(type == AUDIO_OSS_DEV_SINK && vi->count[type] > 0) { + errno = EBUSY; + return -1; + } + + vi->count[type]++; + return vi->fdesc; + } + + // Open device in read/write mode + // as NetBSD can only call open() once per device + fd = ::open(device.c_str(), O_RDWR); + + if(fd < 0) + return fd; + +#if defined(__NetBSD__) + int audio_props = 0; + + // Get device properties and enable fullduplex mode + // for devices that support it + if((ioctl(fd, AUDIO_GETPROPS, &audio_props)) != -1) { + audio_props &= AUDIO_PROP_FULLDUPLEX; + ioctl(fd, AUDIO_SETFD, &audio_props); + } +#endif + + // Create a temporary data structure + audio_oss_dev_t dev; + + // Initialize counters + dev.count[AUDIO_OSS_DEV_SOURCE] = 0; + dev.count[AUDIO_OSS_DEV_SINK] = 0; + + // Store device data + dev.fdesc = fd; + dev.name = device; + dev.count[type]++; + device_list.push_back(dev); + + // Return device file descriptor + return fd; +} + +/* + * Check if device has an entry in the vector list. If so, + * decrement the counter of the requested device type. Close + * and erase device if both, the sink and source counter, are + * zero. + */ +int +audio_oss_dev::close(int fdesc, audio_oss_dev_type_t type) +{ + std::vector::iterator vi = get(fdesc); + + if(vi != device_list.end()) { + if(vi->count[type] > 0) { + + vi->count[type]--; + + if(vi->count[AUDIO_OSS_DEV_SOURCE] == 0 && + vi->count[AUDIO_OSS_DEV_SINK] == 0) { + device_list.erase(vi); + return ::close(fdesc); + } + + return 0; + } + } + + return -1; +} + +/* + * Search for device by name and return vector iterator + */ +std::vector::iterator +audio_oss_dev::get(const std::string device) +{ + std::vector::iterator vi; + + // Find device in list and return vector iterator + for(vi = device_list.begin(); vi != device_list.end(); vi++) { + if(vi->name == device) + return vi; + } + + // Returns end of vector if unsuccessful + return vi; +} + +/* + * Search for device by file descriptor and return vector iterator + */ +std::vector::iterator +audio_oss_dev::get(int fdesc) +{ + std::vector::iterator vi; + + // Find device in list and return vector iterator + for(vi = device_list.begin(); vi != device_list.end(); vi++) { + if(vi->fdesc == fdesc) + return vi; + } + + // Returns end of vector if unsuccessful + return vi; +} --- /dev/null 2004-10-17 11:18:48.000000000 +0930 +++ audio_oss_dev.h 2004-10-17 11:02:58.000000000 +0930 @@ -0,0 +1,21 @@ +#include +#include + +enum audio_oss_dev_type_t {AUDIO_OSS_DEV_SOURCE, AUDIO_OSS_DEV_SINK}; + +struct audio_oss_dev_t { + std::string name; + int fdesc; + int count[2]; +}; + +class audio_oss_dev +{ +private: + static std::vector::iterator get(int fdesc); + static std::vector::iterator get(const std::string device); + +public: + static int open(const std::string device, audio_oss_dev_type_t type); + static int close(int fdesc, audio_oss_dev_type_t type); +}; --- audio_oss_source.cc.orig 2004-10-04 04:27:39.000000000 +0930 +++ audio_oss_source.cc 2004-10-17 10:52:53.000000000 +0930 @@ -24,6 +24,7 @@ #include "config.h" #endif +#include #include #include #include @@ -48,7 +49,7 @@ d_sampling_freq (sampling_freq), d_device_name (device_name), d_fd (-1), d_buffer (0), d_chunk_size (0) { - if ((d_fd = open (device_name.c_str (), O_RDONLY)) < 0){ + if ((d_fd = audio_oss_dev::open (device_name.c_str (), AUDIO_OSS_DEV_SOURCE)) < 0){ fprintf (stderr, "audio_oss_source: "); perror (device_name.c_str ()); throw std::runtime_error ("audio_oss_source"); --- audio_oss_sink.cc.orig 2004-10-04 04:27:24.000000000 +0930 +++ audio_oss_sink.cc 2004-10-17 10:57:49.000000000 +0930 @@ -24,6 +24,7 @@ #include "config.h" #endif +#include #include #include #include @@ -36,7 +37,6 @@ #include #include - static const double CHUNK_TIME = 0.001; // 1 ms @@ -48,7 +48,7 @@ d_sampling_freq (sampling_freq), d_device_name (device_name), d_fd (-1), d_buffer (0), d_chunk_size (0) { - if ((d_fd = open (device_name.c_str (), O_WRONLY)) < 0){ + if ((d_fd = audio_oss_dev::open (device_name, AUDIO_OSS_DEV_SINK)) < 0){ fprintf (stderr, "audio_oss_sink: "); perror (device_name.c_str ()); throw std::runtime_error ("audio_oss_sink"); @@ -95,7 +95,7 @@ audio_oss_sink::~audio_oss_sink () { - close (d_fd); + audio_oss_dev::close (d_fd, AUDIO_OSS_DEV_SOURCE); delete [] d_buffer; }