Jack2 1.9.6
|
00001 /* 00002 Copyright (C) 2008 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 00023 using namespace std; 00024 00025 PortAudioDevices::PortAudioDevices() 00026 { 00027 PaError err; 00028 PaDeviceIndex id; 00029 jack_log("Initializing PortAudio..."); 00030 if ( ( err = Pa_Initialize() ) == paNoError ) 00031 { 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 fHostName = new string[fNumHostApi]; 00038 for ( id = 0; id < fNumHostApi; id++ ) 00039 fHostName[id] = string ( Pa_GetHostApiInfo(id)->name ); 00040 } 00041 else 00042 jack_error("JackPortAudioDriver::Pa_Initialize error = %s", Pa_GetErrorText(err)); 00043 } 00044 00045 PortAudioDevices::~PortAudioDevices() 00046 { 00047 // Desactivate for now: crash the server.. 00048 //Pa_Terminate(); 00049 00050 delete[] fDeviceInfo; 00051 delete[] fHostName; 00052 } 00053 00054 PaDeviceIndex PortAudioDevices::GetNumDevice() 00055 { 00056 return fNumDevice; 00057 } 00058 00059 PaDeviceInfo* PortAudioDevices::GetDeviceInfo ( PaDeviceIndex id ) 00060 { 00061 return fDeviceInfo[id]; 00062 } 00063 00064 string PortAudioDevices::GetDeviceName ( PaDeviceIndex id ) 00065 { 00066 return string ( fDeviceInfo[id]->name ); 00067 } 00068 00069 string PortAudioDevices::GetHostFromDevice ( PaDeviceInfo* device ) 00070 { 00071 return fHostName[device->hostApi]; 00072 } 00073 00074 string PortAudioDevices::GetHostFromDevice ( PaDeviceIndex id ) 00075 { 00076 return fHostName[fDeviceInfo[id]->hostApi]; 00077 } 00078 00079 string PortAudioDevices::GetFullName ( PaDeviceIndex id ) 00080 { 00081 string hostname = GetHostFromDevice ( id ); 00082 string devicename = GetDeviceName ( id ); 00083 //some hostname are quite long...use shortcuts 00084 if ( hostname.compare ( "Windows DirectSound" ) == 0 ) 00085 hostname = string ( "DirectSound" ); 00086 return ( hostname + "::" + devicename ); 00087 } 00088 00089 string PortAudioDevices::GetFullName ( std::string hostname, std::string devicename ) 00090 { 00091 //some hostname are quite long...use shortcuts 00092 if ( hostname.compare ( "Windows DirectSound" ) == 0 ) 00093 hostname = string ( "DirectSound" ); 00094 return ( hostname + "::" + devicename ); 00095 } 00096 00097 PaDeviceInfo* PortAudioDevices::GetDeviceFromFullName ( string fullname, PaDeviceIndex& id, bool isInput ) 00098 { 00099 PaDeviceInfo* ret = NULL; 00100 //no driver to find 00101 if ( fullname.size() == 0 ) 00102 return NULL; 00103 //first get host and device names from fullname 00104 string::size_type separator = fullname.find ( "::", 0 ); 00105 if ( separator == 0 ) 00106 return NULL; 00107 char* hostname = (char*)malloc(separator + 9); 00108 fill_n ( hostname, separator + 9, 0 ); 00109 fullname.copy ( hostname, separator ); 00110 00111 //we need the entire hostname, replace shortcuts 00112 if ( strcmp ( hostname, "DirectSound" ) == 0 ) 00113 strcpy ( hostname, "Windows DirectSound" ); 00114 string devicename = fullname.substr ( separator + 2 ); 00115 //then find the corresponding device 00116 for ( PaDeviceIndex dev_id = 0; dev_id < fNumDevice; dev_id++ ) 00117 { 00118 bool flag = (isInput) ? (fDeviceInfo[dev_id]->maxInputChannels > 0) : (fDeviceInfo[dev_id]->maxOutputChannels > 0); 00119 if ( ( GetHostFromDevice(dev_id).compare(hostname) == 0 ) 00120 && ( GetDeviceName(dev_id).compare(devicename) == 0 ) 00121 && flag ) 00122 { 00123 id = dev_id; 00124 ret = fDeviceInfo[dev_id]; 00125 } 00126 } 00127 free(hostname); 00128 return ret; 00129 } 00130 00131 void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters) 00132 { 00133 static double standardSampleRates[] = 00134 { 00135 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 00136 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */ 00137 }; 00138 int i, printCount; 00139 PaError err; 00140 00141 printCount = 0; 00142 for (i = 0; standardSampleRates[i] > 0; i++) 00143 { 00144 err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]); 00145 if (err == paFormatIsSupported) 00146 { 00147 if (printCount == 0) 00148 { 00149 jack_info("\t%8.2f", standardSampleRates[i]); 00150 printCount = 1; 00151 } 00152 else if (printCount == 4) 00153 { 00154 jack_info(",\n\t%8.2f", standardSampleRates[i]); 00155 printCount = 1; 00156 } 00157 else 00158 { 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 { 00179 id = Pa_GetDefaultInputDevice(); 00180 if ( fullname.size() ) 00181 jack_error("Can't open %s, PortAudio will use default input device.", devicename); 00182 if ( id == paNoDevice ) 00183 return -1; 00184 max_input = GetDeviceInfo(id)->maxInputChannels; 00185 } 00186 return id; 00187 } 00188 00189 int PortAudioDevices::GetOutputDeviceFromName(const char* devicename, PaDeviceIndex& id, int& max_output) 00190 { 00191 string fullname = string ( devicename ); 00192 PaDeviceInfo* device = GetDeviceFromFullName ( fullname, id, false ); 00193 if ( device ) 00194 max_output = device->maxOutputChannels; 00195 else 00196 { 00197 id = Pa_GetDefaultOutputDevice(); 00198 if ( fullname.size() ) 00199 jack_error("Can't open %s, PortAudio will use default output device.", devicename); 00200 if ( id == paNoDevice ) 00201 return -1; 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 { 00215 jack_info ( "-------- device #%d ------------------------------------------------", id ); 00216 00217 if ( id == Pa_GetDefaultInputDevice() ) 00218 { 00219 jack_info("[ Default Input ]"); 00220 } 00221 else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi)->defaultInputDevice ) 00222 { 00223 const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi ); 00224 jack_info ( "[ Default %s Input ]", host_info->name ); 00225 } 00226 00227 if ( id == Pa_GetDefaultOutputDevice() ) 00228 { 00229 jack_info ( "[ Default Output ]" ); 00230 } 00231 else if ( id == Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi )->defaultOutputDevice ) 00232 { 00233 const PaHostApiInfo *host_info = Pa_GetHostApiInfo ( fDeviceInfo[id]->hostApi ); 00234 jack_info ( "[ Default %s Output ]", host_info->name ); 00235 } 00236 00237 /* print device info fields */ 00238 jack_info ( "Name = %s", GetFullName ( id ).c_str() ); 00239 jack_info ( "Max inputs = %d", fDeviceInfo[id]->maxInputChannels ); 00240 jack_info ( "Max outputs = %d", fDeviceInfo[id]->maxOutputChannels ); 00241 00242 #ifdef WIN32 00243 /* ASIO specific latency information */ 00244 if ( Pa_GetHostApiInfo(fDeviceInfo[id]->hostApi)->type == paASIO ) 00245 { 00246 long minLatency, maxLatency, preferredLatency, granularity; 00247 00248 PaAsio_GetAvailableLatencyValues ( id, &minLatency, &maxLatency, &preferredLatency, &granularity ); 00249 00250 jack_info ( "ASIO minimum buffer size = %ld", minLatency ); 00251 jack_info ( "ASIO maximum buffer size = %ld", maxLatency ); 00252 jack_info ( "ASIO preferred buffer size = %ld", preferredLatency ); 00253 00254 if ( granularity == -1 ) 00255 jack_info ( "ASIO buffer granularity = power of 2" ); 00256 else 00257 jack_info ( "ASIO buffer granularity = %ld", granularity ); 00258 } 00259 #endif 00260 00261 jack_info ( "Default sample rate = %8.2f", fDeviceInfo[id]->defaultSampleRate ); 00262 00263 /* poll for standard sample rates */ 00264 inputParameters.device = id; 00265 inputParameters.channelCount = fDeviceInfo[id]->maxInputChannels; 00266 inputParameters.sampleFormat = paInt16; 00267 inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ 00268 inputParameters.hostApiSpecificStreamInfo = NULL; 00269 00270 outputParameters.device = id; 00271 outputParameters.channelCount = fDeviceInfo[id]->maxOutputChannels; 00272 outputParameters.sampleFormat = paInt16; 00273 outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ 00274 outputParameters.hostApiSpecificStreamInfo = NULL; 00275 } 00276 jack_info ( "**************************** End of list ****************************" ); 00277 } 00278 00279 bool PortAudioDevices::IsDuplex ( PaDeviceIndex id ) 00280 { 00281 //does the device has in and out facilities 00282 if ( fDeviceInfo[id]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels ) 00283 return true; 00284 //else is another complementary device ? (search in devices with the same name) 00285 for ( PaDeviceIndex i = 0; i < fNumDevice; i++ ) 00286 if ( ( i != id ) && ( GetDeviceName ( i ) == GetDeviceName ( id ) ) ) 00287 if ( ( fDeviceInfo[i]->maxInputChannels && fDeviceInfo[id]->maxOutputChannels ) 00288 || ( fDeviceInfo[i]->maxOutputChannels && fDeviceInfo[id]->maxInputChannels ) ) 00289 return true; 00290 //then the device isn't full duplex 00291 return false; 00292 }