2
* Purpose: Utility to make phone calls using Open Sound System modem support.
7
* This file is part of Open Sound System.
9
* Copyright (C) 4Front Technologies 1996-2008.
11
* This this source file is released under GPL v2 license (no other versions).
12
* See the COPYING file included in the main directory of this source
13
* distribution for the license terms and conditions.
26
#include <sys/types.h>
29
#include <sys/ioctl.h>
30
#include <sys/select.h>
31
#include <soundcard.h>
36
int modem_out_fd = -1;
39
char *dspdev_name = "/dev/dsp"; /* Local audio device (headset) */
41
double digit_duration = 0.2;
42
double silence_duration = 0.1;
45
* http://en.wikipedia.org/wiki/DTMF#Keypad
48
const double dtmf_keypad_row[] = { 697.0, 770.0, 852.0, 941.0 };
49
const double dtmf_keypad_col[] = { 1209.0, 1336.0, 1477.0, 1633.0 };
50
const char *dtmf_keypad_keys = "123A456B789C*0#D";
53
modem_write(int fd, const void *buf, size_t count)
55
if (write(fd, buf, count) != count)
57
perror("Modem write");
63
modem_read(int fd, void *buf, size_t count)
65
if (read(fd, buf, count) != count)
73
dtmf_fill_digit(uint16_t *buf, size_t buf_len, int digit)
75
const double A = 65536.0 / 8.0;
76
const double pi = 3.14159265358979323846;
78
const char *keypad_digit;
80
double t, sample_duration;
83
keypad_digit = strchr(dtmf_keypad_keys, toupper(digit));
85
if (keypad_digit == NULL)
88
pos = (int)(keypad_digit - dtmf_keypad_keys);
90
/* compute angular frequencies */
91
w1 = 2.0*pi*dtmf_keypad_row[pos / 4];
92
w2 = 2.0*pi*dtmf_keypad_col[pos % 4];
95
sample_duration = 1.0 / (double)srate;
97
for (i = 0; i < buf_len; i++)
99
buf[i] = (uint16_t)(A + A*sin(w1*t) + A + A*sin(w2*t));
100
t += sample_duration;
107
dtmf_fill_silence(uint16_t *buf, size_t buf_len)
109
const uint16_t A = (uint16_t)(65536.0 / 4.0);
112
for (i = 0; i < buf_len; i++)
119
evaluate_dc_level(uint16_t *buf, size_t buf_len)
124
for (i = 0; i < buf_len; i++)
126
sum += ((double)buf[i]) / 65536.0;
129
return (sum / (double)buf_len);
137
printf("Off-hook\n");
138
ioctl (modem_out_fd, SNDCTL_DSP_MODEM_OFFHOOK, &offhook);
141
static int wait_dialtone()
143
double dc_level = 0.0;
144
const double min_dc_level = 0.2;
149
const int max_retries = 10;
151
printf("Waiting for dial tone...\n");
152
while (dc_level < min_dc_level)
155
modem_read(modem_in_fd, buf, sizeof(buf));
156
dummy=write(dev_dsp_fd, buf, sizeof(buf));
158
dc_level = evaluate_dc_level(buf, sizeof(buf)/sizeof(uint16_t));
160
if (retries++ > max_retries)
170
dial_phone_number(const char *phone_number)
172
size_t digit_len = (size_t)(digit_duration*srate);
173
size_t silence_len = (size_t)(silence_duration*srate);
174
size_t digit_size = digit_len * sizeof(uint16_t);
175
size_t silence_size = silence_len * sizeof(uint16_t);
177
uint16_t *digit = (uint16_t *)malloc(digit_size);
178
uint16_t *silence = (uint16_t *)malloc(silence_size);
179
uint16_t *buf = (uint16_t *)malloc(silence_size);
181
dtmf_fill_silence (silence, silence_len);
183
printf("Dialing... ");
186
while (*phone_number != '\0')
188
if (dtmf_fill_digit (digit, digit_len, *phone_number) >= 0)
192
printf("%c", *phone_number);
195
modem_write (modem_out_fd, digit, digit_size);
196
modem_read (modem_in_fd, digit, digit_size);
197
dummy=write (dev_dsp_fd, digit, digit_size);
199
modem_write (modem_out_fd, silence, silence_size);
200
modem_read (modem_in_fd, buf, silence_size);
201
dummy=write (dev_dsp_fd, buf, silence_size);
216
fprintf (stderr, "Usage: %s [options] mdmin-dev mdmout-dev [phone-number]\n", cmdname);
217
fprintf (stderr, " Options: -d<devname> Change sound device (default: %s)\n", dspdev_name);
218
fprintf (stderr, " -s<rate> Change sampling rate (default: %d)\n", srate);
219
fprintf (stderr, " -t<duration> Change DTMF digit duration (default: %.1f s)\n", digit_duration);
220
fprintf (stderr, " -l<duration> Change DTMF silence duration (default: %.1f s)\n", silence_duration);
227
if (modem_in_fd >= 0)
232
if (modem_out_fd >= 0)
236
ioctl (modem_out_fd, SNDCTL_DSP_MODEM_OFFHOOK, &offhook);
237
close (modem_out_fd);
248
sigint_handler(int sig)
254
main(int argc, char **argv)
256
char *phone_number = "";
259
int format = AFMT_S16_LE;
267
signal(SIGINT, sigint_handler);
274
while ((c = getopt (argc, argv, "d:s:t:l:")) != EOF)
279
dspdev_name = optarg;
282
srate = atoi (optarg);
285
digit_duration = atof (optarg);
288
silence_duration = atof (optarg);
295
if ((argc - optind) < 2)
298
atexit(exit_handler);
300
dev_dsp_fd = open (dspdev_name, O_RDWR);
303
perror (dspdev_name);
307
modem_in_fd = open (argv[optind], O_RDWR);
310
perror (argv[optind]);
314
ioctl(modem_in_fd, SNDCTL_DSP_COOKEDMODE, &tmp); // No error checking with this call
317
modem_out_fd = open(argv[optind], O_RDWR);
318
if (modem_out_fd < 0)
320
perror (argv[optind]);
324
ioctl(modem_out_fd, SNDCTL_DSP_COOKEDMODE, &tmp); // No error checking with this call
328
phone_number = argv[optind];
330
assert ( ioctl (modem_in_fd, SNDCTL_DSP_CHANNELS, &channels) >= 0 );
331
assert ( ioctl (modem_out_fd, SNDCTL_DSP_CHANNELS, &channels) >= 0 );
332
assert ( ioctl (dev_dsp_fd, SNDCTL_DSP_CHANNELS, &channels) >= 0 );
334
assert ( ioctl (modem_in_fd, SNDCTL_DSP_SETFMT, &format) >= 0 );
335
assert ( ioctl (modem_out_fd, SNDCTL_DSP_SETFMT, &format) >= 0 );
336
assert ( ioctl (dev_dsp_fd, SNDCTL_DSP_SETFMT, &format) >= 0 );
338
assert ( ioctl (modem_in_fd, SNDCTL_DSP_SPEED, &srate) >= 0 );
339
assert ( ioctl (modem_out_fd, SNDCTL_DSP_SPEED, &srate) >= 0 );
340
assert ( ioctl (dev_dsp_fd, SNDCTL_DSP_SPEED, &srate) >= 0 );
345
assert ( ioctl (modem_in_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
346
tmp = PCM_ENABLE_INPUT;
347
assert ( ioctl (modem_in_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
349
assert ( ioctl (modem_out_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
350
tmp = PCM_ENABLE_OUTPUT;
351
assert ( ioctl (modem_out_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
353
assert ( ioctl (dev_dsp_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
354
tmp = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
355
assert ( ioctl (dev_dsp_fd, SNDCTL_DSP_SETTRIGGER, &tmp) >= 0 );
360
if (phone_number[0] != '\0')
362
if (wait_dialtone () < 0)
364
printf("No dial tone.\n");
367
dial_phone_number(phone_number);
370
printf("Call in progress...\n");
371
printf("Press Ctrl-C to quit.\n");
378
int max_fd = modem_in_fd;
379
if (dev_dsp_fd > max_fd)
386
FD_SET(modem_in_fd, &rfds);
387
FD_SET(dev_dsp_fd, &rfds);
389
retval = select(max_fd+1, &rfds, NULL, NULL, NULL);
396
if (FD_ISSET(modem_in_fd, &rfds))
398
modem_read(modem_in_fd, buf, sizeof(buf));
399
dummy=write(dev_dsp_fd, buf, sizeof(buf));
401
if (FD_ISSET(dev_dsp_fd, &rfds))
403
dummy=read(dev_dsp_fd, buf, sizeof(buf));
404
modem_write(modem_out_fd, buf, sizeof(buf));
410
// return 0; /* NOT REACHED */