2 Copyright (C) 2008 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"
25 PortAudioDevices::PortAudioDevices()
29 jack_log("Initializing PortAudio...");
30 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
));
37 fHostName
= new string
[fNumHostApi
];
38 for ( id
= 0; id
< fNumHostApi
; id
++ )
39 fHostName
[id
] = string ( Pa_GetHostApiInfo(id
)->name
);
42 jack_error("JackPortAudioDriver::Pa_Initialize error = %s", Pa_GetErrorText(err
));
45 PortAudioDevices::~PortAudioDevices()
47 // Desactivate for now: crash the server..
54 PaDeviceIndex
PortAudioDevices::GetNumDevice()
59 PaDeviceInfo
* PortAudioDevices::GetDeviceInfo ( PaDeviceIndex id
)
61 return fDeviceInfo
[id
];
64 string
PortAudioDevices::GetDeviceName ( PaDeviceIndex id
)
66 return string ( fDeviceInfo
[id
]->name
);
69 string
PortAudioDevices::GetHostFromDevice ( PaDeviceInfo
* device
)
71 return fHostName
[device
->hostApi
];
74 string
PortAudioDevices::GetHostFromDevice ( PaDeviceIndex id
)
76 return fHostName
[fDeviceInfo
[id
]->hostApi
];
79 string
PortAudioDevices::GetFullName ( PaDeviceIndex id
)
81 string hostname
= GetHostFromDevice ( id
);
82 string devicename
= GetDeviceName ( id
);
83 //some hostname are quite long...use shortcuts
84 if ( hostname
.compare ( "Windows DirectSound" ) == 0 )
85 hostname
= string ( "DirectSound" );
86 return ( hostname
+ "::" + devicename
);
89 string
PortAudioDevices::GetFullName ( std::string hostname
, std::string devicename
)
91 //some hostname are quite long...use shortcuts
92 if ( hostname
.compare ( "Windows DirectSound" ) == 0 )
93 hostname
= string ( "DirectSound" );
94 return ( hostname
+ "::" + devicename
);
97 PaDeviceInfo
* PortAudioDevices::GetDeviceFromFullName ( string fullname
, PaDeviceIndex
& id
, bool isInput
)
99 PaDeviceInfo
* ret
= NULL
;
101 if ( fullname
.size() == 0 )
103 //first get host and device names from fullname
104 string::size_type separator
= fullname
.find ( "::", 0 );
105 if ( separator
== 0 )
107 char* hostname
= (char*)malloc(separator
+ 9);
108 fill_n ( hostname
, separator
+ 9, 0 );
109 fullname
.copy ( hostname
, separator
);
111 //we need the entire hostname, replace shortcuts
112 if ( strcmp ( hostname
, "DirectSound" ) == 0 )
113 strcpy ( hostname
, "Windows DirectSound" );
114 string devicename
= fullname
.substr ( separator
+ 2 );
115 //then find the corresponding device
116 for ( PaDeviceIndex dev_id
= 0; dev_id
< fNumDevice
; dev_id
++ )
118 bool flag
= (isInput
) ? (fDeviceInfo
[dev_id
]->maxInputChannels
> 0) : (fDeviceInfo
[dev_id
]->maxOutputChannels
> 0);
119 if ( ( GetHostFromDevice(dev_id
).compare(hostname
) == 0 )
120 && ( GetDeviceName(dev_id
).compare(devicename
) == 0 )
124 ret
= fDeviceInfo
[dev_id
];
131 void PortAudioDevices::PrintSupportedStandardSampleRates(const PaStreamParameters
* inputParameters
, const PaStreamParameters
* outputParameters
)
133 static double standardSampleRates
[] =
135 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
136 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
142 for (i
= 0; standardSampleRates
[i
] > 0; i
++)
144 err
= Pa_IsFormatSupported(inputParameters
, outputParameters
, standardSampleRates
[i
]);
145 if (err
== paFormatIsSupported
)
149 jack_info("\t%8.2f", standardSampleRates
[i
]);
152 else if (printCount
== 4)
154 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
;
179 id
= Pa_GetDefaultInputDevice();
180 if ( fullname
.size() )
181 jack_error("Can't open %s, PortAudio will use default input device.", devicename
);
182 if ( id
== paNoDevice
)
184 max_input
= GetDeviceInfo(id
)->maxInputChannels
;
189 int PortAudioDevices::GetOutputDeviceFromName(const char* devicename
, PaDeviceIndex
& id
, int& max_output
)
191 string fullname
= string ( devicename
);
192 PaDeviceInfo
* device
= GetDeviceFromFullName ( fullname
, id
, false );
194 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
);
200 if ( id
== paNoDevice
)
202 max_output
= GetDeviceInfo(id
)->maxOutputChannels
;
207 void PortAudioDevices::DisplayDevicesNames()
210 PaStreamParameters inputParameters
, outputParameters
;
211 jack_info ( "********************** Devices list, %d detected **********************", fNumDevice
);
213 for ( id
= 0; id
< fNumDevice
; id
++ )
215 jack_info ( "-------- device #%d ------------------------------------------------", id
);
217 if ( id
== Pa_GetDefaultInputDevice() )
219 jack_info("[ Default Input ]");
221 else if ( id
== Pa_GetHostApiInfo ( fDeviceInfo
[id
]->hostApi
)->defaultInputDevice
)
223 const PaHostApiInfo
*host_info
= Pa_GetHostApiInfo ( fDeviceInfo
[id
]->hostApi
);
224 jack_info ( "[ Default %s Input ]", host_info
->name
);
227 if ( id
== Pa_GetDefaultOutputDevice() )
229 jack_info ( "[ Default Output ]" );
231 else if ( id
== Pa_GetHostApiInfo ( fDeviceInfo
[id
]->hostApi
)->defaultOutputDevice
)
233 const PaHostApiInfo
*host_info
= Pa_GetHostApiInfo ( fDeviceInfo
[id
]->hostApi
);
234 jack_info ( "[ Default %s Output ]", host_info
->name
);
237 /* print device info fields */
238 jack_info ( "Name = %s", GetFullName ( id
).c_str() );
239 jack_info ( "Max inputs = %d", fDeviceInfo
[id
]->maxInputChannels
);
240 jack_info ( "Max outputs = %d", fDeviceInfo
[id
]->maxOutputChannels
);
243 /* ASIO specific latency information */
244 if ( Pa_GetHostApiInfo(fDeviceInfo
[id
]->hostApi
)->type
== paASIO
)
246 long minLatency
, maxLatency
, preferredLatency
, granularity
;
248 PaAsio_GetAvailableLatencyValues ( id
, &minLatency
, &maxLatency
, &preferredLatency
, &granularity
);
250 jack_info ( "ASIO minimum buffer size = %ld", minLatency
);
251 jack_info ( "ASIO maximum buffer size = %ld", maxLatency
);
252 jack_info ( "ASIO preferred buffer size = %ld", preferredLatency
);
254 if ( granularity
== -1 )
255 jack_info ( "ASIO buffer granularity = power of 2" );
257 jack_info ( "ASIO buffer granularity = %ld", granularity
);
261 jack_info ( "Default sample rate = %8.2f", fDeviceInfo
[id
]->defaultSampleRate
);
263 /* poll for standard sample rates */
264 inputParameters
.device
= id
;
265 inputParameters
.channelCount
= fDeviceInfo
[id
]->maxInputChannels
;
266 inputParameters
.sampleFormat
= paInt16
;
267 inputParameters
.suggestedLatency
= 0; /* ignored by Pa_IsFormatSupported() */
268 inputParameters
.hostApiSpecificStreamInfo
= NULL
;
270 outputParameters
.device
= id
;
271 outputParameters
.channelCount
= fDeviceInfo
[id
]->maxOutputChannels
;
272 outputParameters
.sampleFormat
= paInt16
;
273 outputParameters
.suggestedLatency
= 0; /* ignored by Pa_IsFormatSupported() */
274 outputParameters
.hostApiSpecificStreamInfo
= NULL
;
276 jack_info ( "**************************** End of list ****************************" );
279 bool PortAudioDevices::IsDuplex ( PaDeviceIndex id
)
281 //does the device has in and out facilities
282 if ( fDeviceInfo
[id
]->maxInputChannels
&& fDeviceInfo
[id
]->maxOutputChannels
)
284 //else is another complementary device ? (search in devices with the same name)
285 for ( PaDeviceIndex i
= 0; i
< fNumDevice
; i
++ )
286 if ( ( i
!= id
) && ( GetDeviceName ( i
) == GetDeviceName ( id
) ) )
287 if ( ( fDeviceInfo
[i
]->maxInputChannels
&& fDeviceInfo
[id
]->maxOutputChannels
)
288 || ( fDeviceInfo
[i
]->maxOutputChannels
&& fDeviceInfo
[id
]->maxInputChannels
) )
290 //then the device isn't full duplex