Added lirc.
[irreco.git] / lirc-0.8.4a / daemons / hw_audio.c
blob32cb21efac0f85262f5a0db1edf395a65a3cb868
1 /* $Id: hw_audio.c,v 5.5 2008/09/14 18:04:37 lirc Exp $ */
3 /****************************************************************************
4 ** hw_audio.c **************************************************************
5 ****************************************************************************
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>
13 * Distribute under GPL version 2 or later.
15 * Using ... hardware ...
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
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
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"
47 static int ptyfd; /* the pty */
49 /* PortAudio Includes */
50 #include <portaudio.h>
52 #define SAMPLE_RATE (44100)
53 #define NUM_CHANNELS (2)
54 #define DITHER_FLAG (0) /**/
56 /* Select sample format. */
57 #define PA_SAMPLE_TYPE paUInt8
58 typedef unsigned char SAMPLE;
60 typedef struct
62 int lastFrames[3];
63 int lastSign;
64 int pulseSign;
65 unsigned int lastCount;
67 paTestData;
69 PaStream *stream;
72 extern struct ir_remote *repeat_remote;
73 extern struct rbuf rec_buffer;
75 char ptyName[256];
76 int master;
79 int myfd = -1;
81 void addCode( lirc_t data)
83 write( master, &data, sizeof( lirc_t ) );
86 /* This routine will be called by the PortAudio engine when audio is needed.
87 ** It may be called at interrupt level on some machines so don't do anything
88 ** that could mess up the system like calling malloc() or free().
91 static int recordCallback( void *inputBuffer, void *outputBuffer,
92 unsigned long framesPerBuffer,
93 PaStreamCallbackTimeInfo outTime,
94 PaStreamCallbackFlags status,
95 void *userData )
97 paTestData *data = (paTestData*)userData;
98 SAMPLE *rptr = (SAMPLE*)inputBuffer;
99 long i;
101 SAMPLE *myPtr = rptr;
103 unsigned int time;
104 int samplerate = SAMPLE_RATE;
105 int diff;
107 (void) outputBuffer; /* Prevent unused variable warnings. */
108 (void) outTime;
110 for ( i=0; i < framesPerBuffer; i++, myPtr++)
112 /* New Algo */
113 diff = abs(data->lastFrames[0] - *myPtr);
114 if ( diff > 100)
116 if (data->pulseSign == 0)
118 // we got the first signal, this is a PULSE
119 if ( *myPtr > data->lastFrames[0] )
121 data->pulseSign = 1;
123 else
125 data->pulseSign = -1;
129 if (data->lastCount > 0)
131 if ( *myPtr > data->lastFrames[0] && data->lastSign <= 0)
133 // printf("CHANGE ++ ");
134 data->lastSign = 1;
136 time = data->lastCount * 1000000 / samplerate;
137 if (data->lastSign == data->pulseSign)
139 addCode( time );
140 // printf("Pause: %d us, %d \n", time, data->lastCount);
142 else
144 addCode( time | PULSE_BIT );
145 // printf("Pulse: %d us, %d \n", time, data->lastCount);
147 data->lastCount = 0;
150 else if ( *myPtr < data->lastFrames[0] && data->lastSign >= 0)
152 // printf("CHANGE -- ");
153 data->lastSign = -1;
155 time = data->lastCount * 1000000 / samplerate;
156 if (data->lastSign == data->pulseSign)
158 // printf("Pause: %d us, %d \n", time, data->lastCount);
159 addCode( time );
161 else
163 // printf("Pulse: %d us, %d \n", time, data->lastCount);
164 addCode( time | PULSE_BIT);
165 }data->lastCount = 0;
170 if ( data->lastCount < 100000 )
172 data->lastCount++;
175 data->lastFrames[0] = data->lastFrames[1];
176 data->lastFrames[1] = *myPtr;
178 // skip 2. channel
179 if (NUM_CHANNELS == 2)
180 myPtr++;
182 return 0;
186 decoding stuff
189 #define BUFSIZE 20
190 #define SAMPLE 47999
193 lirc_t audio_readdata(lirc_t timeout)
195 lirc_t data;
196 int ret;
198 if (!waitfordata((long) timeout))
199 return 0;
201 ret=read(hw.fd,&data,sizeof(data));
202 if(ret!=sizeof(data))
204 LOGPRINTF(1,"error reading from lirc");
205 LOGPERROR(1,NULL);
206 raise(SIGTERM);
207 return 0;
209 return(data);
214 interface functions
216 paTestData data;
218 int audio_init()
221 PaStreamParameters inputParameters;
222 PaError err;
223 int flags;
224 struct termios t;
226 LOGPRINTF(1,"hw_audio_init()");
229 logprintf(LOG_INFO,"Initializing %s...",hw.device);
230 init_rec_buffer();
231 rewind_rec_buffer();
233 // new
234 data.lastFrames[0] = 128;
235 data.lastFrames[1] = 128;
236 data.lastFrames[2] = 128;
237 data.lastSign = 0;
238 data.lastCount = 0;
239 data.pulseSign = 0;
241 err = Pa_Initialize();
242 if( err != paNoError ) goto error;
244 inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
245 if (inputParameters.device == paNoDevice) {
246 logprintf(LOG_ERR, "No default input device");
247 goto error;
249 inputParameters.channelCount = NUM_CHANNELS; /* stereo input */
250 inputParameters.sampleFormat = PA_SAMPLE_TYPE;
251 inputParameters.suggestedLatency =
252 Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
253 inputParameters.hostApiSpecificStreamInfo = NULL;
256 // Record some audio. --------------------------------------------
257 err = Pa_OpenStream
259 &stream,
260 &inputParameters,
261 NULL, // output parameters
262 SAMPLE_RATE,
263 512, // frames per buffer
264 0, // flags
265 recordCallback,
266 &data );
268 if( err != paNoError ) goto error;
270 // open pty
271 if ( openpty( &master, &ptyfd, ptyName, 0, 0) == -1)
273 logprintf(LOG_ERR,"openpty failed");
274 logperror(LOG_ERR,"openpty()");
275 goto error;
278 // regular device file
279 if( tcgetattr( master, &t ) < 0 ) {
280 logprintf(LOG_ERR,"tcgetattr failed");
281 logperror(LOG_ERR,"tcgetattr()");
284 cfmakeraw( &t );
286 // apply file descriptor options
287 if( tcsetattr( master, TCSANOW, &t ) < 0) {
288 logprintf(LOG_ERR,"tcsetattr failed");
289 logperror(LOG_ERR,"tcsetattr()");
292 flags=fcntl(ptyfd,F_GETFL,0);
293 if(flags!=-1)
295 fcntl(ptyfd,F_SETFL,flags|O_NONBLOCK);
298 LOGPRINTF(LOG_INFO,"PTY name: %s", ptyName);
300 hw.fd=ptyfd;
302 err = Pa_StartStream( stream );
303 if( err != paNoError ) goto error;
305 return(1);
307 error:
308 Pa_Terminate();
309 logprintf(LOG_ERR, "an error occured while using the portaudio stream" );
310 logprintf(LOG_ERR, "error number: %d", err );
311 logprintf(LOG_ERR, "error message: %s", Pa_GetErrorText( err ) );
313 return (0);
316 int audio_deinit(void)
318 PaError err;
320 LOGPRINTF(1,"hw_audio_deinit()");
322 // close port audio
323 err = Pa_CloseStream( stream );
324 if( err != paNoError ) goto error;
326 Pa_Terminate();
328 // wair for terminaton
329 usleep(20000);
331 // close pty
332 close(master);
333 close(ptyfd);
335 return 1;
337 error:
338 Pa_Terminate();
339 logprintf(LOG_ERR,
340 "an error occured while using the portaudio stream");
341 logprintf(LOG_ERR,"error number: %d",err);
342 logprintf(LOG_ERR,"eError message: %s",Pa_GetErrorText(err));
343 return 0;
346 char *audio_rec(struct ir_remote *remotes)
348 if(!clear_rec_buffer()) return(NULL);
349 return(decode_all(remotes));
352 struct hardware hw_audio=
354 "pty", /* simple device */
355 -1, /* fd */
356 LIRC_CAN_REC_MODE2, /* features */
357 0, /* send_mode */
358 LIRC_MODE_MODE2, /* rec_mode */
359 0, /* code_length */
360 audio_init, /* init_func */
361 NULL, /* config_func */
362 audio_deinit, /* deinit_func */
363 NULL, /* send_func */
364 audio_rec, /* rec_func */
365 receive_decode, /* decode_func */
366 NULL, /* ioctl_func */
367 audio_readdata,
368 "audio"