device.cpp

Go to the documentation of this file.
00001 // *sigh*, looking forward to VS.NET...
00002 #ifdef _MSC_VER
00003 #pragma warning(disable : 4786)
00004 #endif
00005 
00006 
00007 #include <string>
00008 #include "audiere.h"
00009 #include "debug.h"
00010 #include "device_null.h"
00011 #include "internal.h"
00012 #include "threads.h"
00013 
00014 #ifdef _MSC_VER
00015 
00016   #include <windows.h>
00017   #include <mmsystem.h>
00018   #include "device_ds.h"
00019   #include "device_mm.h"
00020 
00021 #endif
00022 
00023 #ifdef HAVE_OSS
00024   #include "device_oss.h"
00025 #endif
00026 
00027 #ifdef HAVE_AL
00028   #include "device_al.h"
00029 #endif
00030 
00031 #ifdef HAVE_DSOUND
00032   #include "device_ds.h"
00033 #endif
00034 
00035 #ifdef HAVE_WINMM
00036   #include "device_mm.h"
00037 #endif
00038 
00039 
00040 namespace audiere {
00041 
00042   AbstractDevice::AbstractDevice() {
00043     m_thread_exists = false;
00044     m_thread_should_die = false;
00045 
00046     bool result = AI_CreateThread(eventThread, this, 2);
00047     if (!result) {
00048       ADR_LOG("THREAD CREATION FAILED");
00049     }
00050   }
00051 
00052   AbstractDevice::~AbstractDevice() {
00053     m_thread_should_die = true;
00054 
00055     // Trick the thread into no longer waiting.
00056     m_events_available.notify();
00057 
00058     while (m_thread_exists) {
00059       AI_Sleep(50);
00060     }
00061   }
00062 
00063   void AbstractDevice::registerCallback(Callback* callback) {
00064     m_callbacks.push_back(callback);
00065   }
00066 
00067   void AbstractDevice::unregisterCallback(Callback* callback) {
00068     for (size_t i = 0; i < m_callbacks.size(); ++i) {
00069       if (m_callbacks[i] == callback) {
00070         m_callbacks.erase(m_callbacks.begin() + i);
00071         return;
00072       }
00073     }
00074   }
00075 
00076   void AbstractDevice::clearCallbacks() {
00077     m_callbacks.clear();
00078   }
00079 
00080   void AbstractDevice::fireStopEvent(OutputStream* stream, StopEvent::Reason reason) {
00081     StopEventPtr event = new StopEventImpl(stream, reason);
00082     fireStopEvent(event);
00083   }
00084 
00085   void AbstractDevice::fireStopEvent(const StopEventPtr& event) {
00086     m_event_mutex.lock();
00087     m_events.push(event.get());
00088     m_event_mutex.unlock();
00089     m_events_available.notify();
00090   }
00091 
00092   void AbstractDevice::eventThread(void* arg) {
00093     ADR_GUARD("AbstractDevice::eventThread[static]");
00094     ADR_LOG(arg ? "arg is valid" : "arg is not valid");
00095     
00096     AbstractDevice* This = static_cast<AbstractDevice*>(arg);
00097     This->eventThread();
00098   }
00099 
00100   void AbstractDevice::eventThread() {
00101     ADR_GUARD("AbstractDevice::eventThread");
00102     m_thread_exists = true;
00103     while (!m_thread_should_die) {
00104       m_event_mutex.lock();
00105       while (m_events.empty()) {
00106         m_events_available.wait(m_event_mutex, 1);
00107         if (m_thread_should_die) {
00108           break;
00109         }
00110       }
00111       if (m_thread_should_die) {
00112         m_event_mutex.unlock();
00113         break;
00114       }
00115 
00116       // Make a local copy of the events so they can be processed without
00117       // leaving the mutex locked.
00118       EventQueue events = m_events;
00119 
00120       // Queues don't support clear().  o_o
00121       while (!m_events.empty()) {
00122         m_events.pop();
00123       }
00124 
00125       m_event_mutex.unlock();
00126 
00127       // Process the events.
00128       while (!events.empty()) {
00129         EventPtr event = events.front();
00130         events.pop();
00131         processEvent(event.get());
00132       }
00133     }
00134     m_thread_exists = false;
00135   }
00136 
00137   void AbstractDevice::processEvent(Event* event) {
00138     for (size_t i = 0; i < m_callbacks.size(); ++i) {
00139       if (event->getType() == m_callbacks[i]->getType()) {
00140         m_callbacks[i]->call(event);
00141       }
00142     }
00143   }
00144 
00145 
00146   ADR_EXPORT(const char*) AdrGetSupportedAudioDevices() {
00147     return
00148 #ifdef _MSC_VER
00149       "directsound:DirectSound (high-performance)"  ";"
00150       "winmm:Windows Multimedia (compatible)"  ";"
00151 #else
00152 #ifdef HAVE_OSS
00153       "oss:Open Sound System"  ";"
00154 #endif
00155 #ifdef HAVE_DSOUND
00156       "directsound:DirectSound (high-performance)"  ";"
00157 #endif
00158 #ifdef HAVE_WINMM
00159       "winmm:Windows Multimedia (compatible)"  ";"
00160 #endif
00161 #ifdef HAVE_AL
00162       "al:SGI AL"  ";"
00163 #endif
00164 #endif
00165       "null:Null output (no sound)"  ;
00166   }
00167 
00168 
00169   #define NEED_SEMICOLON do ; while (false)
00170 
00171   #define TRY_GROUP(group_name) {                               \
00172     AudioDevice* device = DoOpenDevice(group_name, parameters); \
00173     if (device) {                                               \
00174       return device;                                            \
00175     }                                                           \
00176   } NEED_SEMICOLON
00177 
00178   #define TRY_DEVICE(DeviceType) {                         \
00179     DeviceType* device = DeviceType::create(parameters);   \
00180     if (device) {                                          \
00181       return device;                                       \
00182     }                                                      \
00183   } NEED_SEMICOLON
00184 
00185 
00186   AudioDevice* DoOpenDevice(
00187     const std::string& name,
00188     const ParameterList& parameters)
00189   {
00190     ADR_GUARD("DoOpenDevice");
00191 
00192     #ifdef _MSC_VER
00193 
00194       if (name == "" || name == "autodetect") {
00195         TRY_GROUP("directsound");
00196         TRY_GROUP("winmm");
00197         return 0;
00198       }
00199 
00200       if (name == "directsound") {
00201         TRY_DEVICE(DSAudioDevice);
00202         return 0;
00203       }
00204 
00205       if (name == "winmm") {
00206         TRY_DEVICE(MMAudioDevice);
00207         return 0;
00208       }
00209 
00210       if (name == "null") {
00211         TRY_DEVICE(NullAudioDevice);
00212         return 0;
00213       }
00214 
00215     #else  // not Win32 - assume autoconf UNIX
00216 
00217       if (name == "" || name == "autodetect") {
00218         // in decreasing order of sound API quality
00219         TRY_GROUP("al");
00220         TRY_GROUP("directsound");
00221         TRY_GROUP("winmm");
00222         TRY_GROUP("oss");
00223         return 0;
00224       }
00225 
00226       #ifdef HAVE_OSS
00227         if (name == "oss") {
00228           TRY_DEVICE(OSSAudioDevice);
00229           return 0;
00230         }
00231       #endif
00232 
00233       #ifdef HAVE_DSOUND
00234         if (name == "directsound") {
00235           TRY_DEVICE(DSAudioDevice);
00236           return 0;
00237         }
00238       #endif
00239 
00240       #ifdef HAVE_WINMM
00241         if (name == "winmm") {
00242           TRY_DEVICE(MMAudioDevice);
00243           return 0;
00244         }
00245       #endif
00246 
00247       #ifdef HAVE_AL
00248         if (name == "al") {
00249           TRY_DEVICE(ALAudioDevice);
00250           return 0;
00251         }
00252       #endif
00253 
00254       if (name == "null") {
00255         TRY_DEVICE(NullAudioDevice);
00256         return 0;
00257       }
00258 
00259     #endif
00260 
00261     // no devices
00262     return 0;
00263   }
00264 
00265 
00266   class ThreadedDevice : public RefImplementation<AudioDevice> {
00267   public:
00268     ThreadedDevice(AudioDevice* device) {
00269       ADR_GUARD("ThreadedDevice::ThreadedDevice");
00270       if (device) {
00271         ADR_LOG("Device is valid");
00272       } else {
00273         ADR_LOG("Device is not valid");
00274       }
00275 
00276       m_device = device;
00277       m_thread_exists = false;
00278       m_thread_should_die = false;
00279 
00281       bool result = AI_CreateThread(threadRoutine, this, 2);
00282       if (!result) {
00283         ADR_LOG("THREAD CREATION FAILED");
00284       }
00285     }
00286 
00287     ~ThreadedDevice() {
00288       m_thread_should_die = true;
00289       while (m_thread_exists) {
00290         AI_Sleep(50);
00291       }
00292     }
00293 
00294     // don't need to update the device...  the thread does it for us
00295     void ADR_CALL update() {
00296     }
00297 
00298     OutputStream* ADR_CALL openStream(SampleSource* source) {
00299       return m_device->openStream(source);
00300     }
00301 
00302     OutputStream* ADR_CALL openBuffer(
00303       void* samples, int frame_count,
00304       int channel_count, int sample_rate, SampleFormat sample_format)
00305     {
00306       return m_device->openBuffer(
00307         samples, frame_count,
00308         channel_count, sample_rate, sample_format);
00309     }
00310 
00311     const char* ADR_CALL getName() {
00312       return m_device->getName();
00313     }
00314 
00315     void ADR_CALL registerCallback(Callback* callback) {
00316       m_device->registerCallback(callback);
00317     }
00318 
00319     void ADR_CALL unregisterCallback(Callback* callback) {
00320       m_device->unregisterCallback(callback);
00321     }
00322 
00323     void ADR_CALL clearCallbacks() {
00324       m_device->clearCallbacks();
00325     }
00326 
00327   private:
00328     void run() {
00329       ADR_GUARD("ThreadedDevice::run");
00330       m_thread_exists = true;
00331       while (!m_thread_should_die) {
00332         m_device->update();
00333       }
00334       m_thread_exists = false;
00335     }
00336 
00337     static void threadRoutine(void* arg) {
00338       ADR_GUARD("ThreadedDevice::threadRoutine");
00339       if (arg) {
00340         ADR_LOG("arg is valid");
00341       } else {
00342         ADR_LOG("arg is not valid");
00343       }
00344 
00345       ThreadedDevice* This = (ThreadedDevice*)arg;
00346       This->run();
00347     }
00348 
00349   private:
00350     RefPtr<AudioDevice> m_device;
00351     volatile bool m_thread_should_die;
00352     volatile bool m_thread_exists;
00353   };
00354 
00355 
00356   ADR_EXPORT(AudioDevice*) AdrOpenDevice(
00357     const char* name,
00358     const char* parameters)
00359   {
00360     ADR_GUARD("AdrOpenDevice");
00361 
00362     if (!name) {
00363       name = "";
00364     }
00365     if (!parameters) {
00366       parameters = "";
00367     }
00368 
00369     // first, we need an unthreaded audio device
00370     AudioDevice* device = DoOpenDevice(
00371       std::string(name),
00372       ParameterList(parameters));
00373     if (!device) {
00374       ADR_LOG("Could not open device");
00375       return 0;
00376     }
00377 
00378     ADR_LOG("creating threaded device");
00379     return new ThreadedDevice(device);
00380   }
00381 
00382 }

Generated on Mon Feb 13 23:07:46 2006 for audiere by  doxygen 1.4.6