| static int mInCallbackFinishedState = false; | static int mInCallbackFinishedState = false; | ||||
| #if (USE_PORTAUDIO == 18) | #if (USE_PORTAUDIO == 18) | ||||
| static PaDeviceID myOutputDevice = 0; | |||||
| static PortAudioStream *pa_stream = NULL; | static PortAudioStream *pa_stream = NULL; | ||||
| #endif | #endif | ||||
| #if (USE_PORTAUDIO == 19) | #if (USE_PORTAUDIO == 19) | ||||
| out_channels = 1; | out_channels = 1; | ||||
| #if USE_PORTAUDIO == 18 | #if USE_PORTAUDIO == 18 | ||||
| PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | |||||
| err = Pa_OpenStream(&pa_stream, | err = Pa_OpenStream(&pa_stream, | ||||
| // capture parameters | // capture parameters | ||||
| paNoDevice, | paNoDevice, | ||||
| paInt16, | paInt16, | ||||
| NULL, | NULL, | ||||
| // playback parameters | // playback parameters | ||||
| playbackDevice, | |||||
| myOutputDevice, | |||||
| out_channels, | out_channels, | ||||
| paInt16, | paInt16, | ||||
| NULL, | NULL, | ||||
| paInt16, | paInt16, | ||||
| NULL, | NULL, | ||||
| // playback parameters | // playback parameters | ||||
| playbackDevice, | |||||
| myOutputDevice, | |||||
| out_channels, | out_channels, | ||||
| paInt16, | paInt16, | ||||
| NULL, | NULL, | ||||
| return err != paNoError; | return err != paNoError; | ||||
| } | } | ||||
| #if (USE_PORTAUDIO == 19) | |||||
| static void update_output_parameters(int selectedDevice, const PaDeviceInfo *deviceInfo) | static void update_output_parameters(int selectedDevice, const PaDeviceInfo *deviceInfo) | ||||
| { | { | ||||
| #if (USE_PORTAUDIO == 19) | |||||
| myOutputParameters.device = selectedDevice; | myOutputParameters.device = selectedDevice; | ||||
| myOutputParameters.channelCount = 1; | myOutputParameters.channelCount = 1; | ||||
| myOutputParameters.sampleFormat = paInt16; | myOutputParameters.sampleFormat = paInt16; | ||||
| myOutputParameters.suggestedLatency = (double)0.1; // 100ms | myOutputParameters.suggestedLatency = (double)0.1; // 100ms | ||||
| myOutputParameters.hostApiSpecificStreamInfo = NULL; | myOutputParameters.hostApiSpecificStreamInfo = NULL; | ||||
| } | |||||
| #else | |||||
| myOutputDevice = selectedDevice; | |||||
| #endif | #endif | ||||
| } | |||||
| static void select_device() | |||||
| static const PaDeviceInfo *select_device(const char *device) | |||||
| { | { | ||||
| #if (USE_PORTAUDIO == 19) | #if (USE_PORTAUDIO == 19) | ||||
| int numDevices = Pa_GetDeviceCount(); | int numDevices = Pa_GetDeviceCount(); | ||||
| #else | |||||
| int numDevices = Pa_CountDevices(); | |||||
| #endif | |||||
| if (numDevices < 0) | if (numDevices < 0) | ||||
| assert(0); | |||||
| return NULL; | |||||
| PaDeviceIndex i = 0, selectedIndex = 0, defaultAlsaIndex = numDevices; | |||||
| #if (USE_PORTAUDIO == 19) | |||||
| PaDeviceIndex i = 0, selectedIndex = 0; | |||||
| #else | |||||
| PaDeviceID i = 0, selectedIndex = 0; | |||||
| #endif | |||||
| const PaDeviceInfo *deviceInfo = NULL; | const PaDeviceInfo *deviceInfo = NULL; | ||||
| const PaDeviceInfo *selectedDeviceInfo = NULL; | const PaDeviceInfo *selectedDeviceInfo = NULL; | ||||
| selectedDeviceInfo = Pa_GetDeviceInfo(selectedIndex); | selectedDeviceInfo = Pa_GetDeviceInfo(selectedIndex); | ||||
| } | } | ||||
| if (device == NULL) { | |||||
| #if (USE_PORTAUDIO == 19) | |||||
| selectedIndex = Pa_GetDefaultOutputDevice(); | |||||
| #else | |||||
| selectedIndex = Pa_GetDefaultOutputDeviceID(); | |||||
| #endif | |||||
| selectedDeviceInfo = Pa_GetDeviceInfo(selectedIndex); | |||||
| } | |||||
| if (selectedDeviceInfo == NULL) { | if (selectedDeviceInfo == NULL) { | ||||
| for (i = 0; i < numDevices; i++) { | for (i = 0; i < numDevices; i++) { | ||||
| deviceInfo = Pa_GetDeviceInfo(i); | deviceInfo = Pa_GetDeviceInfo(i); | ||||
| if (deviceInfo == NULL) | |||||
| break; | |||||
| const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); | |||||
| if (hostInfo && hostInfo->type == paALSA) { | |||||
| // Check (once) the default output device | |||||
| if (defaultAlsaIndex == numDevices) { | |||||
| defaultAlsaIndex = hostInfo->defaultOutputDevice; | |||||
| const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(defaultAlsaIndex); | |||||
| update_output_parameters(defaultAlsaIndex, deviceInfo); | |||||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) { | |||||
| selectedIndex = defaultAlsaIndex; | |||||
| selectedDeviceInfo = deviceInfo; | |||||
| break; | |||||
| } | |||||
| } | |||||
| // if the default output device does not match, | |||||
| // look for the device with the highest number of output channels | |||||
| update_output_parameters(i, deviceInfo); | |||||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) { | |||||
| if (!selectedDeviceInfo | |||||
| || (selectedDeviceInfo->maxOutputChannels < deviceInfo->maxOutputChannels)) { | |||||
| selectedIndex = i; | |||||
| selectedDeviceInfo = deviceInfo; | |||||
| } | |||||
| } | |||||
| if (deviceInfo != NULL && !strcmp(device, deviceInfo->name)) { | |||||
| selectedIndex = i; | |||||
| selectedDeviceInfo = deviceInfo; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (selectedDeviceInfo) | if (selectedDeviceInfo) | ||||
| update_output_parameters(selectedIndex, selectedDeviceInfo); | update_output_parameters(selectedIndex, selectedDeviceInfo); | ||||
| else { | |||||
| i = Pa_GetDefaultOutputDevice(); | |||||
| deviceInfo = Pa_GetDeviceInfo(i); | |||||
| update_output_parameters(i, deviceInfo); | |||||
| } | |||||
| #endif | |||||
| return selectedDeviceInfo; | |||||
| } | } | ||||
| void wave_set_callback_is_output_enabled(t_wave_callback *cb) | void wave_set_callback_is_output_enabled(t_wave_callback *cb) | ||||
| void *wave_open(int srate, const char *device) | void *wave_open(int srate, const char *device) | ||||
| { | { | ||||
| (void)device; // unused | |||||
| PaError err; | PaError err; | ||||
| pa_stream = NULL; | pa_stream = NULL; | ||||
| static int once = 0; | static int once = 0; | ||||
| if (!once) { | if (!once) { | ||||
| select_device(); | |||||
| if (!select_device(device)) | |||||
| return NULL; | |||||
| once = 1; | once = 1; | ||||
| } | } | ||||