copy over current Waves version of their backend, along with minor changes in libs/ardour and libs/backend/jack to fit with API changes

This commit is contained in:
Paul Davis 2014-09-30 20:35:31 -04:00
parent 38e975d6b1
commit 8d59afb048
25 changed files with 844 additions and 430 deletions

View file

@ -345,6 +345,28 @@ WTErr WCMRAudioDevice::SetStreaming (bool newState)
return (eNoErr);
}
WTErr WCMRAudioDevice::ResetDevice ()
{
// Keep device sates
bool wasStreaming = Streaming();
bool wasActive = Active();
WTErr err = SetStreaming(false);
if (err == eNoErr)
SetActive(false);
if (err == eNoErr && wasActive)
SetActive(true);
if (err == eNoErr && wasStreaming)
SetStreaming(true);
return err;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// IsProcessActive - returns true if process code is running.
// A normal audio device should return the Streaming() value
@ -632,6 +654,13 @@ WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatc
}
WTErr WCMRAudioDeviceManager::GetDeviceSampleRates(const std::string & nameToMatch, std::vector<int>& sampleRates) const
{
return getDeviceSampleRatesImpl(nameToMatch, sampleRates);
}
WTErr WCMRAudioDeviceManager::GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const
{
return getDeviceBufferSizesImpl(nameToMatch, bufferSizes);

View file

@ -151,6 +151,8 @@ public:
virtual bool Streaming();///<Streaming Status?
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
virtual WTErr ResetDevice ();
virtual bool IsProcessActive();
virtual WTErr DoIdle();///<Do Idle Processing
@ -218,6 +220,7 @@ public://< Public functions for the class.
void DestroyCurrentDevice();
const DeviceInfoVec DeviceInfoList () const;
WTErr GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const;
WTErr GetDeviceSampleRates(const std::string & nameToMatch, std::vector<int>& sampleRates) const;
WTErr GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const;
//virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
@ -238,6 +241,7 @@ private:
// made private to avoid pure virtual function call
virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName) = 0;
virtual void destroyCurrentDeviceImpl() = 0;
virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const = 0;
virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const = 0;
virtual WTErr generateDeviceListImpl() = 0;
virtual WTErr updateDeviceListImpl() = 0;

View file

