muted.c 17 KB

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