00001
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
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
00117
00118 EventQueue events = m_events;
00119
00120
00121 while (!m_events.empty()) {
00122 m_events.pop();
00123 }
00124
00125 m_event_mutex.unlock();
00126
00127
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
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
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
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
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 }