@ -25,7 +25,7 @@ using namespace wvNS;
///< Supported Sample rates
static const double gAllSampleRates[] =
{
44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, -1 /* negative terminated list */
};
@ -356,7 +356,7 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
memset (pStreamBuffers, 0, propSize);
// Get the Input channels
err = AudioDeviceGetProperty (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
err = AudioDeviceGetProperty (m_DeviceID, 0, true/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
if (err == kAudioHardwareNoError)
{
// Calculate the number of input channels
@ -387,12 +387,54 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
// Update input channels
m_InputChannels.clear();
for (int channel = 0; channel < maxInputChannels; channel++)
{
CFStringRef cfName;
std::stringstream chNameStream;
//A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
chNameStream << "Input " << (channel+1);
UInt32 nameSize = 0;
OSStatus error = kAudioHardwareNoError;
error = AudioDeviceGetPropertyInfo (m_DeviceID,
channel + 1,
true /* Input */,
kAudioDevicePropertyChannelNameCFString,
&nameSize,
NULL);
if (error == kAudioHardwareNoError)
{
error = AudioDeviceGetProperty (m_DeviceID,
channel + 1,
true /* Input */,
kAudioDevicePropertyChannelNameCFString,
&nameSize,
&cfName);
}
bool decoded = false;
char* cstr_name = 0;
if (error == kAudioHardwareNoError)
{
CFIndex length = CFStringGetLength(cfName);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
cstr_name = new char[maxSize];
decoded = CFStringGetCString(cfName, cstr_name, maxSize, kCFStringEncodingUTF8);
}
chNameStream << (channel+1) << " - ";
if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) {
chNameStream << cstr_name;
}
else
{
chNameStream << "Input " << (channel+1);
}
m_InputChannels.push_back (chNameStream.str());
delete [] cstr_name;
}
return retVal;
@ -470,10 +512,51 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceOutputs()
m_OutputChannels.clear();
for (int channel = 0; channel < maxOutputChannels; channel++)
{
CFStringRef cfName;
std::stringstream chNameStream;
//A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
chNameStream << "Output " << (channel+1);
UInt32 nameSize = 0;
OSStatus error = kAudioHardwareNoError;
error = AudioDeviceGetPropertyInfo (m_DeviceID,
channel + 1,
false /* Output */,
kAudioDevicePropertyChannelNameCFString,
&nameSize,
NULL);
if (error == kAudioHardwareNoError)
{
error = AudioDeviceGetProperty (m_DeviceID,
channel + 1,
false /* Output */,
kAudioDevicePropertyChannelNameCFString,
&nameSize,
&cfName);
}
bool decoded = false;
char* cstr_name = 0;
if (error == kAudioHardwareNoError )
{
CFIndex length = CFStringGetLength(cfName);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
cstr_name = new char[maxSize];
decoded = CFStringGetCString(cfName, cstr_name, maxSize, kCFStringEncodingUTF8);
}
chNameStream << (channel+1) << " - ";
if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) {
chNameStream << cstr_name;
}
else
{
chNameStream << "Output " << (channel+1);
}
m_OutputChannels.push_back (chNameStream.str());
delete [] cstr_name;
}
return retVal;
@ -1178,12 +1261,17 @@ WTErr WCMRCoreAudioDevice::EnableListeners()
goto Exit;
}
#if ENABLE_DEVICE_CHANGE_LISTNER
#if ENABLE_DEVICE_CHANGE_LISTNER
{
//listner for device change...
err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
StaticPropertyChangeProc, this);
err = AudioDeviceAddPropertyListener (m_DeviceID,
kAudioPropertyWildcardChannel,
true,
kAudioDevicePropertyDeviceHasChanged,
StaticPropertyChangeProc,
this);
if (err)
{
DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err);
@ -1239,14 +1327,18 @@ WTErr WCMRCoreAudioDevice::DisableListeners()
#if ENABLE_DEVICE_CHANGE_LISTNER
{
err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
StaticPropertyChangeProc);
err = AudioDeviceRemovePropertyListener (m_DeviceID,
kAudioPropertyWildcardChannel,
true/* Input */,
kAudioDevicePropertyDeviceHasChanged,
StaticPropertyChangeProc);
if (err)
{
DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
DEBUG_MSG("Couldn't Cleanup device input stream change Property Listner, error = " << err);
//not sure if we need to report this...
}
}
#endif //ENABLE_DEVICE_CHANGE_LISTNER
@ -1315,15 +1407,19 @@ void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID
case kAudioDevicePropertyDeviceHasChanged:
{
m_ResetRequested++;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
}
break;
#endif //ENABLE_DEVICE_CHANGE_LISTNER
case kAudioDeviceProcessorOverload:
{
if (m_IgnoreThisDrop)
m_IgnoreThisDrop = false; //We'll ignore once, just once!
else
m_DropsDetected++;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout );
break;
}
default:
break;
}
@ -1589,35 +1685,7 @@ WTErr WCMRCoreAudioDevice::SetupAUHAL()
retVal = EnableListeners();
if (retVal != eNoErr)
goto Exit;
//also prepare the buffer list for input...
if (!m_InputChannels.empty())
{
//now setup the buffer list.
memset (&m_InputAudioBufferList, 0, sizeof (m_InputAudioBufferList));
m_InputAudioBufferList.mNumberBuffers = 1;
m_InputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
m_InputAudioBufferList.mBuffers[0].mDataByteSize = m_InputAudioBufferList.mBuffers[0].mNumberChannels *
m_CurrentBufferSize * sizeof(float);
//allocate the data buffer...
try
{
m_pInputData = new float[m_InputAudioBufferList.mBuffers[0].mNumberChannels * m_CurrentBufferSize];
}
catch (...)
{
retVal = eMemNewFailed;
goto Exit;
}
m_InputAudioBufferList.mBuffers[0].mData = m_pInputData;
//zero it out...
memset (m_InputAudioBufferList.mBuffers[0].mData, 0, m_InputAudioBufferList.mBuffers[0].mDataByteSize);
}
//initialize the audio-unit now!
err = AudioUnitInitialize(m_AUHALAudioUnit);
if (err != kAudioHardwareNoError)
@ -1657,8 +1725,6 @@ WTErr WCMRCoreAudioDevice::TearDownAUHAL()
CloseComponent(m_AUHALAudioUnit);
m_AUHALAudioUnit = NULL;
}
safe_delete_array(m_pInputData);
return retVal;
}
@ -1689,7 +1755,6 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState)
if (newState)
{
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL.");
retVal = SetupAUHAL();
@ -1837,7 +1902,6 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
SetupToneGenerator ();
#endif //WV_USE_TONE_GEN
m_StopRequested = false;
m_SampleCountAtLastIdle = 0;
m_StalledSampleCounter = 0;
m_SampleCounter = 0;
@ -1854,6 +1918,8 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
err = AudioOutputUnitStart (m_AUHALAudioUnit);
m_StopRequested = false;
if(err)
{
DEBUG_MSG( "Failed to start AudioUnit, err " << err );
@ -1868,11 +1934,11 @@ WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
err = AudioOutputUnitStop (m_AUHALAudioUnit);
if (!err)
{
if (!m_InputChannels.empty());
//if (!m_InputChannels.empty());
{
err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT);
}
if (!m_OutputChannels.empty());
//if (!m_OutputChannels.empty());
{
err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT);
}
@ -1911,6 +1977,7 @@ Exit:
//**********************************************************************************************
WTErr WCMRCoreAudioDevice::DoIdle ()
{
/*
if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported)
{
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
@ -1963,7 +2030,7 @@ WTErr WCMRCoreAudioDevice::DoIdle ()
m_StalledSampleCounter = 0;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount);
}
}
}*/
return (eNoErr);
@ -2055,6 +2122,18 @@ WTErr WCMRCoreAudioDevice::ShowConfigPanel (void */*pParam*/)
{
LSOpenFSRef(&theAppFSRef, NULL);
}
else
{
// open default AudioMIDISetup if device app is not found
CFStringRef audiMidiSetupApp = CFStringCreateWithCString(kCFAllocatorDefault, "com.apple.audio.AudioMIDISetup", kCFStringEncodingMacRoman);
theError = LSFindApplicationForInfo(kLSUnknownCreator, audiMidiSetupApp, NULL, &theAppFSRef, NULL);
if (!theError)
{
LSOpenFSRef(&theAppFSRef, NULL);
}
}
CFRelease (configAP);
}
@ -2116,19 +2195,38 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags * ioAction
OSStatus retVal = 0;
if (m_StopRequested)
goto Exit;
return retVal;
if (m_IOProcThreadPort == 0)
m_IOProcThreadPort = mach_thread_self ();
//cannot really deal with it unless the number of frames are the same as our buffer size!
if (inNumberFrames != (UInt32)m_CurrentBufferSize)
goto Exit;
return retVal;
//Retrieve the input data...
if (!m_InputChannels.empty())
{
retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &m_InputAudioBufferList);
UInt32 expectedDataSize = m_InputChannels.size() * m_CurrentBufferSize * sizeof(float);
AudioBufferList inputAudioBufferList;
inputAudioBufferList.mNumberBuffers = 1;
inputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
inputAudioBufferList.mBuffers[0].mDataByteSize = expectedDataSize;
inputAudioBufferList.mBuffers[0].mData = NULL;//new float[expectedDataSize]; // we are going to get buffer from CoreAudio
retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &inputAudioBufferList);
if (retVal == kAudioHardwareNoError &&
inputAudioBufferList.mBuffers[0].mNumberChannels == m_InputChannels.size() &&
inputAudioBufferList.mBuffers[0].mDataByteSize == expectedDataSize )
{
m_pInputData = (float*)inputAudioBufferList.mBuffers[0].mData;
}
else
{
m_pInputData = NULL;
return retVal;
}
}
//is this an input only device?
@ -2137,7 +2235,6 @@ OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags * ioAction
else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size()))
AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
Exit:
return retVal;
}
@ -2316,7 +2413,7 @@ WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerCli
}
//add a listener to find out when devices change...
AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, DevicePropertyChangeCallback, this);
AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, HardwarePropertyChangeCallback, this);
//Always add the None device first...
m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
@ -2415,7 +2512,7 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceI
{
//! 2. Get property: cannels output.
// Allocate size accrding to the number of audio values
// Allocate size according to the number of audio values
int numRates = propSize / sizeof(AudioValueRange);
AudioValueRange* supportedRates = new AudioValueRange[numRates];
@ -2465,7 +2562,7 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, u
OSStatus err = kAudioHardwareNoError;
UInt32 propSize = 0;
inputChannels = 0;
// 1. Get property cannels input size.
err = AudioDeviceGetPropertyInfo (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
if (err == kAudioHardwareNoError)
@ -2521,7 +2618,7 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceMaxOutputChannels(DeviceID deviceId,
OSStatus err = kAudioHardwareNoError;
UInt32 propSize = 0;
outputChannels = 0;
//! 1. Get property cannels output size.
err = AudioDeviceGetPropertyInfo (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
if (err == kAudioHardwareNoError)
@ -2786,6 +2883,84 @@ WTErr WCMRCoreAudioDeviceManager::updateDeviceListImpl()
}
WTErr WCMRCoreAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const
{
AUTO_FUNC_DEBUG;
WTErr retVal = eNoErr;
OSStatus err = kAudioHardwareNoError;
UInt32 propSize = 0;
sampleRates.clear();
//first check if the request has been made for None device
if (deviceName == m_NoneDevice->DeviceName() )
{
sampleRates = m_NoneDevice->SamplingRates();
return retVal;
}
if (m_CurrentDevice && m_CurrentDevice->DeviceName () == deviceName) {
sampleRates.assign(m_CurrentDevice->SamplingRates().begin(), m_CurrentDevice->SamplingRates().end() );
return retVal;
}
DeviceInfo devInfo;
retVal = GetDeviceInfoByName(deviceName, devInfo);
//! 1. Get sample rate property size.
err = AudioDeviceGetPropertyInfo(devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL);
if (err == kAudioHardwareNoError)
{
//! 2. Get property: cannels output.
// Allocate size accrding to the number of audio values
int numRates = propSize / sizeof(AudioValueRange);
AudioValueRange* supportedRates = new AudioValueRange[numRates];
// Get sampling rates from Audio device
err = AudioDeviceGetProperty(devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates);
if (err == kAudioHardwareNoError)
{
//! 3. Update sample rates
// now iterate through our standard SRs
for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++)
{
//check to see if our SR is in the supported rates...
for (int deviceSR = 0; deviceSR < numRates; deviceSR++)
{
if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) &&
(supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR]))
{
sampleRates.push_back ((int)gAllSampleRates[ourSR]);
break;
}
}
}
}
else
{
retVal = eCoreAudioFailed;
DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str());
}
delete [] supportedRates;
}
else
{
retVal = eCoreAudioFailed;
DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str());
}
devInfo.m_AvailableSampleRates.assign(sampleRates.begin(), sampleRates.end() );
return retVal;
}
WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const
{
AUTO_FUNC_DEBUG;
@ -2803,6 +2978,11 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
return retVal;
}
if (m_CurrentDevice && m_CurrentDevice->DeviceName () == deviceName) {
bufferSizes.assign(m_CurrentDevice->BufferSizes().begin(), m_CurrentDevice->BufferSizes().end() );
return retVal;
}
DeviceInfo devInfo;
retVal = GetDeviceInfoByName(deviceName, devInfo);
@ -2847,7 +3027,7 @@ WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
}
OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData)
OSStatus WCMRCoreAudioDeviceManager::HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData)
{
switch (inPropertyID)
{
@ -2858,6 +3038,7 @@ OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardware
pManager->updateDeviceListImpl();
}
break;
default:
break;
}

