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.

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