mirror of https://github.com/mpv-player/mpv
Mac OS X Audio with AudioUnits and AudioToolbox format converters, Patch by Chris Roccati<roccati@pobox.com
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@15647 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
58087baeb7
commit
f7169a98e8
|
@ -37,7 +37,9 @@
|
|||
* access to a sound card that supports it.
|
||||
*/
|
||||
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -55,7 +57,7 @@ static ao_info_t info =
|
|||
{
|
||||
"Darwin/Mac OS X native audio output",
|
||||
"macosx",
|
||||
"Timothy J. Wood & Dan Christiansen",
|
||||
"Timothy J. Wood & Dan Christiansen & Chris Roccati",
|
||||
""
|
||||
};
|
||||
|
||||
|
@ -70,15 +72,17 @@ LIBAO_EXTERN(macosx)
|
|||
|
||||
typedef struct ao_macosx_s
|
||||
{
|
||||
/* CoreAudio */
|
||||
AudioDeviceID outputDeviceID;
|
||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||
/* AudioUnit */
|
||||
AudioUnit theOutputUnit;
|
||||
AudioConverterRef theConverter;
|
||||
int packetSize;
|
||||
|
||||
/* Ring-buffer */
|
||||
/* does not need explicit synchronization, but needs to allocate
|
||||
* (num_chunks + 1) * chunk_size memory to store num_chunks * chunk_size
|
||||
* data */
|
||||
unsigned char *buffer;
|
||||
unsigned char *chunk;
|
||||
unsigned int buffer_len; ///< must always be (num_chunks + 1) * chunk_size
|
||||
unsigned int num_chunks;
|
||||
unsigned int chunk_size;
|
||||
|
@ -153,55 +157,61 @@ static int read_buffer(unsigned char* data,int len){
|
|||
|
||||
/* end ring buffer stuff */
|
||||
|
||||
/* The function that the CoreAudio thread calls when it wants more data */
|
||||
static OSStatus audioDeviceIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData)
|
||||
OSStatus ACComplexInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
|
||||
{
|
||||
outOutputData->mBuffers[0].mDataByteSize =
|
||||
read_buffer((char *)outOutputData->mBuffers[0].mData, ao->chunk_size);
|
||||
int amt=buf_used();
|
||||
int req=(*ioNumberDataPackets)*ao->packetSize;
|
||||
|
||||
return 0;
|
||||
|
||||
ioData->mBuffers[0].mData = ao->chunk;
|
||||
ioData->mBuffers[0].mDataByteSize = req;
|
||||
|
||||
// fprintf(stderr, "##### req=%d amt=%d #####\n", req, amt);
|
||||
|
||||
if(amt>req)
|
||||
amt=req;
|
||||
|
||||
if(amt)
|
||||
read_buffer((unsigned char *)ioData->mBuffers[0].mData, amt);
|
||||
|
||||
if(req-amt)
|
||||
memset(ioData->mBuffers[0].mData+amt, 0, req-amt);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus theRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
void *inInputDataProcUserData = NULL;
|
||||
AudioStreamPacketDescription *outPacketDescription = NULL;
|
||||
|
||||
|
||||
err = AudioConverterFillComplexBuffer(ao->theConverter, ACComplexInputProc, inInputDataProcUserData, &inNumFrames, ioData, outPacketDescription);
|
||||
|
||||
/*Parameters for AudioConverterFillComplexBuffer()
|
||||
converter - the converter being used
|
||||
ACComplexInputProc() - input procedure to supply data to the Audio Converter
|
||||
inInputDataProcUserData - Used to hold any data that needs to be passed on.
|
||||
inNumFrames - The amount of requested data. On output, this number is the amount actually received.
|
||||
ioData - Buffer of the converted data recieved on return
|
||||
outPacketDescription - contains the format of the returned data.
|
||||
*/
|
||||
|
||||
if(err)
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "AudioConverterFillComplexBuffer failed status %-8d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int control(int cmd,void *arg){
|
||||
OSStatus status;
|
||||
UInt32 propertySize;
|
||||
ao_control_vol_t* vol = (ao_control_vol_t*)arg;
|
||||
UInt32 stereoChannels[2];
|
||||
static float volume=0.5;
|
||||
switch (cmd) {
|
||||
case AOCONTROL_SET_DEVICE:
|
||||
case AOCONTROL_GET_DEVICE:
|
||||
/* unimplemented/meaningless */
|
||||
return CONTROL_FALSE;
|
||||
case AOCONTROL_GET_VOLUME:
|
||||
propertySize=sizeof(stereoChannels);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false,
|
||||
kAudioDevicePropertyPreferredChannelsForStereo, &propertySize,
|
||||
&stereoChannels);
|
||||
// printf("OSX: stereochannels %d ; %d \n",stereoChannels[0],stereoChannels[1]);
|
||||
propertySize=sizeof(volume);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, stereoChannels[0], false, kAudioDevicePropertyVolumeScalar, &propertySize, &volume);
|
||||
// printf("OSX: get volume=%5.3f status=%d \n",volume,status);
|
||||
vol->left=(int)(volume*100.0);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, stereoChannels[1], false, kAudioDevicePropertyVolumeScalar, &propertySize, &volume);
|
||||
vol->right=(int)(volume*100.0);
|
||||
return CONTROL_TRUE;
|
||||
case AOCONTROL_SET_VOLUME:
|
||||
propertySize=sizeof(stereoChannels);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false,
|
||||
kAudioDevicePropertyPreferredChannelsForStereo, &propertySize,
|
||||
&stereoChannels);
|
||||
// printf("OSX: stereochannels %d ; %d \n",stereoChannels[0],stereoChannels[1]);
|
||||
propertySize=sizeof(volume);
|
||||
volume=vol->left/100.0;
|
||||
status = AudioDeviceSetProperty(ao->outputDeviceID, 0, stereoChannels[0], 0, kAudioDevicePropertyVolumeScalar, propertySize, &volume);
|
||||
// printf("OSX: set volume=%5.3f status=%d\n",volume,status);
|
||||
volume=vol->right/100.0;
|
||||
status = AudioDeviceSetProperty(ao->outputDeviceID, 0, stereoChannels[1], 0, kAudioDevicePropertyVolumeScalar, propertySize, &volume);
|
||||
return CONTROL_TRUE;
|
||||
case AOCONTROL_QUERY_FORMAT:
|
||||
/* stick with what CoreAudio requests */
|
||||
/* Everything is currently unimplemented */
|
||||
return CONTROL_FALSE;
|
||||
default:
|
||||
return CONTROL_FALSE;
|
||||
|
@ -239,145 +249,126 @@ static void print_format(const char* str,AudioStreamBasicDescription *f){
|
|||
|
||||
static int init(int rate,int channels,int format,int flags)
|
||||
{
|
||||
OSStatus status;
|
||||
UInt32 propertySize;
|
||||
int rc;
|
||||
int i;
|
||||
AudioStreamBasicDescription inDesc, outDesc;
|
||||
ComponentDescription desc;
|
||||
Component comp;
|
||||
AURenderCallbackStruct renderCallback;
|
||||
OSStatus err;
|
||||
UInt32 size, maxFrames;
|
||||
|
||||
ao = (ao_macosx_t *)malloc(sizeof(ao_macosx_t));
|
||||
ao = (ao_macosx_t *)malloc(sizeof(ao_macosx_t));
|
||||
|
||||
/* get default output device */
|
||||
propertySize = sizeof(ao->outputDeviceID);
|
||||
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &(ao->outputDeviceID));
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN,
|
||||
"AudioHardwareGetProperty returned %d\n",
|
||||
(int)status);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
if (ao->outputDeviceID == kAudioDeviceUnknown) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioHardwareGetProperty: ao->outputDeviceID is kAudioDeviceUnknown\n");
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &ao->outputStreamBasicDescription);
|
||||
if(!status) print_format("default:",&ao->outputStreamBasicDescription);
|
||||
|
||||
|
||||
#if 1
|
||||
// dump supported format list:
|
||||
{ AudioStreamBasicDescription* p;
|
||||
Boolean ow;
|
||||
int i;
|
||||
propertySize=0; //sizeof(p);
|
||||
// status = AudioDeviceGetPropertyInfo(ao->outputDeviceID, 0, false, kAudioStreamPropertyPhysicalFormats, &propertySize, &ow);
|
||||
status = AudioDeviceGetPropertyInfo(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormats, &propertySize, &ow);
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceGetPropertyInfo returned 0x%X when getting kAudioDevicePropertyStreamFormats\n", (int)status);
|
||||
}
|
||||
p=malloc(propertySize);
|
||||
// status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioStreamPropertyPhysicalFormats, &propertySize, p);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormats, &propertySize, p);
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceGetProperty returned 0x%X when getting kAudioDevicePropertyStreamFormats\n", (int)status);
|
||||
// return CONTROL_FALSE;
|
||||
}
|
||||
for(i=0;i<propertySize/sizeof(AudioStreamBasicDescription);i++)
|
||||
print_format("support:",&p[i]);
|
||||
// printf("FORMATS: (%d) %p %p %p %p\n",propertySize,p[0],p[1],p[2],p[3]);
|
||||
free(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
// fill in our wanted format, and let's see if the driver accepts it or
|
||||
// offers some similar alternative:
|
||||
propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
memset(&ao->outputStreamBasicDescription,0,propertySize);
|
||||
ao->outputStreamBasicDescription.mSampleRate=rate;
|
||||
ao->outputStreamBasicDescription.mFormatID=kAudioFormatLinearPCM;
|
||||
ao->outputStreamBasicDescription.mChannelsPerFrame=channels;
|
||||
|
||||
print_format("wanted: ",&ao->outputStreamBasicDescription);
|
||||
|
||||
// try 1: ask if it accepts our specific requirements?
|
||||
propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
// status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioStreamPropertyPhysicalFormatMatch, &propertySize, &ao->outputStreamBasicDescription);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormatMatch, &propertySize, &ao->outputStreamBasicDescription);
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_V, "AudioDeviceGetProperty returned 0x%X when getting kAudioDevicePropertyStreamFormatMatch\n", (int)status);
|
||||
// Build Description for the input format
|
||||
memset(&inDesc, 0, sizeof(AudioStreamBasicDescription));
|
||||
inDesc.mSampleRate=rate;
|
||||
inDesc.mFormatID=kAudioFormatLinearPCM;
|
||||
inDesc.mChannelsPerFrame=channels;
|
||||
switch(format&AF_FORMAT_BITS_MASK){
|
||||
case AF_FORMAT_8BIT:
|
||||
inDesc.mBitsPerChannel=8;
|
||||
break;
|
||||
case AF_FORMAT_16BIT:
|
||||
inDesc.mBitsPerChannel=16;
|
||||
break;
|
||||
case AF_FORMAT_24BIT:
|
||||
inDesc.mBitsPerChannel=24;
|
||||
break;
|
||||
case AF_FORMAT_32BIT:
|
||||
inDesc.mBitsPerChannel=32;
|
||||
break;
|
||||
default:
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unsupported format (0x%08x)\n", format);
|
||||
return CONTROL_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if((format&AF_FORMAT_POINT_MASK)==AF_FORMAT_F) {
|
||||
// float
|
||||
inDesc.mFormatFlags = kAudioFormatFlagIsFloat|kAudioFormatFlagIsPacked;
|
||||
}
|
||||
|
||||
// propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
// status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormatSupported, &propertySize, &ao->outputStreamBasicDescription);
|
||||
// if (status) {
|
||||
// ao_msg(MSGT_AO,MSGL_V, "AudioDeviceGetProperty returned 0x%X when getting kAudioDevicePropertyStreamFormatSupported\n", (int)status);
|
||||
// }
|
||||
|
||||
// ok, now try to set the new (default or matched) audio format:
|
||||
print_format("best: ",&ao->outputStreamBasicDescription);
|
||||
propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
status = AudioDeviceSetProperty(ao->outputDeviceID, 0, 0, false, kAudioDevicePropertyStreamFormat, propertySize, &ao->outputStreamBasicDescription);
|
||||
if(status)
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceSetProperty returned 0x%X when getting kAudioDevicePropertyStreamFormat\n", (int)status);
|
||||
|
||||
// see what did we get finally... we'll be forced to use this anyway :(
|
||||
propertySize = sizeof(ao->outputStreamBasicDescription);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &ao->outputStreamBasicDescription);
|
||||
print_format("final: ",&ao->outputStreamBasicDescription);
|
||||
|
||||
/* get requested buffer length */
|
||||
// TODO: set NUM_BUFS dinamically, based on buffer size!
|
||||
propertySize = sizeof(ao->chunk_size);
|
||||
status = AudioDeviceGetProperty(ao->outputDeviceID, 0, false, kAudioDevicePropertyBufferSize, &propertySize, &ao->chunk_size);
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceGetProperty returned %d when getting kAudioDevicePropertyBufferSize\n", (int)status);
|
||||
return CONTROL_FALSE;
|
||||
else if((format&AF_FORMAT_SIGN_MASK)==AF_FORMAT_SI) {
|
||||
// signed int
|
||||
inDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
|
||||
}
|
||||
ao_msg(MSGT_AO,MSGL_V, "%5d chunk size\n", (int)ao->chunk_size);
|
||||
|
||||
ao_data.samplerate = ao->outputStreamBasicDescription.mSampleRate;
|
||||
ao_data.channels = channels;
|
||||
ao_data.outburst = ao_data.buffersize = ao->chunk_size;
|
||||
ao_data.bps =
|
||||
ao_data.samplerate * ao->outputStreamBasicDescription.mBytesPerFrame;
|
||||
|
||||
if (ao->outputStreamBasicDescription.mFormatID == kAudioFormatLinearPCM) {
|
||||
uint32_t flags = ao->outputStreamBasicDescription.mFormatFlags;
|
||||
if (flags & kAudioFormatFlagIsFloat) {
|
||||
ao_data.format = (flags&kAudioFormatFlagIsBigEndian) ? AF_FORMAT_FLOAT_BE : AF_FORMAT_FLOAT_LE;
|
||||
} else {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "Unsupported audio output "
|
||||
"format 0x%X. Please report this to the developer\n", format);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* TODO: handle AFMT_AC3, AFMT_MPEG & friends */
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "Default Audio Device doesn't "
|
||||
"support Linear PCM!\n");
|
||||
return CONTROL_FALSE;
|
||||
else {
|
||||
// unsigned int
|
||||
inDesc.mFormatFlags = kAudioFormatFlagIsPacked;
|
||||
}
|
||||
|
||||
/* Allocate ring-buffer memory */
|
||||
if((format&AF_FORMAT_END_MASK)==AF_FORMAT_BE)
|
||||
inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
|
||||
inDesc.mFramesPerPacket = 1;
|
||||
ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*channels*(inDesc.mBitsPerChannel/8);
|
||||
print_format("source: ",&inDesc);
|
||||
|
||||
ao_data.samplerate = inDesc.mSampleRate;
|
||||
ao_data.channels = inDesc.mChannelsPerFrame;
|
||||
ao_data.outburst = ao_data.buffersize = ao->chunk_size;
|
||||
ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame;
|
||||
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
comp = FindNextComponent(NULL, &desc); //Finds an component that meets the desc spec's
|
||||
if (comp == NULL) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to find Output Unit component\n");
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
err = OpenAComponent(comp, &(ao->theOutputUnit)); //gains access to the services provided by the component
|
||||
if (err) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to open Output Unit component (err=%d)\n", err);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
// Initialize AudioUnit
|
||||
err = AudioUnitInitialize(ao->theOutputUnit);
|
||||
if (err) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to initialize Output Unit component (err=%d)\n", err);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
size = sizeof(AudioStreamBasicDescription);
|
||||
err = AudioUnitGetProperty(ao->theOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outDesc, &size);
|
||||
print_format("destination: ", &outDesc);
|
||||
err = AudioUnitSetProperty(ao->theOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outDesc, size);
|
||||
|
||||
err = AudioConverterNew(&inDesc, &outDesc, &(ao->theConverter));
|
||||
if (err) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to create the AudioConverter component (err=%d)\n", err);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
size=sizeof(UInt32);
|
||||
maxFrames=8192; // This was calculated empirically. On MY system almost everything works more or less the same...
|
||||
err = AudioUnitSetProperty(ao->theOutputUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input, 0, &maxFrames, size);
|
||||
|
||||
if(err) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to set the maximum number of frames per slice!! (err=%d)\n", err);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
ao_msg(MSGT_AO, MSGL_DBG2, "Maximum number of frames per request %d (that is %d bytes)", err, maxFrames, maxFrames*inDesc.mBytesPerFrame);
|
||||
|
||||
ao->chunk_size = maxFrames*inDesc.mBytesPerFrame;
|
||||
ao->num_chunks = NUM_BUFS;
|
||||
ao->buffer_len = (ao->num_chunks + 1) * ao->chunk_size;
|
||||
ao->buffer = (unsigned char *)malloc(ao->buffer_len);
|
||||
ao->buffer = (unsigned char *)calloc(ao->num_chunks + 1, ao->chunk_size);
|
||||
ao->chunk = (unsigned char*)calloc(1, ao->chunk_size);
|
||||
|
||||
memset(&renderCallback, 0, sizeof(AURenderCallbackStruct));
|
||||
renderCallback.inputProc = theRenderProc;
|
||||
renderCallback.inputProcRefCon = 0;
|
||||
err = AudioUnitSetProperty(ao->theOutputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct));
|
||||
if (err) {
|
||||
ao_msg(MSGT_AO, MSGL_WARN, "Unable to set the render callback (err=%d)\n", err);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
/* Prepare for playback */
|
||||
|
||||
/* Set the IO proc that CoreAudio will call when it needs data */
|
||||
status = AudioDeviceAddIOProc(ao->outputDeviceID, audioDeviceIOProc, NULL);
|
||||
if (status) {
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceAddIOProc returned %d\n", (int)status);
|
||||
return CONTROL_FALSE;
|
||||
}
|
||||
|
||||
/* Start callback */
|
||||
reset();
|
||||
|
||||
return CONTROL_OK;
|
||||
|
@ -426,11 +417,12 @@ static void uninit(int immed)
|
|||
|
||||
reset();
|
||||
|
||||
status = AudioDeviceRemoveIOProc(ao->outputDeviceID, audioDeviceIOProc);
|
||||
if (status)
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceRemoveIOProc "
|
||||
"returned %d\n", (int)status);
|
||||
AudioConverterDispose(ao->theConverter);
|
||||
AudioOutputUnitStop(ao->theOutputUnit);
|
||||
AudioUnitUninitialize(ao->theOutputUnit);
|
||||
CloseComponent(ao->theOutputUnit);
|
||||
|
||||
free(ao->chunk);
|
||||
free(ao->buffer);
|
||||
free(ao);
|
||||
}
|
||||
|
@ -439,12 +431,12 @@ static void uninit(int immed)
|
|||
/* stop playing, keep buffers (for pause) */
|
||||
static void audio_pause()
|
||||
{
|
||||
OSErr status;
|
||||
OSErr status=noErr;
|
||||
|
||||
/* stop callback */
|
||||
status = AudioDeviceStop(ao->outputDeviceID, audioDeviceIOProc);
|
||||
status=AudioOutputUnitStop(ao->theOutputUnit);
|
||||
if (status)
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceStop returned %d\n",
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioOutputUnitStop returned %d\n",
|
||||
(int)status);
|
||||
}
|
||||
|
||||
|
@ -452,8 +444,10 @@ static void audio_pause()
|
|||
/* resume playing, after audio_pause() */
|
||||
static void audio_resume()
|
||||
{
|
||||
OSErr status = AudioDeviceStart(ao->outputDeviceID, audioDeviceIOProc);
|
||||
OSErr status=noErr;
|
||||
|
||||
status=AudioOutputUnitStart(ao->theOutputUnit);
|
||||
if (status)
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioDeviceStart returned %d\n",
|
||||
ao_msg(MSGT_AO,MSGL_WARN, "AudioOutputUnitStart returned %d\n",
|
||||
(int)status);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue