2 Copyright (C) 2008-2011 Romain Moret at Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "JackPortAudioDevices.h"
21 #include "JackError.h"
26 PortAudioDevices::PortAudioDevices()
30 jack_log("Initializing PortAudio...");
31 if ((err
= Pa_Initialize()) == paNoError
) {
32 fNumHostApi
= Pa_GetHostApiCount();
33 fNumDevice
= Pa_GetDeviceCount();
34 fDeviceInfo
= new PaDeviceInfo
*[fNumDevice
];
35 for (id
= 0; id
< fNumDevice
; id
++) {
36 fDeviceInfo
[id
] = const_cast<PaDeviceInfo
*>(Pa_GetDeviceInfo(id
));
38 fHostName
= new string
[fNumHostApi
];
39 for (id
= 0; id
< fNumHostApi
; id
++) {
40 fHostName
[id
] = string(Pa_GetHostApiInfo(id
)->name
);
43 jack_error("JackPortAudioDriver::Pa_Initialize error = %s", Pa_GetErrorText(err
));
47 PortAudioDevices::~PortAudioDevices()
49 jack_log("Terminate PortAudio...");
56 PaDeviceIndex
PortAudioDevices::GetNumDevice()
61 PaDeviceInfo
* PortAudioDevices::GetDeviceInfo(PaDeviceIndex id
)
63 return fDeviceInfo
[id
];
66 string
PortAudioDevices::GetDeviceName(PaDeviceIndex id
)
68 return string(fDeviceInfo
[id
]->name
);
71 string
PortAudioDevices::GetHostFromDevice(PaDeviceInfo
* device
)
73 return fHostName
[device
->hostApi
];
76 string
PortAudioDevices::GetHostFromDevice(PaDeviceIndex id
)
78 return fHostName
[fDeviceInfo
[id
]->hostApi
];
81 string
PortAudioDevices::GetFullName(PaDeviceIndex id
)
83 string hostname
= GetHostFromDevice(id
);
84 string devicename
= GetDeviceName(id
);
85 //some hostname are quite long...use shortcuts
86 if (hostname
.compare("Windows DirectSound") == 0) {
87 hostname
= string("DirectSound");
89 return (hostname
+ "::" + devicename
);
92 string
PortAudioDevices::GetFullName(std::string hostname
, std::string devicename
)
94 //some hostname are quite long...use shortcuts
95 if (hostname
.compare("Windows DirectSound") == 0) {
96 hostname
= string("DirectSound");
98 return (hostname
+ "::" + devicename
);
101 PaDeviceInfo
* PortAudioDevices::GetDeviceFromFullName(string fullname
, PaDeviceIndex
& id
, bool isInput
)
103 PaDeviceInfo
* ret
= NULL
;
105 if (fullname
.size() == 0) {
108 //first get host and device names from fullname
109 string::size_type separator
= fullname
.find("::", 0);
111 if (separator
== string::npos
) {
115 char* hostname
= (char*)malloc(separator
+ 9);
116 fill_n(hostname
, separator
+ 9, 0);
117 fullname
.copy(hostname
, separator
);
119 //we need the entire hostname, replace shortcuts
120 if (strcmp(hostname
, "DirectSound") == 0) {
121 strcpy(hostname
, "Windows DirectSound");
123 string devicename
= fullname
.substr(separator
+ 2);
124 //then find the corresponding device
125 for (PaDeviceIndex dev_id
= 0; dev_id
< fNumDevice
; dev_id
++) {
126 bool flag
= (isInput
) ? (fDeviceInfo
[dev_id
]->maxInputChannels
> 0) : (fDeviceInfo
[dev_id
]->maxOutputChannels
> 0);
127 if ((GetHostFromDevice(dev_id
).compare(hostname
) == 0)
128 && (GetDeviceName(dev_id
).compare(devicename
) == 0)
131 ret
= fDeviceInfo
[dev_id
];
138 void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters
* inputParameters
, const PaStreamParameters
* outputParameters
)
140 static double standardSampleRates
[] =
142 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
143 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
149 for (i
= 0; standardSampleRates
[i
] > 0; i
++) {
150 err
= Pa_IsFormatSupported(inputParameters
, outputParameters
, standardSampleRates
[i
]);
151 if (err
== paFormatIsSupported
) {
152 if (printCount
== 0) {
153 jack_info("\t%8.2f", standardSampleRates
[i
]);
155 } else if (printCount
== 4) {
156 jack_info(",\n\t%8.2f", standardSampleRates
[i
]);
159 jack_info(", %8.2f", standardSampleRates
[i
]);
171 int PortAudioDevices::GetInputDeviceFromName(const char* devicename
, PaDeviceIndex
& id
, int& max_input
)
173 string fullname
= string(devicename
);
174 PaDeviceInfo
* device
= GetDeviceFromFullName(fullname
, id
, true);
176 max_input
= device
->maxInputChannels
;
178 id
= Pa_GetDefaultInputDevice();
179 if (fullname
.size()) {
180 jack_error("Can't open %s, PortAudio will use default input device.", devicename
);
182 if (id
== paNoDevice
) {
185 max_input
= GetDeviceInfo(id
)->maxInputChannels
;
190 int PortAudioDevices::GetOutputDeviceFromName(const char* devicename
, PaDeviceIndex
& id
, int& max_output
)
192 string fullname
= string(devicename
);
193 PaDeviceInfo
* device
= GetDeviceFromFullName(fullname
, id
, false);
195 max_output
= device
->maxOutputChannels
;
197 id
= Pa_GetDefaultOutputDevice();
198 if (fullname
.size()) {
199 jack_error("Can't open %s, PortAudio will use default output device.", devicename
);
201 if (id
== paNoDevice
) {
204 max_output
= GetDeviceInfo(id
)->maxOutputChannels
;
209 int PortAudioDevices::GetPreferredBufferSize(PaDeviceIndex id
)
211 #if defined(WIN32) && defined(HAVE_ASIO)
212 /* ASIO specific latency information */
213 if (Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
)->type
== paASIO
) {
214 long minLatency
, maxLatency
, preferredLatency
, granularity
;
216 PaAsio_GetAvailableBufferSizes(id
, &minLatency
, &maxLatency
, &preferredLatency
, &granularity
);
218 jack_info("ASIO minimum buffer size = %ld", minLatency
);
219 jack_info("ASIO maximum buffer size = %ld", maxLatency
);
220 jack_info("ASIO preferred buffer size = %ld", preferredLatency
);
222 if (granularity
== -1) {
223 jack_info("ASIO buffer granularity = power of 2");
225 jack_info("ASIO buffer granularity = %ld", granularity
);
228 return preferredLatency
;
232 return 512; // Non ASIO driver, returns generic value
236 void PortAudioDevices::DisplayDevicesNames()
239 PaStreamParameters inputParameters
, outputParameters
;
240 jack_info("********************** Devices list, %d detected **********************", fNumDevice
);
242 for (id
= 0; id
< fNumDevice
; id
++) {
243 jack_info("-------- device #%d ------------------------------------------------", id
);
245 if (id
== Pa_GetDefaultInputDevice()) {
246 jack_info("[ Default Input ]");
247 } else if (id
== Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
)->defaultInputDevice
) {
248 const PaHostApiInfo
*host_info
= Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
);
249 jack_info("[ Default %s Input ]", host_info
->name
);
252 if (id
== Pa_GetDefaultOutputDevice()) {
253 jack_info("[ Default Output ]");
254 } else if (id
== Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
)->defaultOutputDevice
) {
255 const PaHostApiInfo
*host_info
= Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
);
256 jack_info("[ Default %s Output ]", host_info
->name
);
259 /* print device info fields */
260 jack_info("Name = %s", GetFullName(id
).c_str());
261 jack_info("Max inputs = %d", fDeviceInfo
[id
]->maxInputChannels
);
262 jack_info("Max outputs = %d", fDeviceInfo
[id
]->maxOutputChannels
);
264 #if defined(WIN32) && defined(HAVE_ASIO)
265 /* ASIO specific latency information */
266 if (Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
)->type
== paASIO
) {
267 long minLatency
, maxLatency
, preferredLatency
, granularity
;
269 PaAsio_GetAvailableBufferSizes(id
, &minLatency
, &maxLatency
, &preferredLatency
, &granularity
);
271 jack_info("ASIO minimum buffer size = %ld", minLatency
);
272 jack_info("ASIO maximum buffer size = %ld", maxLatency
);
273 jack_info("ASIO preferred buffer size = %ld", preferredLatency
);
275 if (granularity
== -1) {
276 jack_info("ASIO buffer granularity = power of 2");
278 jack_info("ASIO buffer granularity = %ld", granularity
);
282 jack_info("Default sample rate = %8.2f", fDeviceInfo
[id
]->defaultSampleRate
);
284 /* poll for standard sample rates */
285 inputParameters
.device
= id
;
286 inputParameters
.channelCount
= fDeviceInfo
[id
]->maxInputChannels
;
287 inputParameters
.sampleFormat
= paInt16
;
288 inputParameters
.suggestedLatency
= 0; /* ignored by Pa_IsFormatSupported() */
289 inputParameters
.hostApiSpecificStreamInfo
= NULL
;
291 outputParameters
.device
= id
;
292 outputParameters
.channelCount
= fDeviceInfo
[id
]->maxOutputChannels
;
293 outputParameters
.sampleFormat
= paInt16
;
294 outputParameters
.suggestedLatency
= 0; /* ignored by Pa_IsFormatSupported() */
295 outputParameters
.hostApiSpecificStreamInfo
= NULL
;
297 jack_info("**************************** End of list ****************************");
300 bool PortAudioDevices::IsDuplex(PaDeviceIndex id
)
302 //does the device has in and out facilities
303 if (fDeviceInfo
[id
]->maxInputChannels
&& fDeviceInfo
[id
]->maxOutputChannels
) {
306 //else is another complementary device ? (search in devices with the same name)
307 for (PaDeviceIndex i
= 0; i
< fNumDevice
; i
++) {
308 if ((i
!= id
) && (GetDeviceName(i
) == GetDeviceName(id
))) {
309 if ((fDeviceInfo
[i
]->maxInputChannels
&& fDeviceInfo
[id
]->maxOutputChannels
)
310 || (fDeviceInfo
[i
]->maxOutputChannels
&& fDeviceInfo
[id
]->maxInputChannels
)) {
315 //then the device isn't full duplex