1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22
23
24 #include <string.h>
25 #include "globdef.h"
26 #include "conf.h"
27 #include "uidef.h"
28 #include "padef.h"
29 #include "rusage.h"
30 #include "thrdef.h"
31 #include "sigdef.h"
32 #include "keyboard_def.h"
33 #include "fft1def.h"
34 #include "screendef.h"
35
36 #define MAX_LATENCY 20
37
38 typedef void PaStream;
39 typedef int PaDeviceIndex;
40 typedef int PaHostApiIndex;
41 typedef int PaError;
42 typedef double PaTime;
43 typedef unsigned long PaSampleFormat;
44 typedef unsigned long PaStreamCallbackFlags;
45 typedef unsigned long PaStreamFlags;
46
47 #define paNoFlag ((PaStreamFlags) 0)
48 #define paClipOff ((PaStreamFlags) 0x00000001)
49 #define paDitherOff ((PaStreamFlags) 0x00000002)
50 #define paInputOverflow ((PaStreamCallbackFlags) 0x00000002)
51 #define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004)
52 #define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
53 #define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
54 #define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
55 #define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
56 #define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
57 #define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
58 #define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */
59 #define paNonInterleaved ((PaSampleFormat) 0x80000000)
60 #define paFormatIsSupported (0)
61
62
63 typedef enum PaErrorCode
64 {
65 paNoError = 0,
66 paNotInitialized = -10000,
67 paUnanticipatedHostError,
68 paInvalidChannelCount,
69 paInvalidSampleRate,
70 paInvalidDevice,
71 paInvalidFlag,
72 paSampleFormatNotSupported,
73 paBadIODeviceCombination,
74 paInsufficientMemory,
75 paBufferTooBig,
76 paBufferTooSmall,
77 paNullCallback,
78 paBadStreamPtr,
79 paTimedOut,
80 paInternalError,
81 paDeviceUnavailable,
82 paIncompatibleHostApiSpecificStreamInfo,
83 paStreamIsStopped,
84 paStreamIsNotStopped,
85 paInputOverflowed,
86 paOutputUnderflowed,
87 paHostApiNotFound,
88 paInvalidHostApi,
89 paCanNotReadFromACallbackStream,
90 paCanNotWriteToACallbackStream,
91 paCanNotReadFromAnOutputOnlyStream,
92 paCanNotWriteToAnInputOnlyStream,
93 paIncompatibleStreamHostApi,
94 paBadBufferPtr
95 }
96 PaErrorCode;
97
98 typedef enum PaHostApiTypeId
99 {
100 paInDevelopment=0,
101 paDirectSound=1,
102 paMME=2,
103 paASIO=3,
104 paSoundManager=4,
105 paCoreAudio=5,
106 paOSS=7,
107 paALSA=8,
108 paAL=9,
109 paBeOS=10,
110 paWDMKS=11,
111 paJACK=12,
112 paWASAPI=13,
113 paAudioScienceHPI=14
114 }
115 PaHostApiTypeId;
116
117 typedef enum PaStreamCallbackResult
118 {
119 paContinue=0,
120 paComplete=1,
121 paAbort=2
122 }
123 PaStreamCallbackResult;
124
125 typedef struct PaStreamCallbackTimeInfo
126 {
127 PaTime inputBufferAdcTime;
128 PaTime currentTime;
129 PaTime outputBufferDacTime;
130 }
131 PaStreamCallbackTimeInfo;
132
133 typedef struct PaHostApiInfo
134 {
135 int structVersion;
136 PaHostApiTypeId type;
137 const char *name;
138 int deviceCount;
139 PaDeviceIndex defaultInputDevice;
140 PaDeviceIndex defaultOutputDevice;
141 }
142 PaHostApiInfo;
143
144 typedef struct PaHostErrorInfo
145 {
146 PaHostApiTypeId hostApiType;
147 long errorCode;
148 const char *errorText;
149 }
150 PaHostErrorInfo;
151
152 typedef struct PaDeviceInfo
153 {
154 int structVersion;
155 const char *name;
156 PaHostApiIndex hostApi;
157 int maxInputChannels;
158 int maxOutputChannels;
159 PaTime defaultLowInputLatency;
160 PaTime defaultLowOutputLatency;
161 PaTime defaultHighInputLatency;
162 PaTime defaultHighOutputLatency;
163 double defaultSampleRate;
164 }
165 PaDeviceInfo;
166
167 typedef struct PaStreamParameters
168 {
169 PaDeviceIndex device;
170 int channelCount;
171 PaSampleFormat sampleFormat;
172 PaTime suggestedLatency;
173 void *hostApiSpecificStreamInfo;
174 }
175 PaStreamParameters;
176
177 typedef struct PaStreamInfo
178 {
179 int structVersion;
180 PaTime inputLatency;
181 PaTime outputLatency;
182 double sampleRate;
183 }
184 PaStreamInfo;
185
186 typedef int PaStreamCallback(const void *input, void *output,
187 unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
188 PaStreamCallbackFlags statusFlags, void *userData );
189
190 typedef int (*p_Pa_GetVersion)(void);
191 typedef const char* (*p_Pa_GetVersionText)(void);
192 typedef const char* (*p_Pa_GetErrorText)(PaError errorCode);
193 typedef PaError (*p_Pa_Initialize)(void);
194 typedef PaError (*p_Pa_Terminate)(void);
195 typedef const PaHostApiInfo* (*p_Pa_GetHostApiInfo)(PaHostApiIndex hostApi);
196 typedef PaDeviceIndex (*p_Pa_GetDeviceCount)(void);
197 typedef const PaDeviceInfo* (*p_Pa_GetDeviceInfo)(PaDeviceIndex device);
198 typedef PaError (*p_Pa_IsFormatSupported)( const PaStreamParameters *inputParameters,
199 const PaStreamParameters *outputParameters,
200 double sampleRate );
201 typedef PaError (*p_Pa_OpenStream)(PaStream** stream,
202 const PaStreamParameters *inputParameters,
203 const PaStreamParameters *outputParameters,
204 double sampleRate, unsigned long framesPerBuffer,
205 PaStreamFlags streamFlags, PaStreamCallback *streamCallback,
206 void *userData );
207 typedef PaError (*p_Pa_CloseStream)(PaStream *stream);
208 typedef PaError (*p_Pa_StartStream)(PaStream *stream);
209 typedef const PaStreamInfo* (*p_Pa_GetStreamInfo)(PaStream *stream);
210 typedef void (*p_PaAlsa_EnableRealtimeScheduling)(PaStream *s, int enable);
211 typedef PaError (*p_PaJack_SetClientName)(const char *name);
212
213
214 p_Pa_GetVersion Pa_GetVersion;
215 p_Pa_GetVersionText Pa_GetVersionText;
216 p_Pa_GetErrorText Pa_GetErrorText;
217 p_Pa_Initialize Pa_Initialize;
218 p_Pa_Terminate Pa_Terminate;
219 p_Pa_GetHostApiInfo Pa_GetHostApiInfo;
220 p_Pa_GetDeviceCount Pa_GetDeviceCount;
221 p_Pa_GetDeviceInfo Pa_GetDeviceInfo;
222 p_Pa_IsFormatSupported Pa_IsFormatSupported;
223 p_Pa_OpenStream Pa_OpenStream;
224 p_Pa_CloseStream Pa_CloseStream;
225 p_Pa_StartStream Pa_StartStream;
226 p_Pa_GetStreamInfo Pa_GetStreamInfo;
227 p_PaAlsa_EnableRealtimeScheduling PaAlsa_EnableRealtimeScheduling;
228 p_PaJack_SetClientName PaJack_SetClientName;
229
230 PaStream *out_stream;
231 PaStream *in_stream;
232 int daout_workload_reset;
233 int pa_version;
234
235
236 #if OSNUM == OSNUM_WINDOWS
237 HANDLE pa_libhandle;
238 // Host processor. Allows to skip internal PA processing completely.
239 // You must set paWinWasapiRedirectHostProcessor flag to PaWasapiStreamInfo::flags member
240 // in order to have host processor redirected to your callback.
241 // Use with caution! inputFrames and outputFrames depend solely on final device setup (buffer
242 // size is just recommendation) but are not changing during run-time once stream is started.
243 typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames,
244 void *outputBuffer, long outputFrames,
245 void *userData);
246
247 typedef unsigned long PaWinWaveFormatChannelMask;
248
249 typedef enum PaWasapiFlags
250 {
251 paWinWasapiExclusive = (1 << 0),
252 paWinWasapiRedirectHostProcessor = (1 << 1),
253 paWinWasapiUseChannelMask = (1 << 2),
254 paWinWasapiPolling = (1 << 3),
255 paWinWasapiThreadPriority = (1 << 4)
256 }
257 PaWasapiFlags;
258
259 typedef enum PaWasapiThreadPriority
260 {
261 eThreadPriorityNone = 0,
262 eThreadPriorityAudio,
263 eThreadPriorityCapture,
264 eThreadPriorityDistribution,
265 eThreadPriorityGames,
266 eThreadPriorityPlayback,
267 eThreadPriorityProAudio,
268 eThreadPriorityWindowManager
269 }
270 PaWasapiThreadPriority;
271
272 typedef struct PaWasapiStreamInfo
273 {
274 unsigned long size;
275 PaHostApiTypeId hostApiType;
276 unsigned long version;
277 unsigned long flags;
278 PaWinWaveFormatChannelMask channelMask;
279 PaWasapiHostProcessorCallback hostProcessorOutput;
280 PaWasapiHostProcessorCallback hostProcessorInput;
281 PaWasapiThreadPriority threadPriority;
282 }
283 PaWasapiStreamInfo;
284
285 #define NO_OF_PADLL 5
286 char* portaudio_dll_files[NO_OF_PADLL]={"palir-03.dll",
287 "palir-02.dll",
288 "palir-01.dll",
289 "portaudio.dll",
290 "libportaudio.dll"};
291
select_portaudio_dll(void)292 int select_portaudio_dll(void)
293 {
294 char s[80];
295 int i, j, k, line;
296 int valid_files[NO_OF_PADLL];
297 clear_screen();
298 line=3;
299 lir_text(5,line,"Select what dll file to use for Portaudio");
300 line++;
301 lir_text(5,line,"Only high-lighted files are available on this system");
302 line+=2;
303 j=0;
304 k=-1;
305 for(i=0; i<NO_OF_PADLL; i++)
306 {
307 pa_libhandle=LoadLibrary(portaudio_dll_files[i]);
308 if(pa_libhandle == NULL)
309 {
310 settextcolor(22);
311 valid_files[i]=FALSE;
312 }
313 else
314 {
315 settextcolor(15);
316 valid_files[i]=TRUE;
317 j++;
318 }
319 sprintf(s,"%d %s",i,portaudio_dll_files[i]);
320 lir_text(8,line,s);
321 line++;
322 }
323 line++;
324 settextcolor(7);
325 if(j==0)
326 {
327 lir_text(5,line,"No library for Portaudio found on this system");
328 line+=2;
329 lir_text(7,line,press_any_key);
330 return-1;
331 }
332 if(j==1)
333 {
334 sprintf(s,"Only one alternative. %s autoselected",portaudio_dll_files[0]);
335 lir_text(5,line,s);
336 line+=2;
337 lir_text(7,line,press_any_key);
338 return 0;
339 }
340 lir_text(5,line,"Select dll file by line number =>");
341 new:;
342 k=lir_get_integer(40,line,1,0,NO_OF_PADLL);
343 if(valid_files[k] == FALSE)goto new;
344 clear_screen();
345 return k;
346 }
347
load_pa_library(void)348 int load_pa_library(void)
349 {
350 int i, info;
351 i=((ui.use_alsa&PORTAUDIO_DLL_VERSION)>>5)-1;
352 info=0;
353 pa_libhandle=LoadLibrary(portaudio_dll_files[i]);
354 if(pa_libhandle == NULL)goto load_error;
355 info=1;
356 Pa_GetErrorText=(p_Pa_GetErrorText)GetProcAddress(pa_libhandle,"Pa_GetErrorText");
357 if(!Pa_GetErrorText)goto sym_error;
358 Pa_Initialize=(p_Pa_Initialize)GetProcAddress(pa_libhandle,"Pa_Initialize");
359 if(!Pa_Initialize)goto sym_error;
360 Pa_Terminate=(p_Pa_Terminate)GetProcAddress(pa_libhandle,"Pa_Terminate");
361 if(!Pa_Terminate)goto sym_error;
362 Pa_GetHostApiInfo=(p_Pa_GetHostApiInfo)GetProcAddress(pa_libhandle,"Pa_GetHostApiInfo");
363 if(!Pa_GetHostApiInfo)goto sym_error;
364 Pa_GetDeviceCount=(p_Pa_GetDeviceCount)GetProcAddress(pa_libhandle,"Pa_GetDeviceCount");
365 if(!Pa_GetDeviceCount)goto sym_error;
366 Pa_GetDeviceInfo=(p_Pa_GetDeviceInfo)GetProcAddress(pa_libhandle,"Pa_GetDeviceInfo");
367 if(!Pa_GetDeviceInfo)goto sym_error;
368 Pa_IsFormatSupported=(p_Pa_IsFormatSupported)GetProcAddress(pa_libhandle,"Pa_IsFormatSupported");
369 if(!Pa_IsFormatSupported)goto sym_error;
370 Pa_OpenStream=(p_Pa_OpenStream)GetProcAddress(pa_libhandle,"Pa_OpenStream");
371 if(!Pa_OpenStream)goto sym_error;
372 Pa_CloseStream=(p_Pa_CloseStream)GetProcAddress(pa_libhandle,"Pa_CloseStream");
373 if(!Pa_CloseStream)goto sym_error;
374 Pa_StartStream=(p_Pa_StartStream)GetProcAddress(pa_libhandle,"Pa_StartStream");
375 if(!Pa_StartStream)goto sym_error;
376 Pa_GetStreamInfo=(p_Pa_GetStreamInfo)GetProcAddress(pa_libhandle,"Pa_GetStreamInfo");
377 if(!Pa_GetStreamInfo)goto sym_error;
378 pa_version=1;
379 Pa_GetVersionText=(p_Pa_GetVersionText)GetProcAddress(pa_libhandle,"Pa_GetVersionText");
380 if(!Pa_GetVersionText)pa_version=0;
381 Pa_GetVersion=(p_Pa_GetVersion)GetProcAddress(pa_libhandle, "Pa_GetVersion");
382 if(!Pa_GetVersion)pa_version=0;
383 return 0;
384 sym_error:;
385 FreeLibrary(pa_libhandle);
386 load_error:;
387 library_error_screen(portaudio_dll_files[i],info);
388 return -1;
389 }
390
391
392
unload_pa_library(void)393 void unload_pa_library(void)
394 {
395 FreeLibrary(pa_libhandle);
396 }
397
398
399
400 #endif
401
402
403
404 #if(OSNUM == OSNUM_LINUX)
405 #include <dlfcn.h>
406 void *pa_libhandle;
407 const char linrad_name[8] ="linrad";
408 int pa_linux_realtime;
409 int pa_linux_jack;
410
load_pa_library(void)411 int load_pa_library(void)
412 {
413 int info;
414 info=0;
415 pa_libhandle=dlopen(PA_LIBNAME, RTLD_LAZY);
416 if(pa_libhandle == NULL)goto load_error;
417 info=1;
418 Pa_GetErrorText=(p_Pa_GetErrorText)dlsym(pa_libhandle,"Pa_GetErrorText");
419 if(dlerror() != 0)goto sym_error;
420 Pa_Initialize=(p_Pa_Initialize)dlsym(pa_libhandle,"Pa_Initialize");
421 if(dlerror() != 0)goto sym_error;
422 Pa_Terminate=(p_Pa_Terminate)dlsym(pa_libhandle,"Pa_Terminate");
423 if(dlerror() != 0)goto sym_error;
424 Pa_GetHostApiInfo=(p_Pa_GetHostApiInfo)dlsym(pa_libhandle,"Pa_GetHostApiInfo");
425 if(dlerror() != 0)goto sym_error;
426 Pa_GetDeviceCount=(p_Pa_GetDeviceCount)dlsym(pa_libhandle,"Pa_GetDeviceCount");
427 if(dlerror() != 0)goto sym_error;
428 Pa_GetDeviceInfo=(p_Pa_GetDeviceInfo)dlsym(pa_libhandle,"Pa_GetDeviceInfo");
429 if(dlerror() != 0)goto sym_error;
430 Pa_IsFormatSupported=(p_Pa_IsFormatSupported)dlsym(pa_libhandle,"Pa_IsFormatSupported");
431 if(dlerror() != 0)goto sym_error;
432 Pa_OpenStream=(p_Pa_OpenStream)dlsym(pa_libhandle,"Pa_OpenStream");
433 if(dlerror() != 0)goto sym_error;
434 Pa_CloseStream=(p_Pa_CloseStream)dlsym(pa_libhandle,"Pa_CloseStream");
435 if(dlerror() != 0)goto sym_error;
436 Pa_StartStream=(p_Pa_StartStream)dlsym(pa_libhandle,"Pa_StartStream");
437 if(dlerror() != 0)goto sym_error;
438 Pa_GetStreamInfo=(p_Pa_GetStreamInfo)dlsym(pa_libhandle,"Pa_GetStreamInfo");
439 if(dlerror() != 0)goto sym_error;
440 PaAlsa_EnableRealtimeScheduling=(p_PaAlsa_EnableRealtimeScheduling)
441 dlsym(pa_libhandle, "PaAlsa_EnableRealtimeScheduling");
442 if(dlerror() == 0)
443 {
444 pa_linux_realtime=1;
445 }
446 else
447 {
448 pa_linux_realtime=0;
449 }
450 PaJack_SetClientName=(p_PaJack_SetClientName)dlsym(pa_libhandle,
451 "PaJack_SetClientName");
452 if(dlerror() == 0)
453 {
454 pa_linux_jack=1;
455 }
456 else
457 {
458 pa_linux_jack=0;
459 }
460 pa_version=1;
461 Pa_GetVersionText=(p_Pa_GetVersionText)dlsym(pa_libhandle,"Pa_GetVersionText");
462 if(dlerror() != 0)pa_version=0;
463 Pa_GetVersion=(p_Pa_GetVersion)dlsym(pa_libhandle, "Pa_GetVersion");
464 if(dlerror() != 0)pa_version=0;
465 return 0;
466 sym_error:;
467 dlclose(pa_libhandle);
468 load_error:;
469 library_error_screen(PA_LIBNAME,info);
470 return -1;
471 }
472
unload_pa_library(void)473 void unload_pa_library(void)
474 {
475 if(!ftdi_library_flag)return;
476 dlclose(pa_libhandle);
477 ftdi_library_flag=FALSE;
478 }
479
480 #endif
481
482 #if(OSNUM == OSNUM_WINDOWS)
483 int pa_linux_realtime=0;
484 #endif
485
486
487
488 /// This routine will be called by the PortAudio engine when audio is needed.
489 /// It may be called at interrupt level on some machines so don't do anything
490 /// that could mess up the system like calling malloc() or free().
491
recordCallback(const void * inputBuffer,void * outputBuffer,unsigned long framesToProcess,const PaStreamCallbackTimeInfo * timeInfo,PaStreamCallbackFlags statusFlags,void * userData)492 extern int recordCallback( const void *inputBuffer, void *outputBuffer,
493 unsigned long framesToProcess,
494 const PaStreamCallbackTimeInfo* timeInfo,
495 PaStreamCallbackFlags statusFlags,
496 void *userData )
497 {
498 char s[80];
499 // Prevent unused variable warnings.
500 (void) outputBuffer;
501 (void) timeInfo;
502 (void) userData;
503 if(portaudio_active_flag == FALSE)
504 {
505 lirerr(701401);
506 return paAbort;
507 }
508 if(snd[RXAD].block_frames != (int)framesToProcess)
509 {
510 lirerr(520674);
511 return paAbort;
512 }
513 if( (statusFlags&paInputOverflow) != 0)
514 {
515 no_of_rx_overrun_errors++;
516 sprintf(s,"RX%s%d",overrun_error_msg,no_of_rx_overrun_errors);
517 wg_error(s,WGERR_RXIN);
518 }
519 memcpy(&timf1_char[timf1p_sdr],inputBuffer,snd[RXAD].block_bytes);
520 timf1p_sdr=(timf1p_sdr+snd[RXAD].block_bytes)&timf1_bytemask;
521 lir_set_event(EVENT_PORTAUDIO_RXREADY);
522 return paContinue;
523 }
524
playCallback(const void * inputBuffer,void * outputBuffer,unsigned long framesToProcess,const PaStreamCallbackTimeInfo * timeInfo,PaStreamCallbackFlags statusFlags,void * userData)525 extern int playCallback( const void *inputBuffer, void *outputBuffer,
526 unsigned long framesToProcess,
527 const PaStreamCallbackTimeInfo* timeInfo,
528 PaStreamCallbackFlags statusFlags,
529 void *userData )
530 {
531 char s[80];
532 // Prevent unused variable warnings.
533 (void) inputBuffer;
534 (void) timeInfo;
535 (void) userData;
536 int samps;
537 if(portaudio_active_flag == FALSE)
538 {
539 lirerr(701400);
540 return paAbort;
541 }
542 if(snd[RXDA].block_frames != (int)framesToProcess)
543 {
544 lirerr(520673);
545 return paAbort;
546 }
547 if(thread_command_flag[THREAD_RX_OUTPUT]==THRFLAG_IDLE ||
548 thread_status_flag[THREAD_RX_OUTPUT]==THRFLAG_IDLE)goto idle;
549 if(daout_workload_reset!=workload_reset_flag)
550 {
551 min_daout_samps=baseband_size;
552 daout_workload_reset=workload_reset_flag;
553 }
554 if(audio_dump_flag == 1)goto idle;
555 if( (statusFlags&paOutputUnderflow) != 0)
556 {
557 if(count_rx_underrun_flag)
558 {
559 no_of_rx_underrun_errors++;
560 sprintf(s,"RX%s%d",underrun_error_msg,no_of_rx_underrun_errors);
561 wg_error(s,WGERR_RXOUT);
562 }
563 }
564 samps=(daout_pa-daout_px+daout_size)&daout_bufmask;
565 if( samps > snd[RXDA].block_bytes)
566 {
567 memcpy(outputBuffer,&daout[daout_px],snd[RXDA].block_bytes);
568 daout_px=(daout_px+snd[RXDA].block_bytes)&daout_bufmask;
569 samps-=snd[RXDA].block_bytes;
570 if(min_daout_samps > samps)min_daout_samps=samps;
571 }
572 else
573 {
574 min_daout_samps=0;
575 idle:;
576 memset(outputBuffer, 0, snd[RXDA].block_bytes);
577 }
578 return paContinue;
579 }
580
pa_rx_input(void)581 void pa_rx_input(void)
582 {
583 while (!kill_all_flag && timf1p_sdr == timf1p_pa)
584 {
585 lir_await_event(EVENT_PORTAUDIO_RXREADY);
586 }
587 }
588
589
portaudio_stop(void)590 void portaudio_stop(void)
591 {
592 if(portaudio_active_flag == FALSE)
593 {
594 lirerr(711401);
595 return;
596 }
597 Pa_Terminate();
598 }
599
open_portaudio_rxad(void)600 void open_portaudio_rxad(void)
601 {
602 PaStreamParameters rxadParameters;
603 const PaStreamInfo *streamInfo;
604 PaError pa_err;
605 if(portaudio_active_flag == FALSE)
606 {
607 lir_rxin_status=LIR_PA_FLAG_ERROR;
608 lirerr(701402);
609 return;
610 }
611 // Set sample format
612 if( (ui.rx_input_mode&DWORD_INPUT) == 0)
613 {
614 rxadParameters.sampleFormat = paInt16; // 2 byte samples
615 }
616 else
617 {
618 rxadParameters.sampleFormat = paInt32; // 4 byte samples
619 }
620 rxadParameters.device = ui.rx_addev_no;
621 rxadParameters.channelCount = ui.rx_ad_channels;
622 rxadParameters.suggestedLatency = ui.rx_ad_latency/snd[RXAD].interrupt_rate;
623 // ******************************************************************************
624 #if (OSNUM == OSNUM_WINDOWS)
625 //TO GET BEST LATENCY WITH WASAPI: SELECT EXCLUSIVE MODE INSTEAD OF THE DEFAULT SHARED MODE
626 //EXCLUSIVE MODE WORKS FOR VISTAX64, VISTAX86, WINDOWS7
627 //EXCLUSIVE MODE DOES NOT WORK FOR WOW64 (32-bit applications running on VISTAX64)
628 const PaDeviceInfo *deviceInfo;
629 int i;
630 deviceInfo = Pa_GetDeviceInfo(ui.rx_addev_no);
631 i = strncmp(Pa_GetHostApiInfo( deviceInfo->hostApi )->name,"Windows WASAPI", 14);
632 if (i==0)
633 {
634 PaWasapiStreamInfo LinradWasapiStreaminfo;
635 LinradWasapiStreaminfo.size=sizeof(PaWasapiStreamInfo);
636 LinradWasapiStreaminfo.hostApiType=paWASAPI;
637 LinradWasapiStreaminfo.version=1;
638 LinradWasapiStreaminfo.flags=paWinWasapiExclusive;
639 rxadParameters.hostApiSpecificStreamInfo = &LinradWasapiStreaminfo;
640 }
641 else
642 #endif
643 {
644 rxadParameters.hostApiSpecificStreamInfo = NULL;
645 }
646 // ********************************************************************************
647 pa_err = Pa_IsFormatSupported( &rxadParameters, NULL, ui.rx_ad_speed);
648 if( pa_err != paFormatIsSupported )
649 {
650 DEB"\npa_err=%s\n",Pa_GetErrorText(pa_err));
651 lir_rxin_status=LIR_PA_FORMAT_NOT_SUPPORTED;
652 goto start_pa_end;
653 }
654 timf1p_sdr=timf1p_pa;
655 lir_init_event(EVENT_PORTAUDIO_RXREADY);
656 pa_err = Pa_IsFormatSupported( &rxadParameters, NULL, ui.rx_ad_speed);
657 // Open and Start audio I/O stream.
658 pa_err = Pa_OpenStream(
659 &in_stream,
660 &rxadParameters,
661 NULL,
662 (double)(ui.rx_ad_speed), //SAMPLE_RATE,
663 snd[RXAD].block_frames, //frames per buffer
664 paClipOff, //no clipping
665 recordCallback,
666 NULL ); //no userdata
667 if( pa_err != paNoError )
668 {
669 DEB"\npa_err=%s\n",Pa_GetErrorText(pa_err));
670 lir_close_event(EVENT_PORTAUDIO_RXREADY);
671 lir_rxin_status=LIR_PA_OPENSTREAM_FAILED;
672 goto start_pa_end;
673 }
674
675 #if OSNUM == OSNUM_LINUX
676 if(pa_linux_realtime == 1)
677 {
678 #if ALSA_PRESENT == 1
679 PaAlsa_EnableRealtimeScheduling ( in_stream, 1);
680 #endif
681 }
682 #endif
683 pa_err = Pa_StartStream( in_stream );
684 if( pa_err != paNoError )
685 {
686 DEB"\npa_err=%s\n",Pa_GetErrorText(pa_err));
687 lir_rxin_status=LIR_PA_START_STREAM_FAILED;
688 goto start_pa_end;
689 }
690 streamInfo = Pa_GetStreamInfo(in_stream);
691 DEB"\nLATENCY %f\n",streamInfo->inputLatency);
692 DEB"\nRXout interrupt_rate: Actual %f",snd[RXAD].interrupt_rate);
693 start_pa_end:;
694 snd[RXAD].tot_bytes=snd[RXAD].no_of_blocks*snd[RXAD].block_bytes;
695 }
696
open_portaudio_rxda(void)697 void open_portaudio_rxda(void)
698 {
699 PaStreamParameters rxdaParameters;
700 const PaStreamInfo *streamInfo;
701 PaError pa_err;
702 if(portaudio_active_flag == FALSE)
703 {
704 lir_rxout_status=LIR_PA_FLAG_ERROR;
705 lirerr(721401);
706 return;
707 }
708 // Set sample format
709 if(rx_daout_bytes == 1)
710 {
711 rxdaParameters.sampleFormat = paUInt8; // 1 byte samples
712 }
713 else
714 {
715 rxdaParameters.sampleFormat = paInt16; // 2 byte samples
716 }
717 rxdaParameters.device = ui.rx_dadev_no;
718 rxdaParameters.channelCount = rx_daout_channels;
719 rxdaParameters.suggestedLatency = ui.rx_da_latency/snd[RXDA].interrupt_rate;
720 // ******************************************************************************
721 #if (OSNUM == OSNUM_WINDOWS)
722 //TO GET BEST LATENCY WITH WASAPI: SELECT EXCLUSIVE MODE INSTEAD OF THE DEFAULT SHARED MODE
723 //EXCLUSIVE MODE WORKS FOR VISTAX64, VISTAX86, WINDOWS7
724 //EXCLUSIVE MODE DOES NOT WORK FOR WOW64 (32-bit applications running on VISTAX64)
725 const PaDeviceInfo *deviceInfo;
726 int i;
727 deviceInfo = Pa_GetDeviceInfo(ui.rx_dadev_no);
728 i = strncmp(Pa_GetHostApiInfo( deviceInfo->hostApi )->name,"Windows WASAPI", 14);
729 if (i==0)
730 {
731 PaWasapiStreamInfo LinradWasapiStreaminfo;
732 LinradWasapiStreaminfo.size=sizeof(PaWasapiStreamInfo);
733 LinradWasapiStreaminfo.hostApiType=paWASAPI;
734 LinradWasapiStreaminfo.version=1;
735 LinradWasapiStreaminfo.flags=paWinWasapiExclusive;
736 rxdaParameters.hostApiSpecificStreamInfo = &LinradWasapiStreaminfo;
737 }
738 else
739 #endif
740 {
741 rxdaParameters.hostApiSpecificStreamInfo = NULL;
742 }
743 // ********************************************************************************
744 pa_err = Pa_IsFormatSupported( NULL,&rxdaParameters, genparm[DA_OUTPUT_SPEED] );
745 if( pa_err != paFormatIsSupported )
746 {
747 lir_rxout_status=LIR_PA_FORMAT_NOT_SUPPORTED;
748 goto start_pa_end;
749 }
750 // Open and Start audio I/O stream.
751 pa_err = Pa_OpenStream(
752 &out_stream,
753 NULL, //no input
754 &rxdaParameters,
755 (double)(genparm[DA_OUTPUT_SPEED]), //SAMPLE_RATE,
756 snd[RXDA].block_frames, //frames per buffer
757 paClipOff, //no clipping
758 playCallback,
759 NULL ); //no userdata
760 if( pa_err != paNoError )
761 {
762 lir_rxout_status=LIR_PA_OPENSTREAM_FAILED;
763 goto start_pa_end;
764 }
765 #if OSNUM == OSNUM_LINUX
766 if(pa_linux_realtime == 1)
767 {
768 #if ALSA_PRESENT == 1
769 PaAlsa_EnableRealtimeScheduling ( out_stream, 1);
770 #endif
771 }
772 #endif
773 pa_err = Pa_StartStream( out_stream );
774 if( pa_err != paNoError )
775 {
776 lir_rxout_status=LIR_PA_START_STREAM_FAILED;
777 goto start_pa_end;
778 }
779 streamInfo = Pa_GetStreamInfo(out_stream);
780 DEB"\nLATENCY %f\n",streamInfo->outputLatency);
781 DEB"\nRXout interrupt_rate: Actual %f",snd[RXDA].interrupt_rate);
782 start_pa_end:;
783 // set an arbitrary positive value.
784 if(lir_rxout_status == LIR_OK)rx_audio_out=1;
785 snd[RXDA].tot_bytes=snd[RXDA].no_of_blocks*snd[RXDA].block_bytes;
786 daout_workload_reset=workload_reset_flag;
787 }
788
close_portaudio_rxda(void)789 void close_portaudio_rxda(void)
790 {
791 PaError pa_err;
792 pa_err = Pa_CloseStream( out_stream );
793 if( pa_err != paNoError )
794 {
795 lirerr(1168);
796 }
797 }
798
close_portaudio_rxad(void)799 void close_portaudio_rxad(void)
800 {
801 PaError pa_err;
802 pa_err = Pa_CloseStream( in_stream );
803 lir_close_event(EVENT_PORTAUDIO_RXREADY);
804 if( pa_err != paNoError )
805 {
806 lirerr(1229);
807 }
808 }
809
pa_get_device_info(int n,int sound_type,void * pa_device_name,void * pa_device_hostapi,double * pa_device_max_speed,double * pa_device_min_speed,int * pa_device_max_bytes,int * pa_device_min_bytes,int * pa_device_max_channels,int * pa_device_min_channels)810 int pa_get_device_info (int n,
811 int sound_type,
812 void *pa_device_name,
813 void *pa_device_hostapi,
814 double *pa_device_max_speed,
815 double *pa_device_min_speed,
816 int *pa_device_max_bytes,
817 int *pa_device_min_bytes,
818 int *pa_device_max_channels,
819 int *pa_device_min_channels )
820
821 {
822 (void) n ;
823 (void) sound_type;
824 (void) pa_device_name;
825 (void) pa_device_hostapi;
826 (void) pa_device_max_speed;
827 (void) pa_device_min_speed;
828 (void) pa_device_max_bytes;
829 (void) pa_device_min_bytes;
830 (void) pa_device_max_channels;
831 (void) pa_device_min_channels;
832 const PaDeviceInfo *deviceInfo;
833 PaError pa_err;
834 PaStreamParameters inputParameters;
835 PaStreamParameters outputParameters;
836 int i,j, speed_warning;
837 int minBytes, maxBytes;
838 int maxInputChannels, maxOutputChannels;
839 int minInputChannels, minOutputChannels;
840 double maxStandardSampleRate;
841 double minStandardSampleRate;
842 // negative terminated list
843 static double standardSampleRates[] = {8000.0, 9600.0,
844 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
845 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1};
846 // *******************************************************
847 sprintf((char*)(pa_device_name),"%s"," ");
848 sprintf((char*)(pa_device_hostapi),"%s"," ");
849 *pa_device_max_speed=0;
850 *pa_device_min_speed=0;
851 *pa_device_max_bytes=0;
852 *pa_device_min_bytes=0;
853 *pa_device_max_channels=0;
854 *pa_device_min_channels=0;
855 minInputChannels=0;
856 minOutputChannels=0;
857 if(n >= Pa_GetDeviceCount() ) return -1;
858 deviceInfo = Pa_GetDeviceInfo(n);
859 if (deviceInfo->maxOutputChannels==0 &&
860 (sound_type==RXDA || sound_type==TXDA))return -1;
861 if (deviceInfo->maxInputChannels==0 &&
862 (sound_type==RXAD || sound_type==TXAD))return -1;
863 sprintf((char*)(pa_device_name),"%s",deviceInfo->name);
864 sprintf((char*)(pa_device_hostapi),"%s",Pa_GetHostApiInfo( deviceInfo->hostApi )->name);
865 speed_warning=0;
866 #if (OSNUM == OSNUM_WINDOWS)
867 // bypass bug in Juli@ ASIO driver:
868 // this driver hangs after a Pa_IsFormatSupported call
869 i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19);
870 if (i == 0)
871 {
872 minStandardSampleRate=44100;
873 maxStandardSampleRate=192000;
874 minBytes=1;
875 maxBytes=4;
876 maxInputChannels= deviceInfo->maxInputChannels;
877 minInputChannels= 1;
878 maxOutputChannels= deviceInfo->maxOutputChannels;
879 minOutputChannels= 1;
880 goto end_pa_get_device_info;
881 }
882 #endif
883 // Investigate device capabilities.
884 // Check min and max samplerates with 16 bit data.
885 maxStandardSampleRate=0;
886 minStandardSampleRate=0;
887 inputParameters.device = n;
888 inputParameters.channelCount = deviceInfo->maxInputChannels;
889 inputParameters.sampleFormat = paInt16;
890 inputParameters.suggestedLatency = 0;
891 inputParameters.hostApiSpecificStreamInfo = NULL;
892 outputParameters.device = n;
893 outputParameters.channelCount = deviceInfo->maxOutputChannels;
894 outputParameters.sampleFormat = paInt16; /*paInt24;*/
895 outputParameters.suggestedLatency = 0;
896 outputParameters.hostApiSpecificStreamInfo = NULL;
897 SNDLOG"\n\nTESTING PORTAUDIO DEVICE %i FOR %s\n",n, sndtype[sound_type]);
898 SNDLOG"\nid=%d device=%s hostapi=%s max_input_chan=%d max_output_chan=%d",
899 n,
900 deviceInfo->name,
901 Pa_GetHostApiInfo( deviceInfo->hostApi )->name,
902 deviceInfo->maxInputChannels,
903 deviceInfo->maxOutputChannels);
904 fflush(sndlog);
905 // ************************************************************************
906 //filter for portaudio Windows hostapi's with non experts.
907 #if (OSNUM == OSNUM_WINDOWS)
908 //only allow ASIO or WASAPI or WDM-KS
909 i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "ASIO", 4);
910 if (i==0 ) goto end_filter_hostapi;
911 i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "Windows WASAPI", 14);
912 if (i==0 ) goto end_filter_hostapi;
913 i = strncmp(Pa_GetHostApiInfo(deviceInfo->hostApi)->name, "Windows WDM-KS", 14);
914 if (i==0 ) goto end_filter_hostapi;
915 if(ui.operator_skil == OPERATOR_SKIL_EXPERT)
916 {
917 speed_warning=1;
918 }
919 else
920 {
921 return -1;
922 }
923 end_filter_hostapi:;
924 #endif
925 // ************************************************************************
926 i=0;
927 while(standardSampleRates[i] > 0 && minStandardSampleRate==0)
928 {
929 SNDLOG"\nTesting %d %f",i,standardSampleRates[i]);
930 if(sound_type==RXDA || sound_type==TXDA)
931 {
932 pa_err=Pa_IsFormatSupported(
933 NULL, &outputParameters, standardSampleRates[i] );
934 }
935 else
936 {
937 pa_err=Pa_IsFormatSupported(
938 &inputParameters, NULL, standardSampleRates[i] );
939 }
940 SNDLOG" err=%d %s",pa_err, Pa_GetErrorText(pa_err));
941 fflush(sndlog);
942 if(pa_err == paDeviceUnavailable)return -1;
943 if(pa_err == paInvalidDevice) return -1;
944 if(pa_err == paFormatIsSupported )
945 {
946 minStandardSampleRate=standardSampleRates[i];
947 }
948 i++;
949 }
950 if(minStandardSampleRate != 0)
951 {
952 j=i;
953 while(standardSampleRates[i] > 0 )i++;
954 i--;
955 while(i >= j && maxStandardSampleRate==0)
956 {
957 SNDLOG"\nTesting %d %f",i,standardSampleRates[i]);
958 if(sound_type==RXDA || sound_type==TXDA)
959 {
960 pa_err=Pa_IsFormatSupported(
961 NULL, &outputParameters, standardSampleRates[i] );
962 }
963 else
964 {
965 pa_err=Pa_IsFormatSupported(
966 &inputParameters, NULL, standardSampleRates[i] );
967 }
968 SNDLOG" err=%d %s",pa_err, Pa_GetErrorText(pa_err));
969 fflush(sndlog);
970 if(pa_err == paDeviceUnavailable)return -1;
971 if(pa_err == paInvalidDevice) return -1;
972 if( pa_err == paFormatIsSupported )
973 {
974 maxStandardSampleRate=standardSampleRates[i];
975 }
976 i--;
977 }
978 // check if min SampleRate = max SampleRate
979 if(maxStandardSampleRate==0)
980 {
981 maxStandardSampleRate=minStandardSampleRate;
982 }
983 }
984 if(minStandardSampleRate==0)
985 {
986 minStandardSampleRate=deviceInfo->defaultSampleRate;
987 maxStandardSampleRate=deviceInfo->defaultSampleRate;
988 }
989 // check min and max bytes
990 minBytes=2;
991 maxBytes=2;
992 if(sound_type==RXDA || sound_type==TXDA)
993 {
994 outputParameters.sampleFormat = paUInt8;
995 pa_err=Pa_IsFormatSupported(
996 NULL, &outputParameters, maxStandardSampleRate );
997 }
998 else
999 {
1000 inputParameters.sampleFormat = paUInt8;
1001 pa_err=Pa_IsFormatSupported(
1002 &inputParameters, NULL, maxStandardSampleRate );
1003 }
1004 if( pa_err == paFormatIsSupported )
1005 {
1006 minBytes=1;
1007 }
1008 SNDLOG"\nminBytes=%i", minBytes);
1009 fflush(sndlog);
1010 if(sound_type==RXDA || sound_type==TXDA)
1011 {
1012 outputParameters.sampleFormat = paInt32;
1013 pa_err=Pa_IsFormatSupported(
1014 NULL, &outputParameters, maxStandardSampleRate );
1015 }
1016 else
1017 {
1018 inputParameters.sampleFormat = paInt32;
1019 pa_err=Pa_IsFormatSupported(
1020 &inputParameters, NULL, maxStandardSampleRate );
1021 }
1022 if( pa_err == paFormatIsSupported )
1023 {
1024 maxBytes=4;
1025 }
1026 SNDLOG"\nmaxBytes=%i", maxBytes);
1027 fflush(sndlog);
1028 // check min channel count
1029 maxInputChannels= deviceInfo->maxInputChannels;
1030 maxOutputChannels= deviceInfo->maxOutputChannels;
1031 if(sound_type==RXDA || sound_type==TXDA)
1032 {
1033 outputParameters.channelCount = 1;
1034 outputParameters.sampleFormat = paInt16;
1035 pa_err=paFormatIsSupported+32000;
1036 while(pa_err != paFormatIsSupported &&
1037 ( outputParameters.channelCount < (maxOutputChannels+1)) )
1038 {
1039 pa_err=Pa_IsFormatSupported(
1040 NULL, &outputParameters, maxStandardSampleRate );
1041 outputParameters.channelCount++;
1042 }
1043 if( pa_err == paFormatIsSupported )
1044 {
1045 minOutputChannels=outputParameters.channelCount-1;
1046 SNDLOG"\nminOutputChannels=%i", minOutputChannels);
1047 SNDLOG"\nmaxOutputChannels=%i\n\n", maxOutputChannels);
1048 fflush(sndlog);
1049 }
1050 else
1051 {
1052 SNDLOG"\nminOutputChannels=%i samplerate=%6.0f err=%d %s"
1053 , (outputParameters.channelCount-1), maxStandardSampleRate, pa_err, Pa_GetErrorText(pa_err));
1054 fflush(sndlog);
1055 return -1;
1056 }
1057 }
1058 else
1059 {
1060 inputParameters.channelCount = 1;
1061 inputParameters.sampleFormat = paInt16;
1062 pa_err=paFormatIsSupported+32000;
1063 while(pa_err != paFormatIsSupported &&
1064 ( inputParameters.channelCount < (maxInputChannels+1)) )
1065 {
1066 pa_err=Pa_IsFormatSupported(
1067 &inputParameters, NULL, maxStandardSampleRate );
1068 inputParameters.channelCount++;
1069 }
1070 if( pa_err == paFormatIsSupported )
1071 {
1072 minInputChannels=inputParameters.channelCount-1;
1073 SNDLOG"\nminInputChannels=%i", minInputChannels);
1074 SNDLOG"\nmaxInputChannels=%i\n\n", maxInputChannels);
1075 fflush(sndlog);
1076 }
1077 else
1078 {
1079 SNDLOG"\nminInputChannels=%i samplerate=%6.0f err=%d %s"
1080 ,( inputParameters.channelCount-1), maxStandardSampleRate, pa_err, Pa_GetErrorText(pa_err));
1081 fflush(sndlog);
1082 return -1;
1083 }
1084 }
1085 #if (OSNUM == OSNUM_WINDOWS)
1086 end_pa_get_device_info:;
1087 #endif
1088 *pa_device_max_speed=maxStandardSampleRate;
1089 *pa_device_min_speed=minStandardSampleRate;
1090 *pa_device_max_bytes=maxBytes;
1091 *pa_device_min_bytes=minBytes;
1092 if(sound_type==RXDA || sound_type==TXDA)
1093 {
1094 *pa_device_max_channels= maxOutputChannels;
1095 *pa_device_min_channels= minOutputChannels;
1096 }
1097 else
1098 {
1099 *pa_device_max_channels= maxInputChannels;
1100 *pa_device_min_channels= minInputChannels;
1101 }
1102 // Change the limits for RXDA if they are too generous or seem incorrect.
1103 if(sound_type==RXDA )
1104 {
1105 if(*pa_device_max_bytes > 2)*pa_device_max_bytes=2;
1106 if(*pa_device_min_channels >= 2)*pa_device_min_channels=2;
1107 else *pa_device_min_channels=1;
1108 if(*pa_device_max_channels < 2 )*pa_device_max_channels=1;
1109 else *pa_device_max_channels=2;
1110 }
1111 return speed_warning;
1112 }
1113
set_portaudio(int sound_type,int * line)1114 void set_portaudio(int sound_type, int *line)
1115 {
1116 (void) sound_type;
1117 (void) line;
1118 char s[128];
1119 int i, j, k;
1120 char devflag[MAX_PA_DEVICES];
1121 double devmaxStandardSampleRate[MAX_PA_DEVICES];
1122 double devminStandardSampleRate[MAX_PA_DEVICES];
1123 int devmaxBytes[MAX_PA_DEVICES];
1124 int devminBytes[MAX_PA_DEVICES];
1125 int devmaxInputChannels[MAX_PA_DEVICES];
1126 int devminInputChannels[MAX_PA_DEVICES];
1127 int devmaxOutputChannels[MAX_PA_DEVICES];
1128 int devminOutputChannels[MAX_PA_DEVICES];
1129 int id, err, numDevices, valid_dev_cnt;
1130 char pa_device_name[128];
1131 char pa_device_hostapi[128];
1132 double pa_device_max_speed;
1133 double pa_device_min_speed;
1134 int pa_device_max_bytes;
1135 int pa_device_min_bytes;
1136 int pa_device_max_channels;
1137 int pa_device_min_channels;
1138
1139 SNDLOG"\nTESTING ALL PORTAUDIO DEVICES FOR %s\n",sndtype[sound_type]);
1140 if(pa_version != 0)
1141 {
1142 SNDLOG"\nPortAudio ver %d \n%s\n", Pa_GetVersion(),Pa_GetVersionText());
1143 }
1144 else
1145 {
1146 SNDLOG"\nOld PortAudio no support for version info\n");
1147 }
1148 valid_dev_cnt=0;
1149 clear_screen();
1150 line[0]=4;
1151 numDevices=Pa_GetDeviceCount();
1152 if(numDevices < 0)
1153 {
1154 lirerr(1166);
1155 return;
1156 }
1157 if(numDevices == 0)
1158 {
1159 lir_text(5,2,"No portaudio device detected for testing.");
1160 SNDLOG"\nNo portaudio device detected for testing.");
1161 lir_text(5,4,press_any_key);
1162 await_keyboard();
1163 goto end_portaudiotest;
1164 }
1165 else
1166 {
1167 SNDLOG"\nNumber of portaudio devices to be tested=%i\n",numDevices);
1168 }
1169 fflush(sndlog);
1170 settextcolor(14);
1171 sprintf(s,"LIST OF VALID PORTAUDIO DEVICES FOR %s :",sndtype[sound_type]);
1172 lir_text(20,0,s);
1173 settextcolor(13);
1174 lir_text(28,1,"This may take a very long time.");
1175 if(numDevices > MAX_PA_DEVICES)
1176 {
1177 lir_text(2,line[0],"TOO MANY DEVICES. List truncated.");
1178 numDevices=MAX_PA_DEVICES;
1179 line[0]++;
1180 }
1181 settextcolor(7);
1182 // headings
1183 lir_text(75,line[0],"SAMPLE RATE");
1184 lir_text(90,line[0],"CHANNELS");
1185 lir_text(102,line[0],"BYTES");
1186 line[0]++;
1187 lir_text(2,line[0],"ID NAME");
1188 lir_text(54,line[0],"HOST-API");
1189 lir_text(77,line[0],"MIN/MAX");
1190 lir_text(91,line[0],"MIN/MAX");
1191 lir_text(101,line[0],"MIN/MAX");
1192 line[0]++;
1193 lir_text(2,line[0],"-- ------------------------");
1194 lir_text(54,line[0],"-------");
1195 lir_text(74,line[0],"-------------");
1196 lir_text(91,line[0],"-------");
1197 lir_text(101,line[0],"-------");
1198 line[0]++;
1199 lir_refresh_screen();
1200 // look for valid devices
1201 for(id=0; id < numDevices; id++)
1202 {
1203 devflag[id]=0;
1204 sprintf(s,"--- Testing device %d ---",id);
1205 lir_text(5,line[0],s);
1206 err=pa_get_device_info (id,
1207 sound_type,
1208 &pa_device_name,
1209 &pa_device_hostapi,
1210 &pa_device_max_speed,
1211 &pa_device_min_speed,
1212 &pa_device_max_bytes,
1213 &pa_device_min_bytes,
1214 &pa_device_max_channels,
1215 &pa_device_min_channels);
1216 if (err >= 0 )
1217 {
1218 clear_lines(line[0],line[0]);
1219 if(strcmp( pa_device_hostapi,"ASIO")!=0 ||asio_flag==FALSE)
1220 {
1221 devflag[id]=1+err;
1222 valid_dev_cnt++;
1223 //display result on screen
1224 sprintf(s,"%2d/%2d",pa_device_min_channels,pa_device_max_channels);
1225 lir_text(91,line[0],s);
1226 sprintf(s,"%03d %s", id, pa_device_name);
1227 lir_text(1,line[0],s);
1228 sprintf(s," %s", pa_device_hostapi );
1229 lir_text(53,line[0],s);
1230 sprintf(s,"%6.0f/%6.0f",pa_device_min_speed, pa_device_max_speed);
1231 lir_text(73,line[0],s);
1232 sprintf(s,"%i/%i",pa_device_min_bytes, pa_device_max_bytes);
1233 lir_text(103,line[0],s);
1234 line[0]++;
1235 if(line[0] >= screen_last_line)
1236 {
1237 screenerr:;
1238 lirerr(1235);
1239 return;
1240 }
1241 lir_refresh_screen();
1242 //save values
1243 devmaxStandardSampleRate[id]=pa_device_max_speed;
1244 devminStandardSampleRate[id]=pa_device_min_speed;
1245 devmaxBytes[id]=pa_device_max_bytes;
1246 devminBytes[id]=pa_device_min_bytes;
1247 if(sound_type==RXDA || sound_type==TXDA)
1248 {
1249 devmaxOutputChannels[id]=pa_device_max_channels;
1250 devminOutputChannels[id]=pa_device_min_channels;
1251 }
1252 else
1253 {
1254 devmaxInputChannels[id]=pa_device_max_channels;
1255 devminInputChannels[id]=pa_device_min_channels;
1256 }
1257 }
1258 }
1259 }
1260 SNDLOG"\n\nEND TESTING PORTAUDIO DEVICES\n");
1261 fflush(sndlog);
1262 if (valid_dev_cnt !=0)
1263 {
1264 line[0]+=3;
1265 if(line[0] >= screen_last_line)goto screenerr;
1266 sprintf(s,"Select portaudio device ID for %s from list >",sndtype[sound_type]);
1267 SNDLOG"\n%s",s);
1268 gtdev:;
1269 settextcolor(14);
1270 clear_lines(line[0],line[0]+1);
1271 lir_text(2,line[0],s);
1272 settextcolor(7);
1273 id=lir_get_integer(strlen(s)+4,line[0], 3, 0, numDevices-1);
1274 SNDLOG"\nUser selected %i\n",id);
1275 if(kill_all_flag)return;
1276 if(devflag[id] == 0)goto gtdev;
1277 if(devflag[id] != 1)
1278 {
1279 lir_text(2,line[0]+1,"This is a very slow device. Really use it? (Y/N)");
1280 really:;
1281 to_upper_await_keyboard();
1282 if(lir_inkey == 'N')goto gtdev;
1283 if(lir_inkey != 'Y')goto really;
1284 line[0]++;
1285 if(line[0] >= screen_last_line)goto screenerr;
1286 }
1287 line[0]++;
1288 if(line[0] >= screen_last_line-6)
1289 {
1290 line[0]=5;
1291 clear_screen();
1292 }
1293 switch (sound_type)
1294 {
1295 case RXDA:
1296 ui.rx_dadev_no=id;
1297 ui.rx_max_da_speed=devmaxStandardSampleRate[id];
1298 ui.rx_min_da_speed=devminStandardSampleRate[id];
1299 ui.rx_min_da_bytes=devminBytes[id];
1300 ui.rx_max_da_bytes=devmaxBytes[id];
1301 ui.rx_min_da_channels= devminOutputChannels[id];
1302 ui.rx_max_da_channels=devmaxOutputChannels[id];
1303 if(ui.operator_skil != OPERATOR_SKIL_NEWCOMER)
1304 {
1305 line[0]+=2;
1306 sprintf(s,"Latency Factor (1 to %d)",MAX_LATENCY);
1307 lir_text(0,line[0],s);
1308 ui.rx_da_latency=lir_get_integer(26,line[0], 2, 1, MAX_LATENCY);
1309 }
1310 else
1311 {
1312 ui.rx_da_latency=2;
1313 }
1314 break;
1315
1316 case RXAD:
1317 ui.rx_addev_no=id;
1318 line[0]+=2;
1319 lir_text(10,line[0],"Sampling speed (Hz)>");
1320 ui.rx_ad_speed=lir_get_integer(31,line[0], 6,
1321 devminStandardSampleRate[id],
1322 devmaxStandardSampleRate[id]);
1323 if(kill_all_flag) return;
1324 if(devmaxBytes[id] < 2)
1325 {
1326 lirerr(1217);
1327 return;
1328 }
1329 if(devminBytes[id] < 2)devminBytes[id]=2;
1330 ui.rx_input_mode=0;
1331 if(devmaxBytes[id] == 3)
1332 {
1333 lirerr(366132);
1334 return;
1335 }
1336 get_rxbits:;
1337 lir_text(40,line[0],"No of bits (16/32):");
1338 i=lir_get_integer(60,line[0], 2, 16, 32);
1339 if(kill_all_flag) return;
1340 clear_screen();
1341 if(i==32)
1342 {
1343 ui.rx_input_mode=DWORD_INPUT;
1344 }
1345 else
1346 {
1347 if(i != 16)goto get_rxbits;
1348 }
1349 clear_screen();
1350 // Ask for the desired processing mode.
1351 sel_radio:;
1352 clear_screen();
1353 lir_text(10,10,"Select radio interface>");
1354 j=1;
1355 if(devmaxInputChannels[id]>=2)j=3;
1356 if(devmaxInputChannels[id]>=4)j=4;
1357 if(devminInputChannels[id]==1)
1358 {
1359 k=0;
1360 }
1361 else
1362 {
1363 k=1;
1364 }
1365 for(i=k; i<j; i++)
1366 {
1367 sprintf(s,"%d: %s",i+1,audiomode_text[i]);
1368 lir_text(10,12+i,s);
1369 }
1370 lir_text(10,13+i,"F1 for help/info");
1371 line[0]=15+i;
1372 chsel:;
1373 await_processed_keyboard();
1374 if(lir_inkey == F1_KEY || lir_inkey == '!')
1375 {
1376 if(ui.operator_skil != OPERATOR_SKIL_NEWCOMER)
1377 {
1378 help_message(89);
1379 }
1380 else
1381 {
1382 help_message(109);
1383 }
1384 goto sel_radio;
1385 }
1386 if(lir_inkey-'0'>j)goto chsel;
1387 if(lir_inkey-'0'<k)goto chsel;
1388 switch (lir_inkey)
1389 {
1390 case '1':
1391 ui.rx_rf_channels=1;
1392 ui.rx_ad_channels=1;
1393 break;
1394
1395 case '2':
1396 ui.rx_input_mode|=IQ_DATA;
1397 ui.rx_rf_channels=1;
1398 ui.rx_ad_channels=2;
1399 break;
1400
1401 case '3':
1402 ui.rx_input_mode|=TWO_CHANNELS;
1403 ui.rx_rf_channels=2;
1404 ui.rx_ad_channels=2;
1405 break;
1406
1407 case '4':
1408 ui.rx_input_mode|=TWO_CHANNELS+IQ_DATA;
1409 ui.rx_rf_channels=2;
1410 ui.rx_ad_channels=4;
1411 break;
1412
1413 default:
1414 goto chsel;
1415 }
1416
1417 // Input seems OK.
1418 if(ui.rx_rf_channels == 1 && ui.rx_ad_channels == 2)
1419 {
1420 line[0]+=2;
1421 lir_text(0,line[0],
1422 "Number of points to time shift between I and Q? (-4 to +4)");
1423 ui.sample_shift=lir_get_integer(60,line[0], 2, -4, 4);
1424 }
1425 if(ui.operator_skil != OPERATOR_SKIL_NEWCOMER)
1426 {
1427 line[0]+=2;
1428 sprintf(s,"Latency Factor (1 to %d)",MAX_LATENCY);
1429 lir_text(0,line[0],s);
1430 ui.rx_ad_latency=lir_get_integer(26,line[0], 2, 1, MAX_LATENCY);
1431 }
1432 else
1433 {
1434 ui.rx_ad_latency=2;
1435 }
1436 }
1437 }
1438 else
1439 {
1440 line[0]++;
1441 settextcolor(14);
1442 lir_text(2,line[0],"No valid portaudio device detected ");
1443 SNDLOG"\nNo valid portaudio device detected ");
1444 line[0]++;
1445 lir_text(2,line[0],press_any_key);
1446 settextcolor(7);
1447 await_keyboard();
1448 }
1449 end_portaudiotest:;
1450 }
1451
pa_get_valid_samplerate(int n,int mode,int * line,unsigned int * returned_sampling_rate)1452 int pa_get_valid_samplerate (int n,
1453 int mode,
1454 int *line,
1455 unsigned int *returned_sampling_rate)
1456 {
1457 (void) n;
1458 (void) mode;
1459 (void) line;
1460 (void) returned_sampling_rate;
1461 int i,k,id;
1462 unsigned int val;
1463 char s[80];
1464 unsigned int valid_sampling_rate[16];
1465 // negative terminated list
1466 static double standardSampleRates[] = {8000.0, 9600.0,
1467 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
1468 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1};
1469 const PaDeviceInfo *deviceInfo;
1470 PaError pa_err;
1471 PaStreamParameters inputParameters;
1472 PaStreamParameters outputParameters;
1473 deviceInfo = Pa_GetDeviceInfo(n);
1474 inputParameters.device = n;
1475 inputParameters.channelCount = deviceInfo->maxInputChannels;
1476 inputParameters.sampleFormat = paInt16;
1477 inputParameters.suggestedLatency = 0;
1478 inputParameters.hostApiSpecificStreamInfo = NULL;
1479 outputParameters.device = n;
1480 outputParameters.channelCount = deviceInfo->maxOutputChannels;
1481 outputParameters.sampleFormat = paInt16;
1482 outputParameters.suggestedLatency = 0;
1483 outputParameters.hostApiSpecificStreamInfo = NULL;
1484 line[0]+=2;
1485 sprintf(s,"This is a portaudio device.");
1486 lir_text(1,line[0], s);
1487 line[0]+=1;
1488 sprintf(s,"Select sampling rate by line number from list :");
1489 lir_text(1,line[0], s);
1490 line[0]+=2;
1491 #if (OSNUM == OSNUM_WINDOWS)
1492 // bypass bug in Juli@ ASIO driver:
1493 // this driver hangs after a Pa_IsFormatSupported call
1494 static double JuliSampleRates[] = {
1495 44100.0, 48000.0, 88200.0, 96000.0, 176400., 192000.0, -1};
1496 i = strncmp(deviceInfo->name, "ASIO 2.0 - ESI Juli@", 19);
1497 k=0;
1498 if (i == 0)
1499 {
1500 while(JuliSampleRates[k] > 0 )
1501 {
1502 valid_sampling_rate[k]= JuliSampleRates[k];
1503 sprintf(s,"%2d -> %6d ",k,valid_sampling_rate[k]);
1504 lir_text(1,line[0],s);
1505 line[0]++;
1506 k++;
1507 }
1508 goto end_pa_get_valid_samplerate;
1509 }
1510 #endif
1511 i=0;
1512 k=0;
1513 while(standardSampleRates[i] > 0 )
1514 {
1515 val= standardSampleRates[i];
1516 if(mode==RXDA || mode==TXDA)
1517 {
1518 pa_err=Pa_IsFormatSupported(
1519 NULL, &outputParameters, standardSampleRates[i] );
1520 }
1521 else
1522 {
1523 pa_err=Pa_IsFormatSupported(
1524 &inputParameters, NULL, standardSampleRates[i] );
1525 }
1526 if(pa_err == paFormatIsSupported )
1527 {
1528 sprintf(s,"%2d -> %6d ",k,val);
1529 lir_text(1,line[0],s);
1530 valid_sampling_rate[k]= val;
1531 line[0]++;
1532 k++;
1533 }
1534 i++;
1535 }
1536 #if (OSNUM == OSNUM_WINDOWS)
1537 end_pa_get_valid_samplerate:;
1538 #endif
1539 line[0]++;
1540 sprintf(s,"Enter line number >");
1541 lir_text(1,line[0],s);
1542 id=lir_get_integer(21,line[0],2, 0, k-1);
1543 *returned_sampling_rate=valid_sampling_rate[id];
1544 return 0;
1545 }
1546
portaudio_startstop(void)1547 int portaudio_startstop(void)
1548 {
1549 PaErrorCode err;
1550 if( (ui.use_alsa&PORTAUDIO_RX_IN) != 0 ||
1551 (ui.use_alsa&PORTAUDIO_RX_OUT) != 0 ||
1552 (ui.use_alsa&PORTAUDIO_TX_IN) != 0 ||
1553 (ui.use_alsa&PORTAUDIO_TX_OUT) != 0 )
1554 {
1555 if(portaudio_active_flag == FALSE)
1556 {
1557 if(load_pa_library() != 0)
1558 {
1559 return FALSE;
1560 }
1561 #if(OSNUM == OSNUM_LINUX)
1562 if(pa_linux_jack == 1)
1563 {
1564 PaJack_SetClientName(linrad_name);
1565 }
1566 #endif
1567 err=Pa_Initialize();
1568 if(err < 0)
1569 {
1570 lirerr(847297);
1571 return FALSE;
1572 }
1573 if(pa_version != 0)
1574 {
1575 DEB"\nPortAudio ver %d \n%s\n", Pa_GetVersion(),Pa_GetVersionText());
1576 }
1577 else
1578 {
1579 DEB"\nOld PortAudio no support for version info\n");
1580 }
1581 }
1582 portaudio_active_flag=TRUE;
1583 }
1584 else
1585 {
1586 if(portaudio_active_flag == TRUE)
1587 {
1588 err=Pa_Terminate();
1589 DEB"\nPortaudio terminated.\n");
1590 if(err < 0)
1591 {
1592 lirerr(847298);
1593 return FALSE;
1594 }
1595 }
1596 portaudio_active_flag=FALSE;
1597 unload_pa_library();
1598 }
1599 return TRUE;
1600 }
1601