2 Copyright (C) 2013 Waves Audio Ltd.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 //----------------------------------------------------------------------------------
22 //! \file WCMRNativeAudio.cpp
24 //! WCMRNativeAudioConnection and related class defienitions
26 //---------------------------------------------------------------------------------*/
27 #if defined(__MACOS__)
28 #include <CoreAudio/CoreAudio.h>
31 #include "WCMRNativeAudio.h"
32 #include "MiscUtils/safe_delete.h"
34 #include <boost/assign/list_of.hpp>
36 #define NONE_DEVICE_NAME "None"
37 #define NONE_DEVICE_INPUT_NAMES "Input "
38 #define NONE_DEVICE_OUTPUT_NAMES "Output "
40 //**********************************************************************************************
41 // WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice
43 //! Constructor for the dummy "None" device. This constructor simply adds supported SRs,
44 //! buffer sizes, and channels, so that it may look like a real native device to
47 //! \param pManager : The managing device manager - simply passed on to the base class.
50 //**********************************************************************************************
51 WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
52 : WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
54 #if defined (_WINDOWS)
55 , _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
58 m_DeviceName = NONE_DEVICE_NAME;
60 m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000);
62 m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
64 for (int channel = 0; channel < __m_NumInputChannels; channel++)
66 std::stringstream name;
67 name << NONE_DEVICE_INPUT_NAMES;
68 name << (channel + 1);
69 m_InputChannels.push_back(name.str());
72 for (int channel = 0; channel < __m_NumOutputChannels; channel++)
74 std::stringstream name;
75 name << NONE_DEVICE_INPUT_NAMES;
76 name << (channel + 1);
77 m_OutputChannels.push_back(name.str());
79 _m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()];
80 _m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()];
84 WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice ()
86 #if defined (_WINDOWS)
87 if(_waitableTimerForUsleep) {
88 CloseHandle(_waitableTimerForUsleep);
93 WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState)
95 //This will most likely be overridden, the base class simply
97 if (Active() == newState)
102 if (Active() && Streaming())
106 return WCMRAudioDevice::SetActive(newState);
109 WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
112 //changes the status.
113 int oldSize = CurrentBufferSize();
114 bool oldActive = Active();
116 //same size, nothing to do.
117 if (oldSize == newSize)
120 //see if this is one of our supported rates...
121 std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
122 if (intIter == m_BufferSizes.end())
124 //Can't change, perhaps use an "invalid param" type of error
125 return eCommandLineParameter;
130 //Can't change, perhaps use an "in use" type of error
135 return WCMRAudioDevice::SetCurrentBufferSize(newSize);
139 WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
141 if (Streaming() == newState)
146 WCMRAudioDevice::SetStreaming(newState);
150 std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
152 pthread_attr_t attributes;
153 size_t stack_size = 100000;
155 stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
157 if (pthread_attr_init (&attributes)) {
158 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl;
162 if (pthread_attr_setstacksize (&attributes, stack_size)) {
163 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl;
167 if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
169 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
175 if (!m_SilenceThread)
177 std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
180 while (m_SilenceThread)
182 _usleep(1); //now wait for ended thread;
189 void WCMRNativeAudioNoneDevice::_SilenceThread()
191 #if defined(_WINDOWS)
192 float* theInpBuffers[__m_NumInputChannels];
193 for(int i = 0; i < __m_NumInputChannels; ++i)
195 theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i;
198 float* theInpBuffers = _m_inputBuffer;
201 uint32_t currentSampleTime = 0;
202 const size_t buffer_size = CurrentBufferSize();
203 const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate();
205 struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
207 (const float*)theInpBuffers,
214 audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos();
216 // VERY ROUGH IMPLEMENTATION:
219 uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos;
221 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
223 currentSampleTime += buffer_size;
225 int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000;
227 if (timeToSleepUsecs > 0) {
228 _usleep (timeToSleepUsecs);
230 audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
235 void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)
237 ((WCMRNativeAudioNoneDevice*)This)->_SilenceThread();
241 #if defined(_WINDOWS)
242 void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec)
246 ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time
248 SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0);
249 WaitForSingleObject(_waitableTimerForUsleep, INFINITE);
254 WCMRNativeAudioNoneDevice::__get_time_nanos ()
257 // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,
258 // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the
259 // audio device transport time�.
260 return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());
264 LARGE_INTEGER Frequency, Count ;
266 QueryPerformanceFrequency (&Frequency) ;
267 QueryPerformanceCounter (&Count);
268 return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart));