1 /* $Id: hw_audio.c,v 5.9 2010/04/11 18:50:38 lirc Exp $ */
2
3 /****************************************************************************
4 ** hw_audio.c **************************************************************
5 ****************************************************************************
6 *
7 * routines for using a IR receiver in microphone input using portaudio library
8 *
9 * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
10 * Copyright (C) 2001, 2002 Pavel Machek <pavel@ucw.cz>
11 * Copyright (C) 2002 Matthias Ringwald <ringwald@inf.ethz.ch>
12 *
13 * Distribute under GPL version 2 or later.
14 *
15 * Using ... hardware ...
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <termios.h>
34 #ifdef __APPLE__
35 #include <util.h>
36 #else
37 #include <pty.h>
38 #endif
39
40 #include "hardware.h"
41 #include "ir_remote.h"
42 #include "lircd.h"
43 #include "receive.h"
44 #include "transmit.h"
45 #include "hw_default.h"
46
47 static int ptyfd; /* the pty */
48
49 /* PortAudio Includes */
50 #include <portaudio.h>
51
52 #define DEFAULT_SAMPLERATE (48000)
53 #define NUM_CHANNELS (2)
54 #define PI (3.141592654)
55
56 /* Select sample format. */
57 #define PA_SAMPLE_TYPE paUInt8
58 typedef unsigned char SAMPLE;
59
60 typedef struct {
61 int lastFrames[3];
62 int lastSign;
63 int pulseSign;
64 unsigned int lastCount;
65 lirc_t carrierFreq;
66 /* position the sine generator is in */
67 double carrierPos;
68 /* length of the remaining signal is stored here when the
69 callback exits */
70 double remainingSignal;
71 /* 1 = pulse, 0 = space */
72 int signalPhase;
73 int signaledDone;
74 int samplesToIgnore;
75 int samplerate;
76 } paTestData;
77
78 static PaStream *stream;
79
80 extern struct ir_remote *repeat_remote;
81 extern struct rbuf rec_buffer;
82
83 static char ptyName[256];
84 static int master;
85 static int sendPipe[2]; /* signals are written from audio_send
86 and read from the callback */
87 static int completedPipe[2]; /* a byte is written here when the
88 callback has processed all signals */
89 static int outputLatency;
90 static int inDevicesPrinted = 0;
91 static int outDevicesPrinted = 0;
92
addCode(lirc_t data)93 static void addCode(lirc_t data)
94 {
95 write(master, &data, sizeof(lirc_t));
96 }
97
98 /* This routine will be called by the PortAudio engine when audio is needed.
99 ** It may be called at interrupt level on some machines so don't do anything
100 ** that could mess up the system like calling malloc() or free().
101 */
102
recordCallback(const void * inputBuffer,void * outputBuffer,__u32 framesPerBuffer,const PaStreamCallbackTimeInfo * outTime,PaStreamCallbackFlags status,void * userData)103 static int recordCallback(const void *inputBuffer, void *outputBuffer, __u32 framesPerBuffer,
104 const PaStreamCallbackTimeInfo * outTime, PaStreamCallbackFlags status, void *userData)
105 {
106 paTestData *data = (paTestData *) userData;
107 SAMPLE *rptr = (SAMPLE *) inputBuffer;
108 long i;
109
110 SAMPLE *myPtr = rptr;
111
112 unsigned int time;
113 int diff;
114
115 SAMPLE *outptr = (SAMPLE *) outputBuffer;
116 int out;
117 double currentSignal = data->remainingSignal;
118 lirc_t signal;
119
120 /* Prevent unused variable warnings. */
121 (void)outTime;
122
123 if (status & paOutputUnderflow)
124 logprintf(LOG_WARNING, "Output underflow %s", hw.device);
125 if (status & paInputOverflow)
126 logprintf(LOG_WARNING, "Input overflow %s", hw.device);
127
128 for (i = 0; i < framesPerBuffer; i++, myPtr++) {
129 /* check if we have to ignore this sample */
130 if (data->samplesToIgnore) {
131 *myPtr = 128;
132 data->samplesToIgnore--;
133 }
134
135 /* New Algo */
136 diff = abs(data->lastFrames[0] - *myPtr);
137 if (diff > 100) {
138 if (data->pulseSign == 0) {
139 /* we got the first signal, this is a PULSE */
140 if (*myPtr > data->lastFrames[0]) {
141 data->pulseSign = 1;
142 } else {
143 data->pulseSign = -1;
144 }
145 }
146
147 if (data->lastCount > 0) {
148 if (*myPtr > data->lastFrames[0] && data->lastSign <= 0) {
149 /* printf("CHANGE ++ "); */
150 data->lastSign = 1;
151
152 time = data->lastCount * 1000000 / data->samplerate;
153 if (data->lastSign == data->pulseSign) {
154 addCode(time);
155 /* printf("Pause: %d us, %d \n", time, data->lastCount); */
156 } else {
157 addCode(time | PULSE_BIT);
158 /* printf("Pulse: %d us, %d \n", time, data->lastCount); */
159 }
160 data->lastCount = 0;
161 }
162
163 else if (*myPtr < data->lastFrames[0] && data->lastSign >= 0) {
164 /* printf("CHANGE -- "); */
165 data->lastSign = -1;
166
167 time = data->lastCount * 1000000 / data->samplerate;
168 if (data->lastSign == data->pulseSign) {
169 /* printf("Pause: %d us, %d \n", time, data->lastCount); */
170 addCode(time);
171 } else {
172 /* printf("Pulse: %d us, %d \n", time, data->lastCount); */
173 addCode(time | PULSE_BIT);
174 }
175 data->lastCount = 0;
176 }
177 }
178 }
179
180 if (data->lastCount < 100000) {
181 data->lastCount++;
182 }
183
184 data->lastFrames[0] = data->lastFrames[1];
185 data->lastFrames[1] = *myPtr;
186
187 /* skip 2. channel */
188 if (NUM_CHANNELS == 2)
189 myPtr++;
190 }
191
192 /* generate output */
193 for (i = 0; i < framesPerBuffer; i++) {
194 if (currentSignal <= 0.0) { /* last signal we sent went out */
195 /* try to read a new signal, non blocking */
196 if (read(sendPipe[0], &signal, sizeof(signal)) > 0) {
197 if (data->signaledDone) {
198 /* first one sent is the
199 carrier frequency */
200 data->carrierFreq = signal;
201 data->signaledDone = 0;
202 } else {
203 /* when a new signal is read,
204 add it */
205 currentSignal += signal;
206 /* invert the phase */
207 data->signalPhase = data->signalPhase ? 0 : 1;
208 }
209
210 /* when transmitting, ignore input
211 samples for one second */
212 data->samplesToIgnore = data->samplerate;
213 } else {
214 /* no more signals, reset phase */
215 data->signalPhase = 0;
216 /* signal that we have written all
217 signals */
218 if (!data->signaledDone) {
219 char done = 0;
220 data->signaledDone = 1;
221 (void)write(completedPipe[1], &done, sizeof(done));
222 }
223 }
224 }
225
226 if (currentSignal > 0.0) {
227 if (data->signalPhase) {
228 /* write carrier */
229 out = rint(sin(data->carrierPos / (180.0 / PI)) * 127.0 + 128.0);
230 } else {
231 out = 128;
232 }
233
234 /* one channel is inverted, so both channels
235 can be used to double the voltage */
236 *outptr++ = out;
237 if (NUM_CHANNELS == 2)
238 *outptr++ = 256 - out;
239
240 /* subtract how much of the current signal was sent */
241 currentSignal -= 1000000.0 / data->samplerate;
242 } else {
243 *outptr++ = 128;
244 if (NUM_CHANNELS == 2)
245 *outptr++ = 128;
246 }
247
248 /* increase carrier position */
249 /* carrier frequency is halved */
250 data->carrierPos += (double)data->carrierFreq / data->samplerate * 360.0 / 2.0;
251
252 if (data->carrierPos >= 360.0)
253 data->carrierPos -= 360.0;
254 }
255
256 /* save how much we still have to write */
257 data->remainingSignal = currentSignal;
258
259 return 0;
260 }
261
262 /*
263 decoding stuff
264 */
265
266 #define BUFSIZE 20
267 #define SAMPLE 47999
268
audio_readdata(lirc_t timeout)269 lirc_t audio_readdata(lirc_t timeout)
270 {
271 lirc_t data;
272 int ret;
273
274 if (!waitfordata((long)timeout))
275 return 0;
276
277 ret = read(hw.fd, &data, sizeof(data));
278 if (ret != sizeof(data)) {
279 LOGPRINTF(1, "error reading from lirc");
280 LOGPERROR(1, NULL);
281 raise(SIGTERM);
282 return 0;
283 }
284 return (data);
285 }
286
audio_send(struct ir_remote * remote,struct ir_ncode * code)287 int audio_send(struct ir_remote *remote, struct ir_ncode *code)
288 {
289 int length;
290 lirc_t *signals;
291 int flags;
292 char completed;
293 lirc_t freq;
294 static lirc_t prevfreq = 0;
295
296 if (!init_send(remote, code))
297 return 0;
298
299 length = send_buffer.wptr;
300 signals = send_buffer.data;
301
302 if (length <= 0 || signals == NULL) {
303 LOGPRINTF(1, "nothing to send");
304 return 0;
305 }
306
307 /* set completed pipe to non blocking */
308 flags = fcntl(completedPipe[0], F_GETFL, 0);
309 fcntl(completedPipe[0], F_SETFL, flags | O_NONBLOCK);
310
311 /* remove any unwanted completed bytes */
312 while (read(completedPipe[0], &completed, sizeof(completed)) == 1) ;
313
314 /* set completed pipe to blocking */
315 fcntl(completedPipe[0], F_SETFL, flags & ~O_NONBLOCK);
316
317 /* write carrier frequency */
318 freq = remote->freq ? remote->freq : DEFAULT_FREQ;
319 write(sendPipe[1], &freq, sizeof(freq));
320 if (freq != prevfreq) {
321 prevfreq = freq;
322 logprintf(LOG_INFO, "Using carrier frequency %i", freq);
323 }
324
325 /* write signals to sendpipe */
326 if (write(sendPipe[1], signals, length * sizeof(lirc_t)) == -1) {
327 logprintf(LOG_ERR, "write failed");
328 logperror(LOG_ERR, "write()");
329 return 0;
330 }
331
332 /* wait for the callback to signal us that all signals are written */
333 read(completedPipe[0], &completed, sizeof(completed));
334
335 return 1;
336 }
337
audio_parsedevicestr(char * api,char * device,int * rate,double * latency)338 static void audio_parsedevicestr(char *api, char *device, int *rate, double *latency)
339 {
340 int ret;
341
342 /* empty device string means default */
343 if (strlen(hw.device)) {
344 /* device string is api:device[@rate] or @rate */
345 ret = sscanf(hw.device, "%1023[^:]:%1023[^@]@%i:%lf", api, device, rate, latency);
346
347 if (ret == 2 || *rate <= 0)
348 *rate = DEFAULT_SAMPLERATE;
349
350 if (ret <= 3)
351 *latency = -1.0;
352
353 if (ret >= 2)
354 return;
355
356 /* check for @rate:latency */
357 ret = sscanf(hw.device, "@%i:%lf", rate, latency);
358 if (ret >= 1) {
359 api[0] = 0;
360 device[0] = 0;
361 if (*rate <= 0)
362 *rate = DEFAULT_SAMPLERATE;
363
364 if (ret == 1)
365 *latency = -1.0;
366
367 return;
368 }
369
370 logprintf(LOG_ERR,
371 "malformed device string %s, syntax is api:device[@rate[:latency]] or @rate[:latency]",
372 hw.device);
373 }
374
375 api[0] = 0;
376 device[0] = 0;
377 *rate = DEFAULT_SAMPLERATE;
378 *latency = -1.0;
379 }
380
audio_choosedevice(PaStreamParameters * streamparameters,int input,char * api,char * device,double latency)381 static void audio_choosedevice(PaStreamParameters * streamparameters, int input, char *api, char *device,
382 double latency)
383 {
384 char *direction = input ? "input" : "output";
385 int chosendevice = -1;
386 int i;
387 int nrdevices = Pa_GetDeviceCount();
388 const PaDeviceInfo *deviceinfo;
389 const PaHostApiInfo *hostapiinfo;
390 const char *devicetype = "custom";
391 const char *latencytype = "custom";
392
393 for (i = 0; i < nrdevices; i++) {
394 deviceinfo = Pa_GetDeviceInfo(i);
395
396 /* check if device can do input or output if
397 we need it */
398 if ((deviceinfo->maxOutputChannels >= NUM_CHANNELS && !input)
399 || (deviceinfo->maxInputChannels >= NUM_CHANNELS && input)) {
400 hostapiinfo = Pa_GetHostApiInfo(deviceinfo->hostApi);
401 /*check if this matches the custom device */
402 if (strlen(api) && strlen(device)) {
403 if (strcmp(api, hostapiinfo->name) == 0 && strcmp(device, deviceinfo->name) == 0)
404 chosendevice = i;
405 }
406
407 /*allow devices to be printed to the log twice */
408 /*once for input, once for output */
409 if ((!inDevicesPrinted && input) || (!outDevicesPrinted && !input)) {
410 logprintf(LOG_INFO, "Found %s device %i %s:%s", direction, i, hostapiinfo->name,
411 deviceinfo->name);
412 }
413 }
414 }
415
416 if (input)
417 inDevicesPrinted = 1;
418 else
419 outDevicesPrinted = 1;
420
421 if (chosendevice == -1) {
422 devicetype = "default";
423
424 if (strlen(api) && strlen(device))
425 logprintf(LOG_ERR, "Device %s %s:%s not found", direction, api, device);
426
427 if (input)
428 chosendevice = Pa_GetDefaultInputDevice();
429 else
430 chosendevice = Pa_GetDefaultOutputDevice();
431 }
432
433 streamparameters->device = chosendevice;
434 if (latency < 0.0) {
435 if (input) {
436 streamparameters->suggestedLatency = Pa_GetDeviceInfo(chosendevice)->defaultHighInputLatency;
437 latencytype = "default high input";
438 } else {
439 streamparameters->suggestedLatency = Pa_GetDeviceInfo(chosendevice)->defaultHighOutputLatency;
440 latencytype = "default high output";
441 }
442 } else {
443 streamparameters->suggestedLatency = latency;
444 }
445
446 deviceinfo = Pa_GetDeviceInfo(chosendevice);
447 hostapiinfo = Pa_GetHostApiInfo(deviceinfo->hostApi);
448 logprintf(LOG_INFO, "Using %s %s device %i: %s:%s with %s latency %f", devicetype, direction, chosendevice,
449 hostapiinfo->name, deviceinfo->name, latencytype, streamparameters->suggestedLatency);
450 }
451
452 /*
453 interface functions
454 */
455 static paTestData data;
456
audio_init()457 int audio_init()
458 {
459
460 PaStreamParameters inputParameters;
461 PaStreamParameters outputParameters;
462 PaError err;
463 int flags;
464 struct termios t;
465 char api[1024];
466 char device[1024];
467 double latency;
468
469 LOGPRINTF(1, "hw_audio_init()");
470
471 //
472 logprintf(LOG_INFO, "Initializing %s...", hw.device);
473 init_rec_buffer();
474 rewind_rec_buffer();
475
476 /* new */
477 data.lastFrames[0] = 128;
478 data.lastFrames[1] = 128;
479 data.lastFrames[2] = 128;
480 data.lastSign = 0;
481 data.lastCount = 0;
482 data.pulseSign = 0;
483 data.carrierPos = 0.0;
484 data.remainingSignal = 0.0;
485 data.signalPhase = 0;
486 data.signaledDone = 1;
487 data.samplesToIgnore = 0;
488 data.carrierFreq = DEFAULT_FREQ;
489
490 err = Pa_Initialize();
491 if (err != paNoError)
492 goto error;
493
494 audio_parsedevicestr(api, device, &data.samplerate, &latency);
495 logprintf(LOG_INFO, "Using samplerate %i", data.samplerate);
496
497 /* choose input device */
498 audio_choosedevice(&inputParameters, 1, api, device, latency);
499 if (inputParameters.device == paNoDevice) {
500 logprintf(LOG_ERR, "No input device found");
501 goto error;
502 }
503 inputParameters.channelCount = NUM_CHANNELS; /* stereo input */
504 inputParameters.sampleFormat = PA_SAMPLE_TYPE;
505 inputParameters.hostApiSpecificStreamInfo = NULL;
506
507 /* choose output device */
508 audio_choosedevice(&outputParameters, 0, api, device, latency);
509 if (outputParameters.device == paNoDevice) {
510 logprintf(LOG_ERR, "No output device found");
511 goto error;
512 }
513 outputParameters.channelCount = NUM_CHANNELS; /* stereo output */
514 outputParameters.sampleFormat = PA_SAMPLE_TYPE;
515 outputParameters.hostApiSpecificStreamInfo = NULL;
516
517 outputLatency = outputParameters.suggestedLatency * 1000000;
518
519 /* Record some audio. -------------------------------------------- */
520 err = Pa_OpenStream(&stream, &inputParameters, &outputParameters, data.samplerate, 512, /* frames per buffer */
521 paPrimeOutputBuffersUsingStreamCallback, recordCallback, &data);
522
523 if (err != paNoError)
524 goto error;
525
526 /* open pty */
527 if (openpty(&master, &ptyfd, ptyName, 0, 0) == -1) {
528 logprintf(LOG_ERR, "openpty failed");
529 logperror(LOG_ERR, "openpty()");
530 goto error;
531 }
532
533 /* regular device file */
534 if (tcgetattr(master, &t) < 0) {
535 logprintf(LOG_ERR, "tcgetattr failed");
536 logperror(LOG_ERR, "tcgetattr()");
537 }
538
539 cfmakeraw(&t);
540
541 /* apply file descriptor options */
542 if (tcsetattr(master, TCSANOW, &t) < 0) {
543 logprintf(LOG_ERR, "tcsetattr failed");
544 logperror(LOG_ERR, "tcsetattr()");
545 }
546
547 flags = fcntl(ptyfd, F_GETFL, 0);
548 if (flags != -1) {
549 fcntl(ptyfd, F_SETFL, flags | O_NONBLOCK);
550 }
551
552 LOGPRINTF(LOG_INFO, "PTY name: %s", ptyName);
553
554 hw.fd = ptyfd;
555
556 /* make a pipe for sending signals to the callback */
557 /* make a pipe for signaling from the callback that everything
558 was sent */
559 if (pipe(sendPipe) == -1 || pipe(completedPipe) == -1) {
560 logprintf(LOG_ERR, "pipe failed");
561 logperror(LOG_ERR, "pipe()");
562 }
563
564 /* make the readable end non-blocking */
565 flags = fcntl(sendPipe[0], F_GETFL, 0);
566 if (flags != -1) {
567 fcntl(sendPipe[0], F_SETFL, flags | O_NONBLOCK);
568 } else {
569 logprintf(LOG_ERR, "fcntl failed");
570 logperror(LOG_ERR, "fcntl()");
571 }
572
573 err = Pa_StartStream(stream);
574 if (err != paNoError)
575 goto error;
576
577 /* wait for portaudio to settle */
578 usleep(50000);
579
580 return (1);
581
582 error:
583 Pa_Terminate();
584 logprintf(LOG_ERR, "an error occured while using the portaudio stream");
585 logprintf(LOG_ERR, "error number: %d", err);
586 logprintf(LOG_ERR, "error message: %s", Pa_GetErrorText(err));
587
588 return (0);
589 }
590
audio_deinit(void)591 int audio_deinit(void)
592 {
593 PaError err;
594
595 LOGPRINTF(1, "hw_audio_deinit()");
596
597 logprintf(LOG_INFO, "Deinitializing %s...", hw.device);
598
599 /* make absolutely sure the full output buffer has played out
600 even though portaudio should wait for it, it doesn't always
601 happen */
602 sleep(outputLatency / 1000000);
603 usleep(outputLatency % 1000000);
604
605 /* close port audio */
606 err = Pa_CloseStream(stream);
607 if (err != paNoError)
608 goto error;
609
610 Pa_Terminate();
611
612 /* wait for terminaton */
613 usleep(20000);
614
615 /* close pty */
616 close(master);
617 close(ptyfd);
618
619 close(sendPipe[0]);
620 close(sendPipe[1]);
621 close(completedPipe[0]);
622 close(completedPipe[1]);
623
624 return 1;
625
626 error:
627 Pa_Terminate();
628 logprintf(LOG_ERR, "an error occured while using the portaudio stream");
629 logprintf(LOG_ERR, "error number: %d", err);
630 logprintf(LOG_ERR, "eError message: %s", Pa_GetErrorText(err));
631 return 0;
632 }
633
audio_rec(struct ir_remote * remotes)634 char *audio_rec(struct ir_remote *remotes)
635 {
636 if (!clear_rec_buffer())
637 return (NULL);
638 return (decode_all(remotes));
639 }
640
641 struct hardware hw_audio = {
642 "", /* default device */
643 -1, /* fd */
644 LIRC_CAN_REC_MODE2 | LIRC_CAN_SEND_PULSE, /* features */
645 LIRC_MODE_PULSE, /* send_mode */
646 LIRC_MODE_MODE2, /* rec_mode */
647 0, /* code_length */
648 audio_init, /* init_func */
649 audio_deinit, /* deinit_func */
650 audio_send, /* send_func */
651 audio_rec, /* rec_func */
652 receive_decode, /* decode_func */
653 NULL, /* ioctl_func */
654 audio_readdata,
655 "audio"
656 };
657