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.

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