summaryrefslogtreecommitdiffstats
path: root/src/c/libcsd-client.c
blob: 11db08760528fecee27b6b01ac5d9e7715c884d0 (plain)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright 2020 Joey Hewitt <joey@joeyhewitt.com>
 *
 * This file is part of ril_ofono.
 *
 * ril_ofono is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ril_ofono is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ril_ofono.  If not, see <http://www.gnu.org/licenses/>.
 */

// The libcsd-client.so built by this file is loaded by the LineageOS Audio HAL.
// CSD stands for "Core Sound Driver", a service within the modem that handles audio setup
// for telephony.
//
// The original library is properietary, but here we implement a subset of the functions the
// HAL uses, by calling ofono via dbus.

// TODO implement the rest of the interface called in audio_hw.c. This is enough to get a simple
// handset call scenario working.

#define LOG_TAG "ofono libcsd-client"

#include <cutils/log.h>
#include <cutils/properties.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define OFONO_MODEM_PATH "/gobi_0"
#define OFONO_SERVICE_PROPERTY_NAME "init.svc.ofonod"
#define OFONO_INTERFACE_NAME "org.ofono.QualcommCoreSoundDriver_Beta1"
// Note: DBUS_SEND may be used in printf format string
// XXX for some reason print-reply seems to be needed to get it to work at all
#define DBUS_SEND "logwrapper dbus-send --system --print-reply --reply-timeout=2000 --dest=org.ofono " OFONO_MODEM_PATH " " OFONO_INTERFACE_NAME "."

// The sleep period is kind of long, and placed in the loop below such that ofono has time to register the CSD dbus path
#define WAIT_ON_OFONO_SLEEP 5
#define WAIT_ON_OFONO_MAXTRIES 18

// XXX using system() is lazy and ugly, but probably better than building and learning a dbus lib.
// We probably have libdbus built already, but it's own docs say it's painful and shouldn't be used.

static inline int system_failed(int rc) {
	return rc == -1 || !WIFEXITED(rc);
}

static int log_and_call_system(char *cmd) {
	//ALOGD("calling system(%s)", cmd);
	int rc = system(cmd);
	//ALOGD("system(%s) = %d", cmd, rc);
	return rc;
}

static void wait_until_ofono_started(void);

int csd_client_init_lb() {
	wait_until_ofono_started();

	int rc = log_and_call_system(DBUS_SEND "Init");
	if (system_failed(rc)) {
		ALOGE("system() Init failed");
		return -1;
	}
	if (WEXITSTATUS(rc) != 0) {
		ALOGE("Init failed");
		return -1;
	}
	return 0;
}

int csd_client_start_voice(int rx_dev_id, int tx_dev_id, int keep_previous_handles) {
	// I've inferred the meaning of the last parameter. The opensource HAL always passes 1.
	// For 0, ofono would close then re-open and reconfigure the stream and the manager.
	if (!keep_previous_handles) {
		ALOGE("keep_previous_handles must be true");
		return -1;
	}

	char *str;
	if (asprintf(&str, DBUS_SEND "StartVoice uint32:%d uint32:%d", rx_dev_id, tx_dev_id) < 0) {
		ALOGE("asprintf() StartVoice failed");
		return -1;
	}
	int rc = log_and_call_system(str);
	free(str);
	if (system_failed(rc)) {
		ALOGE("system() StartVoice failed");
		return -1;
	}
	if (WEXITSTATUS(rc) != 0) {
		ALOGE("StartVoice failed");
		return -1;
	}
	return 0;
}

int csd_client_stop_voice(int always_1) {
	if (always_1 != 1) {
		ALOGE("unknown parameter passed");
		return -1;
	}

	int rc = log_and_call_system(DBUS_SEND "StopVoice");
	if (system_failed(rc)) {
		ALOGE("system() StopVoice failed");
		return -1;
	}
	if (WEXITSTATUS(rc) != 0) {
		ALOGE("StopVoice failed");
		return -1;
	}
	return 0;
}

static void wait_until_ofono_started(void) {
	char prop_value[PROP_VALUE_MAX];
	unsigned int tries_left = WAIT_ON_OFONO_MAXTRIES;

	ALOGI("waiting for ofono to start");
	do {
		property_get(OFONO_SERVICE_PROPERTY_NAME, prop_value, "");
		sleep(WAIT_ON_OFONO_SLEEP);
	} while(strcmp(prop_value, "running") && --tries_left);

	ALOGI("done waiting for ofono. status = %s", prop_value);
}