Jack2 1.9.8

JackPortAudioDevices.cpp

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     // Desactivate for now: crash the server..
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     if (separator == 0) {
00111         return NULL;
00112     }
00113     char* hostname = (char*)malloc(separator + 9);
00114     fill_n (hostname, separator + 9, 0);
00115     fullname.copy (hostname, separator);
00116 
00117     //we need the entire hostname, replace shortcuts
00118     if (strcmp (hostname, "DirectSound") == 0) {
00119         strcpy (hostname, "Windows DirectSound");
00120     }
00121     string devicename = fullname.substr (separator + 2);
00122     //then find the corresponding device
00123     for (PaDeviceIndex dev_id = 0; dev_id < fNumDevice; dev_id++) {
00124         bool flag = (isInput) ? (fDeviceInfo[dev_id]->maxInputChannels > 0) : (fDeviceInfo[dev_id]->maxOutputChannels > 0);
00125         if ((GetHostFromDevice(dev_id).compare(hostname) == 0)
00126             && (GetDeviceName(dev_id).compare(devicename) == 0)
00127             && flag) {
00128             id = dev_id;
00129             ret = fDeviceInfo[dev_id];
00130         }
00131     }
00132         free(hostname);
00133     return ret;
00134 }
00135 
00136 void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters)
00137 {
00138     static double standardSampleRates[] =
00139     {
00140         8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
00141         44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated  list */
00142     };
00143     int i, printCount;
00144     PaError err;
00145 
00146     printCount = 0;
00147     for (i = 0; standardSampleRates[i] > 0; i++) {
00148         err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]);
00149         if (err == paFormatIsSupported) {
00150             if (printCount == 0) {
00151                 jack_info("\t%8.2f", standardSampleRates[i]);
00152                 printCount = 1;
00153             } else if (printCount == 4) {
00154                 jack_info(",\n\t%8.2f", standardSampleRates[i]);
00155                 printCount = 1;
00156             } else {
00157                 jack_info(", %8.2f", standardSampleRates[i]);
00158                 ++printCount;
00159             }
00160         }
00161     }
00162     if (!printCount) {
00163         jack_info("None");
00164         } else {
00165         jack_info("\n");
00166         }
00167 }
00168 
00169 int PortAudioDevices::GetInputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_input)
00170 {
00171     string fullname = string (devicename);
00172     PaDeviceInfo* device = GetDeviceFromFullName (fullname, id, true);
00173     if (device) {
00174         max_input = device->maxInputChannels;
00175     } else {
00176         id = Pa_GetDefaultInputDevice();
00177         if (fullname.size()) {
00178             jack_error("Can't open %s, PortAudio will use default input device.", devicename);
00179         }
00180         if (id == paNoDevice) {
00181             return -1;
00182         }
00183         max_input = GetDeviceInfo(id)->maxInputChannels;
00184     }
00185     return id;
00186 }
00187 
00188 int PortAudioDevices::GetOutputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_output)
00189 {
00190     string fullname = string (devicename);
00191     PaDeviceInfo* device = GetDeviceFromFullName (fullname, id, false);
00192     if (device) {
00193         max_output = device->maxOutputChannels;
00194     } else {
00195         id = Pa_GetDefaultOutputDevice();
00196         if (fullname.size()) {
00197             jack_error("Can't open %s, PortAudio will use default output device.", devicename);
00198         }
00199         if (id == paNoDevice) {
00200             return -1;
00201         }
00202         max_output = GetDeviceInfo(id)->maxOutputChannels;
00203     }
00204     return id;
00205 }
00206 
00207 void PortAudioDevices::DisplayDevicesNames()
00208 {
00209     PaDeviceIndex id;
00210     PaStreamParameters inputParameters, outputParameters;
00211     jack_info ("********************** Devices list, %d detected **********************", fNumDevice);
00212 
00213     for (id = 0; id < fNumDevice; id++) {
00214         jack_info ("-------- device #%d ------------------------------------------------", id);
00215 
00216         if (id == Pa_GetDefaultInputDevice()) {
00217             jack_info("[ Default Input ]");
00218         } else if (id == Pa_GetHostApiInfo (fDeviceInfo[id]->hostApi)->defaultInputDevice) {
00219             const PaHostApiInfo *host_info = Pa_GetHostApiInfo (fDeviceInfo[id]->hostApi);
00220             jack_info("[ Default %s Input ]", host_info->name);
00221         }
00222 
00223         if (id == Pa_GetDefaultOutputDevice()) {
00224             jack_info ("[ Default Output ]");
00225         } else if (id == Pa_GetHostApiInfo (fDeviceInfo[id]->hostApi)->defaultOutputDevice) {
00226             const PaHostApiInfo *host_info = Pa_GetHostApiInfo (fDeviceInfo[id]->hostApi);
00227             jack_info("[ Default %s Output ]", host_info->name);
00228         }
00229 
00230         /* print device info fields */
00231         jack_info ("Name                        = %s", GetFullName (id).c_str());
00232         jack_info ("Max inputs                  = %d", fDeviceInfo[id]->maxInputChannels);
00233         jack_info ("Max outputs                 = %d", fDeviceInfo[id]->maxOutputChannels);
00234 
00235 #ifdef WIN32
00236         /* ASIO specific latency information */
00237         if (Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO) {
00238             long minLatency, maxLatency, preferredLatency, granularity;
00239 
00240             PaAsio_GetAvailableLatencyValues (id, &minLatency, &maxLatency, &preferredLatency, &granularity);
00241 
00242             jack_info ("ASIO minimum buffer size    = %ld", minLatency);
00243             jack_info ("ASIO maximum buffer size    = %ld", maxLatency);
00244             jack_info ("ASIO preferred buffer size  = %ld", preferredLatency);
00245 
00246             if (granularity == -1) {
00247                 jack_info ("ASIO buffer granularity     = power of 2");
00248             } else {
00249                 jack_info ("ASIO buffer granularity     = %ld", granularity);
00250             }
00251         }
00252 #endif
00253 
00254         jack_info ("Default sample rate         = %8.2f", fDeviceInfo[id]->defaultSampleRate);
00255 
00256         /* poll for standard sample rates */
00257         inputParameters.device = id;
00258         inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels;
00259         inputParameters.sampleFormat = paInt16;
00260         inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
00261         inputParameters.hostApiSpecificStreamInfo = NULL;
00262 
00263         outputParameters.device = id;
00264         outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels;
00265         outputParameters.sampleFormat = paInt16;
00266         outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
00267         outputParameters.hostApiSpecificStreamInfo = NULL;
00268     }
00269     jack_info("**************************** End of list ****************************");
00270 }
00271 
00272 bool PortAudioDevices::IsDuplex (PaDeviceIndex id)
00273 {
00274     //does the device has in and out facilities
00275     if (fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels) {
00276         return true;
00277     }
00278     //else is another complementary device ? (search in devices with the same name)
00279     for (PaDeviceIndex i = 0; i < fNumDevice; i++) {
00280         if ((i != id) && (GetDeviceName (i) == GetDeviceName (id))) {
00281             if ((fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels)
00282                     || (fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels)) {
00283                 return true;
00284             }
00285         }
00286     }
00287     //then the device isn't full duplex
00288     return false;
00289 }
00290