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