1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-16 07:31:16 +02:00

svn:eol-style was not set to native for DeviceManager.cpp/h

This commit is contained in:
mchinen
2011-06-01 18:55:51 +00:00
parent b9725a6c13
commit fec888198a
2 changed files with 383 additions and 383 deletions

View File

@@ -1,308 +1,308 @@
/********************************************************************** /**********************************************************************
Audacity - A Digital Audio Editor Audacity - A Digital Audio Editor
Copyright 1999-2010 Audacity Team Copyright 1999-2010 Audacity Team
Michael Chinen Michael Chinen
******************************************************************/ ******************************************************************/
#include "portaudio.h" #include "portaudio.h"
#include "portmixer.h" #include "portmixer.h"
#include "Audacity.h" #include "Audacity.h"
// For compilers that support precompilation, includes "wx/wx.h". // For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h> #include <wx/wxprec.h>
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include <wx/choice.h> #include <wx/choice.h>
#include <wx/event.h> #include <wx/event.h>
#include <wx/intl.h> #include <wx/intl.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/statbmp.h> #include <wx/statbmp.h>
#include <wx/tooltip.h> #include <wx/tooltip.h>
#endif #endif
#include "Project.h" #include "Project.h"
#include "AudioIO.h" #include "AudioIO.h"
#include "DeviceManager.h" #include "DeviceManager.h"
#include "toolbars/DeviceToolBar.h" #include "toolbars/DeviceToolBar.h"
DeviceManager DeviceManager::dm; DeviceManager DeviceManager::dm;
/// Gets the singleton instance /// Gets the singleton instance
DeviceManager* DeviceManager::Instance() DeviceManager* DeviceManager::Instance()
{ {
return &dm; return &dm;
} }
/// Releases memory assosiated with the singleton /// Releases memory assosiated with the singleton
void DeviceManager::Destroy() void DeviceManager::Destroy()
{ {
} }
const std::vector<DeviceSourceMap> &DeviceManager::GetInputDeviceMaps() const std::vector<DeviceSourceMap> &DeviceManager::GetInputDeviceMaps()
{ {
if (!m_inited) if (!m_inited)
Init(); Init();
return mInputDeviceSourceMaps; return mInputDeviceSourceMaps;
} }
const std::vector<DeviceSourceMap> &DeviceManager::GetOutputDeviceMaps() const std::vector<DeviceSourceMap> &DeviceManager::GetOutputDeviceMaps()
{ {
if (!m_inited) if (!m_inited)
Init(); Init();
return mOutputDeviceSourceMaps; return mOutputDeviceSourceMaps;
} }
wxString MakeDeviceSourceString(const DeviceSourceMap *map) wxString MakeDeviceSourceString(const DeviceSourceMap *map)
{ {
wxString ret; wxString ret;
ret = map->deviceString; ret = map->deviceString;
if (map->totalSources > 1) if (map->totalSources > 1)
ret += wxString(": ", wxConvLocal) + map->sourceString; ret += wxString(": ", wxConvLocal) + map->sourceString;
return ret; return ret;
} }
DeviceSourceMap* DeviceManager::GetDefaultDevice(int hostIndex, int isInput) DeviceSourceMap* DeviceManager::GetDefaultDevice(int hostIndex, int isInput)
{ {
if (hostIndex < 0 || hostIndex >= Pa_GetHostApiCount()) { if (hostIndex < 0 || hostIndex >= Pa_GetHostApiCount()) {
return NULL; return NULL;
} }
const struct PaHostApiInfo *apiinfo = Pa_GetHostApiInfo(hostIndex); // get info on API const struct PaHostApiInfo *apiinfo = Pa_GetHostApiInfo(hostIndex); // get info on API
std::vector<DeviceSourceMap> & maps = isInput ? mInputDeviceSourceMaps : mOutputDeviceSourceMaps; std::vector<DeviceSourceMap> & maps = isInput ? mInputDeviceSourceMaps : mOutputDeviceSourceMaps;
size_t i; size_t i;
int targetDevice = isInput ? apiinfo->defaultInputDevice : apiinfo->defaultOutputDevice; int targetDevice = isInput ? apiinfo->defaultInputDevice : apiinfo->defaultOutputDevice;
for (i = 0; i < maps.size(); i++) { for (i = 0; i < maps.size(); i++) {
if (maps[i].deviceIndex == targetDevice) if (maps[i].deviceIndex == targetDevice)
return &maps[i]; return &maps[i];
} }
wxLogDebug(wxT("GetDefaultDevice() no default device")); wxLogDebug(wxT("GetDefaultDevice() no default device"));
return NULL; return NULL;
} }
DeviceSourceMap* DeviceManager::GetDefaultOutputDevice(int hostIndex) DeviceSourceMap* DeviceManager::GetDefaultOutputDevice(int hostIndex)
{ {
return GetDefaultDevice(hostIndex, 0); return GetDefaultDevice(hostIndex, 0);
} }
DeviceSourceMap* DeviceManager::GetDefaultInputDevice(int hostIndex) DeviceSourceMap* DeviceManager::GetDefaultInputDevice(int hostIndex)
{ {
return GetDefaultDevice(hostIndex, 1); return GetDefaultDevice(hostIndex, 1);
} }
//--------------- Device Enumeration -------------------------- //--------------- Device Enumeration --------------------------
//Port Audio requires we open the stream with a callback or a lot of devices will fail //Port Audio requires we open the stream with a callback or a lot of devices will fail
//as this means open in blocking mode, so we use a dummy one. //as this means open in blocking mode, so we use a dummy one.
static int DummyPaStreamCallback( static int DummyPaStreamCallback(
const void *input, void *output, const void *input, void *output,
unsigned long frameCount, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo, const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, PaStreamCallbackFlags statusFlags,
void *userData ) void *userData )
{ {
return 0; return 0;
} }
static void FillHostDeviceInfo(DeviceSourceMap *map, const PaDeviceInfo *info, int deviceIndex, int isInput) static void FillHostDeviceInfo(DeviceSourceMap *map, const PaDeviceInfo *info, int deviceIndex, int isInput)
{ {
wxString hostapiName(Pa_GetHostApiInfo(info->hostApi)->name, wxConvLocal); wxString hostapiName(Pa_GetHostApiInfo(info->hostApi)->name, wxConvLocal);
wxString infoName(info->name, wxConvLocal); wxString infoName(info->name, wxConvLocal);
map->deviceIndex = deviceIndex; map->deviceIndex = deviceIndex;
map->hostIndex = info->hostApi; map->hostIndex = info->hostApi;
map->deviceString = infoName; map->deviceString = infoName;
map->hostString = hostapiName; map->hostString = hostapiName;
map->numChannels = isInput ? info->maxInputChannels : info->maxOutputChannels; map->numChannels = isInput ? info->maxInputChannels : info->maxOutputChannels;
} }
static void AddSourcesFromStream(int deviceIndex, const PaDeviceInfo *info, std::vector<DeviceSourceMap> *maps, PaStream *stream) static void AddSourcesFromStream(int deviceIndex, const PaDeviceInfo *info, std::vector<DeviceSourceMap> *maps, PaStream *stream)
{ {
int i; int i;
PxMixer *portMixer; PxMixer *portMixer;
DeviceSourceMap map; DeviceSourceMap map;
map.sourceIndex = -1; map.sourceIndex = -1;
map.totalSources = 0; map.totalSources = 0;
// Only inputs have sources, so we call FillHostDeviceInfo with a 1 to indicate this // Only inputs have sources, so we call FillHostDeviceInfo with a 1 to indicate this
FillHostDeviceInfo(&map, info, deviceIndex, 1); FillHostDeviceInfo(&map, info, deviceIndex, 1);
portMixer = Px_OpenMixer(stream, 0); portMixer = Px_OpenMixer(stream, 0);
if (!portMixer) { if (!portMixer) {
maps->push_back(map); maps->push_back(map);
return; return;
} }
//if there is only one source, we don't need to concatenate the source //if there is only one source, we don't need to concatenate the source
//or enumerate, because it is something meaningless like 'master' //or enumerate, because it is something meaningless like 'master'
//(as opposed to 'mic in' or 'line in'), and the user doesn't have any choice. //(as opposed to 'mic in' or 'line in'), and the user doesn't have any choice.
//note that some devices have no input sources at all but are still valid. //note that some devices have no input sources at all but are still valid.
//the behavior we do is the same for 0 and 1 source cases. //the behavior we do is the same for 0 and 1 source cases.
map.totalSources = Px_GetNumInputSources(portMixer); map.totalSources = Px_GetNumInputSources(portMixer);
if (map.totalSources <= 1) { if (map.totalSources <= 1) {
map.sourceIndex = 0; map.sourceIndex = 0;
maps->push_back(map); maps->push_back(map);
} else { } else {
//open up a stream with the device so portmixer can get the info out of it. //open up a stream with the device so portmixer can get the info out of it.
for (i = 0; i < map.totalSources; i++) { for (i = 0; i < map.totalSources; i++) {
map.sourceIndex = i; map.sourceIndex = i;
map.sourceString = wxString(Px_GetInputSourceName(portMixer, i), wxConvLocal); map.sourceString = wxString(Px_GetInputSourceName(portMixer, i), wxConvLocal);
maps->push_back(map); maps->push_back(map);
} }
} }
Px_CloseMixer(portMixer); Px_CloseMixer(portMixer);
} }
static bool IsInputDeviceAMapperDevice(const PaDeviceInfo *info) static bool IsInputDeviceAMapperDevice(const PaDeviceInfo *info)
{ {
// For Windows only, portaudio returns the default mapper object // For Windows only, portaudio returns the default mapper object
// as the first index after a new hostApi index is detected (true for MME and DS) // as the first index after a new hostApi index is detected (true for MME and DS)
// this is a bit of a hack, but there's no other way to find out which device is a mapper, // this is a bit of a hack, but there's no other way to find out which device is a mapper,
// I've looked at string comparisons, but if the system is in a different language this breaks. // I've looked at string comparisons, but if the system is in a different language this breaks.
#ifdef __WXMSW__ #ifdef __WXMSW__
static int lastHostApiTypeId = -1; static int lastHostApiTypeId = -1;
int hostApiTypeId = Pa_GetHostApiInfo(info->hostApi)->type; int hostApiTypeId = Pa_GetHostApiInfo(info->hostApi)->type;
if(hostApiTypeId != lastHostApiTypeId && if(hostApiTypeId != lastHostApiTypeId &&
(hostApiTypeId == paMME || hostApiTypeId == paDirectSound)) { (hostApiTypeId == paMME || hostApiTypeId == paDirectSound)) {
lastHostApiTypeId = hostApiTypeId; lastHostApiTypeId = hostApiTypeId;
return true; return true;
} }
#endif #endif
return false; return false;
} }
static void AddSources(int deviceIndex, int rate, std::vector<DeviceSourceMap> *maps, int isInput) static void AddSources(int deviceIndex, int rate, std::vector<DeviceSourceMap> *maps, int isInput)
{ {
int error = 0; int error = 0;
DeviceSourceMap map; DeviceSourceMap map;
const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceIndex); const PaDeviceInfo *info = Pa_GetDeviceInfo(deviceIndex);
// This tries to open the device with the samplerate worked out above, which // This tries to open the device with the samplerate worked out above, which
// will be the highest available for play and record on the device, or // will be the highest available for play and record on the device, or
// 44.1kHz if the info cannot be fetched. // 44.1kHz if the info cannot be fetched.
PaStream *stream = NULL; PaStream *stream = NULL;
PaStreamParameters parameters; PaStreamParameters parameters;
parameters.device = deviceIndex; parameters.device = deviceIndex;
parameters.sampleFormat = paFloat32; parameters.sampleFormat = paFloat32;
parameters.hostApiSpecificStreamInfo = NULL; parameters.hostApiSpecificStreamInfo = NULL;
parameters.channelCount = 1; parameters.channelCount = 1;
// If the device is for input, open a stream so we can use portmixer to query // If the device is for input, open a stream so we can use portmixer to query
// the number of inputs. We skip this for outputs because there are no 'sources' // the number of inputs. We skip this for outputs because there are no 'sources'
// and some platforms (e.g. XP) have the same device for input and output, (while // and some platforms (e.g. XP) have the same device for input and output, (while
// Vista/Win7 seperate these into two devices with the same names (but different // Vista/Win7 seperate these into two devices with the same names (but different
// portaudio indecies) // portaudio indecies)
// Also, for mapper devices we don't want to keep any sources, so check for it here // Also, for mapper devices we don't want to keep any sources, so check for it here
if (isInput && !IsInputDeviceAMapperDevice(info)) { if (isInput && !IsInputDeviceAMapperDevice(info)) {
if (info) if (info)
parameters.suggestedLatency = info->defaultLowInputLatency; parameters.suggestedLatency = info->defaultLowInputLatency;
else else
parameters.suggestedLatency = 10.0; parameters.suggestedLatency = 10.0;
error = Pa_OpenStream(&stream, error = Pa_OpenStream(&stream,
&parameters, &parameters,
NULL, NULL,
rate, paFramesPerBufferUnspecified, rate, paFramesPerBufferUnspecified,
paClipOff | paDitherOff, paClipOff | paDitherOff,
DummyPaStreamCallback, NULL); DummyPaStreamCallback, NULL);
} }
if (stream && !error) { if (stream && !error) {
AddSourcesFromStream(deviceIndex, info, maps, stream); AddSourcesFromStream(deviceIndex, info, maps, stream);
Pa_CloseStream(stream); Pa_CloseStream(stream);
} else { } else {
map.sourceIndex = -1; map.sourceIndex = -1;
map.totalSources = 0; map.totalSources = 0;
FillHostDeviceInfo(&map, info, deviceIndex, isInput); FillHostDeviceInfo(&map, info, deviceIndex, isInput);
maps->push_back(map); maps->push_back(map);
} }
if(error) { if(error) {
wxLogDebug(wxT("PortAudio stream error creating device list: ") + wxLogDebug(wxT("PortAudio stream error creating device list: ") +
map.hostString + wxT(":") + map.deviceString + wxT(": ") + map.hostString + wxT(":") + map.deviceString + wxT(": ") +
wxString(Pa_GetErrorText( (PaError)error), wxConvLocal)); wxString(Pa_GetErrorText( (PaError)error), wxConvLocal));
} }
} }
/// Gets a new list of devices by terminating and restarting portaudio /// Gets a new list of devices by terminating and restarting portaudio
/// Assumes that DeviceManager is only used on the main thread. /// Assumes that DeviceManager is only used on the main thread.
void DeviceManager::Rescan() void DeviceManager::Rescan()
{ {
// get rid of the previous scan info // get rid of the previous scan info
this->mInputDeviceSourceMaps.clear(); this->mInputDeviceSourceMaps.clear();
this->mOutputDeviceSourceMaps.clear(); this->mOutputDeviceSourceMaps.clear();
// if we are doing a second scan then restart portaudio to get new devices // if we are doing a second scan then restart portaudio to get new devices
if (m_inited) { if (m_inited) {
// check to see if there is a stream open - can happen if monitoring, // check to see if there is a stream open - can happen if monitoring,
// but otherwise Rescan() should not be available to the user. // but otherwise Rescan() should not be available to the user.
if (gAudioIO) { if (gAudioIO) {
if (gAudioIO->IsMonitoring()) if (gAudioIO->IsMonitoring())
{ {
gAudioIO->StopStream(); gAudioIO->StopStream();
while (gAudioIO->IsBusy()) while (gAudioIO->IsBusy())
wxMilliSleep(100); wxMilliSleep(100);
} }
} }
// restart portaudio - this updates the device list // restart portaudio - this updates the device list
Pa_Terminate(); Pa_Terminate();
Pa_Initialize(); Pa_Initialize();
} }
int nDevices = Pa_GetDeviceCount(); int nDevices = Pa_GetDeviceCount();
int i; int i;
//The heirarchy for devices is Host/device/source. //The heirarchy for devices is Host/device/source.
//Some newer systems aggregate this. //Some newer systems aggregate this.
//So we need to call port mixer for every device to get the sources //So we need to call port mixer for every device to get the sources
for (i = 0; i < nDevices; i++) { for (i = 0; i < nDevices; i++) {
const PaDeviceInfo *info = Pa_GetDeviceInfo(i); const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
if (info->maxOutputChannels > 0) { if (info->maxOutputChannels > 0) {
AddSources(i, info->defaultSampleRate, &mOutputDeviceSourceMaps, 0); AddSources(i, info->defaultSampleRate, &mOutputDeviceSourceMaps, 0);
} }
if (info->maxInputChannels > 0) { if (info->maxInputChannels > 0) {
AddSources(i, info->defaultSampleRate, &mInputDeviceSourceMaps, 1); AddSources(i, info->defaultSampleRate, &mInputDeviceSourceMaps, 1);
} }
} }
// If this was not an initial scan update each device toolbar. // If this was not an initial scan update each device toolbar.
// Hosts may have disappeared or appeared so a complete repopulate is needed. // Hosts may have disappeared or appeared so a complete repopulate is needed.
if (m_inited) { if (m_inited) {
DeviceToolBar *dt; DeviceToolBar *dt;
for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) {
dt = gAudacityProjects[i]->GetDeviceToolBar(); dt = gAudacityProjects[i]->GetDeviceToolBar();
dt->RefillCombos(); dt->RefillCombos();
} }
} }
m_inited = true; m_inited = true;
} }
//private constructor - Singleton. //private constructor - Singleton.
DeviceManager::DeviceManager() DeviceManager::DeviceManager()
{ {
m_inited = false; m_inited = false;
} }
DeviceManager::~DeviceManager() DeviceManager::~DeviceManager()
{ {
} }
void DeviceManager::Init() void DeviceManager::Init()
{ {
Rescan(); Rescan();
} }

