Nasty behaviour with CoreAudio on El Capitan


#1

Hello!
I’ve stumbled upon a problem that makes audio completely mute on El Capitan.
It happens when you instantiate an AudioDeviceManager for a second time.
Here’s a very simple test app that reproduces the problem.

Header:

/*
  ==============================================================================

    This file was auto-generated!

  ==============================================================================
*/

#ifndef MAINCOMPONENT_H_INCLUDED
#define MAINCOMPONENT_H_INCLUDED

#include "../JuceLibraryCode/JuceHeader.h"


//==============================================================================
/*
    A very simple audio engine.
*/
class AudioEngine : public AudioSource
{
public:
    //==============================================================================
    AudioEngine();
    ~AudioEngine();
    
    void prepareToPlay (int samplesPerBlockExpected,
                        double sampleRate) override;
    
    void releaseResources() override;
    
    void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override;
    
private:
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioEngine)
    
    AudioDeviceManager deviceManager;
    AudioSourcePlayer sourcePlayer;
};

//==============================================================================
/*
    This component lives inside our window, and this is where you should put all
    your controls and content.
*/
class MainContentComponent   : public Component,
                               public Button::Listener
{
public:
    //==============================================================================
    MainContentComponent();
    ~MainContentComponent();

    void paint (Graphics&) override;
    void resized() override;
    void buttonClicked (Button* button) override;

private:
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
    
    TextButton textButton;
    ScopedPointer<AudioEngine> currentAudioEngine;
};


#endif  // MAINCOMPONENT_H_INCLUDED

Implementation:

/*
  ==============================================================================

    This file was auto-generated!

  ==============================================================================
*/

#include "MainComponent.h"


//==============================================================================
MainContentComponent::MainContentComponent()
{
    textButton.setButtonText("New Engine");
    textButton.addListener(this);
    addAndMakeVisible(textButton);
    
    setSize (600, 400);
}

MainContentComponent::~MainContentComponent()
{
}

void MainContentComponent::paint (Graphics& g)
{
    g.fillAll (Colours::lightgrey);
}

void MainContentComponent::resized()
{
    textButton.setBounds(10, 10, 120, 40);
}

void MainContentComponent::buttonClicked (Button* button)
{
    if (button == &textButton)
    {
        currentAudioEngine = new AudioEngine();
    }
}

//==============================================================================
AudioEngine::AudioEngine()
{
    deviceManager.initialise(2, 2, nullptr, true);
    sourcePlayer.setSource(this);
    deviceManager.addAudioCallback(&sourcePlayer);
}

AudioEngine::~AudioEngine()
{
    deviceManager.removeAudioCallback(&sourcePlayer);
    sourcePlayer.setSource(nullptr);
}

void AudioEngine::prepareToPlay (int samplesPerBlockExpected,
                    double sampleRate)
{
    
}

void AudioEngine::releaseResources()
{
    
}

void AudioEngine::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{
    
}

Steps to reproduce the issue:

  • turn up your mac’s volume
  • launch test app
  • press “New Engine” button and hear audio feedback
  • press “New Engine” button again and hear nothing

Additional notes:

  • I’ve not tested it with previous OSX versions yet.
  • The issue is not happening on windows.
  • After reproducing the issue, if you change buffer size it all goes ok.
  • Yes, this is with the latest tip.

Cheers!


#2

Why would you ever need to create multiple AudioDeviceManager instances?

You also didn’t call deviceManager.closeAudioDevice() in your AudioEngine destructor after you initialize it in the constructor.


#3

Well, thanks, I did miss the closeAudioDevice() call (which, BTW, doesn’t help in my case).
Why do I need multiple instances? Because I need to :slight_smile:


#4

The whole point of AudioDeviceManager is that you use a single instance, and attach multiple clients that share the same audio device…

I agree that what you’re reporting sounds wrong, and may be fixable (if it’s not just something new in OSX or your particular audio driver that prevents more than one instance of that device being opened). BUT… even though I’d expect this to work correctly (in theory) on OSX, if you try using multiple audiodevicemanagers on other systems, e.g. ASIO on Windows, then you will almost certainly have problems with some uncooperative drivers. So you might want to save yourself a lot of pain by avoiding doing that.


#5

Gotcha! Thanks Jules.