mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 742160 - Import AudioUnit cubeb backend. r=doublec
This commit is contained in:
parent
c6d2de46e7
commit
b5111a2ca4
@ -45,14 +45,20 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = cubeb
|
||||
LIBRARY_NAME = cubeb
|
||||
FORCE_STATIC_LIB= 1
|
||||
ifeq (WINNT,$(OS_TARGET))
|
||||
ifeq ($(OS_TARGET),WINNT)
|
||||
VISIBILITY_FLAGS =
|
||||
endif
|
||||
|
||||
ifeq (WINNT,$(OS_TARGET))
|
||||
ifeq ($(OS_TARGET),WINNT)
|
||||
CSRCS = \
|
||||
cubeb_winmm.c \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),Darwin)
|
||||
CSRCS = \
|
||||
cubeb_audiounit.c \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
253
media/libcubeb/src/cubeb_audiounit.c
Normal file
253
media/libcubeb/src/cubeb_audiounit.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright © 2011 Mozilla Foundation
|
||||
*
|
||||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
*/
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
#define NBUFS 4
|
||||
|
||||
struct cubeb_stream {
|
||||
AudioUnit unit;
|
||||
cubeb_data_callback data_callback;
|
||||
cubeb_state_callback state_callback;
|
||||
void * user_ptr;
|
||||
AudioStreamBasicDescription sample_spec;
|
||||
pthread_mutex_t mutex;
|
||||
uint64_t frames_played;
|
||||
uint64_t frames_queued;
|
||||
int shutdown;
|
||||
int draining;
|
||||
};
|
||||
|
||||
static OSStatus
|
||||
audio_unit_output_callback(void * user_ptr, AudioUnitRenderActionFlags * flags,
|
||||
AudioTimeStamp const * tstamp, UInt32 bus, UInt32 nframes,
|
||||
AudioBufferList * bufs)
|
||||
{
|
||||
cubeb_stream * stm;
|
||||
unsigned char * buf;
|
||||
long got;
|
||||
OSStatus r;
|
||||
|
||||
assert(bufs->mNumberBuffers == 1);
|
||||
buf = bufs->mBuffers[0].mData;
|
||||
|
||||
stm = user_ptr;
|
||||
|
||||
pthread_mutex_lock(&stm->mutex);
|
||||
|
||||
if (stm->draining || stm->shutdown) {
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
if (stm->draining) {
|
||||
r = AudioOutputUnitStop(stm->unit);
|
||||
assert(r == 0);
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
got = stm->data_callback(stm, stm->user_ptr, buf, nframes);
|
||||
pthread_mutex_lock(&stm->mutex);
|
||||
if (got < 0) {
|
||||
// XXX handle this case.
|
||||
assert(false);
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (got < nframes) {
|
||||
size_t got_bytes = got * stm->sample_spec.mBytesPerFrame;
|
||||
size_t rem_bytes = (nframes - got) * stm->sample_spec.mBytesPerFrame;
|
||||
|
||||
stm->draining = 1;
|
||||
|
||||
memset(buf + got_bytes, 0, rem_bytes);
|
||||
}
|
||||
|
||||
stm->frames_played = stm->frames_queued;
|
||||
stm->frames_queued += got;
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_init(cubeb ** context, char const * context_name)
|
||||
{
|
||||
*context = (void *) 0xdeadbeef;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
void
|
||||
cubeb_destroy(cubeb * ctx)
|
||||
{
|
||||
assert(ctx == (void *) 0xdeadbeef);
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
|
||||
cubeb_stream_params stream_params, unsigned int latency,
|
||||
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
|
||||
void * user_ptr)
|
||||
{
|
||||
AudioStreamBasicDescription ss;
|
||||
ComponentDescription desc;
|
||||
cubeb_stream * stm;
|
||||
Component comp;
|
||||
AURenderCallbackStruct input;
|
||||
unsigned int buffer_size;
|
||||
OSStatus r;
|
||||
|
||||
assert(context == (void *) 0xdeadbeef);
|
||||
*stream = NULL;
|
||||
|
||||
if (stream_params.rate < 1 || stream_params.rate > 192000 ||
|
||||
stream_params.channels < 1 || stream_params.channels > 32 ||
|
||||
latency < 1 || latency > 2000) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
ss.mFormatFlags = 0;
|
||||
|
||||
switch (stream_params.format) {
|
||||
case CUBEB_SAMPLE_S16LE:
|
||||
ss.mBitsPerChannel = 16;
|
||||
ss.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case CUBEB_SAMPLE_S16BE:
|
||||
ss.mBitsPerChannel = 16;
|
||||
ss.mFormatFlags |= kAudioFormatFlagIsSignedInteger |
|
||||
kAudioFormatFlagIsBigEndian;
|
||||
break;
|
||||
case CUBEB_SAMPLE_FLOAT32LE:
|
||||
ss.mBitsPerChannel = 32;
|
||||
ss.mFormatFlags |= kAudioFormatFlagIsFloat;
|
||||
break;
|
||||
case CUBEB_SAMPLE_FLOAT32BE:
|
||||
ss.mBitsPerChannel = 32;
|
||||
ss.mFormatFlags |= kAudioFormatFlagIsFloat |
|
||||
kAudioFormatFlagIsBigEndian;
|
||||
break;
|
||||
default:
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
ss.mFormatID = kAudioFormatLinearPCM;
|
||||
ss.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
|
||||
ss.mSampleRate = stream_params.rate;
|
||||
ss.mChannelsPerFrame = stream_params.channels;
|
||||
|
||||
ss.mBytesPerFrame = (ss.mBitsPerChannel / 8) * ss.mChannelsPerFrame;
|
||||
ss.mFramesPerPacket = 1;
|
||||
ss.mBytesPerPacket = ss.mBytesPerFrame * ss.mFramesPerPacket;
|
||||
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
comp = FindNextComponent(NULL, &desc);
|
||||
assert(comp);
|
||||
|
||||
stm = calloc(1, sizeof(*stm));
|
||||
assert(stm);
|
||||
|
||||
stm->data_callback = data_callback;
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
|
||||
stm->sample_spec = ss;
|
||||
|
||||
r = pthread_mutex_init(&stm->mutex, NULL);
|
||||
assert(r == 0);
|
||||
|
||||
stm->frames_played = 0;
|
||||
stm->frames_queued = 0;
|
||||
|
||||
r = OpenAComponent(comp, &stm->unit);
|
||||
assert(r == 0);
|
||||
|
||||
input.inputProc = audio_unit_output_callback;
|
||||
input.inputProcRefCon = stm;
|
||||
r = AudioUnitSetProperty(stm->unit, kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Global, 0, &input, sizeof(input));
|
||||
assert(r == 0);
|
||||
|
||||
r = AudioUnitSetProperty(stm->unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
|
||||
0, &ss, sizeof(ss));
|
||||
assert(r == 0);
|
||||
|
||||
buffer_size = ss.mSampleRate / 1000.0 * latency * ss.mBytesPerFrame / NBUFS;
|
||||
if (buffer_size % ss.mBytesPerFrame != 0) {
|
||||
buffer_size += ss.mBytesPerFrame - (buffer_size % ss.mBytesPerFrame);
|
||||
}
|
||||
assert(buffer_size % ss.mBytesPerFrame == 0);
|
||||
|
||||
r = AudioUnitInitialize(stm->unit);
|
||||
assert(r == 0);
|
||||
|
||||
*stream = stm;
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
void
|
||||
cubeb_stream_destroy(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
|
||||
stm->shutdown = 1;
|
||||
|
||||
r = AudioOutputUnitStop(stm->unit);
|
||||
assert(r == 0);
|
||||
|
||||
r = AudioUnitUninitialize(stm->unit);
|
||||
assert(r == 0);
|
||||
|
||||
r = CloseComponent(stm->unit);
|
||||
assert(r == 0);
|
||||
|
||||
r = pthread_mutex_destroy(&stm->mutex);
|
||||
assert(r == 0);
|
||||
|
||||
free(stm);
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_stream_start(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
r = AudioOutputUnitStart(stm->unit);
|
||||
assert(r == 0);
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_stream_stop(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
r = AudioOutputUnitStop(stm->unit);
|
||||
assert(r == 0);
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
int
|
||||
cubeb_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
||||
{
|
||||
pthread_mutex_lock(&stm->mutex);
|
||||
*position = stm->frames_played;
|
||||
pthread_mutex_unlock(&stm->mutex);
|
||||
return CUBEB_OK;
|
||||
}
|
Loading…
Reference in New Issue
Block a user