coreaudio fixes and cleanups.
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmBQjMgACgkQTLbY7tPo cThL8hAAweNP5/pO5jOStrLBiqJtWOlbu3nmGytiYhGo3ShC7+aQ3tvt4gOubCj+ CGTjzDaZ1pEPsWvObSGlCX8gP0bUcqBYxlw0R/MHD9lJlQPd+HU7U9unnV9cN67/ Jd8QuBT2vfLXVOwyFieRpeliVeHWtyfD/ydwc85uGu62yzZcpPoT+DRiKGC5Q80v m1LVWiPk5xj3+2IuLJFqSVbekB7rI7xbY8l0+oxrpb0imTrbGDBHWfg55CUTUiL4 VgDtGaMBAfH5n6yBwKG/p2vFclxoQ3uNfFe15lK1WD8/a3SgeP1WMTiW5DkUodJw 45lCFmzmUJMtVVtWn3h3x58lNCJ7sY4XiW7ZKRLRofgzo4RynhroqUt/V7G68qdB hWroxBntpmMp2Xx0FwaAfusLUDwNsj7caBC5zWR7BJJ+QPXfHlK/kGAwbmwqV2+G 3FJ6aT4dRNZi4vPdtg1NK+GZA5BTJi16aHer1SR16V8Gr1cO1ZMeW2fDhtpNYJbe IUGjcm3zKVqRCYHM0nc50gGbuqYjmLPgznthI5/mPc0sJsrLJYIkb2+yMHqrzws0 XeqguDqKhitlbDefBJeEG0bgRnAm1LbvgxNuXpiM2VQkQKYipFAHdeNKB5wRx/3s c89twh5FK5FegV48oQ7x/K8tdvW5NGEOm1nIzwqAE+/0T3k/cbw= =6soQ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/audio-20210316-pull-request' into staging coreaudio fixes and cleanups. # gpg: Signature made Tue 16 Mar 2021 10:47:36 GMT # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/audio-20210316-pull-request: coreaudio: Handle output device change coreaudio: Extract device operations coreaudio: Drop support for macOS older than 10.6 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ce90fecbeb
@ -32,152 +32,32 @@
|
|||||||
#define AUDIO_CAP "coreaudio"
|
#define AUDIO_CAP "coreaudio"
|
||||||
#include "audio_int.h"
|
#include "audio_int.h"
|
||||||
|
|
||||||
#ifndef MAC_OS_X_VERSION_10_6
|
|
||||||
#define MAC_OS_X_VERSION_10_6 1060
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct coreaudioVoiceOut {
|
typedef struct coreaudioVoiceOut {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
AudioDeviceID outputDeviceID;
|
AudioDeviceID outputDeviceID;
|
||||||
|
int frameSizeSetting;
|
||||||
|
uint32_t bufferCount;
|
||||||
UInt32 audioDevicePropertyBufferFrameSize;
|
UInt32 audioDevicePropertyBufferFrameSize;
|
||||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||||
AudioDeviceIOProcID ioprocid;
|
AudioDeviceIOProcID ioprocid;
|
||||||
|
bool enabled;
|
||||||
} coreaudioVoiceOut;
|
} coreaudioVoiceOut;
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
static const AudioObjectPropertyAddress voice_addr = {
|
||||||
/* The APIs used here only become available from 10.6 */
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*id);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioHardwarePropertyDefaultOutputDevice,
|
kAudioHardwarePropertyDefaultOutputDevice,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
|
|
||||||
AudioValueRange *framerange)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*framerange);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
framerange);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*framesize);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
framesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*framesize);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectSetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
size,
|
|
||||||
framesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
|
|
||||||
AudioStreamBasicDescription *d)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*d);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyStreamFormat,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
|
||||||
AudioStreamBasicDescription *d)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*d);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyStreamFormat,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectSetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
size,
|
|
||||||
d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
|
||||||
{
|
|
||||||
UInt32 size = sizeof(*result);
|
|
||||||
AudioObjectPropertyAddress addr = {
|
|
||||||
kAudioDevicePropertyDeviceIsRunning,
|
|
||||||
kAudioDevicePropertyScopeOutput,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
|
||||||
&addr,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Legacy versions of functions using deprecated APIs */
|
|
||||||
|
|
||||||
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*id);
|
UInt32 size = sizeof(*id);
|
||||||
|
|
||||||
return AudioHardwareGetProperty(
|
return AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||||
kAudioHardwarePropertyDefaultOutputDevice,
|
&voice_addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
&size,
|
&size,
|
||||||
id);
|
id);
|
||||||
}
|
}
|
||||||
@ -186,12 +66,16 @@ static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
|
|||||||
AudioValueRange *framerange)
|
AudioValueRange *framerange)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*framerange);
|
UInt32 size = sizeof(*framerange);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceGetProperty(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
kAudioDevicePropertyBufferFrameSizeRange,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectGetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
&size,
|
&size,
|
||||||
framerange);
|
framerange);
|
||||||
}
|
}
|
||||||
@ -199,12 +83,16 @@ static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
|
|||||||
static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*framesize);
|
UInt32 size = sizeof(*framesize);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceGetProperty(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectGetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
&size,
|
&size,
|
||||||
framesize);
|
framesize);
|
||||||
}
|
}
|
||||||
@ -212,13 +100,16 @@ static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
|||||||
static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*framesize);
|
UInt32 size = sizeof(*framesize);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceSetProperty(
|
|
||||||
id,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectSetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
size,
|
size,
|
||||||
framesize);
|
framesize);
|
||||||
}
|
}
|
||||||
@ -227,12 +118,16 @@ static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
|
|||||||
AudioStreamBasicDescription *d)
|
AudioStreamBasicDescription *d)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*d);
|
UInt32 size = sizeof(*d);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceGetProperty(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
kAudioDevicePropertyStreamFormat,
|
kAudioDevicePropertyStreamFormat,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectGetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
&size,
|
&size,
|
||||||
d);
|
d);
|
||||||
}
|
}
|
||||||
@ -241,13 +136,16 @@ static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
|||||||
AudioStreamBasicDescription *d)
|
AudioStreamBasicDescription *d)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*d);
|
UInt32 size = sizeof(*d);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceSetProperty(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
kAudioDevicePropertyStreamFormat,
|
kAudioDevicePropertyStreamFormat,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectSetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
size,
|
size,
|
||||||
d);
|
d);
|
||||||
}
|
}
|
||||||
@ -255,16 +153,19 @@ static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
|||||||
static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
||||||
{
|
{
|
||||||
UInt32 size = sizeof(*result);
|
UInt32 size = sizeof(*result);
|
||||||
|
AudioObjectPropertyAddress addr = {
|
||||||
return AudioDeviceGetProperty(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
kAudioDevicePropertyDeviceIsRunning,
|
kAudioDevicePropertyDeviceIsRunning,
|
||||||
|
kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
|
return AudioObjectGetPropertyData(id,
|
||||||
|
&addr,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
&size,
|
&size,
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void coreaudio_logstatus (OSStatus status)
|
static void coreaudio_logstatus (OSStatus status)
|
||||||
{
|
{
|
||||||
@ -356,17 +257,8 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
|
|||||||
coreaudio_logstatus (status);
|
coreaudio_logstatus (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
|
#define coreaudio_playback_logerr(status, ...) \
|
||||||
{
|
coreaudio_logerr2(status, "playback", __VA_ARGS__)
|
||||||
OSStatus status;
|
|
||||||
UInt32 result = 0;
|
|
||||||
status = coreaudio_get_isrunning(outputDeviceID, &result);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr(status,
|
|
||||||
"Could not determine whether Device is playing\n");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
|
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
|
||||||
{
|
{
|
||||||
@ -439,6 +331,11 @@ static OSStatus audioDeviceIOProc(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inDevice != core->outputDeviceID) {
|
||||||
|
coreaudio_unlock (core, "audioDeviceIOProc(old device)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
frameCount = core->audioDevicePropertyBufferFrameSize;
|
frameCount = core->audioDevicePropertyBufferFrameSize;
|
||||||
pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
|
pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
|
||||||
|
|
||||||
@ -471,24 +368,225 @@ static OSStatus audioDeviceIOProc(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OSStatus init_out_device(coreaudioVoiceOut *core)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
AudioValueRange frameRange;
|
||||||
|
|
||||||
|
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not get default output Device\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (core->outputDeviceID == kAudioDeviceUnknown) {
|
||||||
|
dolog ("Could not initialize playback - Unknown Audiodevice\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get minimum and maximum buffer frame sizes */
|
||||||
|
status = coreaudio_get_framesizerange(core->outputDeviceID,
|
||||||
|
&frameRange);
|
||||||
|
if (status == kAudioHardwareBadObjectError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not get device buffer frame range\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frameRange.mMinimum > core->frameSizeSetting) {
|
||||||
|
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
|
||||||
|
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
|
||||||
|
} else if (frameRange.mMaximum < core->frameSizeSetting) {
|
||||||
|
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
|
||||||
|
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
|
||||||
|
} else {
|
||||||
|
core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set Buffer Frame Size */
|
||||||
|
status = coreaudio_set_framesize(core->outputDeviceID,
|
||||||
|
&core->audioDevicePropertyBufferFrameSize);
|
||||||
|
if (status == kAudioHardwareBadObjectError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not set device buffer frame size %" PRIu32 "\n",
|
||||||
|
(uint32_t)core->audioDevicePropertyBufferFrameSize);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get Buffer Frame Size */
|
||||||
|
status = coreaudio_get_framesize(core->outputDeviceID,
|
||||||
|
&core->audioDevicePropertyBufferFrameSize);
|
||||||
|
if (status == kAudioHardwareBadObjectError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not get device buffer frame size\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
|
||||||
|
|
||||||
|
/* get StreamFormat */
|
||||||
|
status = coreaudio_get_streamformat(core->outputDeviceID,
|
||||||
|
&core->outputStreamBasicDescription);
|
||||||
|
if (status == kAudioHardwareBadObjectError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not get Device Stream properties\n");
|
||||||
|
core->outputDeviceID = kAudioDeviceUnknown;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set Samplerate */
|
||||||
|
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||||
|
&core->outputStreamBasicDescription);
|
||||||
|
if (status == kAudioHardwareBadObjectError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr (status,
|
||||||
|
"Could not set samplerate %lf\n",
|
||||||
|
core->outputStreamBasicDescription.mSampleRate);
|
||||||
|
core->outputDeviceID = kAudioDeviceUnknown;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set Callback */
|
||||||
|
core->ioprocid = NULL;
|
||||||
|
status = AudioDeviceCreateIOProcID(core->outputDeviceID,
|
||||||
|
audioDeviceIOProc,
|
||||||
|
&core->hw,
|
||||||
|
&core->ioprocid);
|
||||||
|
if (status == kAudioHardwareBadDeviceError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
|
||||||
|
coreaudio_playback_logerr (status, "Could not set IOProc\n");
|
||||||
|
core->outputDeviceID = kAudioDeviceUnknown;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fini_out_device(coreaudioVoiceOut *core)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
UInt32 isrunning;
|
||||||
|
|
||||||
|
/* stop playback */
|
||||||
|
status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
|
||||||
|
if (status != kAudioHardwareBadObjectError) {
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_logerr(status,
|
||||||
|
"Could not determine whether Device is playing\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isrunning) {
|
||||||
|
status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
|
||||||
|
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_logerr(status, "Could not stop playback\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove callback */
|
||||||
|
status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
|
||||||
|
core->ioprocid);
|
||||||
|
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_logerr(status, "Could not remove IOProc\n");
|
||||||
|
}
|
||||||
|
core->outputDeviceID = kAudioDeviceUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_device_playback_state(coreaudioVoiceOut *core)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
UInt32 isrunning;
|
||||||
|
|
||||||
|
status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
if (status != kAudioHardwareBadObjectError) {
|
||||||
|
coreaudio_logerr(status,
|
||||||
|
"Could not determine whether Device is playing\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core->enabled) {
|
||||||
|
/* start playback */
|
||||||
|
if (!isrunning) {
|
||||||
|
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
|
||||||
|
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_logerr (status, "Could not resume playback\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* stop playback */
|
||||||
|
if (isrunning) {
|
||||||
|
status = AudioDeviceStop(core->outputDeviceID,
|
||||||
|
core->ioprocid);
|
||||||
|
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_logerr(status, "Could not pause playback\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus handle_voice_change(
|
||||||
|
AudioObjectID in_object_id,
|
||||||
|
UInt32 in_number_addresses,
|
||||||
|
const AudioObjectPropertyAddress *in_addresses,
|
||||||
|
void *in_client_data)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
coreaudioVoiceOut *core = in_client_data;
|
||||||
|
|
||||||
|
if (coreaudio_lock(core, __func__)) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core->outputDeviceID) {
|
||||||
|
fini_out_device(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = init_out_device(core);
|
||||||
|
if (!status) {
|
||||||
|
update_device_playback_state(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
coreaudio_unlock (core, __func__);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||||
void *drv_opaque)
|
void *drv_opaque)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||||
int err;
|
int err;
|
||||||
const char *typ = "playback";
|
|
||||||
AudioValueRange frameRange;
|
|
||||||
Audiodev *dev = drv_opaque;
|
Audiodev *dev = drv_opaque;
|
||||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||||
int frames;
|
|
||||||
struct audsettings obt_as;
|
struct audsettings obt_as;
|
||||||
|
|
||||||
/* create mutex */
|
/* create mutex */
|
||||||
err = pthread_mutex_init(&core->mutex, NULL);
|
err = pthread_mutex_init(&core->mutex, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
dolog("Could not create mutex\nReason: %s\n", strerror (err));
|
dolog("Could not create mutex\nReason: %s\n", strerror (err));
|
||||||
return -1;
|
goto mutex_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coreaudio_lock(core, __func__)) {
|
||||||
|
goto lock_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
obt_as = *as;
|
obt_as = *as;
|
||||||
@ -496,94 +594,49 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
as->fmt = AUDIO_FORMAT_F32;
|
as->fmt = AUDIO_FORMAT_F32;
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
|
|
||||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
core->frameSizeSetting = audio_buffer_frames(
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr2 (status, typ,
|
|
||||||
"Could not get default output Device\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (core->outputDeviceID == kAudioDeviceUnknown) {
|
|
||||||
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get minimum and maximum buffer frame sizes */
|
|
||||||
status = coreaudio_get_framesizerange(core->outputDeviceID,
|
|
||||||
&frameRange);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr2 (status, typ,
|
|
||||||
"Could not get device buffer frame range\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
frames = audio_buffer_frames(
|
|
||||||
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
|
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
|
||||||
if (frameRange.mMinimum > frames) {
|
|
||||||
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
|
|
||||||
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
|
|
||||||
} else if (frameRange.mMaximum < frames) {
|
|
||||||
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
|
|
||||||
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
|
|
||||||
} else {
|
|
||||||
core->audioDevicePropertyBufferFrameSize = frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set Buffer Frame Size */
|
core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
|
||||||
status = coreaudio_set_framesize(core->outputDeviceID,
|
|
||||||
&core->audioDevicePropertyBufferFrameSize);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr2 (status, typ,
|
|
||||||
"Could not set device buffer frame size %" PRIu32 "\n",
|
|
||||||
(uint32_t)core->audioDevicePropertyBufferFrameSize);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get Buffer Frame Size */
|
|
||||||
status = coreaudio_get_framesize(core->outputDeviceID,
|
|
||||||
&core->audioDevicePropertyBufferFrameSize);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr2 (status, typ,
|
|
||||||
"Could not get device buffer frame size\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) *
|
|
||||||
core->audioDevicePropertyBufferFrameSize;
|
|
||||||
|
|
||||||
/* get StreamFormat */
|
|
||||||
status = coreaudio_get_streamformat(core->outputDeviceID,
|
|
||||||
&core->outputStreamBasicDescription);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr2 (status, typ,
|
|
||||||
"Could not get Device Stream properties\n");
|
|
||||||
core->outputDeviceID = kAudioDeviceUnknown;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set Samplerate */
|
|
||||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||||
|
|
||||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
|
||||||
&core->outputStreamBasicDescription);
|
&voice_addr, handle_voice_change,
|
||||||
|
core);
|
||||||
if (status != kAudioHardwareNoError) {
|
if (status != kAudioHardwareNoError) {
|
||||||
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
|
coreaudio_playback_logerr (status,
|
||||||
as->freq);
|
"Could not listen to voice property change\n");
|
||||||
core->outputDeviceID = kAudioDeviceUnknown;
|
goto listener_error;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set Callback */
|
if (init_out_device(core)) {
|
||||||
core->ioprocid = NULL;
|
goto device_error;
|
||||||
status = AudioDeviceCreateIOProcID(core->outputDeviceID,
|
|
||||||
audioDeviceIOProc,
|
|
||||||
hw,
|
|
||||||
&core->ioprocid);
|
|
||||||
if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
|
|
||||||
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
|
|
||||||
core->outputDeviceID = kAudioDeviceUnknown;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coreaudio_unlock(core, __func__);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
device_error:
|
||||||
|
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||||
|
&voice_addr,
|
||||||
|
handle_voice_change,
|
||||||
|
core);
|
||||||
|
if (status != kAudioHardwareNoError) {
|
||||||
|
coreaudio_playback_logerr(status,
|
||||||
|
"Could not remove voice property change listener\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
listener_error:
|
||||||
|
coreaudio_unlock(core, __func__);
|
||||||
|
|
||||||
|
lock_error:
|
||||||
|
err = pthread_mutex_destroy(&core->mutex);
|
||||||
|
if (err) {
|
||||||
|
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_error:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coreaudio_fini_out (HWVoiceOut *hw)
|
static void coreaudio_fini_out (HWVoiceOut *hw)
|
||||||
@ -592,21 +645,21 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
|
|||||||
int err;
|
int err;
|
||||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||||
|
|
||||||
/* stop playback */
|
if (coreaudio_lock(core, __func__)) {
|
||||||
if (isPlaying(core->outputDeviceID)) {
|
abort();
|
||||||
status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr(status, "Could not stop playback\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove callback */
|
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||||
status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
|
&voice_addr,
|
||||||
core->ioprocid);
|
handle_voice_change,
|
||||||
|
core);
|
||||||
if (status != kAudioHardwareNoError) {
|
if (status != kAudioHardwareNoError) {
|
||||||
coreaudio_logerr(status, "Could not remove IOProc\n");
|
coreaudio_logerr(status, "Could not remove voice property change listener\n");
|
||||||
}
|
}
|
||||||
core->outputDeviceID = kAudioDeviceUnknown;
|
|
||||||
|
fini_out_device(core);
|
||||||
|
|
||||||
|
coreaudio_unlock(core, __func__);
|
||||||
|
|
||||||
/* destroy mutex */
|
/* destroy mutex */
|
||||||
err = pthread_mutex_destroy(&core->mutex);
|
err = pthread_mutex_destroy(&core->mutex);
|
||||||
@ -617,27 +670,16 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
|
|||||||
|
|
||||||
static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
|
static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
|
||||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||||
|
|
||||||
if (enable) {
|
if (coreaudio_lock(core, __func__)) {
|
||||||
/* start playback */
|
abort();
|
||||||
if (!isPlaying(core->outputDeviceID)) {
|
|
||||||
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr (status, "Could not resume playback\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* stop playback */
|
|
||||||
if (isPlaying(core->outputDeviceID)) {
|
|
||||||
status = AudioDeviceStop(core->outputDeviceID,
|
|
||||||
core->ioprocid);
|
|
||||||
if (status != kAudioHardwareNoError) {
|
|
||||||
coreaudio_logerr(status, "Could not pause playback\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core->enabled = enable;
|
||||||
|
update_device_playback_state(core);
|
||||||
|
|
||||||
|
coreaudio_unlock(core, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *coreaudio_audio_init(Audiodev *dev)
|
static void *coreaudio_audio_init(Audiodev *dev)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user