muted.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * Updated for Mac OSX CoreAudio
  9. * by Josh Roberson <josh@asteriasgi.com>
  10. *
  11. * See http://www.asterisk.org for more information about
  12. * the Asterisk project. Please do not directly contact
  13. * any of the maintainers of this project for assistance;
  14. * the project provides a web site, mailing lists and IRC
  15. * channels for your use.
  16. *
  17. * This program is free software, distributed under the terms of
  18. * the GNU General Public License Version 2. See the LICENSE file
  19. * at the top of the source tree.
  20. */
  21. /*! \file
  22. * \brief Mute Daemon
  23. *
  24. * \note Specially written for Malcolm Davenport, but I think I'll use it too
  25. * Connects to the Asterisk Manager Interface, AMI, and listens for events
  26. * on certain devices. If a phone call is connected to one of the devices (phones)
  27. * the local sound is muted to a lower volume during the call.
  28. *
  29. */
  30. #ifndef __Darwin__
  31. #include <linux/soundcard.h>
  32. #else
  33. #include <CoreAudio/AudioHardware.h>
  34. #endif
  35. #include <stdio.h>
  36. #include <errno.h>
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <fcntl.h>
  40. #include <string.h>
  41. #include <netdb.h>
  42. #include <sys/socket.h>
  43. #include <sys/ioctl.h>
  44. #include <netinet/in.h>
  45. #include <arpa/inet.h>
  46. static char *config = "/etc/muted.conf";
  47. static char host[256] = "";
  48. static char user[256] = "";
  49. static char pass[256] = "";
  50. static int smoothfade = 0;
  51. static int mutelevel = 20;
  52. static int muted = 0;
  53. static int needfork = 1;
  54. static int debug = 0;
  55. static int stepsize = 3;
  56. #ifndef __Darwin__
  57. static int mixchan = SOUND_MIXER_VOLUME;
  58. #endif
  59. struct subchannel {
  60. char *name;
  61. struct subchannel *next;
  62. };
  63. static struct channel {
  64. char *tech;
  65. char *location;
  66. struct channel *next;
  67. struct subchannel *subs;
  68. } *channels;
  69. static void add_channel(char *tech, char *location)
  70. {
  71. struct channel *chan;
  72. chan = malloc(sizeof(struct channel));
  73. if (chan) {
  74. memset(chan, 0, sizeof(struct channel));
  75. chan->tech = strdup(tech);
  76. chan->location = strdup(location);
  77. chan->next = channels;
  78. channels = chan;
  79. }
  80. }
  81. static int load_config(void)
  82. {
  83. FILE *f;
  84. char buf[1024];
  85. char *val;
  86. char *val2;
  87. int lineno=0;
  88. int x;
  89. f = fopen(config, "r");
  90. if (!f) {
  91. fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
  92. return -1;
  93. }
  94. while(!feof(f)) {
  95. fgets(buf, sizeof(buf), f);
  96. if (!feof(f)) {
  97. lineno++;
  98. val = strchr(buf, '#');
  99. if (val) *val = '\0';
  100. while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
  101. buf[strlen(buf) - 1] = '\0';
  102. if (!strlen(buf))
  103. continue;
  104. val = buf;
  105. while(*val) {
  106. if (*val < 33)
  107. break;
  108. val++;
  109. }
  110. if (*val) {
  111. *val = '\0';
  112. val++;
  113. while(*val && (*val < 33)) val++;
  114. }
  115. if (!strcasecmp(buf, "host")) {
  116. if (val && strlen(val))
  117. strncpy(host, val, sizeof(host) - 1);
  118. else
  119. fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
  120. } else if (!strcasecmp(buf, "user")) {
  121. if (val && strlen(val))
  122. strncpy(user, val, sizeof(user) - 1);
  123. else
  124. fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
  125. } else if (!strcasecmp(buf, "pass")) {
  126. if (val && strlen(val))
  127. strncpy(pass, val, sizeof(pass) - 1);
  128. else
  129. fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
  130. } else if (!strcasecmp(buf, "smoothfade")) {
  131. smoothfade = 1;
  132. } else if (!strcasecmp(buf, "mutelevel")) {
  133. if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
  134. mutelevel = x;
  135. } else
  136. fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
  137. } else if (!strcasecmp(buf, "channel")) {
  138. if (val && strlen(val)) {
  139. val2 = strchr(val, '/');
  140. if (val2) {
  141. *val2 = '\0';
  142. val2++;
  143. add_channel(val, val2);
  144. } else
  145. fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
  146. } else
  147. fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
  148. } else {
  149. fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
  150. }
  151. }
  152. }
  153. fclose(f);
  154. if (!strlen(host))
  155. fprintf(stderr, "no 'host' specification in config file\n");
  156. else if (!strlen(user))
  157. fprintf(stderr, "no 'user' specification in config file\n");
  158. else if (!channels)
  159. fprintf(stderr, "no 'channel' specifications in config file\n");
  160. else
  161. return 0;
  162. return -1;
  163. }
  164. static FILE *astf;
  165. #ifndef __Darwin__
  166. static int mixfd;
  167. static int open_mixer(void)
  168. {
  169. mixfd = open("/dev/mixer", O_RDWR);
  170. if (mixfd < 0) {
  171. fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
  172. return -1;
  173. }
  174. return 0;
  175. }
  176. #endif /* !__Darwin */
  177. /*! Connect to the asterisk manager interface */
  178. static int connect_asterisk(void)
  179. {
  180. int sock;
  181. struct hostent *hp;
  182. char *ports;
  183. int port = 5038;
  184. struct sockaddr_in sin;
  185. ports = strchr(host, ':');
  186. if (ports) {
  187. *ports = '\0';
  188. ports++;
  189. if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
  190. fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
  191. return -1;
  192. }
  193. }
  194. hp = gethostbyname(host);
  195. if (!hp) {
  196. fprintf(stderr, "Can't find host '%s'\n", host);
  197. return -1;
  198. }
  199. sock = socket(AF_INET, SOCK_STREAM, 0);
  200. if (sock < 0) {
  201. fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
  202. return -1;
  203. }
  204. sin.sin_family = AF_INET;
  205. sin.sin_port = htons(port);
  206. memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
  207. if (connect(sock, &sin, sizeof(sin))) {
  208. fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
  209. close(sock);
  210. return -1;
  211. }
  212. astf = fdopen(sock, "r+");
  213. if (!astf) {
  214. fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
  215. close(sock);
  216. return -1;
  217. }
  218. return 0;
  219. }
  220. static char *get_line(void)
  221. {
  222. static char buf[1024];
  223. if (fgets(buf, sizeof(buf), astf)) {
  224. while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
  225. buf[strlen(buf) - 1] = '\0';
  226. return buf;
  227. } else
  228. return NULL;
  229. }
  230. /*! Login to the asterisk manager interface */
  231. static int login_asterisk(void)
  232. {
  233. char *welcome;
  234. char *resp;
  235. if (!(welcome = get_line())) {
  236. fprintf(stderr, "disconnected (1)\n");
  237. return -1;
  238. }
  239. fprintf(astf,
  240. "Action: Login\r\n"
  241. "Username: %s\r\n"
  242. "Secret: %s\r\n\r\n", user, pass);
  243. if (!(welcome = get_line())) {
  244. fprintf(stderr, "disconnected (2)\n");
  245. return -1;
  246. }
  247. if (strcasecmp(welcome, "Response: Success")) {
  248. fprintf(stderr, "login failed ('%s')\n", welcome);
  249. return -1;
  250. }
  251. /* Eat the rest of the event */
  252. while((resp = get_line()) && strlen(resp));
  253. if (!resp) {
  254. fprintf(stderr, "disconnected (3)\n");
  255. return -1;
  256. }
  257. fprintf(astf,
  258. "Action: Status\r\n\r\n");
  259. if (!(welcome = get_line())) {
  260. fprintf(stderr, "disconnected (4)\n");
  261. return -1;
  262. }
  263. if (strcasecmp(welcome, "Response: Success")) {
  264. fprintf(stderr, "status failed ('%s')\n", welcome);
  265. return -1;
  266. }
  267. /* Eat the rest of the event */
  268. while((resp = get_line()) && strlen(resp));
  269. if (!resp) {
  270. fprintf(stderr, "disconnected (5)\n");
  271. return -1;
  272. }
  273. return 0;
  274. }
  275. static struct channel *find_channel(char *channel)
  276. {
  277. char tmp[256] = "";
  278. char *s, *t;
  279. struct channel *chan;
  280. strncpy(tmp, channel, sizeof(tmp) - 1);
  281. s = strchr(tmp, '/');
  282. if (s) {
  283. *s = '\0';
  284. s++;
  285. t = strrchr(s, '-');
  286. if (t) {
  287. *t = '\0';
  288. }
  289. if (debug)
  290. printf("Searching for '%s' tech, '%s' location\n", tmp, s);
  291. chan = channels;
  292. while(chan) {
  293. if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
  294. if (debug)
  295. printf("Found '%s'/'%s'\n", chan->tech, chan->location);
  296. break;
  297. }
  298. chan = chan->next;
  299. }
  300. } else
  301. chan = NULL;
  302. return chan;
  303. }
  304. #ifndef __Darwin__
  305. static int getvol(void)
  306. {
  307. int vol;
  308. if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
  309. #else
  310. static float getvol(void)
  311. {
  312. float volumeL, volumeR, vol;
  313. OSStatus err;
  314. AudioDeviceID device;
  315. UInt32 size;
  316. UInt32 channels[2];
  317. size = sizeof(device);
  318. err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
  319. size = sizeof(channels);
  320. if (!err)
  321. err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
  322. size = sizeof(vol);
  323. if (!err)
  324. err = AudioDeviceGetProperty(device, channels[0], false, kAudioDevicePropertyVolumeScalar, &size, &volumeL);
  325. if (!err)
  326. err = AudioDeviceGetProperty(device, channels[1], false, kAudioDevicePropertyVolumeScalar, &size, &volumeR);
  327. if (!err)
  328. vol = (volumeL < volumeR) ? volumeR : volumeL;
  329. else {
  330. #endif
  331. fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
  332. return -1;
  333. }
  334. return vol;
  335. }
  336. #ifndef __Darwin__
  337. static int setvol(int vol)
  338. #else
  339. static int setvol(float vol)
  340. #endif
  341. {
  342. #ifndef __Darwin__
  343. if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
  344. #else
  345. float volumeL = vol;
  346. float volumeR = vol;
  347. OSStatus err;
  348. AudioDeviceID device;
  349. UInt32 size;
  350. UInt32 channels[2];
  351. size = sizeof(device);
  352. err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
  353. size = sizeof(channels);
  354. err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
  355. size = sizeof(vol);
  356. if (!err)
  357. err = AudioDeviceSetProperty(device, 0, channels[0], false, kAudioDevicePropertyVolumeScalar, size, &volumeL);
  358. if (!err)
  359. err = AudioDeviceSetProperty(device, 0, channels[1], false, kAudioDevicePropertyVolumeScalar, size, &volumeR);
  360. if (err) {
  361. #endif
  362. fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
  363. return -1;
  364. }
  365. return 0;
  366. }
  367. #ifndef __Darwin__
  368. static int oldvol = 0;
  369. static int mutevol = 0;
  370. #else
  371. static float oldvol = 0;
  372. static float mutevol = 0;
  373. #endif
  374. #ifndef __Darwin__
  375. static int mutedlevel(int orig, int mutelevel)
  376. {
  377. int l = orig >> 8;
  378. int r = orig & 0xff;
  379. l = (float)(mutelevel) * (float)(l) / 100.0;
  380. r = (float)(mutelevel) * (float)(r) / 100.0;
  381. return (l << 8) | r;
  382. #else
  383. static float mutedlevel(float orig, float mutelevel)
  384. {
  385. float master = orig;
  386. master = mutelevel * master / 100.0;
  387. return master;
  388. #endif
  389. }
  390. static void mute(void)
  391. {
  392. #ifndef __Darwin__
  393. int vol;
  394. int start;
  395. int x;
  396. #else
  397. float vol;
  398. float start = 1.0;
  399. float x;
  400. #endif
  401. vol = getvol();
  402. oldvol = vol;
  403. if (smoothfade)
  404. #ifdef __Darwin__
  405. start = mutelevel;
  406. #else
  407. start = 100;
  408. else
  409. start = mutelevel;
  410. #endif
  411. for (x=start;x>=mutelevel;x-=stepsize) {
  412. mutevol = mutedlevel(vol, x);
  413. setvol(mutevol);
  414. /* Wait 0.01 sec */
  415. usleep(10000);
  416. }
  417. mutevol = mutedlevel(vol, mutelevel);
  418. setvol(mutevol);
  419. if (debug)
  420. #ifdef __Darwin__
  421. printf("Mute from '%f' to '%f'!\n", oldvol, mutevol);
  422. #else
  423. printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
  424. #endif
  425. muted = 1;
  426. }
  427. static void unmute(void)
  428. {
  429. #ifdef __Darwin__
  430. float vol;
  431. float start;
  432. float x;
  433. #else
  434. int vol;
  435. int start;
  436. int x;
  437. #endif
  438. vol = getvol();
  439. if (debug)
  440. #ifdef __Darwin__
  441. printf("Unmute from '%f' (should be '%f') to '%f'!\n", vol, mutevol, oldvol);
  442. mutevol = vol;
  443. if (vol == mutevol) {
  444. #else
  445. printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
  446. if ((int)vol == mutevol) {
  447. #endif
  448. if (smoothfade)
  449. start = mutelevel;
  450. else
  451. #ifdef __Darwin__
  452. start = 1.0;
  453. #else
  454. start = 100;
  455. #endif
  456. for (x=start;x<100;x+=stepsize) {
  457. mutevol = mutedlevel(oldvol, x);
  458. setvol(mutevol);
  459. /* Wait 0.01 sec */
  460. usleep(10000);
  461. }
  462. setvol(oldvol);
  463. } else
  464. printf("Whoops, it's already been changed!\n");
  465. muted = 0;
  466. }
  467. static void check_mute(void)
  468. {
  469. int offhook = 0;
  470. struct channel *chan;
  471. chan = channels;
  472. while(chan) {
  473. if (chan->subs) {
  474. offhook++;
  475. break;
  476. }
  477. chan = chan->next;
  478. }
  479. if (offhook && !muted)
  480. mute();
  481. else if (!offhook && muted)
  482. unmute();
  483. }
  484. static void delete_sub(struct channel *chan, char *name)
  485. {
  486. struct subchannel *sub, *prev;
  487. prev = NULL;
  488. sub = chan->subs;
  489. while(sub) {
  490. if (!strcasecmp(sub->name, name)) {
  491. if (prev)
  492. prev->next = sub->next;
  493. else
  494. chan->subs = sub->next;
  495. free(sub->name);
  496. free(sub);
  497. return;
  498. }
  499. prev = sub;
  500. sub = sub->next;
  501. }
  502. }
  503. static void append_sub(struct channel *chan, char *name)
  504. {
  505. struct subchannel *sub;
  506. sub = chan->subs;
  507. while(sub) {
  508. if (!strcasecmp(sub->name, name))
  509. return;
  510. sub = sub->next;
  511. }
  512. sub = malloc(sizeof(struct subchannel));
  513. if (sub) {
  514. memset(sub, 0, sizeof(struct subchannel));
  515. sub->name = strdup(name);
  516. sub->next = chan->subs;
  517. chan->subs = sub;
  518. }
  519. }
  520. static void hangup_chan(char *channel)
  521. {
  522. struct channel *chan;
  523. if (debug)
  524. printf("Hangup '%s'\n", channel);
  525. chan = find_channel(channel);
  526. if (chan)
  527. delete_sub(chan, channel);
  528. check_mute();
  529. }
  530. static void offhook_chan(char *channel)
  531. {
  532. struct channel *chan;
  533. if (debug)
  534. printf("Offhook '%s'\n", channel);
  535. chan = find_channel(channel);
  536. if (chan)
  537. append_sub(chan, channel);
  538. check_mute();
  539. }
  540. static int wait_event(void)
  541. {
  542. char *resp;
  543. char event[120]="";
  544. char channel[120]="";
  545. char oldname[120]="";
  546. char newname[120]="";
  547. resp = get_line();
  548. if (!resp) {
  549. fprintf(stderr, "disconnected (6)\n");
  550. return -1;
  551. }
  552. if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
  553. strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
  554. /* Consume the rest of the non-event */
  555. while((resp = get_line()) && strlen(resp)) {
  556. if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
  557. strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
  558. if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
  559. strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
  560. if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
  561. strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
  562. }
  563. if (strlen(channel)) {
  564. if (!strcasecmp(event, "Hangup"))
  565. hangup_chan(channel);
  566. else
  567. offhook_chan(channel);
  568. }
  569. if (strlen(newname) && strlen(oldname)) {
  570. if (!strcasecmp(event, "Rename")) {
  571. hangup_chan(oldname);
  572. offhook_chan(newname);
  573. }
  574. }
  575. } else {
  576. /* Consume the rest of the non-event */
  577. while((resp = get_line()) && strlen(resp));
  578. }
  579. if (!resp) {
  580. fprintf(stderr, "disconnected (7)\n");
  581. return -1;
  582. }
  583. return 0;
  584. }
  585. static void usage(void)
  586. {
  587. printf("Usage: muted [-f] [-d]\n"
  588. " -f : Do not fork\n"
  589. " -d : Debug (implies -f)\n");
  590. }
  591. int main(int argc, char *argv[])
  592. {
  593. int x;
  594. while((x = getopt(argc, argv, "fhd")) > 0) {
  595. switch(x) {
  596. case 'd':
  597. debug = 1;
  598. needfork = 0;
  599. break;
  600. case 'f':
  601. needfork = 0;
  602. break;
  603. case 'h':
  604. /* Fall through */
  605. default:
  606. usage();
  607. exit(1);
  608. }
  609. }
  610. if (load_config())
  611. exit(1);
  612. #ifndef __Darwin__
  613. if (open_mixer())
  614. exit(1);
  615. #endif
  616. if (connect_asterisk()) {
  617. #ifndef __Darwin__
  618. close(mixfd);
  619. #endif
  620. exit(1);
  621. }
  622. if (login_asterisk()) {
  623. #ifndef __Darwin__
  624. close(mixfd);
  625. #endif
  626. fclose(astf);
  627. exit(1);
  628. }
  629. if (needfork)
  630. daemon(0,0);
  631. for(;;) {
  632. if (wait_event()) {
  633. fclose(astf);
  634. while(connect_asterisk()) {
  635. sleep(5);
  636. }
  637. if (login_asterisk()) {
  638. fclose(astf);
  639. exit(1);
  640. }
  641. }
  642. }
  643. exit(0);
  644. }