1 //----------------------------------------------------------------------------------
3 // Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
5 //! \file WCMRNativeAudio.cpp
7 //! WCMRNativeAudioConnection and related class defienitions
9 //---------------------------------------------------------------------------------*/
10 #if defined(__APPLE__)
11 #include <CoreAudio/CoreAudio.h>
14 #include "WCMRNativeAudio.h"
15 #include "MiscUtils/pthread_utils.h"
16 #include "MiscUtils/safe_delete.h"
19 #include <boost/assign/list_of.hpp>
21 #define NONE_DEVICE_NAME "None"
22 #define NONE_DEVICE_INPUT_NAMES "Input "
23 #define NONE_DEVICE_OUTPUT_NAMES "Output "
25 //**********************************************************************************************
26 // WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice
28 //! Constructor for the dummy "None" device. This constructor simply adds supported SRs,
29 //! buffer sizes, and channels, so that it may look like a real native device to
32 //! \param pManager : The managing device manager - simply passed on to the base class.
35 //**********************************************************************************************
36 WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
37 : WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
41 #if defined (PLATFORM_WINDOWS)
42 , _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
45 mark_pthread_inactive (m_SilenceThread);
47 m_DeviceName = NONE_DEVICE_NAME;
49 m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000)(176400)(192000);
51 m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
53 for (int channel = 0; channel < __m_NumInputChannels; channel++)
55 std::stringstream name;
56 name << NONE_DEVICE_INPUT_NAMES;
57 name << (channel + 1);
58 m_InputChannels.push_back(name.str());
61 for (int channel = 0; channel < __m_NumOutputChannels; channel++)
63 std::stringstream name;
64 name << NONE_DEVICE_INPUT_NAMES;
65 name << (channel + 1);
66 m_OutputChannels.push_back(name.str());
68 _m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()];
69 _m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()];
70 m_CurrentBufferSize = m_BufferSizes.back();
74 WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice ()
76 #if defined (PLATFORM_WINDOWS)
77 if(_waitableTimerForUsleep) {
78 CloseHandle(_waitableTimerForUsleep);
83 WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState)
85 //This will most likely be overridden, the base class simply
87 if (Active() == newState)
92 if (Active() && Streaming())
96 return WCMRAudioDevice::SetActive(newState);
99 WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
102 //changes the status.
103 int oldSize = CurrentBufferSize();
104 bool oldActive = Active();
106 //same size, nothing to do.
107 if (oldSize == newSize)
110 //see if this is one of our supported rates...
111 std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
112 if (intIter == m_BufferSizes.end())
114 //Can't change, perhaps use an "invalid param" type of error
115 return eCommandLineParameter;
120 //Can't change, perhaps use an "in use" type of error
125 return WCMRAudioDevice::SetCurrentBufferSize(newSize);
129 WTErr WCMRNativeAudioNoneDevice::UpdateDeviceInfo ()
135 WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
137 if (Streaming() == newState)
142 WCMRAudioDevice::SetStreaming(newState);
146 if (is_pthread_active (m_SilenceThread))
147 std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
149 pthread_attr_t attributes;
150 size_t stack_size = 100000;
152 stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
154 if (pthread_attr_init (&attributes)) {
155 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl;
159 if (pthread_attr_setstacksize (&attributes, stack_size)) {
160 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl;
164 if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
165 mark_pthread_inactive (m_SilenceThread);
166 std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
172 if (!is_pthread_active (m_SilenceThread))
174 std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
177 while (is_pthread_active (m_SilenceThread))
179 _usleep(1); //now wait for ended thread;
186 void WCMRNativeAudioNoneDevice::_SilenceThread()
188 #if defined(PLATFORM_WINDOWS)
189 float* theInpBuffers[__m_NumInputChannels];
190 for(int i = 0; i < __m_NumInputChannels; ++i)
192 theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i;
195 float* theInpBuffers = _m_inputBuffer;
198 const size_t buffer_size = CurrentBufferSize();
199 const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate();
201 struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
203 (const float*)theInpBuffers,
210 audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos();
212 // VERY ROUGH IMPLEMENTATION:
215 uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos;
217 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
219 audioCallbackData.acdSampleTime += buffer_size;
221 int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000;
223 if (timeToSleepUsecs > 0) {
224 _usleep (timeToSleepUsecs);
226 audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
228 mark_pthread_inactive (m_SilenceThread);
231 void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)
233 ((WCMRNativeAudioNoneDevice*)This)->_SilenceThread();
237 #if defined(PLATFORM_WINDOWS)
238 void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec)
242 ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time
244 SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0);
245 WaitForSingleObject(_waitableTimerForUsleep, INFINITE);
250 WCMRNativeAudioNoneDevice::__get_time_nanos ()
253 // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,
254 // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the
255 // audio device transport time�.
256 return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());
258 #elif PLATFORM_WINDOWS
260 LARGE_INTEGER Frequency, Count ;
262 QueryPerformanceFrequency (&Frequency) ;
263 QueryPerformanceCounter (&Count);
264 return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart));