17#include <wx/sstream.h>
18#include <wx/txtstrm.h>
77 wxString infoName = wxSafeConvertMB2WX(info->name);
84 wxString hostapiName = wxSafeConvertMB2WX(Pa_GetHostApiInfo(info->hostApi)->name);
104#if defined(USE_PORTMIXER)
105 int oldRecordSource = Px_GetCurrentInputSource(mPortMixer);
106 if ( inputSource != oldRecordSource )
107 Px_SetCurrentInputSource(mPortMixer, inputSource);
137#if defined(USE_PORTMIXER)
145 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
146 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
147 mPreviousHWPlaythrough = -1.0;
149 Px_CloseMixer(mPortMixer);
156 int highestSampleRate;
164 highestSampleRate = 44100;
178 PaStreamParameters playbackParameters;
180 playbackParameters.device = playDeviceNum;
181 playbackParameters.sampleFormat = paFloat32;
182 playbackParameters.hostApiSpecificStreamInfo = NULL;
183 playbackParameters.channelCount = 1;
184 if (Pa_GetDeviceInfo(playDeviceNum))
185 playbackParameters.suggestedLatency =
186 Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
188 playbackParameters.suggestedLatency =
191 PaStreamParameters captureParameters;
193 captureParameters.device = recDeviceNum;
194 captureParameters.sampleFormat = paFloat32;;
195 captureParameters.hostApiSpecificStreamInfo = NULL;
196 captureParameters.channelCount = 1;
197 if (Pa_GetDeviceInfo(recDeviceNum))
198 captureParameters.suggestedLatency =
199 Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
201 captureParameters.suggestedLatency =
206 error = Pa_OpenStream(&stream,
207 &captureParameters, &playbackParameters,
208 highestSampleRate, paFramesPerBufferUnspecified,
209 paClipOff | paDitherOff,
214 mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
216 Pa_CloseStream(stream);
223 error = Pa_OpenStream(&stream,
224 &captureParameters, NULL,
225 highestSampleRate, paFramesPerBufferUnspecified,
226 paClipOff | paDitherOff,
230 mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
232 Pa_CloseStream(stream);
240 error = Pa_OpenStream(&stream,
241 NULL, &playbackParameters,
242 highestSampleRate, paFramesPerBufferUnspecified,
243 paClipOff | paDitherOff,
247 mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
249 Pa_CloseStream(stream);
263 if (sourceIndex >= 0) {
266 sourceIndex = getRecordSourceIndex(mPortMixer);
267 if (sourceIndex >= 0)
276 float inputVol = Px_GetInputVolume(mPortMixer);
278 Px_SetInputVolume(mPortMixer, 0.0);
279 if (Px_GetInputVolume(mPortMixer) > 0.1)
281 Px_SetInputVolume(mPortMixer, 0.2f);
282 if (Px_GetInputVolume(mPortMixer) < 0.1 ||
283 Px_GetInputVolume(mPortMixer) > 0.3)
285 Px_SetInputVolume(mPortMixer, inputVol);
287 Pa_CloseStream(stream);
291 wxPrintf(
"PortMixer: Recording: %s\n"
298 const std::shared_ptr<AudacityProject> &
project,
const std::weak_ptr<Meter> &wMeter)
301 ( pOwningProject ) && ( pOwningProject !=
project))
304 auto meter = wMeter.lock();
308 meter->Reset(
mRate,
true);
315 const std::shared_ptr<AudacityProject> &
project,
const std::weak_ptr<Meter> &wMeter)
318 ( pOwningProject ) && ( pOwningProject !=
project))
321 auto meter = wMeter.lock();
325 meter->Reset(
mRate,
true);
333 return mPaused.load(std::memory_order_relaxed);
346 bool isActive =
false;
351 isActive = isActive ||
353 [](
auto &pExt){ return pExt && pExt->IsOtherStreamActive(); });
386 std::vector<long> supported;
387 int irate = (int)rate;
388 const PaDeviceInfo* devInfo = NULL;
391 devInfo = Pa_GetDeviceInfo(devIndex);
395 wxLogDebug(
wxT(
"GetSupportedPlaybackRates() Could not get device info!"));
401 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
402 bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
404 PaStreamParameters pars;
406 pars.device = devIndex;
407 pars.channelCount = 1;
408 pars.sampleFormat = paFloat32;
409 pars.suggestedLatency = devInfo->defaultHighOutputLatency;
410 pars.hostApiSpecificStreamInfo = NULL;
417 if (!(isDirectSound &&
RatesToTry[i] > 200000)){
418 if (Pa_IsFormatSupported(NULL, &pars,
RatesToTry[i]) == 0)
429 if (!(isDirectSound && irate > 200000))
430 if (Pa_IsFormatSupported(NULL, &pars, irate) == 0)
431 supported.push_back(irate);
451 std::vector<long> supported;
452 int irate = (int)rate;
453 const PaDeviceInfo* devInfo = NULL;
456 devInfo = Pa_GetDeviceInfo(devIndex);
460 wxLogDebug(
wxT(
"GetSupportedCaptureRates() Could not get device info!"));
470 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
471 bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
473 PaStreamParameters pars;
475 pars.device = devIndex;
476 pars.channelCount = recordChannels;
477 pars.sampleFormat = paFloat32;
478 pars.suggestedLatency = latencyDuration / 1000.0;
479 pars.hostApiSpecificStreamInfo = NULL;
485 if (!(isDirectSound &&
RatesToTry[i] > 200000))
487 if (Pa_IsFormatSupported(&pars, NULL,
RatesToTry[i]) == 0)
498 if (!(isDirectSound && irate > 200000))
499 if (Pa_IsFormatSupported(&pars, NULL, irate) == 0)
500 supported.push_back(irate);
507 int playDevice,
int recDevice,
double rate)
510 if (playDevice == -1) {
513 if (recDevice == -1) {
531 std::vector<long> result;
533 for (i = 0; i < (int)playback.size(); i++)
535 result.push_back(playback[i]);
566 if (rates.empty())
return 44100;
572int AudioIOBase::getRecordSourceIndex(PxMixer *portMixer)
576 int numSources = Px_GetNumInputSources(portMixer);
577 for (i = 0; i < numSources; i++) {
578 if (sourceName == wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(portMixer, i))))
587 wxString devName(devNameArg);
593 PaHostApiIndex hostCnt = Pa_GetHostApiCount();
594 PaHostApiIndex hostNum;
595 for (hostNum = 0; hostNum < hostCnt; hostNum++)
597 const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
598 if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
600 for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
602 PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
604 const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
605 if (dinfo &&
DeviceName(dinfo) == devName && dinfo->maxOutputChannels > 0 )
615 return hinfo->defaultOutputDevice;
623 PaDeviceIndex deviceNum = Pa_GetDefaultOutputDevice();
642 wxString devName(devNameArg);
648 PaHostApiIndex hostCnt = Pa_GetHostApiCount();
649 PaHostApiIndex hostNum;
650 for (hostNum = 0; hostNum < hostCnt; hostNum++)
652 const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
653 if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
655 for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
657 PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
659 const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
660 if (dinfo &&
DeviceName(dinfo) == devName && dinfo->maxInputChannels > 0 )
670 return hinfo->defaultInputDevice;
676 PaDeviceIndex deviceNum = Pa_GetDefaultInputDevice();
699 wxStringOutputStream o;
700 wxTextOutputStream s(o, wxEOL_UNIX);
703 return XO(
"Stream is active ... unable to gather information.\n")
709 int recDeviceNum = Pa_GetDefaultInputDevice();
710 int playDeviceNum = Pa_GetDefaultOutputDevice();
711 int cnt = Pa_GetDeviceCount();
714 wxLogDebug(
wxT(
"Portaudio reports %d audio devices"),cnt);
716 s <<
wxT(
"==============================\n");
717 s <<
XO(
"Default recording device number: %d\n").Format( recDeviceNum );
718 s <<
XO(
"Default playback device number: %d\n").Format( playDeviceNum);
726 s <<
XO(
"No devices found\n");
727 return o.GetString();
730 const PaDeviceInfo* info;
732 for (j = 0; j < cnt; j++) {
733 s <<
wxT(
"==============================\n");
735 info = Pa_GetDeviceInfo(j);
737 s <<
XO(
"Device info unavailable for: %d\n").Format( j );
742 s <<
XO(
"Device ID: %d\n").Format( j );
743 s <<
XO(
"Device name: %s\n").Format(
name );
744 s <<
XO(
"Host name: %s\n").Format(
HostName(info) );
745 s <<
XO(
"Recording channels: %d\n").Format( info->maxInputChannels );
746 s <<
XO(
"Playback channels: %d\n").Format( info->maxOutputChannels );
747 s <<
XO(
"Low Recording Latency: %g\n").Format( info->defaultLowInputLatency );
748 s <<
XO(
"Low Playback Latency: %g\n").Format( info->defaultLowOutputLatency );
749 s <<
XO(
"High Recording Latency: %g\n").Format( info->defaultHighInputLatency );
750 s <<
XO(
"High Playback Latency: %g\n").Format( info->defaultHighOutputLatency );
755 s <<
XO(
"Supported Rates:\n");
756 for (
int k = 0; k < (int) rates.size(); k++) {
757 s <<
wxT(
" ") << (int)rates[k] <<
wxT(
"\n");
760 if (
name == playDevice && info->maxOutputChannels > 0)
763 if (
name == recDevice && info->maxInputChannels > 0)
768 if (recDeviceNum < 0 && info->maxInputChannels > 0){
771 if (playDeviceNum < 0 && info->maxOutputChannels > 0){
776 bool haveRecDevice = (recDeviceNum >= 0);
777 bool havePlayDevice = (playDeviceNum >= 0);
779 s <<
wxT(
"==============================\n");
781 s <<
XO(
"Selected recording device: %d - %s\n").Format( recDeviceNum, recDevice );
783 s <<
XO(
"No recording device found for '%s'.\n").Format( recDevice );
786 s <<
XO(
"Selected playback device: %d - %s\n").Format( playDeviceNum, playDevice );
788 s <<
XO(
"No playback device found for '%s'.\n").Format( playDevice );
792 if (havePlayDevice && haveRecDevice) {
795 s <<
XO(
"Supported Rates:\n");
801 s <<
XO(
"Cannot check mutual sample rates without both devices.\n");
802 return o.GetString();
805#if defined(USE_PORTMIXER)
809 bool EmulateMixerInputVol =
true;
810 float MixerInputVol = 1.0;
811 float MixerOutputVol = 1.0;
817 PaStreamParameters playbackParameters;
819 playbackParameters.device = playDeviceNum;
820 playbackParameters.sampleFormat = paFloat32;
821 playbackParameters.hostApiSpecificStreamInfo = NULL;
822 playbackParameters.channelCount = 1;
823 if (Pa_GetDeviceInfo(playDeviceNum)){
824 playbackParameters.suggestedLatency =
825 Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
828 playbackParameters.suggestedLatency =
831 PaStreamParameters captureParameters;
833 captureParameters.device = recDeviceNum;
834 captureParameters.sampleFormat = paFloat32;;
835 captureParameters.hostApiSpecificStreamInfo = NULL;
836 captureParameters.channelCount = 1;
837 if (Pa_GetDeviceInfo(recDeviceNum)){
838 captureParameters.suggestedLatency =
839 Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
842 captureParameters.suggestedLatency =
846 error = Pa_OpenStream(&stream,
847 &captureParameters, &playbackParameters,
848 highestSampleRate, paFramesPerBufferUnspecified,
849 paClipOff | paDitherOff,
853 error = Pa_OpenStream(&stream,
854 &captureParameters, NULL,
855 highestSampleRate, paFramesPerBufferUnspecified,
856 paClipOff | paDitherOff,
861 s <<
XO(
"Received %d while opening devices\n").Format( error );
862 return o.GetString();
865 PxMixer *PortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
868 s <<
XO(
"Unable to open Portmixer\n");
869 Pa_CloseStream(stream);
870 return o.GetString();
873 s <<
wxT(
"==============================\n");
874 s <<
XO(
"Available mixers:\n");
877 cnt = Px_GetNumMixers(stream);
878 for (
int i = 0; i < cnt; i++) {
879 wxString
name = wxSafeConvertMB2WX(Px_GetMixerName(stream, i));
880 s <<
XO(
"%d - %s\n").Format( i,
name );
883 s <<
wxT(
"==============================\n");
884 s <<
XO(
"Available recording sources:\n");
885 cnt = Px_GetNumInputSources(PortMixer);
886 for (
int i = 0; i < cnt; i++) {
887 wxString
name = wxSafeConvertMB2WX(Px_GetInputSourceName(PortMixer, i));
888 s <<
XO(
"%d - %s\n").Format( i,
name );
891 s <<
wxT(
"==============================\n");
892 s <<
XO(
"Available playback volumes:\n");
893 cnt = Px_GetNumOutputVolumes(PortMixer);
894 for (
int i = 0; i < cnt; i++) {
895 wxString
name = wxSafeConvertMB2WX(Px_GetOutputVolumeName(PortMixer, i));
896 s <<
XO(
"%d - %s\n").Format( i,
name );
901 MixerInputVol = Px_GetInputVolume(PortMixer);
902 EmulateMixerInputVol =
false;
903 Px_SetInputVolume(PortMixer, 0.0);
904 if (Px_GetInputVolume(PortMixer) > 0.1)
905 EmulateMixerInputVol =
true;
906 Px_SetInputVolume(PortMixer, 0.2f);
907 if (Px_GetInputVolume(PortMixer) < 0.1 ||
908 Px_GetInputVolume(PortMixer) > 0.3)
909 EmulateMixerInputVol =
true;
910 Px_SetInputVolume(PortMixer, MixerInputVol);
912 Pa_CloseStream(stream);
914 s <<
wxT(
"==============================\n");
915 s << ( EmulateMixerInputVol
916 ?
XO(
"Recording volume is emulated\n")
917 :
XO(
"Recording volume is native\n") );
919 Px_CloseMixer(PortMixer);
923 return o.GetString();
928 std::vector<AudioIODiagnostics> result;
930 wxT(
"audiodev.txt"), GetDeviceInfo(),
wxT(
"Audio Device Info") });
931 for(
auto &pExt : mAudioIOExt )
933 result.emplace_back(pExt->Dump());
938 L
"/AudioIO/Host", L
"" };
940 L
"/AudioIO/LatencyCorrection", -130.0 };
942 L
"/AudioIO/LatencyDuration", 100.0 };
944 L
"/AudioIO/PlaybackDevice", L
"" };
946 L
"/AudioIO/PlaybackSource", L
"" };
948 L
"/AudioIO/PlaybackVolume", 1.0 };
950 L
"/AudioIO/RecordChannels", 2 };
952 L
"/AudioIO/RecordingDevice", L
"" };
954 L
"/AudioIO/RecordingSource", L
"" };
956 L
"/AudioIO/RecordingSourceIndex", -1 };
DoubleSetting AudioIOLatencyCorrection
StringSetting AudioIORecordingSource
DoubleSetting AudioIOPlaybackVolume
StringSetting AudioIOPlaybackSource
StringSetting AudioIOPlaybackDevice
DoubleSetting AudioIOLatencyDuration
StringSetting AudioIORecordingDevice
StringSetting AudioIOHost
IntSetting AudioIORecordingSourceIndex
IntSetting AudioIORecordChannels
const TranslatableString name
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
A singleton object supporting queries of the state of any active audio streams, and audio device capa...
std::weak_ptr< Meter > mOutputMeter
PaStream * mPortStreamV19
static wxString HostName(const PaDeviceInfo *info)
std::atomic< bool > mPaused
True if audio playback is paused.
static std::vector< long > mCachedSampleRates
double mRate
Audio playback rate in samples per second.
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
bool IsMonitoring() const
Returns true if we're monitoring input (but not recording or playing actual audio)
static int mCachedCaptureIndex
wxString GetDeviceInfo() const
Get diagnostic information on all the available audio I/O devices.
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
static const int StandardRates[]
Array of common audio sample rates.
static std::unique_ptr< AudioIOBase > ugAudioIO
std::vector< std::unique_ptr< AudioIOExtBase > > mAudioIOExt
static double mCachedBestRateIn
void SetCaptureMeter(const std::shared_ptr< AudacityProject > &project, const std::weak_ptr< Meter > &meter)
static int getPlayDevIndex(const wxString &devName={})
get the index of the device selected in the preferences.
static AudioIOBase * Get()
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
void HandleDeviceChange()
update state after changing what audio devices are selected
void SetMixer(int inputSource)
std::vector< AudioIODiagnostics > GetAllDeviceInfo()
Get diagnostic information for audio devices and also for extensions.
static wxString DeviceName(const PaDeviceInfo *info)
static std::vector< long > mCachedCaptureRates
static int GetOptimalSupportedSampleRate()
Get a supported sample rate which can be used a an optimal default.
static std::vector< long > GetSupportedSampleRates(int playDevice=-1, int recDevice=-1, double rate=0.0)
Get a list of sample rates the current input/output device combination supports.
std::weak_ptr< AudacityProject > mOwningProject
bool IsAudioTokenActive(int token) const
Returns true if the stream is active, or even if audio I/O is busy cleaning up its data or writing to...
bool mInputMixerWorks
Can we control the hardware input level?
void SetPlaybackMeter(const std::shared_ptr< AudacityProject > &project, const std::weak_ptr< Meter > &meter)
static const int NumRatesToTry
How many sample rates to try.
bool IsPaused() const
Find out if playback / recording is currently paused.
std::weak_ptr< Meter > mInputMeter
static const int NumStandardRates
How many standard sample rates there are.
static std::vector< long > mCachedPlaybackRates
static int mCachedPlaybackIndex
static int getRecordDevIndex(const wxString &devName={})
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
static const int RatesToTry[]
Array of audio sample rates to try to use.
virtual ~AudioIOExtBase()
Specialization of Setting for double.
Specialization of Setting for int.
bool ReadWithDefault(T *pVar, const T &defaultValue) const
overload of ReadWithDefault returning a boolean that is true if the value was previously defined */
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
const T & GetDefault() const
Specialization of Setting for strings.
constexpr int supportedSampleRates[]