00001 #include <algorithm>
00002 #include <sstream>
00003 #include <math.h>
00004 #include "device_ds.h"
00005 #include "device_ds_stream.h"
00006 #include "device_ds_buffer.h"
00007 #include "debug.h"
00008 #include "utility.h"
00009
00010
00011 namespace audiere {
00012
00013 static const int DEFAULT_BUFFER_LENGTH = 1000;
00014
00015
00016 DSAudioDevice*
00017 DSAudioDevice::create(const ParameterList& parameters) {
00018 ADR_GUARD("DSAudioDevice::create");
00019
00020
00021 int stream_buffer_length = parameters.getInt("buffer", 0);
00022 if (stream_buffer_length <= 0) {
00023 stream_buffer_length = DEFAULT_BUFFER_LENGTH;
00024 }
00025 int min_buffer_length = parameters.getInt("min_buffer_size", 0);
00026 min_buffer_length = std::max(1, min_buffer_length);
00027 bool global_focus = parameters.getBoolean("global", true);
00028
00029
00030 HRESULT rv = CoInitialize(NULL);
00031 if (FAILED(rv)) {
00032 return 0;
00033 }
00034
00035 ADR_LOG("COM initialized properly");
00036
00037
00038
00039 WNDCLASS wc;
00040 wc.style = 0;
00041 wc.lpfnWndProc = DefWindowProc;
00042 wc.cbClsExtra = 0;
00043 wc.cbWndExtra = 0;
00044 wc.hInstance = GetModuleHandle(NULL);
00045 wc.hIcon = NULL;
00046 wc.hCursor = NULL;
00047 wc.hbrBackground = NULL;
00048 wc.lpszMenuName = NULL;
00049 wc.lpszClassName = "AudiereHiddenWindow";
00050 RegisterClass(&wc);
00051
00052
00053 HWND anonymous_window = CreateWindow(
00054 "AudiereHiddenWindow", "", WS_POPUP,
00055 0, 0, 0, 0,
00056 NULL, NULL, GetModuleHandle(NULL), NULL);
00057 if (!anonymous_window) {
00058 return false;
00059 }
00060
00061 ADR_LOG("Anonymous window created successfully");
00062
00063
00064 IDirectSound* direct_sound;
00065 rv = CoCreateInstance(
00066 CLSID_DirectSound,
00067 NULL,
00068 CLSCTX_INPROC_SERVER,
00069 IID_IDirectSound,
00070 (void**)&direct_sound);
00071 if (FAILED(rv) || !direct_sound) {
00072 DestroyWindow(anonymous_window);
00073 return 0;
00074 }
00075
00076 ADR_LOG("Created DS object");
00077
00078 LPGUID guid = NULL;
00079 GUID stack_guid;
00080
00081 std::string guid_string = parameters.getValue("device_guid", "");
00082 if (!guid_string.empty()) {
00083 if (UuidFromString((unsigned char*)guid_string.c_str(), &stack_guid) == RPC_S_OK) {
00084 guid = &stack_guid;
00085 }
00086 }
00087
00088
00089 rv = direct_sound->Initialize(guid);
00090 if (FAILED(rv)) {
00091 DestroyWindow(anonymous_window);
00092 direct_sound->Release();
00093 return 0;
00094 }
00095
00096 ADR_LOG("Initialized DS object");
00097
00098
00099 rv = direct_sound->SetCooperativeLevel(anonymous_window, DSSCL_NORMAL);
00100 if (FAILED(rv)) {
00101 DestroyWindow(anonymous_window);
00102 direct_sound->Release();
00103 return 0;
00104 }
00105
00106 ADR_LOG("Set cooperative level");
00107
00108 return new DSAudioDevice(
00109 global_focus, stream_buffer_length, min_buffer_length,
00110 anonymous_window, direct_sound);
00111 }
00112
00113
00114 DSAudioDevice::DSAudioDevice(
00115 bool global_focus,
00116 int stream_buffer_length,
00117 int min_buffer_length,
00118 HWND anonymous_window,
00119 IDirectSound* direct_sound)
00120 {
00121 m_global_focus = global_focus;
00122 m_buffer_length = stream_buffer_length;
00123 m_min_buffer_length = min_buffer_length;
00124 m_anonymous_window = anonymous_window;
00125 m_direct_sound = direct_sound;
00126 }
00127
00128
00129 DSAudioDevice::~DSAudioDevice() {
00130 ADR_ASSERT(m_open_streams.empty(),
00131 "DirectSound device should not die with open streams");
00132 ADR_ASSERT(m_open_buffers.empty(),
00133 "DirectSound device should not die with open buffers");
00134
00135
00136 if (m_direct_sound) {
00137 m_direct_sound->Release();
00138 m_direct_sound = NULL;
00139 }
00140
00141
00142 if (m_anonymous_window) {
00143 DestroyWindow(m_anonymous_window);
00144 m_anonymous_window = NULL;
00145 }
00146
00147 CoUninitialize();
00148 }
00149
00150
00151 void
00152 DSAudioDevice::update() {
00153 ADR_GUARD("DSAudioDevice::update");
00154
00155 {
00156
00157
00158 SYNCHRONIZED(this);
00159
00160
00161 StreamList::iterator i = m_open_streams.begin();
00162 while (i != m_open_streams.end()) {
00163 DSOutputStream* s = *i++;
00164 s->update();
00165 }
00166
00167
00168 BufferList::iterator j = m_open_buffers.begin();
00169 while (j != m_open_buffers.end()) {
00170 DSOutputBuffer* b = *j++;
00171 b->update();
00172 }
00173 }
00174
00175 Sleep(50);
00176 }
00177
00178
00179 OutputStream*
00180 DSAudioDevice::openStream(SampleSource* source) {
00181 if (!source) {
00182 return 0;
00183 }
00184
00185 ADR_GUARD("DSAudioDevice::openStream");
00186
00187 int channel_count, sample_rate;
00188 SampleFormat sample_format;
00189 source->getFormat(channel_count, sample_rate, sample_format);
00190
00191 const int frame_size = channel_count * GetSampleSize(sample_format);
00192
00193
00194 const int buffer_length = sample_rate * m_buffer_length / 1000;
00195
00196
00197 WAVEFORMATEX wfx;
00198 memset(&wfx, 0, sizeof(wfx));
00199 wfx.wFormatTag = WAVE_FORMAT_PCM;
00200 wfx.nChannels = channel_count;
00201 wfx.nSamplesPerSec = sample_rate;
00202 wfx.nAvgBytesPerSec = sample_rate * frame_size;
00203 wfx.nBlockAlign = frame_size;
00204 wfx.wBitsPerSample = GetSampleSize(sample_format) * 8;
00205 wfx.cbSize = sizeof(wfx);
00206
00207 DSBUFFERDESC dsbd;
00208 memset(&dsbd, 0, sizeof(dsbd));
00209 dsbd.dwSize = sizeof(dsbd);
00210 dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN |
00211 DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
00212 if (m_global_focus) {
00213 dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS;
00214 }
00215 dsbd.dwBufferBytes = frame_size * buffer_length;
00216 dsbd.lpwfxFormat = &wfx;
00217
00218
00219 IDirectSoundBuffer* buffer;
00220 HRESULT result = m_direct_sound->CreateSoundBuffer(&dsbd, &buffer, NULL);
00221 if (FAILED(result) || !buffer) {
00222 return 0;
00223 }
00224
00225 ADR_LOG("CreateSoundBuffer succeeded");
00226
00227
00228 DSOutputStream* stream = new DSOutputStream(
00229 this, buffer, buffer_length, source);
00230
00231
00232 SYNCHRONIZED(this);
00233 m_open_streams.push_back(stream);
00234 return stream;
00235 }
00236
00237
00238 OutputStream*
00239 DSAudioDevice::openBuffer(
00240 void* samples, int frame_count,
00241 int channel_count, int sample_rate, SampleFormat sample_format)
00242 {
00243 ADR_GUARD("DSAudioDevice::openBuffer");
00244
00245 const int frame_size = channel_count * GetSampleSize(sample_format);
00246
00247 WAVEFORMATEX wfx;
00248 memset(&wfx, 0, sizeof(wfx));
00249 wfx.wFormatTag = WAVE_FORMAT_PCM;
00250 wfx.nChannels = channel_count;
00251 wfx.nSamplesPerSec = sample_rate;
00252 wfx.nAvgBytesPerSec = sample_rate * frame_size;
00253 wfx.nBlockAlign = frame_size;
00254 wfx.wBitsPerSample = GetSampleSize(sample_format) * 8;
00255 wfx.cbSize = sizeof(wfx);
00256
00257 DSBUFFERDESC dsbd;
00258 memset(&dsbd, 0, sizeof(dsbd));
00259 dsbd.dwSize = sizeof(dsbd);
00260 dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN |
00261 DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
00262 DSBCAPS_STATIC | DSBCAPS_CTRLPOSITIONNOTIFY;
00263 if (m_global_focus) {
00264 dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS;
00265 }
00266
00267 const int buffer_frame_count = std::max(m_min_buffer_length, frame_count);
00268 const int buffer_size = buffer_frame_count * frame_size;
00269 dsbd.dwBufferBytes = buffer_size;
00270 dsbd.lpwfxFormat = &wfx;
00271
00272
00273 IDirectSoundBuffer* buffer;
00274 HRESULT result = m_direct_sound->CreateSoundBuffer(
00275 &dsbd, &buffer, NULL);
00276 if (FAILED(result) || !buffer) {
00277 return 0;
00278 }
00279
00280 ADR_IF_DEBUG {
00281 DSBCAPS caps;
00282 caps.dwSize = sizeof(caps);
00283 result = buffer->GetCaps(&caps);
00284 if (FAILED(result)) {
00285 buffer->Release();
00286 return 0;
00287 } else {
00288 std::ostringstream ss;
00289 ss << "actual buffer size: " << caps.dwBufferBytes << std::endl
00290 << "buffer_size: " << buffer_size;
00291 ADR_LOG(ss.str().c_str());
00292 }
00293 }
00294
00295 void* data;
00296 DWORD data_size;
00297 result = buffer->Lock(0, buffer_size, &data, &data_size, 0, 0, 0);
00298 if (FAILED(result)) {
00299 buffer->Release();
00300 return 0;
00301 }
00302
00303 ADR_IF_DEBUG {
00304 std::ostringstream ss;
00305 ss << "buffer size: " << buffer_size << std::endl
00306 << "data size: " << data_size << std::endl
00307 << "frame count: " << frame_count;
00308 ADR_LOG(ss.str().c_str());
00309 }
00310
00311 const int actual_size = frame_count * frame_size;
00312 memcpy(data, samples, actual_size);
00313 memset((u8*)data + actual_size, 0, buffer_size - actual_size);
00314
00315 buffer->Unlock(data, data_size, 0, 0);
00316
00317 DSOutputBuffer* b = new DSOutputBuffer(
00318 this, buffer, buffer_frame_count, frame_size);
00319 SYNCHRONIZED(this);
00320 m_open_buffers.push_back(b);
00321 return b;
00322 }
00323
00324
00325 const char* ADR_CALL
00326 DSAudioDevice::getName() {
00327 return "directsound";
00328 }
00329
00330
00331 void
00332 DSAudioDevice::removeStream(DSOutputStream* stream) {
00333 SYNCHRONIZED(this);
00334 m_open_streams.remove(stream);
00335 }
00336
00337
00338 void
00339 DSAudioDevice::removeBuffer(DSOutputBuffer* buffer) {
00340 SYNCHRONIZED(this);
00341 m_open_buffers.remove(buffer);
00342 }
00343
00344
00345 int
00346 DSAudioDevice::Volume_AudiereToDirectSound(float volume) {
00347 if (volume == 0) {
00348 return -10000;
00349 } else {
00350 double attenuate = 1000 * log(1 / volume);
00351 return int(-attenuate);
00352 }
00353 }
00354
00355
00356 int
00357 DSAudioDevice::Pan_AudiereToDirectSound(float pan) {
00358 if (pan < 0) {
00359 return -Pan_AudiereToDirectSound(-pan);
00360 } else {
00361 return -Volume_AudiereToDirectSound(1 - pan);
00362 }
00363 }
00364
00365 }