Skip to content

Commit

Permalink
PsychPortAudio: Suppress chatty Linux debug output/warnings at verbos…
Browse files Browse the repository at this point in the history
…ity < 6.

Both the ALSA backend and the JACK backend spill lots of pointless
debug output to stderr, so use dlsym() to get access to their error
callback functions and hook up useful or dummy callbacks which suppress
debug output to the console, depending on verbosity level.

This requires -ldl for the Linux Octave/Matlab/Python build scripts to
have dynamic linking/symbol resolution support for PsychPortAudio.

Also make other output less chatty.

And improve help text output in case of selection of unsupported
samplerate or channel count.

-> Lots of cosmetic, but the amount of spillage was getting a bit
   too much, even for me.
  • Loading branch information
kleinerm committed Nov 7, 2018
1 parent ef27df8 commit cd3607a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 13 deletions.
81 changes: 73 additions & 8 deletions PsychSourceGL/Source/Common/PsychPortAudio/PsychPortAudio.c
Expand Up @@ -45,6 +45,15 @@

#if PSYCH_SYSTEM == PSYCH_LINUX
#include "pa_linux_alsa.h"
#include <alsa/asoundlib.h>
#include <dlfcn.h>

void (*myjack_set_error_function)(void(*)(const char *)) = NULL;

// Dummy error handler to swallow pointless ALSA debug/warning/errr messages, if handler is attached:
static void ALSAErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
{
}

// Pseudo-Defines of Portaudio internal structs, mimicking the memory layout
// of the true Portaudio internal structs just enough so that we can cast a PaStream*
Expand Down Expand Up @@ -136,10 +145,17 @@ typedef void (*PaUtilLogCallback ) (const char *log);
void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb);

#if PSYCH_SYSTEM == PSYCH_LINUX
// Dummy implementation, as many libportaudio.so implementations seem to lack this function :(:
void (*myPaUtil_SetDebugPrintFunction)(PaUtilLogCallback cb) = NULL;

// Wrapper implementation, as many libportaudio.so implementations seem to lack this function :(:
void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb)
{
(void) cb;
// Try to get function dynamically:
myPaUtil_SetDebugPrintFunction = dlsym(RTLD_NEXT, "PaUtil_SetDebugPrintFunction");

if (myPaUtil_SetDebugPrintFunction)
myPaUtil_SetDebugPrintFunction(cb);

return;
}
#endif
Expand Down Expand Up @@ -1958,6 +1974,15 @@ PsychError PsychPortAudioExit(void)
// Detach our callback function for low-level debug output:
PaUtil_SetDebugPrintFunction(NULL);

#if PSYCH_SYSTEM == PSYCH_LINUX
// Disable ALSA error handler:
snd_lib_error_set_handler(NULL);
if (myjack_set_error_function) {
myjack_set_error_function(NULL);
myjack_set_error_function = NULL;
}
#endif

