aboutsummaryrefslogtreecommitdiffstats
path: root/doc/examples/telephony-and-music/monitor.c
blob: 34b90a4c56956818313a4ab1bb8b385cb83d4195 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <bus.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define t(stmt)  if (stmt) goto fail



static size_t pauser_count = 0;
static size_t pausers_size = 0;
static char* pausers = NULL;



static int is_moc_playing(void)
{
	return !WEXITSTATUS(system("env LANG=C mocp -i 2>/dev/null | grep 'State: PLAY' >/dev/null"));
}



/* In a proper implementation, message whould be copyied, and then
 * a new thread would be created that parsed the copy. But that is
 * too much for an example, especially since it would also require
 * a mutex to make sure two threads do not modify data at the same
 * time, causing chaos. */
static int callback(const char *message, void *user_data)
{
 	char *msg = NULL;
	size_t len = 0;
	while ((len < 2047) && message[len])
		len++;
	msg = malloc((len + 1) * sizeof(char));
	t(msg == NULL);
	memcpy(msg, message, len * sizeof(char));
	msg[len] = 0;
	/* BEGIN run as in a separate thread */
	if (pauser_count || is_moc_playing()) {
		char *begin = strchr(msg, ' ');
		ssize_t pid;
		int requests_pause;
		if (begin == NULL)
			goto done;
		*begin++ = 0;
		pid = (ssize_t)atoll(msg);
		if (pid < 1) /* We need a real PID, too bad there is
				no convient way to detect if it dies. */
			goto done;
		if ((strstr(begin, "force-pause ") == begin) || !strcmp(begin, "force-pause"))
			requests_pause = 1;
		else if ((strstr(begin, "unforce-pause ") == begin) || !strcmp(begin, "unforce-pause"))
			requests_pause = 0;
		else
			goto done;
		if ((size_t)pid >= pausers_size) {
			pausers = realloc(pausers, (size_t)(pid + 1) * sizeof(char));
			t(pausers == NULL); /* Let's ignore the memory leak. */
			memset(pausers + pausers_size, 0, ((size_t)(pid + 1) - pausers_size) * sizeof(char));
			pausers_size = (size_t)(pid + 1);
		}
		if (pausers[pid] ^ requests_pause) {
			pauser_count += requests_pause ? 1 : -1;
			pausers[pid] = requests_pause;
			if (pauser_count == (size_t)requests_pause)
				system(requests_pause ? "mocp -P" : "mocp -U");
		}
	}
	/* END run as in a separate thread */
	goto done;
	(void) user_data;

fail:
	perror("monitor");
	return -1;

done:
	free(msg);
	return 1;
}



int main()
{
	bus_t bus;
	t(bus_open(&bus, "/tmp/example-bus", BUS_RDONLY));
	t(bus_read(&bus, callback, NULL));
	bus_close(&bus);
	free(pausers);
	return 0;

fail:
	perror("monitor");
	bus_close(&bus);
	free(pausers);
	return 1;
}