jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
10KB

  1. /*
  2. Copyright (C) 2008 Romain Moret at Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackPortAudioDevices.h"
  16. #include "JackError.h"
  17. using namespace std;
  18. PortAudioDevices::PortAudioDevices()
  19. {
  20. PaError err;
  21. if ( ( err = Pa_Initialize() ) == paNoError )
  22. {
  23. fNumHostApi = Pa_GetHostApiCount();
  24. fNumDevice = Pa_GetDeviceCount();
  25. fDeviceInfo = new PaDeviceInfo*[fNumDevice];
  26. for ( PaDeviceIndex id = 0; id < fNumDevice; id++ )
  27. fDeviceInfo[id] = const_cast<PaDeviceInfo*>(Pa_GetDeviceInfo(id));
  28. fHostName = new string[fNumHostApi];
  29. for ( PaHostApiIndex id = 0; id < fNumHostApi; id++ )
  30. fHostName[id] = string ( Pa_GetHostApiInfo(id)->name );
  31. }
  32. else
  33. printf("JackPortAudioDriver::Pa_Initialize error = %s\n", Pa_GetErrorText(err));
  34. }
  35. PortAudioDevices::~PortAudioDevices()
  36. {
  37. Pa_Terminate();
  38. delete[] fDeviceInfo;
  39. delete[] fHostName;
  40. }
  41. PaDeviceIndex PortAudioDevices::GetNumDevice()
  42. {
  43. return fNumDevice;
  44. }
  45. PaDeviceInfo* PortAudioDevices::GetDeviceInfo ( PaDeviceIndex id )
  46. {
  47. return fDeviceInfo[id];
  48. }
  49. string PortAudioDevices::GetDeviceName ( PaDeviceIndex id )
  50. {
  51. return string ( fDeviceInfo[id]->name );
  52. }
  53. string PortAudioDevices::GetHostFromDevice ( PaDeviceInfo* device )
  54. {
  55. return fHostName[device->hostApi];
  56. }
  57. string PortAudioDevices::GetHostFromDevice ( PaDeviceIndex id )
  58. {
  59. return fHostName[fDeviceInfo[id]->hostApi];
  60. }
  61. string PortAudioDevices::GetFullName ( PaDeviceIndex id )
  62. {
  63. string hostname = GetHostFromDevice ( id );
  64. string devicename = GetDeviceName ( id );
  65. //some hostname are quite long...use shortcuts
  66. if ( hostname.compare ( "Windows DirectSound" ) == 0 )
  67. hostname = string ( "DirectSound" );
  68. return ( hostname + "::" + devicename );
  69. }
  70. string PortAudioDevices::GetFullName ( std::string hostname, std::string devicename )
  71. {
  72. //some hostname are quite long...use shortcuts
  73. if ( hostname.compare ( "Windows DirectSound" ) == 0 )
  74. hostname = string ( "DirectSound" );
  75. return ( hostname + "::" + devicename );
  76. }
  77. PaDeviceInfo* PortAudioDevices::GetDeviceFromFullName ( string fullname, PaDeviceIndex& id )
  78. {
  79. PaDeviceInfo* ret = NULL;
  80. //no driver to find
  81. if ( fullname.size() == 0 )
  82. return NULL;
  83. //first get host and device names from fullname
  84. string::size_type separator = fullname.find ( "::", 0 );
  85. if ( separator == 0 )
  86. return NULL;
  87. char hostname[separator + 9];
  88. fill_n ( hostname, separator + 9, 0 );
  89. fullname.copy ( hostname, separator );
  90. //we need the entire hostname, replace shortcuts
  91. if ( strcmp ( hostname, "DirectSound" ) == 0 )
  92. strcpy ( hostname, "Windows DirectSound" );
  93. string devicename = fullname.substr ( separator + 2 );
  94. //then find the corresponding device
  95. for ( PaDeviceIndex dev_id = 0; dev_id < fNumDevice; dev_id++ )
  96. {
  97. if ( ( GetHostFromDevice(dev_id).compare(hostname) == 0 ) && ( GetDeviceName(dev_id).compare(devicename) == 0 ) )
  98. {
  99. id = dev_id;
  100. ret = fDeviceInfo[dev_id];
  101. }
  102. }
  103. return ret;
  104. }
  105. void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters)
  106. {
  107. static double standardSampleRates[] =
  108. {
  109. 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
  110. 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
  111. };
  112. int i, printCount;
  113. PaError err;
  114. printCount = 0;
  115. for (i = 0; standardSampleRates[i] > 0; i++)
  116. {
  117. err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]);
  118. if (err == paFormatIsSupported)
  119. {
  120. if (printCount == 0)
  121. {
  122. printf("\t%8.2f", standardSampleRates[i]);
  123. printCount = 1;
  124. }
  125. else if (printCount == 4)
  126. {
  127. printf(",\n\t%8.2f", standardSampleRates[i]);
  128. printCount = 1;
  129. }
  130. else
  131. {
  132. printf(", %8.2f", standardSampleRates[i]);
  133. ++printCount;
  134. }
  135. }
  136. }
  137. if (!printCount)
  138. printf("None\n");
  139. else
  140. printf("\n");
  141. }
  142. int PortAudioDevices::GetInputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_input)
  143. {
  144. string fullname = string ( devicename );
  145. PaDeviceInfo* device = GetDeviceFromFullName ( fullname, id );
  146. if ( device )
  147. max_input = device->maxInputChannels;
  148. else
  149. {
  150. id = Pa_GetDefaultInputDevice();
  151. if ( fullname.size() )
  152. printf("Can't open %s, PortAudio will use default input device.\n", devicename);
  153. if ( id == paNoDevice )
  154. return -1;
  155. max_input = GetDeviceInfo(id)->maxInputChannels;
  156. devicename = strdup ( GetDeviceInfo(id)->name );
  157. }
  158. return id;
  159. }
  160. int PortAudioDevices::GetOutputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_output)
  161. {
  162. string fullname = string ( devicename );
  163. PaDeviceInfo* device = GetDeviceFromFullName ( fullname, id );
  164. if ( device )
  165. max_output = device->maxOutputChannels;
  166. else
  167. {
  168. id = Pa_GetDefaultOutputDevice();
  169. if ( fullname.size() )
  170. printf("Can't open %s, PortAudio will use default output device.\n", devicename);
  171. if ( id == paNoDevice )
  172. return -1;
  173. max_output = GetDeviceInfo(id)->maxOutputChannels;
  174. devicename = strdup ( GetDeviceInfo(id)->name );
  175. }
  176. return id;
  177. }
  178. void PortAudioDevices::DisplayDevicesNames()
  179. {
  180. int def_display;
  181. PaStreamParameters inputParameters, outputParameters;
  182. printf ( "********************** Devices list, %d detected **********************\n", fNumDevice );
  183. for ( PaDeviceIndex id = 0; id < fNumDevice; id++ )
  184. {
  185. printf ( "-------- device #%d ------------------------------------------------\n", id );
  186. def_display = 0;
  187. if ( id == Pa_GetDefaultInputDevice() )
  188. {
  189. printf("[ Default Input");
  190. def_display = 1;
  191. }
  192. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi)->defaultInputDevice )
  193. {
  194. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  195. printf ( "[ Default %s Input", host_info->name );
  196. def_display = 1;
  197. }
  198. if ( id == Pa_GetDefaultOutputDevice() )
  199. {
  200. printf ( ( def_display ? "," : "[" ) );
  201. printf ( " Default Output" );
  202. def_display = 1;
  203. }
  204. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi )->defaultOutputDevice )
  205. {
  206. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  207. printf ( ( def_display ? "," : "[" ) );
  208. printf ( " Default %s Output", host_info->name );
  209. def_display = 1;
  210. }
  211. if ( def_display )
  212. printf ( " ]\n" );
  213. /* print device info fields */
  214. printf ( "Name = %s\n", GetFullName ( id ).c_str() );
  215. printf ( "Max inputs = %d\n", fDeviceInfo[id]->maxInputChannels );
  216. printf ( "Max outputs = %d\n", fDeviceInfo[id]->maxOutputChannels );
  217. #ifdef WIN32
  218. /* ASIO specific latency information */
  219. if ( Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO )
  220. {
  221. long minLatency, maxLatency, preferredLatency, granularity;
  222. PaAsio_GetAvailableLatencyValues ( id, &minLatency, &maxLatency, &preferredLatency, &granularity );
  223. printf ( "ASIO minimum buffer size = %ld\n", minLatency );
  224. printf ( "ASIO maximum buffer size = %ld\n", maxLatency );
  225. printf ( "ASIO preferred buffer size = %ld\n", preferredLatency );
  226. if ( granularity == -1 )
  227. printf ( "ASIO buffer granularity = power of 2\n" );
  228. else
  229. printf ( "ASIO buffer granularity = %ld\n", granularity );
  230. }
  231. #endif
  232. printf ( "Default sample rate = %8.2f\n", fDeviceInfo[id]->defaultSampleRate );
  233. /* poll for standard sample rates */
  234. inputParameters.device = id;
  235. inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels;
  236. inputParameters.sampleFormat = paInt16;
  237. inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  238. inputParameters.hostApiSpecificStreamInfo = NULL;
  239. outputParameters.device = id;
  240. outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels;
  241. outputParameters.sampleFormat = paInt16;
  242. outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  243. outputParameters.hostApiSpecificStreamInfo = NULL;
  244. }
  245. printf ( "**************************** End of list ****************************\n" );
  246. }
  247. bool PortAudioDevices::IsDuplex ( PaDeviceIndex id )
  248. {
  249. //does the device has in and out facilities
  250. if ( fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  251. return true;
  252. //else is another complementary device ? (search in devices with the same name)
  253. for ( PaDeviceIndex i = 0; i < fNumDevice; i++ )
  254. if ( ( i != id ) && ( GetDeviceName ( i ) == GetDeviceName ( id ) ) )
  255. if ( ( fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  256. || ( fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels ) )
  257. return true;
  258. //then the device isn't full duplex
  259. return false;
  260. }