View File

@@ -1,75 +1,75 @@
/********************************************************************** /**********************************************************************
Audacity: A Digital Audio Editor Audacity: A Digital Audio Editor
DeviceManager.h DeviceManager.h
Created by Michael Chinen (mchinen) on 2/12/11 Created by Michael Chinen (mchinen) on 2/12/11
Audacity(R) is copyright (c) 1999-2011 Audacity Team. Audacity(R) is copyright (c) 1999-2011 Audacity Team.
License: GPL v2. See License.txt. License: GPL v2. See License.txt.
******************************************************************//** ******************************************************************//**
\class DeviceManager \class DeviceManager
\brief A singleton that manages the audio devices known to Audacity \brief A singleton that manages the audio devices known to Audacity
*//*******************************************************************/ *//*******************************************************************/
#ifndef __AUDACITY_DEVICEMANAGER__ #ifndef __AUDACITY_DEVICEMANAGER__
#define __AUDACITY_DEVICEMANAGER__ #define __AUDACITY_DEVICEMANAGER__
#include <vector> #include <vector>
#include "wx/wx.h" #include "wx/wx.h"
typedef struct DeviceSourceMap { typedef struct DeviceSourceMap {
int deviceIndex; int deviceIndex;
int sourceIndex; int sourceIndex;
int hostIndex; int hostIndex;
int totalSources; int totalSources;
int numChannels; int numChannels;
wxString sourceString; wxString sourceString;
wxString deviceString; wxString deviceString;
wxString hostString; wxString hostString;
} DeviceSourceMap; } DeviceSourceMap;
wxString MakeDeviceSourceString(const DeviceSourceMap *map); wxString MakeDeviceSourceString(const DeviceSourceMap *map);
class DeviceManager class DeviceManager
{ {
public: public:
/// Gets the singleton instance /// Gets the singleton instance
static DeviceManager* Instance(); static DeviceManager* Instance();
/// Releases memory assosiated with the singleton /// Releases memory assosiated with the singleton
static void Destroy(); static void Destroy();
/// Gets a new list of devices by terminating and restarting portaudio /// Gets a new list of devices by terminating and restarting portaudio
/// Assumes that DeviceManager is only used on the main thread. /// Assumes that DeviceManager is only used on the main thread.
void Rescan(); void Rescan();
DeviceSourceMap* GetDefaultOutputDevice(int hostIndex); DeviceSourceMap* GetDefaultOutputDevice(int hostIndex);
DeviceSourceMap* GetDefaultInputDevice(int hostIndex); DeviceSourceMap* GetDefaultInputDevice(int hostIndex);
const std::vector<DeviceSourceMap> &GetInputDeviceMaps(); const std::vector<DeviceSourceMap> &GetInputDeviceMaps();
const std::vector<DeviceSourceMap> &GetOutputDeviceMaps(); const std::vector<DeviceSourceMap> &GetOutputDeviceMaps();
protected: protected:
//private constructor - Singleton. //private constructor - Singleton.
DeviceManager(); DeviceManager();
virtual ~DeviceManager(); virtual ~DeviceManager();
/// Does an initial scan. /// Does an initial scan.
/// Called by GetInputDeviceMaps and GetOutputDeviceMaps when needed. /// Called by GetInputDeviceMaps and GetOutputDeviceMaps when needed.
void Init(); void Init();
DeviceSourceMap* GetDefaultDevice(int hostIndex, int isInput); DeviceSourceMap* GetDefaultDevice(int hostIndex, int isInput);
bool m_inited; bool m_inited;
std::vector<DeviceSourceMap> mInputDeviceSourceMaps; std::vector<DeviceSourceMap> mInputDeviceSourceMaps;
std::vector<DeviceSourceMap> mOutputDeviceSourceMaps; std::vector<DeviceSourceMap> mOutputDeviceSourceMaps;
static DeviceManager dm; static DeviceManager dm;
}; };
#endif #endif