Skip to content

Commit ea97894

Browse files
authored
Merge pull request #16106 from xARSENICx/fix/au-crash-backport-2.5
[2.5] Fix AudioUnit startup crash by loading out-of-process (macOS)
2 parents d84b75a + 2010768 commit ea97894

3 files changed

Lines changed: 36 additions & 5 deletions

File tree

src/effects/backends/audiounit/audiounitmanager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,16 @@ class AudioUnitManager {
3939
/// want to e.g. block on a mutex.
4040
AudioUnit _Nullable getAudioUnit() const;
4141

42+
/// Blocks until the audio unit has been instantiated.
43+
///
44+
/// Returns true if the audio unit was instantiated successfully and false if
45+
/// the timeout was reached instead.
46+
bool waitForAudioUnit(int timeoutMs) const;
47+
4248
private:
4349
QString m_name;
4450
std::atomic<bool> m_isInstantiated;
51+
dispatch_group_t _Nonnull m_instantiationGroup;
4552
AudioUnit _Nullable m_audioUnit;
4653

4754
AudioUnitManager(AVAudioUnitComponent* _Nullable component);

src/effects/backends/audiounit/audiounitmanager.mm

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#import <AVFAudio/AVFAudio.h>
22
#import <AudioToolbox/AudioToolbox.h>
3-
#include "util/assert.h"
3+
#import <dispatch/dispatch.h>
44

55
#include <QString>
66

77
#include "effects/backends/audiounit/audiounitmanager.h"
8+
#include "util/assert.h"
89

910
AudioUnitManager::AudioUnitManager(AVAudioUnitComponent* _Nullable component)
1011
: m_name(component != nil ? QString::fromNSString([component name])
1112
: "Unknown"),
12-
m_isInstantiated(false) {
13+
m_isInstantiated(false),
14+
m_instantiationGroup(dispatch_group_create()) {
1315
}
1416

1517
AudioUnitManagerPointer AudioUnitManager::create(
@@ -56,6 +58,14 @@
5658
return m_audioUnit;
5759
}
5860

61+
bool AudioUnitManager::waitForAudioUnit(int timeoutMs) const {
62+
bool success =
63+
dispatch_group_wait(m_instantiationGroup,
64+
dispatch_time(DISPATCH_TIME_NOW, timeoutMs * 1000000)) == 0;
65+
DEBUG_ASSERT(!success || m_isInstantiated.load());
66+
return success;
67+
}
68+
5969
void AudioUnitManager::instantiateAudioUnitAsync(
6070
AudioUnitManagerPointer pManager,
6171
AVAudioUnitComponent* _Nonnull component,
@@ -75,17 +85,21 @@
7585
qDebug() << "Instantiating Audio Unit" << pManager->m_name
7686
<< "asynchronously";
7787

88+
dispatch_group_enter(pManager->m_instantiationGroup);
89+
7890
// TODO: Fix the weird formatting of blocks
7991
// clang-format off
8092
AudioComponentInstantiate(component.audioComponent, options, ^(AudioUnit _Nullable audioUnit, OSStatus error) {
8193
if (error != noErr) {
8294
qWarning() << "Could not instantiate Audio Unit"
8395
<< pManager->m_name << ":" << error
8496
<< "(Check https://www.osstatus.com for a description)";
97+
dispatch_group_leave(pManager->m_instantiationGroup);
8598
return;
8699
}
87100

88101
pManager->initializeWith(audioUnit);
102+
dispatch_group_leave(pManager->m_instantiationGroup);
89103
});
90104
// clang-format on
91105
}

src/effects/backends/audiounit/audiounitmanifest.mm

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#import <AudioToolbox/AudioToolbox.h>
22
#include "effects/backends/effectmanifestparameter.h"
33

4+
#include <QElapsedTimer>
5+
#include <QThread>
46
#include <memory>
57

68
#include "effects/backends/audiounit/audiounitmanager.h"
@@ -18,9 +20,17 @@
1820
setDescription(QString::fromNSString([component typeName]));
1921
setAuthor(QString::fromNSString([component manufacturerName]));
2022

21-
// Instantiate audio unit (in-process) to load parameters
22-
AudioUnitManagerPointer pManager = AudioUnitManager::create(
23-
component, AudioUnitInstantiationType::Sync);
23+
// Instantiate audio unit (out-of-process) to load parameters
24+
AudioUnitManagerPointer pManager = AudioUnitManager::create(component);
25+
26+
const int TIMEOUT_MS = 2000;
27+
if (!pManager->waitForAudioUnit(TIMEOUT_MS)) {
28+
qWarning() << name() << "took more than" << TIMEOUT_MS
29+
<< "ms to initialize, skipping manifest initialization "
30+
"for this effect. This means this effect will not "
31+
"display any parameters and likely not be useful!";
32+
return;
33+
}
2434

2535
AudioUnit audioUnit = pManager->getAudioUnit();
2636

0 commit comments

Comments
 (0)