thestk / rtaudio

A set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound, ASIO, and WASAPI) operating systems.
Other
1.49k stars 318 forks source link

workaround: check if callback is null before use on macos #376

Closed marty1885 closed 1 year ago

marty1885 commented 1 year ago

Hi, thanks for making this project. We found a rare random crash on macOS (less then 1 in 1000) triggered by the following use of RtAudio. It finds the target audio device and quickly open and close the capture. This helps us works around a macOS 12 bug where the system thinks the mic is in use but in fact not.

void open_close_input(const std::string& device_name) {
  RtAudio adc;
  for (size_t id = 0; id < adc.getDeviceCount(); ++id) {
    auto device = adc.getDeviceInfo(id);
    if (device.name.find(device_name) != std::string::npos) {
      RtAudio::StreamParameters parameters;
      parameters.deviceId = id;
      parameters.nChannels = device.inputChannels;
      parameters.firstChannel = 0;
      unsigned int buffer_frames = 256;
      try {
        std::cout << "openning microphone..." << std::endl;
        adc.openStream(NULL, &parameters, RTAUDIO_SINT16, device.preferredSampleRate, &buffer_frames, NULL);
        if (adc.isStreamOpen()) {
          std::cout << "microphone is openned" << std::endl;
          adc.startStream();
          adc.stopStream();
          adc.closeStream();
          std::cout << "microphone is closed" << std::endl;
        }
      } catch (RtAudioError& e) {
        e.printMessage();
      }
    }
  }
}

The crash is caused by either a NULL pointer in either info or object. However we can't locate the root cause despite our best attempt. Hopefully a workaround can be merged in place.

 static OSStatus callbackHandler( AudioDeviceID inDevice,
                                  const AudioTimeStamp* /*inNow*/,
                                  const AudioBufferList* inInputData,
                                  const AudioTimeStamp* /*inInputTime*/,
                                  AudioBufferList* outOutputData,
                                  const AudioTimeStamp* /*inOutputTime*/,
                                  void* infoPointer )
 {
   CallbackInfo *info = (CallbackInfo *) infoPointer;

   RtApiCore *object = (RtApiCore *) info->object;
   if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )
     return kAudioHardwareUnspecifiedError;
   else
     return kAudioHardwareNoError;
 }