// Restart suspended PulseAudio server if it was suspended by us:
if (pulseaudio_isSuspended) {
int rc = 0;
Expand Down Expand Up @@ -2024,14 +2049,35 @@ void PsychPortAudioInitialize(void)
// Setup callback function for low-level debug output:
PaUtil_SetDebugPrintFunction(PALogger);

#if PSYCH_SYSTEM == PSYCH_LINUX
// Set an error handler for ALSA debug output/errors to stop the spewage of utterly
// pointless ALSA warning messages to stderr. At verbosity <= 5 we sent ALSA chatter
// to a dummy error handler. At levels > 5 we disable our error handler, so ALSA
// chatter goes to stderr. The same is true for the JACK backend, which does only
// set its own error callback if it makes it through initialization in Pa_Initialize().
// During the attempt to connect to the Jack server, it doesn't set its own callback,
// so all error output during jack_client_open() spills into our stderr console -
// and considerable pointless spillage there is :( -- Try to set our own override
// just for the time during Pa_Initialize() -- it will get overriden, but at least
// prevent the ugly spillage during startup:
myjack_set_error_function = dlsym(RTLD_DEFAULT, "jack_set_error_function");
if (myjack_set_error_function)
myjack_set_error_function(PALogger);

if (verbosity <= 5)
snd_lib_error_set_handler(ALSAErrorHandler);
else
snd_lib_error_set_handler(NULL);
#endif

if ((err=Pa_Initialize())!=paNoError) {
printf("PTB-ERROR: Portaudio initialization failed with following port audio error: %s \n", Pa_GetErrorText(err));
PaUtil_SetDebugPrintFunction(NULL);
PsychErrorExitMsg(PsychError_system, "Failed to initialize PortAudio subsystem.");
}
else {
if(verbosity>2) {
printf("PTB-INFO: Using specially modified PortAudio engine, based on offical version: %s\n", Pa_GetVersionText());
printf("PTB-INFO: Using modified %s\n", Pa_GetVersionText());
}
}

Expand Down Expand Up @@ -2795,11 +2841,17 @@ PsychError PSYCHPORTAUDIOOpen(void)
// Check if the requested sample format and settings are likely supported by Audio API:
err = Pa_IsFormatSupported(((mode & kPortAudioCapture) ? &inputParameters : NULL), ((mode & kPortAudioPlayBack) ? &outputParameters : NULL), freq);
if (err != paNoError && err != paDeviceUnavailable) {
printf("PTB-ERROR: Desired audio parameters for device %i unsupported by audio device. PortAudio reports this error: %s \n", deviceid, Pa_GetErrorText(err));
printf("PTB-ERROR: This could be, e.g., due to an unsupported combination of audio sample rate, audio channel allocation, or audio sample format.\n");
printf("PTB-ERROR: Desired audio parameters for device %i unsupported by audio device: %s \n", deviceid, Pa_GetErrorText(err));
if (err == paInvalidSampleRate)
printf("PTB-ERROR: Seems the requested audio sample rate %lf Hz is not supported by this combo of hardware and sound driver.\n", freq);
else if (err == paInvalidChannelCount)
printf("PTB-ERROR: Seems the requested number of audio channels is not supported by this combo of hardware and sound driver.\n");
else
printf("PTB-ERROR: This could be, e.g., due to an unsupported combination of audio sample rate, audio channel count/allocation, or audio sample format.\n");

if (PSYCH_SYSTEM == PSYCH_LINUX)
printf("PTB-ERROR: On Linux you may be able to use ALSA audio converter plugins to make this work.\n");
PsychErrorExitMsg(PsychError_system, "Failed to open PortAudio audio device due to unsupported combination of audio parameters.");
PsychErrorExitMsg(PsychError_user, "Failed to open PortAudio audio device due to unsupported combination of audio parameters.");
}

// Try to create & open stream:
Expand Down Expand Up @@ -2962,7 +3014,7 @@ PsychError PSYCHPORTAUDIOOpen(void)
// Reset to sane mode:
bp->hostBufferSizeMode = paUtilFixedHostBufferSize;

if (verbosity > 3)
if (verbosity > 4)
printf("PTB-INFO: Applying paUtilFixedHostBufferSize workaround for pure half-duplex capture mode.\n");
}
}
Expand Down Expand Up @@ -5237,7 +5289,20 @@ PsychError PSYCHPORTAUDIOVerbosity(void)
PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) verbosity);

// Set new level, if one was provided:
if (level > -1) verbosity = level;
if (level > -1) {
verbosity = level;

#if PSYCH_SYSTEM == PSYCH_LINUX
// Set an error handler for ALSA debug output/errors to stop the spewage of utterly
// pointless ALSA warning messages to stderr. At verbosity <= 5 we sent ALSA chatter
// to a dummy error handler. At levels > 5 we disable our error handler, so ALSA
// chatter goes to stderr...
if (verbosity <= 5)
snd_lib_error_set_handler(ALSAErrorHandler);
else
snd_lib_error_set_handler(NULL);
#endif
}

