mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-23 04:09:43 +00:00
Progress on CoreAudio.framework
This commit is contained in:
parent
31d468bd53
commit
40ebd8d6e1
97
cmake/FindFFmpeg.cmake
Normal file
97
cmake/FindFFmpeg.cmake
Normal file
@ -0,0 +1,97 @@
|
||||
# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
|
||||
# Once done this will define
|
||||
#
|
||||
# FFMPEG_FOUND - system has ffmpeg or libav
|
||||
# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
|
||||
# FFMPEG_LIBRARIES - Link these to use ffmpeg
|
||||
# FFMPEG_LIBAVCODEC
|
||||
# FFMPEG_LIBAVFORMAT
|
||||
# FFMPEG_LIBAVUTIL
|
||||
#
|
||||
# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
|
||||
# Modified for other libraries by Lasse Kärkkäinen <tronic>
|
||||
# Modified for Hedgewars by Stepik777
|
||||
# Modified for FFmpeg-example Tuukka Pasanen 2018
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
#
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
|
||||
# in cache already
|
||||
set(FFMPEG_FOUND TRUE)
|
||||
else()
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
|
||||
pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
|
||||
pkg_check_modules(_FFMPEG_AVUTIL libavutil)
|
||||
endif()
|
||||
|
||||
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
|
||||
NAMES libavcodec/avcodec.h
|
||||
PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
PATH_SUFFIXES ffmpeg libav)
|
||||
|
||||
find_library(FFMPEG_LIBAVCODEC
|
||||
NAMES avcodec
|
||||
PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
find_library(FFMPEG_LIBAVFORMAT
|
||||
NAMES avformat
|
||||
PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
find_library(FFMPEG_LIBAVUTIL
|
||||
NAMES avutil
|
||||
PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib)
|
||||
|
||||
if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT)
|
||||
set(FFMPEG_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
if(FFMPEG_FOUND)
|
||||
set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
|
||||
set(FFMPEG_LIBRARIES
|
||||
${FFMPEG_LIBAVCODEC}
|
||||
${FFMPEG_LIBAVFORMAT}
|
||||
${FFMPEG_LIBAVUTIL})
|
||||
endif()
|
||||
|
||||
if(FFMPEG_FOUND)
|
||||
if(NOT FFMPEG_FIND_QUIETLY)
|
||||
message(STATUS
|
||||
"Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Could not find libavcodec or libavformat or libavutil")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(FFMPEG
|
||||
FOUND_VAR FFMPEG_FOUND
|
||||
REQUIRED_VARS
|
||||
FFMPEG_LIBRARIES
|
||||
FFMPEG_INCLUDE_DIR
|
||||
VERSION_VAR FFMPEG_VERSION
|
||||
)
|
18
cmake/FindPulseAudio.cmake
Normal file
18
cmake/FindPulseAudio.cmake
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(PULSEAUDIO_INCLUDE_DIRS
|
||||
NAMES pulse/pulseaudio.h
|
||||
DOC "PulseAudio include directory"
|
||||
)
|
||||
|
||||
find_library(PULSEAUDIO_LIBRARIES
|
||||
NAMES pulse
|
||||
DOC "PulseAudio library"
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(PulseAudio
|
||||
REQUIRED_VARS PULSEAUDIO_LIBRARIES PULSEAUDIO_INCLUDE_DIRS VERSION_VAR PULSEAUDIO_VERSION
|
||||
FAIL_MESSAGE "Could NOT find PulseAudio!")
|
||||
|
||||
mark_as_advanced(PULSEAUDIO_INCLUDE_DIRS PULSEAUDIO_LIBRARIES)
|
@ -19,7 +19,9 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
#include "AudioHardwareImpl.h"
|
||||
#include "AudioHardwareImplPA.h"
|
||||
#include <CoreServices/MacErrors.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <memory>
|
||||
#include "stub.h"
|
||||
|
||||
@ -27,16 +29,11 @@ static std::unique_ptr<AudioHardwareImpl> g_systemObject;
|
||||
|
||||
static AudioHardwareImpl* GetSystemObject()
|
||||
{
|
||||
if (!g_systemObject)
|
||||
{
|
||||
static std::mutex singleLock;
|
||||
singleLock.lock();
|
||||
|
||||
if (!g_systemObject)
|
||||
g_systemObject.reset(nullptr); // TODO: create ALSA or PA here
|
||||
|
||||
singleLock.unlock();
|
||||
}
|
||||
static dispatch_once_t once;
|
||||
dispatch_once(&once, ^{
|
||||
// TODO: Or ALSA
|
||||
g_systemObject.reset(new AudioHardwareImplPA);
|
||||
});
|
||||
|
||||
return g_systemObject.get();
|
||||
}
|
||||
@ -45,6 +42,8 @@ static AudioHardwareImpl* GetObject(AudioObjectID objID)
|
||||
{
|
||||
if (objID == kAudioObjectSystemObject)
|
||||
return GetSystemObject();
|
||||
|
||||
// TODO: For ALSA, support more objects for every device
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@ -136,7 +135,6 @@ OSStatus AudioObjectRemovePropertyListener(AudioObjectID inObjectID,
|
||||
|
||||
OSStatus AudioHardwareUnload(void)
|
||||
{
|
||||
g_systemObject.reset(nullptr);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
@ -157,14 +155,61 @@ OSStatus AudioHardwareDestroyAggregateDevice(AudioObjectID inDeviceID)
|
||||
|
||||
OSStatus AudioHardwareGetProperty(AudioHardwarePropertyID inPropId, UInt32* ioPropertyDataSize, void* outPropertyData)
|
||||
{
|
||||
STUB();
|
||||
return unimpErr;
|
||||
if (!ioPropertyDataSize)
|
||||
return paramErr;
|
||||
|
||||
return AudioDeviceGetProperty(kAudioObjectSystemObject, 0, false, inPropId, ioPropertyDataSize, outPropertyData);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceGetProperty(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32* ioPropertyDataSize, void* outPropertyData)
|
||||
{
|
||||
AudioObjectPropertyAddress aopa = {
|
||||
inPropertyID,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
return AudioObjectGetPropertyData(inDevice, &aopa, 0, nullptr, ioPropertyDataSize, outPropertyData);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceGetPropertyInfo(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32* outSize, Boolean* outWritable)
|
||||
{
|
||||
AudioObjectPropertyAddress aopa = {
|
||||
inPropertyID,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
OSStatus status;
|
||||
if (outSize)
|
||||
{
|
||||
status = AudioObjectGetPropertyDataSize(inDevice, &aopa, 0, nullptr, outSize);
|
||||
if (status != noErr)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (outWritable)
|
||||
{
|
||||
status = AudioObjectIsPropertySettable(inDevice, &aopa, outWritable);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceSetProperty(AudioDeviceID inDevice, const AudioTimeStamp *inWhen, UInt32 inChannel,
|
||||
Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData)
|
||||
{
|
||||
AudioObjectPropertyAddress aopa = {
|
||||
inPropertyID,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
return AudioObjectSetPropertyData(inDevice, &aopa, 0, nullptr, inPropertyDataSize, inPropertyData);
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareGetPropertyInfo(AudioHardwarePropertyID inPropertyID, UInt32 *outSize, Boolean *outWritable)
|
||||
{
|
||||
STUB();
|
||||
return unimpErr;
|
||||
return AudioDeviceGetPropertyInfo(kAudioObjectSystemObject, 0, false, inPropertyID, outSize, outWritable);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceCreateIOProcID(AudioObjectID inDevice,
|
||||
@ -178,6 +223,14 @@ OSStatus AudioDeviceCreateIOProcID(AudioObjectID inDevice,
|
||||
return obj->createIOProcID(inProc, inClientData, outIOProcID);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceAddIOProc(AudioDeviceID inDevice, AudioDeviceIOProc inProc, void *inClientData)
|
||||
{
|
||||
AudioHardwareImpl* obj = GetObject(inDevice);
|
||||
if (!obj)
|
||||
return kAudioHardwareBadObjectError;
|
||||
return obj->createIOProcID(inProc, inClientData, nullptr);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceDestroyIOProcID(AudioObjectID inDevice,
|
||||
AudioDeviceIOProcID inIOProcID)
|
||||
{
|
||||
@ -188,6 +241,15 @@ OSStatus AudioDeviceDestroyIOProcID(AudioObjectID inDevice,
|
||||
return obj->destroyIOProcID(inIOProcID);
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceRemoveIOProc(AudioDeviceID inDevice, AudioDeviceIOProc inProc)
|
||||
{
|
||||
AudioHardwareImpl* obj = GetObject(inDevice);
|
||||
if (!obj)
|
||||
return kAudioHardwareBadObjectError;
|
||||
|
||||
return obj->destroyIOProcID(AudioDeviceIOProcID(inProc));
|
||||
}
|
||||
|
||||
OSStatus AudioDeviceStart(AudioObjectID inDevice, AudioDeviceIOProcID inProcID)
|
||||
{
|
||||
AudioHardwareImpl* obj = GetObject(inDevice);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
This file is part of Darling.
|
||||
|
||||
Copyright (C) 2015-2016 Lubos Dolezel
|
||||
Copyright (C) 2015-2020 Lubos Dolezel
|
||||
|
||||
Darling is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -20,6 +20,7 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "AudioHardwareImpl.h"
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <CoreServices/MacErrors.h>
|
||||
|
||||
AudioHardwareImpl::AudioHardwareImpl()
|
||||
@ -41,11 +42,16 @@ OSStatus AudioHardwareImpl::createIOProcID(AudioDeviceIOProc inProc, void* inCli
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_procMutex);
|
||||
|
||||
if (!outIOProcID || !inProc)
|
||||
if (!inProc)
|
||||
return paramErr;
|
||||
|
||||
*outIOProcID = reinterpret_cast<AudioDeviceIOProcID>(m_nextProcId++);
|
||||
m_proc[*outIOProcID] = std::make_pair(inProc, inClientData);
|
||||
AudioDeviceIOProcID procId;
|
||||
if (outIOProcID)
|
||||
*outIOProcID = procId = reinterpret_cast<AudioDeviceIOProcID>(m_nextProcId++);
|
||||
else
|
||||
procId = inProc;
|
||||
|
||||
m_proc[procId] = std::make_pair(inProc, inClientData);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
@ -71,6 +77,8 @@ OSStatus AudioHardwareImpl::start(AudioDeviceIOProcID inProcID,
|
||||
return paramErr;
|
||||
|
||||
stream = createStream(inProcID);
|
||||
if (!stream)
|
||||
return kAudioHardwareBadStreamError;
|
||||
m_streams.emplace(std::make_pair(inProcID, std::unique_ptr<AudioHardwareStream>(stream)));
|
||||
|
||||
// TODO: time
|
||||
@ -90,13 +98,15 @@ OSStatus AudioHardwareImpl::stop(AudioDeviceIOProcID inProcID)
|
||||
|
||||
bool AudioHardwareImpl::hasProperty(const AudioObjectPropertyAddress* address)
|
||||
{
|
||||
return false;
|
||||
UInt32 ds;
|
||||
OSStatus status = getPropertyDataSize(address, 0, nullptr, &ds);
|
||||
return status != kAudioHardwareUnknownPropertyError;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::getPropertyDataSize(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32* outDataSize)
|
||||
{
|
||||
return kAudioHardwareUnknownPropertyError;
|
||||
return getPropertyData(inAddress, inQualifierDataSize, inQualifierData, outDataSize, nullptr);
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::isPropertySettable(const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable)
|
||||
@ -105,15 +115,98 @@ OSStatus AudioHardwareImpl::isPropertySettable(const AudioObjectPropertyAddress*
|
||||
return kAudioHardwareUnknownPropertyError;
|
||||
}
|
||||
|
||||
// Examples:
|
||||
// https://gist.github.com/robotconscience/490ee50d8ad75b47ea1f
|
||||
// https://gist.github.com/hpux735/2913436
|
||||
|
||||
OSStatus AudioHardwareImpl::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32* ioDataSize, void* outData)
|
||||
{
|
||||
switch (inAddress->mSelector)
|
||||
{
|
||||
case kAudioDevicePropertyStreamFormat: // returns AudioStreamBasicDescription
|
||||
{
|
||||
if (AudioStreamBasicDescription* asbd = static_cast<AudioStreamBasicDescription*>(outData); asbd && *ioDataSize >= sizeof(AudioStreamBasicDescription))
|
||||
{
|
||||
// These are standard values macOS applications have learned to expect
|
||||
asbd->mChannelsPerFrame = 2;
|
||||
asbd->mSampleRate = 44100;
|
||||
asbd->mBitsPerChannel = 32;
|
||||
asbd->mFormatID = kAudioFormatLinearPCM;
|
||||
asbd->mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
asbd->mFramesPerPacket = 1;
|
||||
asbd->mBytesPerFrame = UInt32(asbd->mBytesPerPacket = asbd->mChannelsPerFrame * asbd->mSampleRate * asbd->mBitsPerChannel / 8);
|
||||
}
|
||||
*ioDataSize = sizeof(AudioStreamBasicDescription);
|
||||
return noErr;
|
||||
}
|
||||
case kAudioDevicePropertyDeviceManufacturer:
|
||||
return getPropertyString(m_manufacturer, ioDataSize, outData);
|
||||
case kAudioDevicePropertyDeviceManufacturerCFString:
|
||||
return getPropertyCFString(m_manufacturer, ioDataSize, outData);
|
||||
case kAudioDevicePropertyDeviceUID: // returns CFStringRef
|
||||
return getPropertyCFString(m_uid, ioDataSize, outData);
|
||||
case kAudioDevicePropertyDeviceNameCFString:
|
||||
return getPropertyCFString(m_name, ioDataSize, outData);
|
||||
case kAudioDevicePropertyDeviceName: // return char[]
|
||||
return getPropertyString(m_name, ioDataSize, outData);
|
||||
case kAudioDevicePropertyNominalSampleRate: // Float64
|
||||
{
|
||||
if (Float64* flt = static_cast<Float64*>(outData); flt && *ioDataSize >= sizeof(Float64))
|
||||
*flt = 44100;
|
||||
|
||||
*ioDataSize = sizeof(Float64);
|
||||
return noErr;
|
||||
}
|
||||
case kAudioDevicePropertyAvailableNominalSampleRates: // AudioValueRange[]
|
||||
{
|
||||
if (AudioValueRange* avr = static_cast<AudioValueRange*>(outData); avr && *ioDataSize >= sizeof(AudioValueRange)*1)
|
||||
{
|
||||
avr->mMinimum = 44100;
|
||||
avr->mMaximum = 44100;
|
||||
}
|
||||
*ioDataSize = sizeof(AudioValueRange) * 1;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
}
|
||||
return kAudioHardwareUnknownPropertyError;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::getPropertyCFString(CFStringRef str, UInt32* ioDataSize, void* outData)
|
||||
{
|
||||
if (CFStringRef* ref = static_cast<CFStringRef*>(outData); ref && *ioDataSize >= sizeof(CFStringRef))
|
||||
{
|
||||
*ref = str;
|
||||
}
|
||||
*ioDataSize = sizeof(CFStringRef);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::getPropertyString(CFStringRef str, UInt32* ioDataSize, void* outData)
|
||||
{
|
||||
const char* cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
|
||||
if (char* target = static_cast<char*>(outData))
|
||||
strlcpy(target, cstr, *ioDataSize);
|
||||
*ioDataSize = strlen(cstr) + 1;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32 inDataSize, const void* inData)
|
||||
{
|
||||
switch (inAddress->mSelector)
|
||||
{
|
||||
case kAudioDevicePropertyBufferSize:
|
||||
{
|
||||
return setBufferSize(*static_cast<const uint32_t*>(inData));
|
||||
}
|
||||
// These make sense only for ALSA, but I find it ridiculous that these properties can be set...
|
||||
case kAudioHardwarePropertyDefaultOutputDevice:
|
||||
return noErr;
|
||||
case kAudioHardwarePropertyDefaultInputDevice:
|
||||
return noErr;
|
||||
}
|
||||
return kAudioHardwareUnknownPropertyError;
|
||||
}
|
||||
|
||||
@ -128,3 +221,27 @@ OSStatus AudioHardwareImpl::removePropertyListener(const AudioObjectPropertyAddr
|
||||
{
|
||||
return kAudioHardwareUnknownPropertyError;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::setBufferSize(uint32_t bufferSize)
|
||||
{
|
||||
m_bufferSize = bufferSize;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::getCurrentTime(AudioTimeStamp* outTime)
|
||||
{
|
||||
std::memset(outTime, 0, sizeof(*outTime));
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::translateTime(const AudioTimeStamp* inTime, AudioTimeStamp* outTime)
|
||||
{
|
||||
*outTime = *inTime;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImpl::getNearestStartTime(AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags)
|
||||
{
|
||||
std::memset(ioRequestedStartTime, 0, sizeof(*ioRequestedStartTime));
|
||||
return noErr;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef AUDIOHARDWAREIMPL_H
|
||||
#define AUDIOHARDWAREIMPL_H
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include "AudioHardwareStream.h"
|
||||
@ -57,13 +58,17 @@ public:
|
||||
AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags);
|
||||
virtual OSStatus stop(AudioDeviceIOProcID inProcID);
|
||||
|
||||
virtual OSStatus getCurrentTime(AudioTimeStamp* outTime) = 0;
|
||||
virtual OSStatus getCurrentTime(AudioTimeStamp* outTime);
|
||||
|
||||
virtual OSStatus translateTime(const AudioTimeStamp* inTime,
|
||||
AudioTimeStamp* outTime) = 0;
|
||||
AudioTimeStamp* outTime);
|
||||
|
||||
virtual OSStatus getNearestStartTime(AudioTimeStamp* ioRequestedStartTime,
|
||||
UInt32 inFlags) = 0;
|
||||
UInt32 inFlags);
|
||||
virtual OSStatus setBufferSize(uint32_t bufferSize);
|
||||
private:
|
||||
static OSStatus getPropertyCFString(CFStringRef str, UInt32* ioDataSize, void* outData);
|
||||
static OSStatus getPropertyString(CFStringRef str, UInt32* ioDataSize, void* outData);
|
||||
protected:
|
||||
virtual AudioHardwareStream* createStream(AudioDeviceIOProcID procID) = 0;
|
||||
protected:
|
||||
@ -72,6 +77,9 @@ protected:
|
||||
int m_nextProcId = 1;
|
||||
|
||||
std::map<AudioDeviceIOProcID, std::unique_ptr<AudioHardwareStream>> m_streams;
|
||||
uint32_t m_bufferSize = 8192;
|
||||
|
||||
CFStringRef m_name = CFSTR("unknown"), m_uid = CFSTR("unknown"), m_manufacturer = CFSTR("unknown");
|
||||
};
|
||||
|
||||
#endif /* AUDIOHARDWAREIMPL_H */
|
||||
|
98
src/CoreAudio/CoreAudio/AudioHardwareImplPA.cpp
Normal file
98
src/CoreAudio/CoreAudio/AudioHardwareImplPA.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
This file is part of Darling.
|
||||
|
||||
Copyright (C) 2020 Lubos Dolezel
|
||||
|
||||
Darling is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Darling is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AudioHardwareImplPA.h"
|
||||
|
||||
AudioHardwareImplPA::AudioHardwareImplPA()
|
||||
{
|
||||
m_name = CFSTR("PulseAudio");
|
||||
m_manufacturer = CFSTR("PulseAudio");
|
||||
m_uid = CFSTR("100");
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImplPA::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32* ioDataSize, void* outData)
|
||||
{
|
||||
switch (inAddress->mSelector)
|
||||
{
|
||||
// BEGIN kAudioObjectSystemObject properties
|
||||
case kAudioHardwarePropertyDefaultInputDevice: // returns AudioDeviceID
|
||||
if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
|
||||
{
|
||||
// We're doing a bit of an abuse here, which works only for PA where we have a single virtual device.
|
||||
// For ALSA, we could do kAudioObjectSystemObject + INDEX of device.
|
||||
*devId = kAudioObjectSystemObject;
|
||||
}
|
||||
*ioDataSize = sizeof(AudioDeviceID);
|
||||
break;
|
||||
case kAudioHardwarePropertyDefaultOutputDevice: // returns AudioDeviceID
|
||||
if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
|
||||
{
|
||||
*devId = kAudioObjectSystemObject;
|
||||
}
|
||||
*ioDataSize = sizeof(AudioDeviceID);
|
||||
break;
|
||||
case kAudioHardwarePropertyDevices:
|
||||
{
|
||||
if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
|
||||
{
|
||||
devId[0] = kAudioObjectSystemObject;
|
||||
}
|
||||
*ioDataSize = sizeof(AudioDeviceID) * 1;
|
||||
break;
|
||||
}
|
||||
// END kAudioObjectSystemObject properties
|
||||
|
||||
// BEGIN properties of a specific audio device (in case of PA, it is kAudioObjectSystemObject as well)
|
||||
case kAudioDevicePropertyStreamConfiguration: // returns AudioBufferList
|
||||
{
|
||||
const size_t size = sizeof(AudioBufferList) + 1* sizeof(AudioBuffer);
|
||||
|
||||
// Number of returned buffers is the number of channels
|
||||
// check inAddress->mScope. If it equals kAudioDevicePropertyScopeInput, the caller cares about input only.
|
||||
if (AudioBufferList* abl = static_cast<AudioBufferList*>(outData); abl && *ioDataSize >= size)
|
||||
{
|
||||
abl->mNumberBuffers = 1;
|
||||
abl->mBuffers[0].mNumberChannels = 2;
|
||||
|
||||
// TODO: Is the below stuff ever used? How?
|
||||
abl->mBuffers[0].mData = nullptr;
|
||||
abl->mBuffers[0].mDataByteSize = 0;
|
||||
}
|
||||
|
||||
*ioDataSize = size;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return AudioHardwareImpl::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData);
|
||||
}
|
||||
|
||||
OSStatus AudioHardwareImplPA::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32 inDataSize, const void* inData)
|
||||
{
|
||||
return AudioHardwareImpl::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData);
|
||||
}
|
||||
|
||||
AudioHardwareStream* AudioHardwareImplPA::createStream(AudioDeviceIOProcID procID)
|
||||
{
|
||||
// TODO
|
||||
return nullptr;
|
||||
}
|
39
src/CoreAudio/CoreAudio/AudioHardwareImplPA.h
Normal file
39
src/CoreAudio/CoreAudio/AudioHardwareImplPA.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
This file is part of Darling.
|
||||
|
||||
Copyright (C) 2020 Lubos Dolezel
|
||||
|
||||
Darling is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Darling is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AUDIOHARDWAREIMPLPA_H
|
||||
#define AUDIOHARDWAREIMPLPA_H
|
||||
#include "AudioHardwareImpl.h"
|
||||
|
||||
class AudioHardwareImplPA : public AudioHardwareImpl
|
||||
{
|
||||
public:
|
||||
AudioHardwareImplPA();
|
||||
|
||||
OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32* ioDataSize, void* outData) override;
|
||||
|
||||
OSStatus setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
|
||||
const void* inQualifierData, UInt32 inDataSize, const void* inData) override;
|
||||
protected:
|
||||
AudioHardwareStream* createStream(AudioDeviceIOProcID procID) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -2,9 +2,12 @@ project(CoreAudio)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/libcxx/include ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
|
||||
set(coreaudio_sources
|
||||
AudioHardware.cpp
|
||||
AudioHardwareImpl.cpp
|
||||
AudioHardwareImpl.cpp
|
||||
AudioHardwareImplPA.cpp
|
||||
AudioHardwareStream.cpp
|
||||
)
|
||||
|
||||
|
@ -176,6 +176,7 @@ typedef AudioDeviceIOProc AudioDeviceIOProcID;
|
||||
OSStatus AudioDeviceCreateIOProcID(AudioObjectID inDevice,
|
||||
AudioDeviceIOProc inProc, void* inClientData,
|
||||
AudioDeviceIOProcID* outIOProcID);
|
||||
OSStatus AudioDeviceAddIOProc(AudioDeviceID inDevice, AudioDeviceIOProc inProc, void *inClientData);
|
||||
|
||||
#ifdef __BLOCKS__
|
||||
|
||||
@ -191,6 +192,7 @@ OSStatus AudioDeviceCreateIOProcIDWithBlock(AudioDeviceIOProcID* outIOProcID,
|
||||
|
||||
OSStatus AudioDeviceDestroyIOProcID(AudioObjectID inDevice,
|
||||
AudioDeviceIOProcID inIOProcID);
|
||||
OSStatus AudioDeviceRemoveIOProc(AudioDeviceID inDevice, AudioDeviceIOProc inProc);
|
||||
|
||||
OSStatus AudioDeviceStart(AudioObjectID inDevice, AudioDeviceIOProcID inProcID);
|
||||
|
||||
@ -208,6 +210,7 @@ struct AudioHardwareIOProcStreamUsage
|
||||
|
||||
OSStatus AudioDeviceGetProperty(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32* ioPropertyDataSize, void* outPropertyData);
|
||||
OSStatus AudioDeviceGetPropertyInfo(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32* outSize, Boolean* outWritable);
|
||||
OSStatus AudioDeviceSetProperty(AudioDeviceID inDevice, const AudioTimeStamp *inWhen, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData);
|
||||
|
||||
OSStatus AudioDeviceGetCurrentTime(AudioObjectID inDevice, AudioTimeStamp* outTime);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
typedef Float32 AudioSampleType;
|
||||
typedef Float32 AudioUnitSampleType;
|
||||
|
||||
struct AudioStreamBasicDescription
|
||||
typedef struct
|
||||
{
|
||||
Float64 mSampleRate;
|
||||
UInt32 mFormatID;
|
||||
@ -18,43 +18,49 @@ struct AudioStreamBasicDescription
|
||||
UInt32 mChannelsPerFrame;
|
||||
UInt32 mBitsPerChannel;
|
||||
UInt32 mReserved;
|
||||
};
|
||||
} AudioStreamBasicDescription;
|
||||
|
||||
struct AudioClassDescription
|
||||
typedef struct
|
||||
{
|
||||
OSType mType;
|
||||
OSType mSubType;
|
||||
OSType mManufacturer;
|
||||
};
|
||||
} AudioClassDescription;
|
||||
|
||||
struct AudioBuffer
|
||||
typedef struct
|
||||
{
|
||||
UInt32 mNumberChannels;
|
||||
UInt32 mDataByteSize;
|
||||
void* mData;
|
||||
};
|
||||
} AudioBuffer;
|
||||
|
||||
struct AudioBufferList
|
||||
typedef struct
|
||||
{
|
||||
UInt32 mNumberBuffers;
|
||||
AudioBuffer mBuffers[1];
|
||||
};
|
||||
} AudioBufferList;
|
||||
|
||||
struct AudioStreamPacketDescription
|
||||
typedef struct
|
||||
{
|
||||
Float64 mMinimum;
|
||||
Float64 mMaximum;
|
||||
} AudioValueRange;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SInt64 mStartOffset;
|
||||
UInt32 mVariableFramesInPacket; // 0 for constant streams
|
||||
UInt32 mDataByteSize;
|
||||
};
|
||||
} AudioStreamPacketDescription;
|
||||
|
||||
struct SMPTETime
|
||||
typedef struct
|
||||
{
|
||||
SInt64 mSubframes, mSubframeDivisor;
|
||||
UInt32 mCounter, mType, mFlags;
|
||||
SInt16 mHours, mMinutes, mSeconds, mFrames;
|
||||
};
|
||||
} SMPTETime;
|
||||
|
||||
struct AudioTimeStamp
|
||||
typedef struct
|
||||
{
|
||||
Float64 mSampleTime;
|
||||
UInt64 mHostTime;
|
||||
@ -62,7 +68,7 @@ struct AudioTimeStamp
|
||||
UInt64 mWordClockTime;
|
||||
SMPTETime mSMPTETime;
|
||||
UInt32 mFlags, mReserved;
|
||||
};
|
||||
} AudioTimeStamp;
|
||||
|
||||
enum
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user