diff --git a/CMakeLists.txt b/CMakeLists.txt index 465516075..5d4a7190e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,8 @@ add_definitions (-DHAVE_BOOST set (BOOST_LINK_LIBS ${Boost_LIBRARIES}) -#message(STATUS "Libs: " ${BOOST_LINK_LIBS}) -#message(STATUS "Includes: " ${Boost_INCLUDE_DIRS}) +#message(STATUS "boost libs: " ${BOOST_LINK_LIBS}) +#message(STATUS "boost includes: " ${Boost_INCLUDE_DIRS}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Modules) @@ -55,6 +55,6 @@ add_subdirectory(src/3rdparty) add_subdirectory(src/core) add_subdirectory(src/musikbox) add_subdirectory(src/contrib/taglib_plugin) -add_subdirectory(src/contrib/mp3decoder) +add_subdirectory(src/contrib/oggdecoder) add_subdirectory(src/contrib/mpg123decoder) add_subdirectory(src/contrib/coreaudioout) diff --git a/src/contrib/coreaudioout/CMakeLists.txt b/src/contrib/coreaudioout/CMakeLists.txt index bdd8d16af..45450d67a 100644 --- a/src/contrib/coreaudioout/CMakeLists.txt +++ b/src/contrib/coreaudioout/CMakeLists.txt @@ -3,9 +3,15 @@ set (coreaudioout_SOURCES CoreAudioOut.cpp ) -add_definitions( - -D_DEBUG -) +IF(APPLE) + FIND_LIBRARY(CORE_FOUNDATION_LIBRARY CoreFoundation) + FIND_LIBRARY(CORE_AUDIO_LIBRARY CoreAudio) + FIND_LIBRARY(AUDIO_TOOLBOX_LIBRARY AudioToolbox) + MARK_AS_ADVANCED (CORE_FOUNDATION_LIBRARY + CORE_AUDIO_LIBRARY + AUDIO_TOOLBOX_LIBRARY) + SET(FRAMEWORK_LIBS ${CORE_FOUNDATION_LIBRARY} ${CORE_AUDIO_LIBRARY} ${AUDIO_TOOLBOX_LIBRARY}) +ENDIF (APPLE) add_library(coreaudioout SHARED ${coreaudioout_SOURCES}) -target_link_libraries(coreaudioout ${musikbox_LINK_LIBS}) +target_link_libraries(coreaudioout ${musikbox_LINK_LIBS} ${FRAMEWORK_LIBS}) diff --git a/src/contrib/coreaudioout/CoreAudioOut.cpp b/src/contrib/coreaudioout/CoreAudioOut.cpp index e73893b87..251760fc9 100644 --- a/src/contrib/coreaudioout/CoreAudioOut.cpp +++ b/src/contrib/coreaudioout/CoreAudioOut.cpp @@ -1,35 +1,183 @@ #include "CoreAudioOut.h" +#include + +#define BUFFER_COUNT 3 + using namespace musik::core::audio; +void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) +{ + OSStatus result = AudioQueueFreeBuffer(queue, buffer); + + if (result != 0) { + std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n"; + } + + CoreAudioOut* output = (CoreAudioOut *) customData; + IBuffer* coreBuffer = (IBuffer *) buffer->mUserData; + output->NotifyBufferCompleted(coreBuffer); +} + +void CoreAudioOut::NotifyBufferCompleted(IBuffer *buffer) { + boost::recursive_mutex::scoped_lock lock(this->mutex); + --bufferCount; + this->bufferProvider->OnBufferProcessed(buffer); +} + CoreAudioOut::CoreAudioOut() { + this->bufferProvider = NULL; + this->quit = false; + this->bufferCount = 0; -} + this->audioFormat = (AudioStreamBasicDescription) { 0 }; -CoreAudioOut::~CoreAudioOut() { + this->audioFormat.mFormatID = kAudioFormatLinearPCM; + this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat; + this->audioFormat.mFramesPerPacket = 1; + this->audioFormat.mBitsPerChannel = 32; + this->audioFormat.mReserved = 0; -} - -void CoreAudioOut::Destroy() { - -} - -void CoreAudioOut::Pause() { - -} - -void CoreAudioOut::Resume() { - -} - -void CoreAudioOut::SetVolume(double volume) { - -} - -void CoreAudioOut::Stop() { + /* these get filled in later */ + this->audioFormat.mChannelsPerFrame = -1; + this->audioFormat.mSampleRate = -1; + this->audioFormat.mBytesPerFrame = -1; + this->audioFormat.mBytesPerPacket = -1; + this->audioQueue = NULL; } bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) { - return false; + boost::recursive_mutex::scoped_lock lock(this->mutex); + + if (this->bufferCount >= BUFFER_COUNT) { + /* enough buffers are already in the queue. bail, we'll notify the + caller when there's more data available */ + return false; + } + + OSStatus result; + + if (buffer->SampleRate() != this->audioFormat.mSampleRate || + buffer->Channels() != this->audioFormat.mChannelsPerFrame || + this->audioQueue == NULL) + { + this->audioFormat.mSampleRate = buffer->SampleRate(); + this->audioFormat.mChannelsPerFrame = buffer->Channels(); + this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame; + this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket; + + this->Stop(); + + result = AudioQueueNewOutput( + &this->audioFormat, + audioCallback, + this, + NULL, + kCFRunLoopCommonModes, + 0, + &this->audioQueue); + + if (result != 0) { + std::cerr << "AudioQueueNewOutput failed: " << result << "\n"; + return false; + } + + result = AudioQueueStart(this->audioQueue, NULL); + + if (result != 0) { + std::cerr << "AudioQueueStart failed: " << result << "\n"; + return false; + } + } + + this->bufferProvider = provider; + + AudioQueueBufferRef audioQueueBuffer = NULL; + + result = AudioQueueAllocateBuffer( + this->audioQueue, buffer->Bytes(), &audioQueueBuffer); + + if (result != 0) { + std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n"; + return false; + } + + audioQueueBuffer->mUserData = (void *) buffer; + audioQueueBuffer->mAudioDataByteSize = buffer->Bytes(); + + memcpy( + audioQueueBuffer->mAudioData, + (void *) buffer->BufferPointer(), + buffer->Bytes()); + + result = AudioQueueEnqueueBuffer( + this->audioQueue, audioQueueBuffer, 0, NULL); + + if (result != 0) { + std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n"; + return false; + } + + ++bufferCount; + + return true; +} + +CoreAudioOut::~CoreAudioOut() { + this->Stop(); +} + +void CoreAudioOut::Destroy() { + delete this; +} + +void CoreAudioOut::Pause() { + boost::recursive_mutex::scoped_lock lock(this->mutex); + + if (this->audioQueue) { + AudioQueuePause(this->audioQueue); + } +} + +void CoreAudioOut::Resume() { + boost::recursive_mutex::scoped_lock lock(this->mutex); + + if (this->audioQueue) { + AudioQueueStart(this->audioQueue, NULL); + } +} + +void CoreAudioOut::SetVolume(double volume) { + boost::recursive_mutex::scoped_lock lock(this->mutex); + + if (this->audioQueue) { + OSStatus result = AudioQueueSetParameter( + this->audioQueue, + kAudioQueueParam_Volume, + volume); + + if (result != 0) { + std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n"; + + } + } +} + +void CoreAudioOut::Stop() { + AudioQueueRef queue = NULL; + + { + /* AudioQueueStop/AudioQueueDispose will trigger the callback, which + will try to dispose of the samples on a separate thread and deadlock. + cache the queue and reset outside of the critical section */ + boost::recursive_mutex::scoped_lock lock(this->mutex); + queue = this->audioQueue; + this->audioQueue = NULL; + } + + if (queue) { + AudioQueueStop(queue, true); + AudioQueueDispose(queue, true); + } } diff --git a/src/contrib/coreaudioout/CoreAudioOut.h b/src/contrib/coreaudioout/CoreAudioOut.h index 1205fbbc2..20742c64f 100644 --- a/src/contrib/coreaudioout/CoreAudioOut.h +++ b/src/contrib/coreaudioout/CoreAudioOut.h @@ -2,6 +2,13 @@ #include #include +#include +#include +#include +#include +#include +#include +#include class CoreAudioOut : public musik::core::audio::IOutput { public: @@ -17,4 +24,15 @@ class CoreAudioOut : public musik::core::audio::IOutput { virtual bool Play( musik::core::audio::IBuffer *buffer, musik::core::audio::IBufferProvider *provider); + + void NotifyBufferCompleted(musik::core::audio::IBuffer *buffer); + + private: + musik::core::audio::IBufferProvider *bufferProvider; + AudioStreamBasicDescription audioFormat; + AudioQueueRef audioQueue; + size_t bufferCount; + boost::thread thread; + boost::recursive_mutex mutex; + bool quit; }; diff --git a/src/contrib/mpg123decoder/mpg123decoder_plugin.cpp b/src/contrib/mpg123decoder/mpg123decoder_plugin.cpp index 9fa0d87e6..a27967430 100644 --- a/src/contrib/mpg123decoder/mpg123decoder_plugin.cpp +++ b/src/contrib/mpg123decoder/mpg123decoder_plugin.cpp @@ -26,5 +26,5 @@ extern "C" DLLEXPORT musik::core::IPlugin* GetPlugin() { } extern "C" DLLEXPORT musik::core::audio::IDecoderFactory* GetDecoderFactory() { - return new Mpg123DecoderFactory(); + return new Mpg123DecoderFactory(); } diff --git a/src/contrib/oggdecoder/CMakeLists.txt b/src/contrib/oggdecoder/CMakeLists.txt index 3f0c08ca2..c575509e3 100644 --- a/src/contrib/oggdecoder/CMakeLists.txt +++ b/src/contrib/oggdecoder/CMakeLists.txt @@ -1,26 +1,9 @@ -set ( oggdecoder_SOURCES - oggdecoder_plugin.cpp - OGGDecoder.cpp - OggSourceSupplier.cpp - stdafx.cpp - ) - -if(CMAKE_SYSTEM_NAME MATCHES "Windows") - add_definitions(-DWIN32) - if(NOT DEFINED MINGW) - - endif(NOT DEFINED MINGW) -else(CMAKE_SYSTEM_NAME MATCHES "Windows") - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fpermissive) -endif(CMAKE_SYSTEM_NAME MATCHES "Windows") - -add_definitions( - -DXML_STATIC - -D_CRT_SECURE_NO_DEPRECATE - -D_DEBUG +set (oggdecoder_SOURCES + oggdecoder_plugin.cpp + OggDecoder.cpp + OggDecoderFactory.cpp + stdafx.cpp ) -add_library( oggdecoder SHARED ${oggdecoder_SOURCES} ) -target_link_libraries( oggdecoder ${musikCube_LINK_LIBS}) - - +add_library(oggdecoder SHARED ${oggdecoder_SOURCES}) +target_link_libraries(oggdecoder ${musikbox_LINK_LIBS} ogg vorbis vorbisfile) diff --git a/src/contrib/oggdecoder/oggdecoder_plugin.cpp b/src/contrib/oggdecoder/oggdecoder_plugin.cpp index 50ffc6411..7d890612b 100644 --- a/src/contrib/oggdecoder/oggdecoder_plugin.cpp +++ b/src/contrib/oggdecoder/oggdecoder_plugin.cpp @@ -40,9 +40,17 @@ #include "OggDecoderFactory.h" +#ifdef WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +#ifdef WIN32 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return true; } +#endif class OggDecoderPlugin : public musik::core::IPlugin { public: @@ -52,10 +60,10 @@ public: const char* Author() { return "Björn Olievier, _avatar"; }; }; -extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin() { +extern "C" DLLEXPORT musik::core::IPlugin* GetPlugin() { return new OggDecoderPlugin(); } -extern "C" __declspec(dllexport) IDecoderFactory* GetDecoderFactory() { +extern "C" DLLEXPORT IDecoderFactory* GetDecoderFactory() { return new OggDecoderFactory(); }