return(PsychError_none);
}
Expand Down
2 changes: 1 addition & 1 deletion PsychSourceGL/Source/linuxmakeit64.m
Expand Up @@ -45,7 +45,7 @@ function linuxmakeit64(mode)

if mode==3
% Build PsychPortAudio.mexa64:
mex CFLAGS='$CFLAGS -fPIC -std=gnu99 -fexceptions -pthread' -v -outdir ../Projects/Linux/build/ -output PsychPortAudio -largeArrayDims -DPTBMODULE_PsychPortAudio -ICommon/Base -ILinux/Base -ICommon/PsychPortAudio -ICommon/Screen "Linux/Base/*.c" "Common/Base/*.c" "Common/PsychPortAudio/*.c" -lportaudio -lc -lrt
mex CFLAGS='$CFLAGS -fPIC -std=gnu99 -fexceptions -pthread' -v -outdir ../Projects/Linux/build/ -output PsychPortAudio -largeArrayDims -DPTBMODULE_PsychPortAudio -ICommon/Base -ILinux/Base -ICommon/PsychPortAudio -ICommon/Screen "Linux/Base/*.c" "Common/Base/*.c" "Common/PsychPortAudio/*.c" -lportaudio -lc -lrt -ldl
unix(['mv ../Projects/Linux/build/PsychPortAudio.' mexext ' ' PsychtoolboxRoot 'PsychBasic/']);
end

Expand Down
2 changes: 1 addition & 1 deletion PsychSourceGL/Source/linuxmakeitoctave3.m
Expand Up @@ -100,7 +100,7 @@ function linuxmakeitoctave3(mode)

if mode==3
% Build PsychPortAudio.mex:
mex -v -g --output ../Projects/Linux/build/PsychPortAudio.mex -Wno-date-time -DPTBMODULE_PsychPortAudio -DPTBOCTAVE3MEX -ICommon/Base -ILinux/Base -ICommon/PsychPortAudio -ICommon/Screen Linux/Base/*.c Common/Base/*.c Common/PsychPortAudio/*.c -lportaudio -lc -lrt
mex -v -g --output ../Projects/Linux/build/PsychPortAudio.mex -Wno-date-time -DPTBMODULE_PsychPortAudio -DPTBOCTAVE3MEX -ICommon/Base -ILinux/Base -ICommon/PsychPortAudio -ICommon/Screen Linux/Base/*.c Common/Base/*.c Common/PsychPortAudio/*.c -lportaudio -lc -lrt -ldl
unix(['cp ../Projects/Linux/build/PsychPortAudio.mex ' PsychtoolboxRoot target]);
striplibsfrommexfile([PsychtoolboxRoot target 'PsychPortAudio.mex']);
end
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Expand Up @@ -58,20 +58,20 @@ def get_basesources(name, osname):
print('Building for Linux...\n');
osname = 'Linux';
# All libraries to link to all modules:
base_libs = ['c', 'rt'];
base_libs = ['c', 'rt', 'dl'];
# No "no reproducible builds" warning:
base_compile_args = ['-Wno-date-time'];
# Extra OS specific libs for PsychPortAudio:
audio_libdirs = [];
audio_extralinkargs = [];
audio_libs = ['portaudio', 'asound']; # Note: libasound not really needed for dynamic link of libportaudio.so.
audio_libs = ['portaudio', 'asound'];
audio_objects = [];

# Static linking for audio_objects aka libportaudio.a no longer used as of v3.0.15:
#if is_64bits == True:
# audio_objects = ['PsychSourceGL/Cohorts/PortAudio/libportaudio64Linux.a'];
#else:
# audio_objects = ['PsychSourceGL/Cohorts/PortAudio/libportaudio32Linux.a'];
audio_objects = [];

# libusb includes:
usb_includes = ['/usr/include/libusb-1.0'];
Expand Down

0 comments on commit cd3607a

Please sign in to comment.