View file

@ -81,7 +81,7 @@ protected:
AudioDeviceID m_DeviceID; ///< The CoreAudio device id
bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise.
float *m_pInputData; ///< This is what came in with the most recent callback.
float *m_pInputData; ///< This is what came in with the most recent callback.
int m_SampleCounter; ///< The current running sample counter, updated by the audio callback.
int m_SampleCountAtLastIdle; ///< What was the sample count last time we checked...
int m_StalledSampleCounter; ///< The number of idle calls with same sample count detected
@ -93,9 +93,7 @@ protected:
// int m_CyclesToAccumulate; ///< The number of cycles to accumulate the values for - maximum for last one second.
// unsigned int m_CyclePeriod; ///< The number of host time units for a cycle period - determined by buffer size and sampling rate
AudioBufferList m_InputAudioBufferList; ///< The buffer list used to get AHHAL to render input to.
AudioUnit m_AUHALAudioUnit;///< The AUHAL AudioUnit
int m_BufferSizeChangeRequested;
@ -152,6 +150,7 @@ protected:
AudioDevicePropertyID inPropertyID, void *inClientData);
void PropertyChangeProc (AudioDevicePropertyID inPropertyID);
void resetAudioDevice();
private:
};
@ -168,12 +167,13 @@ public:
virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor
protected:
static OSStatus DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData);
static OSStatus HardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData);
virtual WCMRAudioDevice* initNewCurrentDeviceImpl(const std::string & deviceName);
virtual void destroyCurrentDeviceImpl();
virtual WTErr generateDeviceListImpl();
virtual WTErr updateDeviceListImpl();
virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const;
virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const;
bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.

