mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-01 01:13:28 +00:00
- Only use mpg123decoder in *nix -- the Tuniac one doesn't work out of the box
- Added CMake support for oggdecoder - Fleshed out most of the CoreAudioOut implementation -- but it's playing at 2x speed (some sort of buffering issue)
This commit is contained in:
parent
e172c258e4
commit
7ed083a692
@ -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)
|
||||
|
@ -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})
|
||||
|
@ -1,35 +1,183 @@
|
||||
#include "CoreAudioOut.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,13 @@
|
||||
|
||||
#include <core/sdk/IOutput.h>
|
||||
#include <core/sdk/IBufferProvider.h>
|
||||
#include <queue>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <AudioToolbox/AudioQueue.h>
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CFRunLoop.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user