coreaudio: Extract device operations

This change prepare to support dynamic device changes, which requires to
perform device initialization/deinitialization multiple times.

Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
Message-Id: <20210311151512.22096-2-akihiko.odaki@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Akihiko Odaki 2021-03-12 00:15:11 +09:00 committed by Gerd Hoffmann
parent c960070c36
commit 7d6948cd98

View File

@ -36,6 +36,8 @@ 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;
@ -253,6 +255,9 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
coreaudio_logstatus (status); coreaudio_logstatus (status);
} }
#define coreaudio_playback_logerr(status, ...) \
coreaudio_logerr2(status, "playback", __VA_ARGS__)
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID) static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
{ {
OSStatus status; OSStatus status;
@ -368,126 +373,100 @@ static OSStatus audioDeviceIOProc(
return 0; return 0;
} }
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as, static OSStatus init_out_device(coreaudioVoiceOut *core)
void *drv_opaque)
{ {
OSStatus status; OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
int err;
const char *typ = "playback";
AudioValueRange frameRange; AudioValueRange frameRange;
Audiodev *dev = drv_opaque;
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
int frames;
struct audsettings obt_as;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
if (err) {
dolog("Could not create mutex\nReason: %s\n", strerror (err));
return -1;
}
obt_as = *as;
as = &obt_as;
as->fmt = AUDIO_FORMAT_F32;
audio_pcm_init_info (&hw->info, as);
status = coreaudio_get_voice(&core->outputDeviceID); status = coreaudio_get_voice(&core->outputDeviceID);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, coreaudio_playback_logerr (status,
"Could not get default output Device\n"); "Could not get default output Device\n");
return -1; return status;
} }
if (core->outputDeviceID == kAudioDeviceUnknown) { if (core->outputDeviceID == kAudioDeviceUnknown) {
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); dolog ("Could not initialize playback - Unknown Audiodevice\n");
return -1; return status;
} }
/* get minimum and maximum buffer frame sizes */ /* get minimum and maximum buffer frame sizes */
status = coreaudio_get_framesizerange(core->outputDeviceID, status = coreaudio_get_framesizerange(core->outputDeviceID,
&frameRange); &frameRange);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, coreaudio_playback_logerr (status,
"Could not get device buffer frame range\n"); "Could not get device buffer frame range\n");
return -1; return status;
} }
frames = audio_buffer_frames( if (frameRange.mMinimum > core->frameSizeSetting) {
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
if (frameRange.mMinimum > frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
} else if (frameRange.mMaximum < frames) { } else if (frameRange.mMaximum < core->frameSizeSetting) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
} else { } else {
core->audioDevicePropertyBufferFrameSize = frames; core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
} }
/* set Buffer Frame Size */ /* set Buffer Frame Size */
status = coreaudio_set_framesize(core->outputDeviceID, status = coreaudio_set_framesize(core->outputDeviceID,
&core->audioDevicePropertyBufferFrameSize); &core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, coreaudio_playback_logerr (status,
"Could not set device buffer frame size %" PRIu32 "\n", "Could not set device buffer frame size %" PRIu32 "\n",
(uint32_t)core->audioDevicePropertyBufferFrameSize); (uint32_t)core->audioDevicePropertyBufferFrameSize);
return -1; return status;
} }
/* get Buffer Frame Size */ /* get Buffer Frame Size */
status = coreaudio_get_framesize(core->outputDeviceID, status = coreaudio_get_framesize(core->outputDeviceID,
&core->audioDevicePropertyBufferFrameSize); &core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, coreaudio_playback_logerr (status,
"Could not get device buffer frame size\n"); "Could not get device buffer frame size\n");
return -1; return status;
} }
hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) * core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */ /* get StreamFormat */
status = coreaudio_get_streamformat(core->outputDeviceID, status = coreaudio_get_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription); &core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, coreaudio_playback_logerr (status,
"Could not get Device Stream properties\n"); "Could not get Device Stream properties\n");
core->outputDeviceID = kAudioDeviceUnknown; core->outputDeviceID = kAudioDeviceUnknown;
return -1; return status;
} }
/* set Samplerate */ /* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
status = coreaudio_set_streamformat(core->outputDeviceID, status = coreaudio_set_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription); &core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", coreaudio_playback_logerr (status,
as->freq); "Could not set samplerate %lf\n",
core->outputStreamBasicDescription.mSampleRate);
core->outputDeviceID = kAudioDeviceUnknown; core->outputDeviceID = kAudioDeviceUnknown;
return -1; return status;
} }
/* set Callback */ /* set Callback */
core->ioprocid = NULL; core->ioprocid = NULL;
status = AudioDeviceCreateIOProcID(core->outputDeviceID, status = AudioDeviceCreateIOProcID(core->outputDeviceID,
audioDeviceIOProc, audioDeviceIOProc,
hw, &core->hw,
&core->ioprocid); &core->ioprocid);
if (status != kAudioHardwareNoError || core->ioprocid == NULL) { if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); coreaudio_playback_logerr (status, "Could not set IOProc\n");
core->outputDeviceID = kAudioDeviceUnknown; core->outputDeviceID = kAudioDeviceUnknown;
return -1; return status;
} }
return 0; return 0;
} }
static void coreaudio_fini_out (HWVoiceOut *hw) static void fini_out_device(coreaudioVoiceOut *core)
{ {
OSStatus status; OSStatus status;
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
/* stop playback */ /* stop playback */
if (isPlaying(core->outputDeviceID)) { if (isPlaying(core->outputDeviceID)) {
@ -504,6 +483,50 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
coreaudio_logerr(status, "Could not remove IOProc\n"); coreaudio_logerr(status, "Could not remove IOProc\n");
} }
core->outputDeviceID = kAudioDeviceUnknown; core->outputDeviceID = kAudioDeviceUnknown;
}
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
int err;
Audiodev *dev = drv_opaque;
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
struct audsettings obt_as;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
if (err) {
dolog("Could not create mutex\nReason: %s\n", strerror (err));
return -1;
}
obt_as = *as;
as = &obt_as;
as->fmt = AUDIO_FORMAT_F32;
audio_pcm_init_info (&hw->info, as);
core->frameSizeSetting = audio_buffer_frames(
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
if (init_out_device(core)) {
return -1;
}
return 0;
}
static void coreaudio_fini_out (HWVoiceOut *hw)
{
OSStatus status;
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
fini_out_device(core);
/* destroy mutex */ /* destroy mutex */
err = pthread_mutex_destroy(&core->mutex); err = pthread_mutex_destroy(&core->mutex);