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.

292 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. jack_log("Initializing PortAudio...");
  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. jack_error("JackPortAudioDriver::Pa_Initialize error = %s", 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, bool isInput )
  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. bool flag = (isInput) ? (fDeviceInfo[dev_id]->maxInputChannels > 0) : (fDeviceInfo[dev_id]->maxOutputChannels > 0);
  100. if ( ( GetHostFromDevice(dev_id).compare(hostname) == 0 )
  101. && ( GetDeviceName(dev_id).compare(devicename) == 0 )
  102. && flag )
  103. {
  104. id = dev_id;
  105. ret = fDeviceInfo[dev_id];
  106. }
  107. }
  108. free(hostname);
  109. return ret;
  110. }
  111. void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters)
  112. {
  113. static double standardSampleRates[] =
  114. {
  115. 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
  116. 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
  117. };
  118. int i, printCount;
  119. PaError err;
  120. printCount = 0;
  121. for (i = 0; standardSampleRates[i] > 0; i++)
  122. {
  123. err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]);
  124. if (err == paFormatIsSupported)
  125. {
  126. if (printCount == 0)
  127. {
  128. jack_info("\t%8.2f", standardSampleRates[i]);
  129. printCount = 1;
  130. }
  131. else if (printCount == 4)
  132. {
  133. jack_info(",\n\t%8.2f", standardSampleRates[i]);
  134. printCount = 1;
  135. }
  136. else
  137. {
  138. jack_info(", %8.2f", standardSampleRates[i]);
  139. ++printCount;
  140. }
  141. }
  142. }
  143. if (!printCount) {
  144. jack_info("None");
  145. } else {
  146. jack_info("\n");
  147. }
  148. }
  149. int PortAudioDevices::GetInputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_input)
  150. {
  151. string fullname = string ( devicename );
  152. PaDeviceInfo* device = GetDeviceFromFullName ( fullname, id, true );
  153. if ( device )
  154. max_input = device->maxInputChannels;
  155. else
  156. {
  157. id = Pa_GetDefaultInputDevice();
  158. if ( fullname.size() )
  159. jack_error("Can't open %s, PortAudio will use default input device.", devicename);
  160. if ( id == paNoDevice )
  161. return -1;
  162. max_input = GetDeviceInfo(id)->maxInputChannels;
  163. }
  164. return id;
  165. }
  166. int PortAudioDevices::GetOutputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_output)
  167. {
  168. string fullname = string ( devicename );
  169. PaDeviceInfo* device = GetDeviceFromFullName ( fullname, id, false );
  170. if ( device )
  171. max_output = device->maxOutputChannels;
  172. else
  173. {
  174. id = Pa_GetDefaultOutputDevice();
  175. if ( fullname.size() )
  176. jack_error("Can't open %s, PortAudio will use default output device.", devicename);
  177. if ( id == paNoDevice )
  178. return -1;
  179. max_output = GetDeviceInfo(id)->maxOutputChannels;
  180. }
  181. return id;
  182. }
  183. void PortAudioDevices::DisplayDevicesNames()
  184. {
  185. int def_display;
  186. PaDeviceIndex id;
  187. PaStreamParameters inputParameters, outputParameters;
  188. jack_info ( "********************** Devices list, %d detected **********************", fNumDevice );
  189. for ( id = 0; id < fNumDevice; id++ )
  190. {
  191. jack_info ( "-------- device #%d ------------------------------------------------", id );
  192. if ( id == Pa_GetDefaultInputDevice() )
  193. {
  194. jack_info("[ Default Input ]");
  195. }
  196. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi)->defaultInputDevice )
  197. {
  198. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  199. jack_info ( "[ Default %s Input ]", host_info->name );
  200. }
  201. if ( id == Pa_GetDefaultOutputDevice() )
  202. {
  203. jack_info ( "[ Default Output ]" );
  204. }
  205. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi )->defaultOutputDevice )
  206. {
  207. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  208. jack_info ( "[ Default %s Output ]", host_info->name );
  209. }
  210. /* print device info fields */
  211. jack_info ( "Name = %s", GetFullName ( id ).c_str() );
  212. jack_info ( "Max inputs = %d", fDeviceInfo[id]->maxInputChannels );
  213. jack_info ( "Max outputs = %d", fDeviceInfo[id]->maxOutputChannels );
  214. #ifdef WIN32
  215. /* ASIO specific latency information */
  216. if ( Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO )
  217. {
  218. long minLatency, maxLatency, preferredLatency, granularity;
  219. PaAsio_GetAvailableLatencyValues ( id, &minLatency, &maxLatency, &preferredLatency, &granularity );
  220. jack_info ( "ASIO minimum buffer size = %ld", minLatency );
  221. jack_info ( "ASIO maximum buffer size = %ld", maxLatency );
  222. jack_info ( "ASIO preferred buffer size = %ld", preferredLatency );
  223. if ( granularity == -1 )
  224. jack_info ( "ASIO buffer granularity = power of 2" );
  225. else
  226. jack_info ( "ASIO buffer granularity = %ld", granularity );
  227. }
  228. #endif
  229. jack_info ( "Default sample rate = %8.2f", fDeviceInfo[id]->defaultSampleRate );
  230. /* poll for standard sample rates */
  231. inputParameters.device = id;
  232. inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels;
  233. inputParameters.sampleFormat = paInt16;
  234. inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  235. inputParameters.hostApiSpecificStreamInfo = NULL;
  236. outputParameters.device = id;
  237. outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels;
  238. outputParameters.sampleFormat = paInt16;
  239. outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  240. outputParameters.hostApiSpecificStreamInfo = NULL;
  241. }
  242. jack_info ( "**************************** End of list ****************************" );
  243. }
  244. bool PortAudioDevices::IsDuplex ( PaDeviceIndex id )
  245. {
  246. //does the device has in and out facilities
  247. if ( fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  248. return true;
  249. //else is another complementary device ? (search in devices with the same name)
  250. for ( PaDeviceIndex i = 0; i < fNumDevice; i++ )
  251. if ( ( i != id ) && ( GetDeviceName ( i ) == GetDeviceName ( id ) ) )
  252. if ( ( fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  253. || ( fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels ) )
  254. return true;
  255. //then the device isn't full duplex
  256. return false;
  257. }