00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00105 if (fullname.size() == 0) {
00106 return NULL;
00107 }
00108
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
00120 if (strcmp(hostname, "DirectSound") == 0) {
00121 strcpy(hostname, "Windows DirectSound");
00122 }
00123 string devicename = fullname.substr(separator + 2);
00124
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
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
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;
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
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
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
00285 inputParameters.device = id;
00286 inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels;
00287 inputParameters.sampleFormat = paInt16;
00288 inputParameters.suggestedLatency = 0;
00289 inputParameters.hostApiSpecificStreamInfo = NULL;
00290
00291 outputParameters.device = id;
00292 outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels;
00293 outputParameters.sampleFormat = paInt16;
00294 outputParameters.suggestedLatency = 0;
00295 outputParameters.hostApiSpecificStreamInfo = NULL;
00296 }
00297 jack_info("**************************** End of list ****************************");
00298 }
00299
00300 bool PortAudioDevices::IsDuplex(PaDeviceIndex id)
00301 {
00302
00303 if (fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels) {
00304 return true;
00305 }
00306
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
00316 return false;
00317 }