Jack2
1.9.10
|
00001 /* 00002 Copyright (C) 2008-2011 Romain Moret at Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #include "JackPortAudioDevices.h" 00021 #include "JackError.h" 00022 #include <stdlib.h> 00023 00024 using namespace std; 00025 00026 PortAudioDevices::PortAudioDevices() 00027 { 00028 PaError err; 00029 PaDeviceIndex id; 00030 jack_log("Initializing PortAudio..."); 00031 if ((err = Pa_Initialize()) == paNoError) { 00032 fNumHostApi = Pa_GetHostApiCount(); 00033 fNumDevice = Pa_GetDeviceCount(); 00034 fDeviceInfo = new PaDeviceInfo*[fNumDevice]; 00035 for (id = 0; id < fNumDevice; id++) { 00036 fDeviceInfo[id] = const_cast<PaDeviceInfo*>(Pa_GetDeviceInfo(id)); 00037 } 00038 fHostName = new string[fNumHostApi]; 00039 for (id = 0; id < fNumHostApi; id++) { 00040 fHostName[id] = string(Pa_GetHostApiInfo(id)->name); 00041 } 00042 } else { 00043 jack_error("JackPortAudioDriver::Pa_Initialize error = %s", Pa_GetErrorText(err)); 00044 } 00045 } 00046 00047 PortAudioDevices::~PortAudioDevices() 00048 { 00049 jack_log("Terminate PortAudio..."); 00050 Pa_Terminate(); 00051 00052 delete[] fDeviceInfo; 00053 delete[] fHostName; 00054 } 00055 00056 PaDeviceIndex PortAudioDevices::GetNumDevice() 00057 { 00058 return fNumDevice; 00059 } 00060 00061 PaDeviceInfo* PortAudioDevices::GetDeviceInfo(PaDeviceIndex id) 00062 { 00063 return fDeviceInfo[id]; 00064 } 00065 00066 string PortAudioDevices::GetDeviceName(PaDeviceIndex id) 00067 { 00068 return string(fDeviceInfo[id]->name); 00069 } 00070 00071 string PortAudioDevices::GetHostFromDevice(PaDeviceInfo* device) 00072 { 00073 return fHostName[device->hostApi]; 00074 } 00075 00076 string PortAudioDevices::GetHostFromDevice(PaDeviceIndex id) 00077 { 00078 return fHostName[fDeviceInfo[id]->hostApi]; 00079 } 00080 00081 string PortAudioDevices::GetFullName(PaDeviceIndex id) 00082 { 00083 string hostname = GetHostFromDevice(id); 00084 string devicename = GetDeviceName(id); 00085 //some hostname are quite long...use shortcuts 00086 if (hostname.compare("Windows DirectSound") == 0) { 00087 hostname = string("DirectSound"); 00088 } 00089 return (hostname + "::" + devicename); 00090 } 00091 00092 string PortAudioDevices::GetFullName(std::string hostname, std::string devicename) 00093 { 00094 //some hostname are quite long...use shortcuts 00095 if (hostname.compare("Windows DirectSound") == 0) { 00096 hostname = string("DirectSound"); 00097 } 00098 return (hostname + "::" + devicename); 00099 } 00100 00101 PaDeviceInfo* PortAudioDevices::GetDeviceFromFullName(string fullname, PaDeviceIndex& id, bool isInput) 00102 { 00103 PaDeviceInfo* ret = NULL; 00104 //no driver to find 00105 if (fullname.size() == 0) { 00106 return NULL; 00107 } 00108 //first get host and device names from fullname 00109 string::size_type separator = fullname.find("::", 0); 00110 00111 if (separator == string::npos) { 00112 return NULL; 00113 } 00114 00115 char* hostname = (char*)malloc(separator + 9); 00116 fill_n(hostname, separator + 9, 0); 00117 fullname.copy(hostname, separator); 00118 00119 //we need the entire hostname, replace shortcuts 00120 if (strcmp(hostname, "DirectSound") == 0) { 00121 strcpy(hostname, "Windows DirectSound"); 00122 } 00123 string devicename = fullname.substr(separator + 2); 00124 //then find the corresponding device 00125 for (PaDeviceIndex dev_id = 0; dev_id < fNumDevice; dev_id++) { 00126 bool flag = (isInput) ? (fDeviceInfo[dev_id]->maxInputChannels > 0) : (fDeviceInfo[dev_id]->maxOutputChannels > 0); 00127 if ((GetHostFromDevice(dev_id).compare(hostname) == 0) 00128 && (GetDeviceName(dev_id).compare(devicename) == 0) 00129 && flag) { 00130 id = dev_id; 00131 ret = fDeviceInfo[dev_id]; 00132 } 00133 } 00134 free(hostname); 00135 return ret; 00136 } 00137 00138 void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters) 00139 { 00140 static double standardSampleRates[] = 00141 { 00142 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 00143 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */ 00144 }; 00145 int i, printCount; 00146 PaError err; 00147 00148 printCount = 0; 00149 for (i = 0; standardSampleRates[i] > 0; i++) { 00150 err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]); 00151 if (err == paFormatIsSupported) { 00152 if (printCount == 0) { 00153 jack_info("\t%8.2f", standardSampleRates[i]); 00154 printCount = 1; 00155 } else if (printCount == 4) { 00156 jack_info(",\n\t%8.2f", standardSampleRates[i]); 00157 printCount = 1; 00158 } else { 00159 jack_info(", %8.2f", standardSampleRates[i]); 00160 ++printCount; 00161 } 00162 } 00163 } 00164 if (!printCount) { 00165 jack_info("None"); 00166 } else { 00167 jack_info("\n"); 00168 } 00169 } 00170 00171 int PortAudioDevices::GetInputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_input) 00172 { 00173 string fullname = string(devicename); 00174 PaDeviceInfo* device = GetDeviceFromFullName(fullname, id, true); 00175 if (device) { 00176 max_input = device->maxInputChannels; 00177 } else { 00178 id = Pa_GetDefaultInputDevice(); 00179 if (fullname.size()) { 00180 jack_error("Can't open %s, PortAudio will use default input device.", devicename); 00181 } 00182 if (id == paNoDevice) { 00183 return -1; 00184 } 00185 max_input = GetDeviceInfo(id)->maxInputChannels; 00186 } 00187 return id; 00188 } 00189 00190 int PortAudioDevices::GetOutputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_output) 00191 { 00192 string fullname = string(devicename); 00193 PaDeviceInfo* device = GetDeviceFromFullName(fullname, id, false); 00194 if (device) { 00195 max_output = device->maxOutputChannels; 00196 } else { 00197 id = Pa_GetDefaultOutputDevice(); 00198 if (fullname.size()) { 00199 jack_error("Can't open %s, PortAudio will use default output device.", devicename); 00200 } 00201 if (id == paNoDevice) { 00202 return -1; 00203 } 00204 max_output = GetDeviceInfo(id)->maxOutputChannels; 00205 } 00206 return id; 00207 } 00208 00209 int PortAudioDevices::GetPreferredBufferSize(PaDeviceIndex id) 00210 { 00211 #if defined(WIN32) && defined(HAVE_ASIO) 00212 /* ASIO specific latency information */ 00213 if (Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO) { 00214 long minLatency, maxLatency, preferredLatency, granularity; 00215 00216 PaAsio_GetAvailableBufferSizes(id, &minLatency, &maxLatency, &preferredLatency, &granularity); 00217 00218 jack_info("ASIO minimum buffer size = %ld", minLatency); 00219 jack_info("ASIO maximum buffer size = %ld", maxLatency); 00220 jack_info("ASIO preferred buffer size = %ld", preferredLatency); 00221 00222 if (granularity == -1) { 00223 jack_info("ASIO buffer granularity = power of 2"); 00224 } else { 00225 jack_info("ASIO buffer granularity = %ld", granularity); 00226 } 00227 00228 return preferredLatency; 00229 } else 00230 #endif 00231 { 00232 return 512; // Non ASIO driver, returns generic value 00233 } 00234 } 00235 00236 void PortAudioDevices::DisplayDevicesNames() 00237 { 00238 PaDeviceIndex id; 00239 PaStreamParameters inputParameters, outputParameters; 00240 jack_info("********************** Devices list, %d detected **********************", fNumDevice); 00241 00242 for (id = 0; id < fNumDevice; id++) { 00243 jack_info("-------- device #%d ------------------------------------------------", id); 00244 00245 if (id == Pa_GetDefaultInputDevice()) { 00246 jack_info("[ Default Input ]"); 00247 } else if (id == Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->defaultInputDevice) { 00248 const PaHostApiInfo *host_info = Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi); 00249 jack_info("[ Default %s Input ]", host_info->name); 00250 } 00251 00252 if (id == Pa_GetDefaultOutputDevice()) { 00253 jack_info("[ Default Output ]"); 00254 } else if (id == Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->defaultOutputDevice) { 00255 const PaHostApiInfo *host_info = Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi); 00256 jack_info("[ Default %s Output ]", host_info->name); 00257 } 00258 00259 /* print device info fields */ 00260 jack_info("Name = %s", GetFullName(id).c_str()); 00261 jack_info("Max inputs = %d", fDeviceInfo[id]->maxInputChannels); 00262 jack_info("Max outputs = %d", fDeviceInfo[id]->maxOutputChannels); 00263 00264 #if defined(WIN32) && defined(HAVE_ASIO) 00265 /* ASIO specific latency information */ 00266 if (Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO) { 00267 long minLatency, maxLatency, preferredLatency, granularity; 00268 00269 PaAsio_GetAvailableBufferSizes(id, &minLatency, &maxLatency, &preferredLatency, &granularity); 00270 00271 jack_info("ASIO minimum buffer size = %ld", minLatency); 00272 jack_info("ASIO maximum buffer size = %ld", maxLatency); 00273 jack_info("ASIO preferred buffer size = %ld", preferredLatency); 00274 00275 if (granularity == -1) { 00276 jack_info("ASIO buffer granularity = power of 2"); 00277 } else { 00278 jack_info("ASIO buffer granularity = %ld", granularity); 00279 } 00280 } 00281 #endif 00282 jack_info("Default sample rate = %8.2f", fDeviceInfo[id]->defaultSampleRate); 00283 00284 /* poll for standard sample rates */ 00285 inputParameters.device = id; 00286 inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels; 00287 inputParameters.sampleFormat = paInt16; 00288 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ 00289 inputParameters.hostApiSpecificStreamInfo = NULL; 00290 00291 outputParameters.device = id; 00292 outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels; 00293 outputParameters.sampleFormat = paInt16; 00294 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ 00295 outputParameters.hostApiSpecificStreamInfo = NULL; 00296 } 00297 jack_info("**************************** End of list ****************************"); 00298 } 00299 00300 bool PortAudioDevices::IsDuplex(PaDeviceIndex id) 00301 { 00302 //does the device has in and out facilities 00303 if (fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels) { 00304 return true; 00305 } 00306 //else is another complementary device ? (search in devices with the same name) 00307 for (PaDeviceIndex i = 0; i < fNumDevice; i++) { 00308 if ((i != id) && (GetDeviceName(i) == GetDeviceName(id))) { 00309 if ((fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels) 00310 || (fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels)) { 00311 return true; 00312 } 00313 } 00314 } 00315 //then the device isn't full duplex 00316 return false; 00317 }