View file

@ -12,7 +12,6 @@
#endif
#include "WCMRNativeAudio.h"
#include "MiscUtils/pthread_utils.h"
#include "MiscUtils/safe_delete.h"
#include <iostream>
#include <sstream>
@ -35,15 +34,14 @@
//**********************************************************************************************
WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
: WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
, m_SilenceThread(0)
#if defined (PLATFORM_WINDOWS)
, _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
#endif
{
mark_pthread_inactive (m_SilenceThread);
m_DeviceName = NONE_DEVICE_NAME;
m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000);
m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000)(176400)(192000);
m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
@ -139,7 +137,7 @@ WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
if (Streaming())
{
if (is_pthread_active (m_SilenceThread))
if (m_SilenceThread)
std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
pthread_attr_t attributes;
@ -158,19 +156,19 @@ WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
}
if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
mark_pthread_inactive (m_SilenceThread);
m_SilenceThread = 0;
std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
return eGenericErr;
}
}
else
{
if (!is_pthread_active (m_SilenceThread))
if (!m_SilenceThread)
{
std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
}
while (is_pthread_active (m_SilenceThread))
while (m_SilenceThread)
{
_usleep(1); //now wait for ended thread;
}
@ -222,7 +220,7 @@ void WCMRNativeAudioNoneDevice::_SilenceThread()
}
audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
}
mark_pthread_inactive (m_SilenceThread);
m_SilenceThread = 0;
}
void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)

