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.

291 lines
9.9KB

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