coreaudio: Commit the result of init in the end
init_out_device may only commit some part of the result and leave the state inconsistent when it encounters a fatal error or the device gets unplugged during the operation, which is expressed by kAudioHardwareBadObjectError or kAudioHardwareBadDeviceError. Commit the result in the end of the function so that it commits the result iff it sees no fatal error and the device remains plugged. With this change, handle_voice_change can rely on core->outputDeviceID to know whether the output device is initialized after calling init_out_device. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20260304-coreaudio-v8-4-bf1d40731e73@rsg.ci.i.u-tokyo.ac.jp>
Akihiko Odaki committed
Mar 4, 2026 at 15:16 UTC
f47a5a3d47fdcc577ed009b414a07d1de483d1e1
1 file changed
+26
-21
audio/coreaudio.m
+26
-21
@@ -357,8 +357,11 @@ static OSStatus out_device_ioproc(
357
358
static OSStatus init_out_device(CoreaudioVoiceOut *core)
359
{
360
+ AudioDeviceID device_id;
361
+ AudioDeviceIOProcID ioprocid;
362
AudioValueRange value_range;
363
OSStatus status;
364
+ UInt32 device_frame_size;
365
366
AudioStreamBasicDescription stream_basic_description = {
367
.mBitsPerChannel = audio_format_bits(core->hw.info.af),
@@ -371,20 +374,20 @@ static OSStatus init_out_device(CoreaudioVoiceOut *core)
374
.mSampleRate = core->hw.info.freq
375
};
376
374
- status = coreaudio_get_voice_out(&core->device_id);
377
+ status = coreaudio_get_voice_out(&device_id);
378
if (status != kAudioHardwareNoError) {
379
coreaudio_playback_logerr(status,
380
"Could not get default output device");
381
return status;
382
}
380
- if (core->device_id == kAudioDeviceUnknown) {
383
+ if (device_id == kAudioDeviceUnknown) {
384
error_report("coreaudio: Could not initialize playback: "
385
"Unknown audio device");
386
return status;
387
}
388
389
/* get minimum and maximum buffer frame sizes */
387
- status = coreaudio_get_out_framesizerange(core->device_id, &value_range);
390
+ status = coreaudio_get_out_framesizerange(device_id, &value_range);
391
if (status == kAudioHardwareBadObjectError) {
392
return 0;
393
}
@@ -395,33 +398,31 @@ static OSStatus init_out_device(CoreaudioVoiceOut *core)
398
}
399
400
if (value_range.mMinimum > core->frame_size_setting) {
398
- core->device_frame_size = value_range.mMinimum;
401
+ device_frame_size = value_range.mMinimum;
402
warn_report("coreaudio: Upsizing buffer frames to %f",
403
value_range.mMinimum);
404
} else if (value_range.mMaximum < core->frame_size_setting) {
402
- core->device_frame_size = value_range.mMaximum;
405
+ device_frame_size = value_range.mMaximum;
406
warn_report("coreaudio: Downsizing buffer frames to %f",
407
value_range.mMaximum);
408
} else {
406
- core->device_frame_size = core->frame_size_setting;
409
+ device_frame_size = core->frame_size_setting;
410
}
411
412
/* set Buffer Frame Size */
410
- status = coreaudio_set_out_framesize(core->device_id,
411
- &core->device_frame_size);
413
+ status = coreaudio_set_out_framesize(device_id, &device_frame_size);
414
if (status == kAudioHardwareBadObjectError) {
415
return 0;
416
}
417
if (status != kAudioHardwareNoError) {
418
coreaudio_playback_logerr(status,
419
"Could not set device buffer frame size %" PRIu32,
418
- (uint32_t)core->device_frame_size);
420
+ (uint32_t)device_frame_size);
421
return status;
422
}
423
424
/* get Buffer Frame Size */
423
- status = coreaudio_get_out_framesize(core->device_id,
424
- &core->device_frame_size);
425
+ status = coreaudio_get_out_framesize(device_id, &device_frame_size);
426
if (status == kAudioHardwareBadObjectError) {
427
return 0;
428
}
@@ -430,10 +431,9 @@ static OSStatus init_out_device(CoreaudioVoiceOut *core)
431
"Could not get device buffer frame size");
432
return status;
433
}
433
- core->hw.samples = core->buffer_count * core->device_frame_size;
434
435
/* set Samplerate */
436
- status = coreaudio_set_out_streamformat(core->device_id,
436
+ status = coreaudio_set_out_streamformat(device_id,
437
&stream_basic_description);
438
if (status == kAudioHardwareBadObjectError) {
439
return 0;
@@ -442,7 +442,6 @@ static OSStatus init_out_device(CoreaudioVoiceOut *core)
442
coreaudio_playback_logerr(status,
443
"Could not set samplerate %lf",
444
stream_basic_description.mSampleRate);
445
- core->device_id = kAudioDeviceUnknown;
445
return status;
446
}
447
@@ -456,20 +455,24 @@ static OSStatus init_out_device(CoreaudioVoiceOut *core)
455
* Therefore, the specified callback must be designed to avoid a deadlock
456
* with the callers of AudioObjectGetPropertyData.
457
*/
459
- core->ioprocid = NULL;
460
- status = AudioDeviceCreateIOProcID(core->device_id,
458
+ ioprocid = NULL;
459
+ status = AudioDeviceCreateIOProcID(device_id,
460
out_device_ioproc,
461
&core->hw,
463
- &core->ioprocid);
462
+ &ioprocid);
463
if (status == kAudioHardwareBadDeviceError) {
464
return 0;
465
}
467
- if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
466
+ if (status != kAudioHardwareNoError || ioprocid == NULL) {
467
coreaudio_playback_logerr(status, "Could not set IOProc");
469
- core->device_id = kAudioDeviceUnknown;
468
return status;
469
}
470
471
+ core->device_id = device_id;
472
+ core->device_frame_size = device_frame_size;
473
+ core->hw.samples = core->buffer_count * core->device_frame_size;
474
+ core->ioprocid = ioprocid;
475
+
476
return 0;
477
}
478
@@ -553,7 +556,9 @@ static OSStatus handle_voice_out_change(
556
fini_out_device(core);
557
}
558
556
- if (!init_out_device(core)) {
559
+ init_out_device(core);
560
+
561
+ if (core->device_id) {
562
update_out_device_playback_state(core);
563
}
564
@@ -650,7 +655,7 @@ static void audio_coreaudio_class_init(ObjectClass *klass, const void *data)
655
656
k->max_voices_out = 1;
657
k->max_voices_in = 0;
653
- k->voice_size_out = sizeof(coreaudioVoiceOut);
658
+ k->voice_size_out = sizeof(CoreaudioVoiceOut);
659
k->voice_size_in = 0;
660
661
k->init_out = coreaudio_init_out;