View file

@ -17,6 +17,10 @@
#include "WCRefManager.h"
#include "WCMRAudioDeviceManager.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
#include <unistd.h>
#endif
class WCMRNativeAudioDevice; //forward

View file

@ -13,16 +13,22 @@
#include <iostream>
#include <sstream>
#include <algorithm>
#include <list>
using namespace wvNS;
#include "IncludeWindows.h"
#include <MMSystem.h>
#include "pa_asio.h"
#include "asio.h"
#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 200
#define DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS 500
#define PROPERTY_CHANGE_TIMEOUT_SECONDS 2
#define PROPERTY_CHANGE_RETRIES 3
///< Supported Sample rates
static const double gAllSampleRates[] =
{
44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 -1 /* negative terminated list */
};
@ -305,14 +311,12 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
//update name.
m_DeviceName = pDeviceInfo->name;
std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
//following parameters are needed opening test stream and for sample rates validation
PaStreamParameters inputParameters, outputParameters;
PaStreamParameters *pInS = NULL, *pOutS = NULL;
inputParameters.device = m_DeviceID;
inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
inputParameters.channelCount = pDeviceInfo->maxInputChannels;
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
inputParameters.hostApiSpecificStreamInfo = 0;
@ -321,7 +325,7 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
pInS = &inputParameters;
outputParameters.device = m_DeviceID;
outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
outputParameters.sampleFormat = paFloat32;
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
outputParameters.hostApiSpecificStreamInfo = 0;
@ -329,7 +333,6 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
if (outputParameters.channelCount)
pOutS = &outputParameters;
std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
////////////////////////////////////////////////////////////////////////////////////
//update list of supported SRs...
m_SamplingRates.clear();
@ -345,54 +348,27 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
}
}
std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
///////////////////////////////////////////////////////////////////////////////////
//update buffer sizes
m_BufferSizes.clear();
bool useDefaultBuffers = true;
PaError paErr = paNoError;
//sometimes devices change buffer size if sample rate changes
//it updates buffer size during stream opening
//we need to find out how device would behave with current sample rate
//try opening test stream to load device driver for current sample rate and buffer size
//(skip this step if the device is Active)
if ( !Active() )
{
if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
{
//buffer size did change
Pa_Terminate();
Pa_Initialize();
// test validness with current sample rate and device prefered buffer size
paErr = testStateValidness(m_CurrentSamplingRate, 0);
}
}
if (paErr == paNoError)
{
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
long minSize, maxSize, preferredSize, granularity;
paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
long minSize, maxSize, preferredSize, granularity;
PaError err = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
if (paErr == paNoError)
{
std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
if (err == paNoError)
{
std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
m_BufferSizes.push_back (preferredSize);
useDefaultBuffers = false;
}
else
{
std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
}
m_BufferSizes.push_back (preferredSize);
useDefaultBuffers = false;
}
else
{
std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
}
if (useDefaultBuffers)
{
std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
@ -410,9 +386,22 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
m_InputChannels.clear();
for (int channel = 0; channel < maxInputChannels; channel++)
{
const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation
std::stringstream chNameStream;
//A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
chNameStream << "Input " << (channel+1);
PaError error = PaAsio_GetInputChannelName(m_DeviceID, channel, channelName);
chNameStream << (channel+1) << " - ";
if (error == paNoError)
{
chNameStream << *channelName;
}
else
{
chNameStream << "Input " << (channel+1);
}
m_InputChannels.push_back (chNameStream.str());
}
@ -421,9 +410,22 @@ void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
m_OutputChannels.clear();
for (int channel = 0; channel < maxOutputChannels; channel++)
{
const char* channelName[32]; // 32 is max leth declared by PortAudio for this operation
std::stringstream chNameStream;
//A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
chNameStream << "Output " << (channel+1);
PaError error = PaAsio_GetOutputChannelName(m_DeviceID, channel, channelName);
chNameStream << (channel+1) << " - ";
if (error == paNoError)
{
chNameStream << *channelName;
}
else
{
chNameStream << "Output " << (channel+1);
}
m_OutputChannels.push_back (chNameStream.str());
}
}
@ -447,18 +449,18 @@ PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
PaStreamParameters *pInS = NULL, *pOutS = NULL;
inputParameters.device = m_DeviceID;
inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
inputParameters.channelCount = pDeviceInfo->maxInputChannels;
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
inputParameters.suggestedLatency = 0;
inputParameters.hostApiSpecificStreamInfo = 0;
if (inputParameters.channelCount)
pInS = &inputParameters;
outputParameters.device = m_DeviceID;
outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
outputParameters.channelCount = pDeviceInfo->maxOutputChannels;
outputParameters.sampleFormat = paFloat32;
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
outputParameters.suggestedLatency = 0;
outputParameters.hostApiSpecificStreamInfo = 0;
if (outputParameters.channelCount)
@ -470,7 +472,7 @@ PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
//it updates buffer size during stream opening
//we need to find out how device would behave with current sample rate
//try opening test stream to load device driver for current sample rate and buffer size
paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, sampleRate, bufferSize, paDitherOff, NULL, NULL);
if (portAudioStream)
{
@ -599,35 +601,18 @@ WTErr WCMRPortAudioDevice::SetCurrentSamplingRate (int newRate)
return (retVal);
}
if (oldActive)
{
//Deactivate it for the change...
SetActive (false);
}
//make the change...
m_CurrentSamplingRate = newRate;
PaError paErr = PaAsio_SetStreamSampleRate (m_PortAudioStream, m_CurrentSamplingRate);
Pa_Sleep(PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS); // sleep some time to make sure the change has place
// Before reactivating the device: opening stream we should try getting buffer size update from the device
// because for new sampling rate some devices may change buffer size as well
int oldBufferSize = m_CurrentBufferSize;
retVal = ResetDevice();
//reactivate it.
if (oldActive && retVal == eNoErr)
if (paErr != paNoError)
{
retVal = SetActive (true);
}
std::cout << "Sample rate change failed: " << Pa_GetErrorText (paErr) << std::endl;
if (paErr == paUnanticipatedHostError)
std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
if (retVal != eNoErr)
{
//revert changes if the device was not activated
m_CurrentSamplingRate = oldRate;
m_CurrentBufferSize = oldBufferSize;
int bufferSize = m_CurrentBufferSize;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
retVal = eCommandLineParameter;
retVal = eWrongObjectState;
}
return (retVal);
@ -676,21 +661,37 @@ WTErr WCMRPortAudioDevice::SetCurrentBufferSize (int newSize)
if (oldSize == newSize)
return (retVal);
//see if this is one of our supported rates...
intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
if (intIter == m_BufferSizes.end())
{
//Can't change, perhaps use an "invalid param" type of error
retVal = eCommandLineParameter;
return (retVal);
}
if (Streaming())
{
//Can't change, perhaps use an "in use" type of error
retVal = eGenericErr;
return (retVal);
}
std::cout << "Setting buffer: " << newSize << std::endl;
//see if this is one of our supported rates...
intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
if (intIter == m_BufferSizes.end())
{
//Sample rate proposed by client is not supported any more
if (m_BufferSizes.size() == 1)
{
// we have only one aloved buffer size which is preffered by PA
// this is the only value which could be set
newSize = m_BufferSizes[0];
int bufferSize = newSize;
// notify client to update sample rate after us
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
return retVal;
} else {
// more then one buffer size value is available
//Can't change, perhaps use an "invalid param" type of error
retVal = eCommandLineParameter;
return (retVal);
}
}
if (oldActive)
{
@ -748,6 +749,17 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
// if device is not active activate it
if (!Active() )
{
std::list<long> buffersSizes;
buffersSizes.push_back(m_CurrentBufferSize);
long minSize, maxSize, preferredSize, granularity;
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
if (paErr == paNoError)
{
buffersSizes.push_front(preferredSize);
}
PaStreamParameters inputParameters, outputParameters;
PaStreamParameters *pInS = NULL, *pOutS = NULL;
@ -771,20 +783,46 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
if (outputParameters.channelCount)
pOutS = &outputParameters;
std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
paErr = Pa_OpenStream(&m_PortAudioStream,
pInS,
pOutS,
m_CurrentSamplingRate,
m_CurrentBufferSize,
paDitherOff,
WCMRPortAudioDevice::TheCallback,
this);
// try opening stream with current buffer and the rest if not successful
std::list<long>::const_iterator bufferIter = buffersSizes.begin();
for (; bufferIter != buffersSizes.end(); ++bufferIter) {
std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << *bufferIter << std::endl;
paErr = Pa_OpenStream(&m_PortAudioStream,
pInS,
pOutS,
m_CurrentSamplingRate,
m_CurrentBufferSize,
paDitherOff,
WCMRPortAudioDevice::TheCallback,
this);
if(paErr == paNoError)
{
break;
}
std::cout << "Cannot open streamm with buffer: "<< *bufferIter << " Error: " << Pa_GetErrorText (paErr) << std::endl;
if (paErr == paUnanticipatedHostError)
std::cout << "Error details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
}
if(paErr == paNoError)
{
long minSize, maxSize, preferredSize, granularity;
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
if (paErr == paNoError && m_CurrentBufferSize != preferredSize)
{
m_CurrentBufferSize = preferredSize;
m_BufferSizes.clear();
m_BufferSizes.push_back(preferredSize);
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&preferredSize);
}
m_DropsDetected = 0;
m_DropsReported = 0;
m_IgnoreThisDrop = true;
@ -806,8 +844,8 @@ void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
else
{
//failed, do not update device state
std::cout << "Failed to open pa stream stream " << paErr << std::endl;
DEBUG_MSG( "Failed to open pa stream stream " << paErr );
std::cout << "Failed to open pa stream: " << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to open pa stream: " << Pa_GetErrorText (paErr) );
m_ConnectionStatus = DeviceErrors;
m_lastErr = eAsioFailed;
}
@ -867,8 +905,8 @@ void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
else
{
//failed, do not update device state
std::cout << "Failed to close pa stream stream " << paErr << std::endl;
DEBUG_MSG( "Failed to open pa stream stream " << paErr );
std::cout << "Failed to close pa stream stream " << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to open pa stream stream " << Pa_GetErrorText (paErr) );
m_ConnectionStatus = DeviceErrors;
m_lastErr = eAsioFailed;
}
@ -899,17 +937,25 @@ void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
m_SampleCounter = 0;
std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
//get device info
const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
unsigned int inChannelCount = pDeviceInfo->maxInputChannels;
unsigned int outChannelCount = pDeviceInfo->maxOutputChannels;
paErr = Pa_StartStream( m_PortAudioStream );
if(paErr == paNoError)
{
// if the stream was started successfully
m_IsStreaming = true;
std::cout << "API::Device" << m_DeviceName << " Device is streaming" << std::endl;
}
else
{
std::cout << "Failed to start PA stream: " << paErr << std::endl;
DEBUG_MSG( "Failed to start PA stream: " << paErr );
std::cout << "Failed to start PA stream: " << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to start PA stream: " << Pa_GetErrorText (paErr) );
m_lastErr = eGenericErr;
}
}
@ -947,8 +993,8 @@ void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
}
else
{
std::cout << "Failed to stop PA stream: " << paErr << std::endl;
DEBUG_MSG( "Failed to stop PA stream " << paErr );
std::cout << "Failed to stop PA stream: " << Pa_GetErrorText (paErr) << std::endl;
DEBUG_MSG( "Failed to stop PA stream " << Pa_GetErrorText (paErr) );
m_lastErr = eGenericErr;
}
}
@ -973,60 +1019,82 @@ void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
{
std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
PaError paErr = paNoError;
// Keep device sates
bool wasStreaming = Streaming();
bool wasActive = Active();
// Notify the Application about reset
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
// Reset the device
stopStreaming();
deactivateDevice();
// Reinitialize PA
Pa_Terminate();
Pa_Initialize();
updateDeviceInfo();
// Cache device buffer size as it might be changed during reset
int oldBufferSize = m_CurrentBufferSize;
// In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
// Backend should always use preffered buffer size value in this case
long minSize, maxSize, preferredSize, granularity;
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
// Now, validate the state and update device info if required
unsigned int retry = PROPERTY_CHANGE_RETRIES;
while (retry-- )
{
// Reinitialize PA
Pa_Terminate();
Pa_Initialize();
std::cout << "Updating device state... " << std::endl;
// update device info
updateDeviceInfo();
// take up buffers
long minSize, maxSize, preferredSize, granularity;
PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
if (paErr != paNoError)
{
continue;
}
m_CurrentBufferSize = preferredSize;
paErr = testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize);
if (paNoError == paErr)
{
std::cout << "Device state is valid" << std::endl;
break;
}
std::cout << "Cannot start with current state: sr: " << m_CurrentSamplingRate << " bs:" << m_CurrentBufferSize \
<< "\nReason: " << Pa_GetErrorText (paErr) << std::endl;
if (paErr == paUnanticipatedHostError)
std::cout << "Details: "<< Pa_GetLastHostErrorInfo ()->errorText << "; code: " << Pa_GetLastHostErrorInfo ()->errorCode << std::endl;
std::cout << "Will try again in " << DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS << "msec" << std::endl;
Pa_Sleep(DEVICE_INFO_UPDATE_SLEEP_TIME_MILLISECONDS);
}
if (paErr == paNoError)
{
m_CurrentBufferSize = preferredSize;
}
else
{
// if we can't get device buffer sizes, use the first one among supported
if (m_BufferSizes.size() != 0)
m_CurrentBufferSize = m_BufferSizes.front();
}
// Notify the Application about device setting changes
if (oldBufferSize != m_CurrentBufferSize)
{
std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
int bufferSize = m_CurrentBufferSize;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
}
// Notify the Application about device setting changes
if (oldBufferSize != m_CurrentBufferSize)
{
std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
int bufferSize = m_CurrentBufferSize;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
}
// Activate the device if it was active before
if (wasActive)
activateDevice();
// Activate the device if it was active before
if (wasActive)
activateDevice();
// Resume streaming if the device was streaming before
if(wasStreaming)
{
// Notify the Application to prepare for the stream start
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
startStreaming();
// Resume streaming if the device was streaming before
if(wasStreaming && m_lastErr == eNoErr && m_ConnectionStatus == DeviceAvailable)
{
// Notify the Application to prepare for the stream start
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
startStreaming();
}
} else {
m_ConnectionStatus = DeviceErrors;
m_lastErr = eWrongObjectState;
}
if (callerIsWaiting)
@ -1050,32 +1118,34 @@ long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(val
{
switch(selector)
{
case kAsioResyncRequest:
m_ResyncRequested++;
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
break;
case kAsioLatenciesChanged:
m_BufferSizeChangeRequested++;
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
break;
case kAsioBufferSizeChange:
m_BufferSizeChangeRequested++;
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
SetEvent(m_hBufferSizeChangedEvent);
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
break;
case kAsioResetRequest:
m_ResetRequested++;
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
SetEvent(m_hResetFromDevRequestedEvent);
break;
case kAsioResyncRequest:
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
m_ResyncRequested++;
break;
case kAsioLatenciesChanged:
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
SetEvent(m_hBufferSizeChangedEvent);
m_BufferSizeChangeRequested++;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
break;
case kAsioOverload:
m_DropsDetected++;
std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
m_DropsDetected++;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::Dropout);
break;
}
return 0;
@ -1642,33 +1712,55 @@ WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
}
WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
WTErr WCMRPortAudioDeviceManager::getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const
{
WTErr retVal = eNoErr;
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
//first check if the request has been made for None device
if (deviceName == m_NoneDevice->DeviceName() )
sampleRates.clear ();
WTErr retVal = eNoErr;
if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
{
buffers = m_NoneDevice->BufferSizes();
sampleRates.assign(m_CurrentDevice->SamplingRates().begin(), m_CurrentDevice->SamplingRates().end() );
return retVal;
}
//if we have current device initialized and it's PA device, reset it
//this procedure will reset PA corrently and update info for all PA devices as well
bool paLocalInit = false;
WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
if (portaudioDevice)
DeviceInfo devInfo;
retVal = GetDeviceInfoByName(deviceName, devInfo);
if (eNoErr == retVal)
{
portaudioDevice->ResetDevice();
sampleRates.assign(devInfo.m_AvailableSampleRates.begin(), devInfo.m_AvailableSampleRates.end() );
}
else
{
//initialize PA to get buffers for the device
Pa_Initialize();
paLocalInit = true;
std::cout << "API::PortAudioDeviceManager::GetSampleRates: Device not found: "<< deviceName << std::endl;
}
return retVal;
}
WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
{
WTErr retVal = eNoErr;
buffers.clear();
//first check if the request has been made for None device
if (deviceName == m_NoneDevice->DeviceName() )
{
buffers.assign(m_NoneDevice->BufferSizes().begin(), m_NoneDevice->BufferSizes().end() );
return retVal;
}
if (m_CurrentDevice && deviceName == m_CurrentDevice->DeviceName() )
{
buffers.assign(m_CurrentDevice->BufferSizes().begin(), m_CurrentDevice->BufferSizes().end() );
return retVal;
}
Pa_Initialize();
DeviceInfo devInfo;
retVal = GetDeviceInfoByName(deviceName, devInfo);
@ -1686,7 +1778,7 @@ WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
else
{
retVal = eAsioFailed;
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << Pa_GetErrorText (paErr) << " getting buffer sizes for device: "<< deviceName << std::endl;
}
}
else
@ -1694,9 +1786,7 @@ WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & d
std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
}
//deinitialize PA now
if (paLocalInit)
Pa_Terminate();
Pa_Terminate();
return retVal;
}

View file

@ -146,6 +146,7 @@ protected:
virtual WTErr generateDeviceListImpl(); // use this in derived class to fill device list
virtual WTErr updateDeviceListImpl() {return eNoErr; } // not supported
virtual WTErr getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const;
virtual WTErr getDeviceSampleRatesImpl(const std::string & deviceName, std::vector<int>& sampleRates) const;
bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.
bool m_bNoCopyAudioBuffer;