|
@@ -24,7 +24,9 @@
|
|
|
SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL
|
|
|
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
|
|
|
|
|
- SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024)
|
|
|
+ SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024)
|
|
|
+ SAUDIO_OSX_USE_SYSTEM_HEADERS - define this to force inclusion of system headers on
|
|
|
+ macOS instead of using embedded CoreAudio declarations
|
|
|
|
|
|
If sokol_audio.h is compiled as a DLL, define the following before
|
|
|
including the declaration or implementation:
|
|
@@ -501,10 +503,10 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
#elif defined(__APPLE__)
|
|
|
#define _SAUDIO_APPLE (1)
|
|
|
#include <TargetConditionals.h>
|
|
|
- #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
|
|
|
- #define _SAUDIO_MACOS (1)
|
|
|
- #else
|
|
|
+ #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
|
|
#define _SAUDIO_IOS (1)
|
|
|
+ #else
|
|
|
+ #define _SAUDIO_MACOS (1)
|
|
|
#endif
|
|
|
#elif defined(__EMSCRIPTEN__)
|
|
|
#define _SAUDIO_EMSCRIPTEN
|
|
@@ -579,14 +581,22 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|
|
#elif defined(_SAUDIO_APPLE)
|
|
|
#define _SAUDIO_PTHREADS (1)
|
|
|
#include <pthread.h>
|
|
|
- #include <AudioToolbox/AudioToolbox.h>
|
|
|
#if defined(_SAUDIO_IOS)
|
|
|
+ // always use system headers on iOS (for now at least)
|
|
|
+ #if !defined(SAUDIO_OSX_USE_SYSTEM_HEADERS)
|
|
|
+ #define SAUDIO_OSX_USE_SYSTEM_HEADERS (1)
|
|
|
+ #endif
|
|
|
#if !defined(__cplusplus)
|
|
|
#if __has_feature(objc_arc) && !__has_feature(objc_arc_fields)
|
|
|
#error "sokol_audio.h on iOS requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)"
|
|
|
#endif
|
|
|
#endif
|
|
|
+ #include <AudioToolbox/AudioToolbox.h>
|
|
|
#include <AVFoundation/AVFoundation.h>
|
|
|
+ #else
|
|
|
+ #if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS)
|
|
|
+ #include <AudioToolbox/AudioToolbox.h>
|
|
|
+ #endif
|
|
|
#endif
|
|
|
#elif defined(_SAUDIO_ANDROID)
|
|
|
#define _SAUDIO_PTHREADS (1)
|
|
@@ -645,8 +655,97 @@ typedef struct {
|
|
|
/*=== COREAUDIO BACKEND DECLARATIONS =========================================*/
|
|
|
#elif defined(_SAUDIO_APPLE)
|
|
|
|
|
|
+#if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS)
|
|
|
+
|
|
|
+typedef AudioQueueRef _saudio_AudioQueueRef;
|
|
|
+typedef AudioQueueBufferRef _saudio_AudioQueueBufferRef;
|
|
|
+typedef AudioStreamBasicDescription _saudio_AudioStreamBasicDescription;
|
|
|
+typedef OSStatus _saudio_OSStatus;
|
|
|
+
|
|
|
+#define _saudio_kAudioFormatLinearPCM (kAudioFormatLinearPCM)
|
|
|
+#define _saudio_kLinearPCMFormatFlagIsFloat (kLinearPCMFormatFlagIsFloat)
|
|
|
+#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked)
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+// embedded AudioToolbox declarations
|
|
|
+typedef uint32_t _saudio_AudioFormatID;
|
|
|
+typedef uint32_t _saudio_AudioFormatFlags;
|
|
|
+typedef int32_t _saudio_OSStatus;
|
|
|
+typedef uint32_t _saudio_SMPTETimeType;
|
|
|
+typedef uint32_t _saudio_SMPTETimeFlags;
|
|
|
+typedef uint32_t _saudio_AudioTimeStampFlags;
|
|
|
+typedef void* _saudio_CFRunLoopRef;
|
|
|
+typedef void* _saudio_CFStringRef;
|
|
|
+typedef void* _saudio_AudioQueueRef;
|
|
|
+
|
|
|
+#define _saudio_kAudioFormatLinearPCM ('lpcm')
|
|
|
+#define _saudio_kLinearPCMFormatFlagIsFloat (1U << 0)
|
|
|
+#define _saudio_kAudioFormatFlagIsPacked (1U << 3)
|
|
|
+
|
|
|
+typedef struct _saudio_AudioStreamBasicDescription {
|
|
|
+ double mSampleRate;
|
|
|
+ _saudio_AudioFormatID mFormatID;
|
|
|
+ _saudio_AudioFormatFlags mFormatFlags;
|
|
|
+ uint32_t mBytesPerPacket;
|
|
|
+ uint32_t mFramesPerPacket;
|
|
|
+ uint32_t mBytesPerFrame;
|
|
|
+ uint32_t mChannelsPerFrame;
|
|
|
+ uint32_t mBitsPerChannel;
|
|
|
+ uint32_t mReserved;
|
|
|
+} _saudio_AudioStreamBasicDescription;
|
|
|
+
|
|
|
+typedef struct _saudio_AudioStreamPacketDescription {
|
|
|
+ int64_t mStartOffset;
|
|
|
+ uint32_t mVariableFramesInPacket;
|
|
|
+ uint32_t mDataByteSize;
|
|
|
+} _saudio_AudioStreamPacketDescription;
|
|
|
+
|
|
|
+typedef struct _saudio_SMPTETime {
|
|
|
+ int16_t mSubframes;
|
|
|
+ int16_t mSubframeDivisor;
|
|
|
+ uint32_t mCounter;
|
|
|
+ _saudio_SMPTETimeType mType;
|
|
|
+ _saudio_SMPTETimeFlags mFlags;
|
|
|
+ int16_t mHours;
|
|
|
+ int16_t mMinutes;
|
|
|
+ int16_t mSeconds;
|
|
|
+ int16_t mFrames;
|
|
|
+} _saudio_SMPTETime;
|
|
|
+
|
|
|
+typedef struct _saudio_AudioTimeStamp {
|
|
|
+ double mSampleTime;
|
|
|
+ uint64_t mHostTime;
|
|
|
+ double mRateScalar;
|
|
|
+ uint64_t mWordClockTime;
|
|
|
+ _saudio_SMPTETime mSMPTETime;
|
|
|
+ _saudio_AudioTimeStampFlags mFlags;
|
|
|
+ uint32_t mReserved;
|
|
|
+} _saudio_AudioTimeStamp;
|
|
|
+
|
|
|
+typedef struct _saudio_AudioQueueBuffer {
|
|
|
+ const uint32_t mAudioDataBytesCapacity;
|
|
|
+ void* const mAudioData;
|
|
|
+ uint32_t mAudioDataByteSize;
|
|
|
+ void * mUserData;
|
|
|
+ const uint32_t mPacketDescriptionCapacity;
|
|
|
+ _saudio_AudioStreamPacketDescription* const mPacketDescriptions;
|
|
|
+ uint32_t mPacketDescriptionCount;
|
|
|
+} _saudio_AudioQueueBuffer;
|
|
|
+typedef _saudio_AudioQueueBuffer* _saudio_AudioQueueBufferRef;
|
|
|
+
|
|
|
+typedef void (*_saudio_AudioQueueOutputCallback)(void* user_data, _saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer);
|
|
|
+
|
|
|
+extern _saudio_OSStatus AudioQueueNewOutput(const _saudio_AudioStreamBasicDescription* inFormat, _saudio_AudioQueueOutputCallback inCallbackProc, void* inUserData, _saudio_CFRunLoopRef inCallbackRunLoop, _saudio_CFStringRef inCallbackRunLoopMode, uint32_t inFlags, _saudio_AudioQueueRef* outAQ);
|
|
|
+extern _saudio_OSStatus AudioQueueDispose(_saudio_AudioQueueRef inAQ, bool inImmediate);
|
|
|
+extern _saudio_OSStatus AudioQueueAllocateBuffer(_saudio_AudioQueueRef inAQ, uint32_t inBufferByteSize, _saudio_AudioQueueBufferRef* outBuffer);
|
|
|
+extern _saudio_OSStatus AudioQueueEnqueueBuffer(_saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer, uint32_t inNumPacketDescs, const _saudio_AudioStreamPacketDescription* inPacketDescs);
|
|
|
+extern _saudio_OSStatus AudioQueueStart(_saudio_AudioQueueRef inAQ, const _saudio_AudioTimeStamp * inStartTime);
|
|
|
+extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate);
|
|
|
+#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS
|
|
|
+
|
|
|
typedef struct {
|
|
|
- AudioQueueRef ca_audio_queue;
|
|
|
+ _saudio_AudioQueueRef ca_audio_queue;
|
|
|
#if defined(_SAUDIO_IOS)
|
|
|
id ca_interruption_handler;
|
|
|
#endif
|
|
@@ -1078,7 +1177,7 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { };
|
|
|
#endif // _SAUDIO_IOS
|
|
|
|
|
|
/* NOTE: the buffer data callback is called on a separate thread! */
|
|
|
-_SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, AudioQueueRef queue, AudioQueueBufferRef buffer) {
|
|
|
+_SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, _saudio_AudioQueueRef queue, _saudio_AudioQueueBufferRef buffer) {
|
|
|
_SOKOL_UNUSED(user_data);
|
|
|
if (_saudio_has_callback()) {
|
|
|
const int num_frames = (int)buffer->mAudioDataByteSize / _saudio.bytes_per_frame;
|
|
@@ -1111,22 +1210,22 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|
|
#endif // _SAUDIO_IOS
|
|
|
|
|
|
/* create an audio queue with fp32 samples */
|
|
|
- AudioStreamBasicDescription fmt;
|
|
|
+ _saudio_AudioStreamBasicDescription fmt;
|
|
|
memset(&fmt, 0, sizeof(fmt));
|
|
|
- fmt.mSampleRate = (Float64) _saudio.sample_rate;
|
|
|
- fmt.mFormatID = kAudioFormatLinearPCM;
|
|
|
- fmt.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked;
|
|
|
+ fmt.mSampleRate = (double) _saudio.sample_rate;
|
|
|
+ fmt.mFormatID = _saudio_kAudioFormatLinearPCM;
|
|
|
+ fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked;
|
|
|
fmt.mFramesPerPacket = 1;
|
|
|
fmt.mChannelsPerFrame = (uint32_t) _saudio.num_channels;
|
|
|
fmt.mBytesPerFrame = (uint32_t)sizeof(float) * (uint32_t)_saudio.num_channels;
|
|
|
fmt.mBytesPerPacket = fmt.mBytesPerFrame;
|
|
|
fmt.mBitsPerChannel = 32;
|
|
|
- OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue);
|
|
|
+ _saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue);
|
|
|
SOKOL_ASSERT((res == 0) && _saudio.backend.ca_audio_queue);
|
|
|
|
|
|
/* create 2 audio buffers */
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
- AudioQueueBufferRef buf = NULL;
|
|
|
+ _saudio_AudioQueueBufferRef buf = NULL;
|
|
|
const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame;
|
|
|
res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf);
|
|
|
SOKOL_ASSERT((res == 0) && buf);
|