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. 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. } else {
  33. jack_error("JackPortAudioDriver::Pa_Initialize error = %s", Pa_GetErrorText(err));
  34. }
  35. }
  36. PortAudioDevices::~PortAudioDevices()
  37. {
  38. // Desactivate for now: crash the server..
  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. PaDeviceIndex id;
  186. PaStreamParameters inputParameters, outputParameters;
  187. jack_info ( "********************** Devices list, %d detected **********************", fNumDevice );
  188. for ( id = 0; id < fNumDevice; id++ )
  189. {
  190. jack_info ( "-------- device #%d ------------------------------------------------", id );
  191. if ( id == Pa_GetDefaultInputDevice() )
  192. {
  193. jack_info("[ Default Input ]");
  194. }
  195. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi)->defaultInputDevice )
  196. {
  197. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  198. jack_info ( "[ Default %s Input ]", host_info->name );
  199. }
  200. if ( id == Pa_GetDefaultOutputDevice() )
  201. {
  202. jack_info ( "[ Default Output ]" );
  203. }
  204. else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi )->defaultOutputDevice )
  205. {
  206. const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi );
  207. jack_info ( "[ Default %s Output ]", host_info->name );
  208. }
  209. /* print device info fields */
  210. jack_info ( "Name = %s", GetFullName ( id ).c_str() );
  211. jack_info ( "Max inputs = %d", fDeviceInfo[id]->maxInputChannels );
  212. jack_info ( "Max outputs = %d", fDeviceInfo[id]->maxOutputChannels );
  213. #ifdef WIN32
  214. /* ASIO specific latency information */
  215. if ( Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO )
  216. {
  217. long minLatency, maxLatency, preferredLatency, granularity;
  218. PaAsio_GetAvailableLatencyValues ( id, &minLatency, &maxLatency, &preferredLatency, &granularity );
  219. jack_info ( "ASIO minimum buffer size = %ld", minLatency );
  220. jack_info ( "ASIO maximum buffer size = %ld", maxLatency );
  221. jack_info ( "ASIO preferred buffer size = %ld", preferredLatency );
  222. if ( granularity == -1 )
  223. jack_info ( "ASIO buffer granularity = power of 2" );
  224. else
  225. jack_info ( "ASIO buffer granularity = %ld", granularity );
  226. }
  227. #endif
  228. jack_info ( "Default sample rate = %8.2f", fDeviceInfo[id]->defaultSampleRate );
  229. /* poll for standard sample rates */
  230. inputParameters.device = id;
  231. inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels;
  232. inputParameters.sampleFormat = paInt16;
  233. inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  234. inputParameters.hostApiSpecificStreamInfo = NULL;
  235. outputParameters.device = id;
  236. outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels;
  237. outputParameters.sampleFormat = paInt16;
  238. outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  239. outputParameters.hostApiSpecificStreamInfo = NULL;
  240. }
  241. jack_info ( "**************************** End of list ****************************" );
  242. }
  243. bool PortAudioDevices::IsDuplex ( PaDeviceIndex id )
  244. {
  245. //does the device has in and out facilities
  246. if ( fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  247. return true;
  248. //else is another complementary device ? (search in devices with the same name)
  249. for ( PaDeviceIndex i = 0; i < fNumDevice; i++ )
  250. if ( ( i != id ) && ( GetDeviceName ( i ) == GetDeviceName ( id ) ) )
  251. if ( ( fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels )
  252. || ( fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels ) )
  253. return true;
  254. //then the device isn't full duplex
  255. return false;
  256. }