void ALAudioDevice::update() { ADR_GUARD("ALAudioDevice::update"); // how much data can we write? const int filled = alGetFilled(m_port); int can_write = 5000 - filled; // empty portion of the buffer // write 1024 frames at a time static const int BUFFER_SIZE = 1024; u8 buffer[BUFFER_SIZE * 4]; while (can_write > 0) { int transfer_count = std::min(can_write, BUFFER_SIZE); ADR_LOG("reading"); read(transfer_count, buffer); ADR_LOG("writing"); alWriteFrames(m_port, buffer, transfer_count); can_write -= transfer_count; } usleep(50000); // 50 milliseconds }
void AbstractDevice::eventThread(void* arg) { ADR_GUARD("AbstractDevice::eventThread[static]"); ADR_LOG(arg ? "arg is valid" : "arg is not valid"); AbstractDevice* This = static_cast<AbstractDevice*>(arg); This->eventThread(); }
void MMAudioDevice::update() { ADR_GUARD("MMAudioDevice::update"); // if a buffer is done playing, add it to the queue again for (int i = 0; i < BUFFER_COUNT; ++i) { WAVEHDR& wh = m_buffers[i]; if (wh.dwFlags & WHDR_DONE) { // unprepare MMRESULT result = waveOutUnprepareHeader(m_device, &wh, sizeof(wh)); if (result != MMSYSERR_NOERROR) { ADR_LOG("waveOutUnprepareHeader failed"); } // fill with new samples read(BUFFER_LENGTH / 4, wh.lpData); wh.dwFlags = 0; // prepare result = waveOutPrepareHeader(m_device, &wh, sizeof(wh)); if (result != MMSYSERR_NOERROR) { ADR_LOG("waveOutPrepareHeader failed"); } // write result = waveOutWrite(m_device, &wh, sizeof(wh)); if (result != MMSYSERR_NOERROR) { ADR_LOG("waveOutWrite failed"); } } } Sleep(10); }
void DSAudioDevice::update() { ADR_GUARD("DSAudioDevice::update"); { /* Put the critical section in its own scope so we don't hold the lock while sleeping. --MattC */ SYNCHRONIZED(this); // enumerate all open streams StreamList::iterator i = m_open_streams.begin(); while (i != m_open_streams.end()) { DSOutputStream* s = *i++; s->update(); } // enumerate all open buffers BufferList::iterator j = m_open_buffers.begin(); while (j != m_open_buffers.end()) { DSOutputBuffer* b = *j++; b->update(); } } Sleep(50); }
MMAudioDevice::MMAudioDevice(HWAVEOUT device, int rate) : MixerDevice(rate) { ADR_GUARD("MMAudioDevice::MMAudioDevice"); m_device = device; m_current_buffer = 0; // fill each buffer with samples and prepare it for output for (int i = 0; i < BUFFER_COUNT; ++i) { WAVEHDR& wh = m_buffers[i]; memset(&wh, 0, sizeof(wh)); wh.lpData = (char*)m_samples + i * BUFFER_LENGTH; wh.dwBufferLength = BUFFER_LENGTH; read(BUFFER_LENGTH / 4, wh.lpData); MMRESULT result = waveOutPrepareHeader(m_device, &wh, sizeof(wh)); if (result != MMSYSERR_NOERROR) { ADR_LOG("waveOutPrepareHeader failed"); } result = waveOutWrite(m_device, &wh, sizeof(wh)); if (result != MMSYSERR_NOERROR) { ADR_LOG("waveOutWrite failed"); } } }
ALAudioDevice::ALAudioDevice(ALport port, int rate) : MixerDevice(rate) { ADR_GUARD("ALAudioDevice::ALAudioDevice"); m_port = port; }
bool AIFFInputStream::findSoundChunk() { ADR_GUARD("AIFFInputStream::findSoundChunk"); // seek to just after the IFF header m_file->seek(12, File::BEGIN); // search for a sound chunk while (true) { u8 chunk_header[8]; if (m_file->read(chunk_header, 8) != 8) { ADR_LOG("Couldn't read SSND chunk header"); return false; } u32 chunk_length = read32_be(chunk_header + 4); // if we found a data chunk, excellent! if (memcmp(chunk_header, "SSND", 4) == 0) { ADR_LOG("Found sound chunk"); u8 chunk_contents[8]; if (m_file->read(chunk_contents, 8) != 8) { ADR_LOG("Couldn't read SSND chunk contents"); return false; } if (read32_be(chunk_contents + 0) != 0 || read32_be(chunk_contents + 4) != 0) { ADR_LOG("Block-aligned AIFF files not supported!"); return false; } // calculate the frame size so we can truncate the data chunk int frame_size = m_channel_count * GetSampleSize(m_sample_format); m_data_chunk_location = m_file->tell(); m_data_chunk_length = (chunk_length - 8) / frame_size; m_frames_left_in_chunk = m_data_chunk_length; return true; } else { ADR_IF_DEBUG { const u8* ci = chunk_header; char str[80]; sprintf(str, "Skipping: %d bytes in chunk '%c%c%c%c'", (int)chunk_length, ci[0], ci[1], ci[2], ci[3]); ADR_LOG(str); } // skip the rest of the chunk if (!skipBytes(chunk_length)) { // oops, end of stream return false; } } } }
OutputStream* DSAudioDevice::openStream(SampleSource* source) { if (!source) { return 0; } ADR_GUARD("DSAudioDevice::openStream"); int channel_count, sample_rate; SampleFormat sample_format; source->getFormat(channel_count, sample_rate, sample_format); const int frame_size = channel_count * GetSampleSize(sample_format); // calculate an ideal buffer size const int buffer_length = sample_rate * m_buffer_length / 1000; // define the wave format WAVEFORMATEX wfx; memset(&wfx, 0, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = channel_count; wfx.nSamplesPerSec = sample_rate; wfx.nAvgBytesPerSec = sample_rate * frame_size; wfx.nBlockAlign = frame_size; wfx.wBitsPerSample = GetSampleSize(sample_format) * 8; wfx.cbSize = sizeof(wfx); DSBUFFERDESC dsbd; memset(&dsbd, 0, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; if (m_global_focus) { dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; } dsbd.dwBufferBytes = frame_size * buffer_length; dsbd.lpwfxFormat = &wfx; // create the DirectSound buffer IDirectSoundBuffer* buffer; HRESULT result = m_direct_sound->CreateSoundBuffer(&dsbd, &buffer, NULL); if (FAILED(result) || !buffer) { return 0; } ADR_LOG("CreateSoundBuffer succeeded"); // now create the output stream DSOutputStream* stream = new DSOutputStream( this, buffer, buffer_length, source); // add it the list of streams and return SYNCHRONIZED(this); m_open_streams.push_back(stream); return stream; }
CondVar::CondVar() { ADR_GUARD("CondVar::CondVar"); m_impl = new Impl; m_impl->event = CreateEvent(0, FALSE, FALSE, 0); if (!m_impl->event) { ADR_LOG("CreateEvent() failed"); abort(); } }
DSOutputBuffer::~DSOutputBuffer() { ADR_GUARD("DSOutputBuffer::~DSOutputBuffer"); m_device->removeBuffer(this); if (m_stop_event) { CloseHandle(m_stop_event); } m_notify->Release(); m_buffer->Release(); }
void MP3InputStream::reset() { ADR_GUARD("MP3InputStream::reset"); m_file->seek(0, File::BEGIN); m_eof = false; m_buffer.clear(); if (m_seekable) mpg123_seek(mh, 0, SEEK_SET); else { mpg123_close(mh); mpg123_open_feed(mh); } m_input_position = 0; m_input_length = 0; m_position = 0; }
DSOutputBuffer::DSOutputBuffer( DSAudioDevice* device, IDirectSoundBuffer* buffer, int length, int frame_size) { ADR_GUARD("DSOutputBuffer::DSOutputBuffer"); m_device = device; // keep the device alive while the buffer exists m_buffer = buffer; m_length = length; m_frame_size = frame_size; DWORD frequency; m_buffer->GetFrequency(&frequency); m_base_frequency = frequency; m_repeating = false; m_volume = 1; m_pan = 0; m_stop_event = 0; // Set up the stop notification if we can. HRESULT rv = m_buffer->QueryInterface( IID_IDirectSoundNotify, (void**)&m_notify); if (SUCCEEDED(rv) && m_notify) { m_stop_event = CreateEvent(0, FALSE, FALSE, 0); if (!m_stop_event) { ADR_LOG("DSOutputBuffer stop event creation failed. Not firing stop events."); } else { DSBPOSITIONNOTIFY n; n.dwOffset = DSBPN_OFFSETSTOP; n.hEventNotify = m_stop_event; m_notify->SetNotificationPositions(1, &n); } } }
void AbstractDevice::eventThread() { ADR_GUARD("AbstractDevice::eventThread"); m_thread_exists = true; while (!m_thread_should_die) { m_event_mutex.lock(); while (m_events.empty()) { m_events_available.wait(m_event_mutex, 1); if (m_thread_should_die) { break; } } if (m_thread_should_die) { m_event_mutex.unlock(); break; } // Make a local copy of the events so they can be processed without // leaving the mutex locked. EventQueue events = m_events; // Queues don't support clear(). o_o while (!m_events.empty()) { m_events.pop(); } m_event_mutex.unlock(); // Process the events. while (!events.empty()) { EventPtr event = events.front(); events.pop(); processEvent(event.get()); } } m_thread_exists = false; }
ALSAAudioDevice::~ALSAAudioDevice() { ADR_GUARD("ALSAAudioDevice::~ALSAAudioDevice"); snd_pcm_drain(m_pcm_handle); snd_pcm_close(m_pcm_handle); delete [] m_buffer; }
AudioDevice* DoOpenDevice( const std::string& name, const ParameterList& parameters) { ADR_GUARD("DoOpenDevice"); #ifdef _MSC_VER if (name == "" || name == "autodetect") { TRY_GROUP("directsound"); TRY_GROUP("winmm"); return 0; } if (name == "directsound") { TRY_DEVICE(DSAudioDevice); return 0; } if (name == "winmm") { TRY_DEVICE(MMAudioDevice); return 0; } if (name == "null") { TRY_DEVICE(NullAudioDevice); return 0; } #else // not Win32 - assume autoconf UNIX if (name == "" || name == "autodetect") { // in decreasing order of sound API quality TRY_GROUP("al"); TRY_GROUP("directsound"); TRY_GROUP("winmm"); TRY_GROUP("oss"); return 0; } #ifdef HAVE_OSS if (name == "oss") { TRY_DEVICE(OSSAudioDevice); return 0; } #endif #ifdef HAVE_DSOUND if (name == "directsound") { TRY_DEVICE(DSAudioDevice); return 0; } #endif #ifdef HAVE_WINMM if (name == "winmm") { TRY_DEVICE(MMAudioDevice); return 0; } #endif #ifdef HAVE_AL if (name == "al") { TRY_DEVICE(ALAudioDevice); return 0; } #endif if (name == "null") { TRY_DEVICE(NullAudioDevice); return 0; } #endif // no devices return 0; }
OutputStream* DSAudioDevice::openBuffer( void* samples, int frame_count, int channel_count, int sample_rate, SampleFormat sample_format) { ADR_GUARD("DSAudioDevice::openBuffer"); const int frame_size = channel_count * GetSampleSize(sample_format); WAVEFORMATEX wfx; memset(&wfx, 0, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = channel_count; wfx.nSamplesPerSec = sample_rate; wfx.nAvgBytesPerSec = sample_rate * frame_size; wfx.nBlockAlign = frame_size; wfx.wBitsPerSample = GetSampleSize(sample_format) * 8; wfx.cbSize = sizeof(wfx); DSBUFFERDESC dsbd; memset(&dsbd, 0, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_STATIC | DSBCAPS_CTRLPOSITIONNOTIFY; if (m_global_focus) { dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS; } const int buffer_frame_count = std::max(m_min_buffer_length, frame_count); const int buffer_size = buffer_frame_count * frame_size; dsbd.dwBufferBytes = buffer_size; dsbd.lpwfxFormat = &wfx; // create the DS buffer IDirectSoundBuffer* buffer; HRESULT result = m_direct_sound->CreateSoundBuffer( &dsbd, &buffer, NULL); if (FAILED(result) || !buffer) { return 0; } ADR_IF_DEBUG { DSBCAPS caps; caps.dwSize = sizeof(caps); result = buffer->GetCaps(&caps); if (FAILED(result)) { buffer->Release(); return 0; } else { std::ostringstream ss; ss << "actual buffer size: " << caps.dwBufferBytes << std::endl << "buffer_size: " << buffer_size; ADR_LOG(ss.str().c_str()); } } void* data; DWORD data_size; result = buffer->Lock(0, buffer_size, &data, &data_size, 0, 0, 0); if (FAILED(result)) { buffer->Release(); return 0; } ADR_IF_DEBUG { std::ostringstream ss; ss << "buffer size: " << buffer_size << std::endl << "data size: " << data_size << std::endl << "frame count: " << frame_count; ADR_LOG(ss.str().c_str()); } const int actual_size = frame_count * frame_size; memcpy(data, samples, actual_size); memset((u8*)data + actual_size, 0, buffer_size - actual_size); buffer->Unlock(data, data_size, 0, 0); DSOutputBuffer* b = new DSOutputBuffer( this, buffer, buffer_frame_count, frame_size); SYNCHRONIZED(this); m_open_buffers.push_back(b); return b; }
ALAudioDevice::~ALAudioDevice() { ADR_GUARD("ALAudioDevice::~ALAudioDevice"); alClosePort(m_port); }
bool AIFFInputStream::findCommonChunk() { ADR_GUARD("AIFFInputStream::findCommonChunk"); // seek to just after the IFF header m_file->seek(12, File::BEGIN); // search for a common chunk for (;;) { u8 chunk_header[8]; if (m_file->read(chunk_header, 8) != 8) { return false; } u32 chunk_length = read32_be(chunk_header + 4); // if we found a format chunk, excellent! if (memcmp(chunk_header, "COMM", 4) == 0 && chunk_length >= 18) { ADR_LOG("Found common chunk"); // read common chunk u8 chunk[18]; if (m_file->read(chunk, 18) != 18) { return false; } chunk_length -= 18; // parse the memory into useful information u16 channel_count = read16_be(chunk + 0); //u32 frame_count = read32_be(chunk + 2); u16 bits_per_sample = read16_be(chunk + 6); u32 sample_rate = readLD_be(chunk + 8); // we only support mono and stereo, 8-bit or 16-bit if (channel_count > 2 || !isValidSampleSize(bits_per_sample)) { ADR_LOG("Invalid AIFF"); return false; } // skip the rest of the chunk if (!skipBytes(chunk_length)) { ADR_LOG("failed skipping rest of common chunk"); return false; } // figure out the sample format if (bits_per_sample == 8) { m_sample_format = SF_U8; } else if (bits_per_sample == 16) { m_sample_format = SF_S16; } else { return false; } // store the other important attributes m_channel_count = channel_count; m_sample_rate = sample_rate; return true; } else { // skip the rest of the chunk if (!skipBytes(chunk_length)) { // oops, end of stream return false; } } } }
AudioDevice* DoOpenDevice( const std::string& name, const ParameterList& parameters) { ADR_GUARD("DoOpenDevice"); if (name == "" || name == "autodetect") { // in decreasing order of sound API quality TRY_RECURSE("alsa"); TRY_RECURSE("al"); TRY_RECURSE("directsound"); TRY_RECURSE("winmm"); TRY_RECURSE("sdl"); TRY_RECURSE("pulse"); TRY_RECURSE("oss"); TRY_RECURSE("portaudio"); TRY_RECURSE("coreaudio"); return 0; } #ifdef HAVE_ALSA if (name == "alsa") { return MAKE_DEVICE(ALSAAudioDevice); } #endif #ifdef HAVE_OSS if (name == "oss") { return MAKE_DEVICE(OSSAudioDevice); } #endif #ifdef HAVE_SDL if (name == "sdl") { return MAKE_DEVICE(SDLAudioDevice); } #endif #ifdef HAVE_PULSE if (name == "pulse") { return MAKE_DEVICE(PulseAudioDevice); } #endif #ifdef HAVE_DSOUND if (name == "directsound") { return MAKE_DEVICE(DSAudioDevice); } #endif #ifdef HAVE_WINMM if (name == "winmm") { return MAKE_DEVICE(MMAudioDevice); } #endif #ifdef HAVE_AL if (name == "al") { return MAKE_DEVICE(ALAudioDevice); } #endif #ifdef HAVE_PA if (name == "portaudio") { return MAKE_DEVICE(PAAudioDevice); } #endif #ifdef HAVE_CORE_AUDIO if (name == "coreaudio") { return MAKE_DEVICE(CAAudioDevice); } #endif if (name == "null") { return MAKE_DEVICE(NullAudioDevice); } // no devices return 0; }
// totally replaced the wasteful vesion here int MP3InputStream::doRead(int frame_count, void* samples) { ADR_GUARD("MP3InputStream::doRead"); return decodeFrames(frame_count,samples); }