snd_card_next( &card );\r
}\r
\r
+ result = snd_ctl_open( &handle, "default", 0 );\r
+ if (result == 0) {\r
+ nDevices++;\r
+ snd_ctl_close( handle );\r
+ }\r
+\r
return nDevices;\r
}\r
\r
snd_card_next( &card );\r
}\r
\r
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+ if ( result == 0 ) {\r
+ if ( nDevices == device ) {\r
+ strcpy( name, "default" );\r
+ goto foundDevice;\r
+ }\r
+ nDevices++;\r
+ }\r
+\r
if ( nDevices == 0 ) {\r
errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
snd_pcm_hw_params_t *params;\r
snd_pcm_hw_params_alloca( ¶ms );\r
\r
- // First try for playback\r
+ // First try for playback unless default device (which has subdev -1)\r
stream = SND_PCM_STREAM_PLAYBACK;\r
- snd_pcm_info_set_device( pcminfo, subdevice );\r
- snd_pcm_info_set_subdevice( pcminfo, 0 );\r
snd_pcm_info_set_stream( pcminfo, stream );\r
+ if ( subdevice != -1 ) {\r
+ snd_pcm_info_set_device( pcminfo, subdevice );\r
+ snd_pcm_info_set_subdevice( pcminfo, 0 );\r
\r
- result = snd_ctl_pcm_info( chandle, pcminfo );\r
- if ( result < 0 ) {\r
- // Device probably doesn't support playback.\r
- goto captureProbe;\r
+ result = snd_ctl_pcm_info( chandle, pcminfo );\r
+ if ( result < 0 ) {\r
+ // Device probably doesn't support playback.\r
+ goto captureProbe;\r
+ }\r
}\r
\r
result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );\r
snd_pcm_close( phandle );\r
\r
captureProbe:\r
- // Now try for capture\r
stream = SND_PCM_STREAM_CAPTURE;\r
snd_pcm_info_set_stream( pcminfo, stream );\r
\r
- result = snd_ctl_pcm_info( chandle, pcminfo );\r
- snd_ctl_close( chandle );\r
- if ( result < 0 ) {\r
- // Device probably doesn't support capture.\r
- if ( info.outputChannels == 0 ) return info;\r
- goto probeParameters;\r
+ // Now try for capture unless default device (with subdev = -1)\r
+ if ( subdevice != -1 ) {\r
+ result = snd_ctl_pcm_info( chandle, pcminfo );\r
+ snd_ctl_close( chandle );\r
+ if ( result < 0 ) {\r
+ // Device probably doesn't support capture.\r
+ if ( info.outputChannels == 0 ) return info;\r
+ goto probeParameters;\r
+ }\r
}\r
\r
result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
snd_card_next( &card );\r
}\r
\r
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+ if ( result == 0 ) {\r
+ if ( nDevices == device ) {\r
+ strcpy( name, "default" );\r
+ goto foundDevice;\r
+ }\r
+ nDevices++;\r
+ }\r
+\r
if ( nDevices == 0 ) {\r
// This should not happen because a check is made before this function is called.\r
errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";\r
RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
double streamTime = getStreamTime();\r
RtAudioStreamStatus status = 0;\r
- int doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+ int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],\r
stream_.bufferSize, streamTime, status,\r
stream_.callbackInfo.userData );\r
\r
}\r
\r
MUTEX_LOCK( &stream_.mutex );\r
+ void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];\r
+ void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];\r
\r
if ( stream_.state != STREAM_RUNNING )\r
goto unlock;\r
\r
int pa_error;\r
size_t bytes;\r
- switch ( stream_.mode ) {\r
- case INPUT:\r
- bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
- if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {\r
- errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
- pa_strerror( pa_error ) << ".";\r
- errorText_ = errorStream_.str();\r
- error( RtError::WARNING );\r
- }\r
- break;\r
- case OUTPUT:\r
- bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
- if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0 ) {\r
+ if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+ if ( stream_.doConvertBuffer[OUTPUT] ) {\r
+ convertBuffer( stream_.deviceBuffer,\r
+ stream_.userBuffer[OUTPUT],\r
+ stream_.convertInfo[OUTPUT] );\r
+ bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *\r
+ formatBytes( stream_.deviceFormat[OUTPUT] );\r
+ } else\r
+ bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *\r
+ formatBytes( stream_.userFormat );\r
+\r
+ if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {\r
errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
pa_strerror( pa_error ) << ".";\r
errorText_ = errorStream_.str();\r
error( RtError::WARNING );\r
}\r
- break;\r
- case DUPLEX:\r
- bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
- if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {\r
+ }\r
+\r
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {\r
+ if ( stream_.doConvertBuffer[INPUT] )\r
+ bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *\r
+ formatBytes( stream_.deviceFormat[INPUT] );\r
+ else\r
+ bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *\r
+ formatBytes( stream_.userFormat );\r
+ \r
+ if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {\r
errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
pa_strerror( pa_error ) << ".";\r
errorText_ = errorStream_.str();\r
error( RtError::WARNING );\r
}\r
- bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
- if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0) {\r
- errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
- pa_strerror( pa_error ) << ".";\r
- errorText_ = errorStream_.str();\r
- error( RtError::WARNING );\r
+ if ( stream_.doConvertBuffer[INPUT] ) {\r
+ convertBuffer( stream_.userBuffer[INPUT],\r
+ stream_.deviceBuffer,\r
+ stream_.convertInfo[INPUT] );\r
}\r
- break;\r
- default:\r
- // ERROR\r
- break;\r
}\r
\r
unlock:\r
return false;\r
}\r
\r
- if ( options && ( options->flags & RTAUDIO_NONINTERLEAVED ) ) {\r
- errorText_ = "RtApiPulse::probeDeviceOpen: only interleaved audio data supported.";\r
- return false;\r
- }\r
-\r
- stream_.userInterleaved = true;\r
- stream_.nBuffers = 1;\r
-\r
+ // Set interleaving parameters.\r
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+ else stream_.userInterleaved = true;\r
stream_.deviceInterleaved[mode] = true;\r
+ stream_.nBuffers = 1;\r
stream_.doByteSwap[mode] = false;\r
- stream_.doConvertBuffer[mode] = false;\r
+ stream_.doConvertBuffer[mode] = channels > 1 && !stream_.userInterleaved;\r
stream_.deviceFormat[mode] = stream_.userFormat;\r
stream_.nUserChannels[mode] = channels;\r
- stream_.nDeviceChannels[mode] = channels;\r
+ stream_.nDeviceChannels[mode] = channels + firstChannel;\r
stream_.channelOffset[mode] = 0;\r
\r
// Allocate necessary internal buffers.\r
}\r
stream_.bufferSize = *bufferSize;\r
\r
+ if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+ bool makeBuffer = true;\r
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+ if ( mode == INPUT ) {\r
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+ }\r
+ }\r
+\r
+ if ( makeBuffer ) {\r
+ bufferBytes *= *bufferSize;\r
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+ if ( stream_.deviceBuffer == NULL ) {\r
+ errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";\r
+ goto error;\r
+ }\r
+ }\r
+ }\r
+ \r
+ stream_.device[mode] = device;\r
+ stream_.state = STREAM_STOPPED;\r
+\r
+ // Setup the buffer conversion information structure.\r
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
if ( !stream_.apiHandle ) {\r
PulseAudioHandle *pah = new PulseAudioHandle;\r
if ( !pah ) {\r
AC_INIT(RtAudio, 4.0, gary@music.mcgill.ca, rtaudio)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(RtAudio.cpp)
-AC_CONFIG_FILES([rtaudio-config Makefile tests/Makefile])
+AC_CONFIG_FILES([rtaudio-config librtaudio.pc Makefile tests/Makefile])
# Fill GXX with something before test.
AC_SUBST( GXX, ["no"] )
+dnl Check for pkg-config program, used for configuring some libraries.
+m4_define_default([PKG_PROG_PKG_CONFIG],
+[AC_MSG_CHECKING([pkg-config])
+AC_MSG_RESULT([no])])
+
+PKG_PROG_PKG_CONFIG
+
+dnl If the pkg-config autoconf support isn't installed, define its
+dnl autoconf macro to disable any packages depending on it.
+m4_define_default([PKG_CHECK_MODULES],
+[AC_MSG_CHECKING([$1])
+AC_MSG_RESULT([no])
+$4])
+
# Checks for programs.
AC_PROG_CXX(g++ CC c++ cxx)
AC_PROG_RANLIB
# Checks for package options and external software
AC_SUBST( api, [""] )
+AC_SUBST( req, [""] )
AC_MSG_CHECKING(for audio API)
case $host in
*-*-netbsd*)
# Look for ALSA flag
AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [
api="$api -D__LINUX_ALSA__"
+ req="$req alsa"
AC_MSG_RESULT(using ALSA)
AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], )
# Look for PULSE flag
AC_ARG_WITH(pulse, [ --with-pulse = choose PulseAudio API support (linux only)], [
api="$api -D__LINUX_PULSE__"
+ req="$req libpulse-simple"
AC_MSG_RESULT(using PulseAudio)
- AC_CHECK_LIB(pulse-simple, pa_simple_new, , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))], )
+ PKG_CHECK_MODULES([PULSE], [libpulse-simple], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))
+ LIBS="$LIBS `pkg-config --libs libpulse-simple`" ], )
# Look for OSS flag
AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [
if [test "$api" == "";] then
AC_MSG_RESULT(using ALSA)
AC_SUBST( api, [-D__LINUX_ALSA__] )
+ req="$req alsa"
AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
fi