blob: 61ed5d0b11e15ceba92564941c5be8ac29dac26f [file] [log] [blame]
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +01001/*
2 * Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "audio_hw_audience"
18#define LOG_NDEBUG 0
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23
24#include <cutils/log.h>
25#include <audience-routes.h>
26
27#include "audience.h"
28
29/*
30 * Writes an Integer to a file.
31 *
32 * @param path The absolute path string.
33 * @param value The Integer value to be written.
Christopher N. Hessed483dd72017-04-02 14:06:24 +020034 * @return 0 on success, errno on error.
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +010035 */
36static int write_int(char const *path, const int value)
37{
Christopher N. Hessed483dd72017-04-02 14:06:24 +020038 int fd, len, num_bytes;
39 int ret = 0;
40 char buffer[20];
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +010041
Christopher N. Hesse658f4472017-04-02 13:24:47 +020042 fd = open(path, O_WRONLY);
Christopher N. Hessed483dd72017-04-02 14:06:24 +020043 if (fd < 0) {
44 ret = errno;
45 ALOGE("%s: failed to open %s (%s)", __func__, path, strerror(errno));
46 goto exit;
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +010047 }
Christopher N. Hessed483dd72017-04-02 14:06:24 +020048
49 num_bytes = sprintf(buffer, "%d", value);
50 len = write(fd, buffer, num_bytes);
51 if (len < 0) {
52 ret = errno;
53 ALOGE("%s: failed to write to %s (%s)", __func__, path, strerror(errno));
54 goto exit;
55 }
56
57exit:
58 close(fd);
59 return ret;
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +010060}
61
62/*
63 * Writes the route value to sysfs.
64 *
65 * @param value The long Integer value to be written.
66 * @return 0 on success, -1 or errno on error.
67 */
68static int es_route_value_set(int value)
69{
70 return write_int(SYSFS_PATH_PRESET, value);
71}
72
73/*
74 * Writes the veq control to sysfs.
75 *
76 * @param value The Integer value to be written.
77 * @return 0 on success, -1 or errno on error.
78 */
79static int es_veq_control_set(int value)
80{
81 return write_int(SYSFS_PATH_VEQ, value);
82}
83
84/*
85 * Writes the extra volume to sysfs.
86 *
87 * @param value The Integer value to be written.
88 * @return 0 on success, -1 or errno on error.
89 */
90static int es_extra_volume_set(int value)
91{
92 return write_int(SYSFS_PATH_EXTRAVOLUME, value);
93}
94
95/*
96 * Convertes an out_device from the session to an earSmart compatible route.
97 *
98 * @param out_device The output device to be converted.
99 * @return Audience earSmart route, coded as long Integer.
100 */
101static long es_device_to_route(struct voice_session *session)
102{
103 long ret;
104 long nb_route;
105 long wb_route;
106
107 switch(session->out_device) {
108 case AUDIO_DEVICE_OUT_EARPIECE:
109 nb_route = Call_CT_NB;
110 wb_route = Call_CT_WB;
111 break;
112 case AUDIO_DEVICE_OUT_SPEAKER:
113 nb_route = Call_FT_NB;
114 wb_route = Call_FT_WB;
115 break;
116 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
117 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
118 nb_route = Call_HS_NB;
119 wb_route = Call_HS_WB;
120 break;
121 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
122 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
123 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
124 nb_route = Call_BT_NB;
125 wb_route = Call_BT_WB;
126 break;
127 default:
128 /* if output device isn't supported, use earpiece by default */
Christopher N. Hesse70524602017-04-02 13:19:36 +0200129 ALOGE("%s: unknown output device: %d, defaulting to earpiece", __func__,
130 session->out_device);
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +0100131 nb_route = Call_CT_NB;
132 wb_route = Call_CT_WB;
133 break;
134 }
135
136 /* TODO: Handle wb_amr=2 */
137 if (session->wb_amr_type >= 1) {
138 ret = wb_route;
139 } else {
140 ret = nb_route;
141 }
142
143 ALOGV("%s: converting out_device=%d to %s route: %ld", __func__, session->out_device,
144 ret == wb_route ? "Wide Band" : "Narrow Band", ret);
145 return ret;
146}
147
148/*
149 * Configures and enables the Audience earSmart IC.
150 *
151 * @param session Reference to the active voice call session.
152 * @return @return 0 on success, -1 or errno on error.
153 */
154int es_start_voice_session(struct voice_session *session)
155{
156 int ret;
157 long es_route = es_device_to_route(session);
158
159 /* TODO: Calculate these */
160 int extra_volume = 0;
161 int veq_control = 4;
162
163 /*
164 * The control flow for audience earSmart chip is as follows:
165 *
166 * route_value >> power_control(internal) >> extra_volume >> veq_control
167 */
168 ret = es_route_value_set(es_route);
169 if (ret != 0) {
170 ALOGE("%s: es_route_value_set(%ld) failed with code: %d", __func__, es_route, ret);
171 goto exit;
172 }
173 ret = es_extra_volume_set(extra_volume);
174 if (ret != 0) {
175 ALOGE("%s: es_extra_volume_set(%d) failed with code: %d", __func__, extra_volume, ret);
176 goto exit;
177 }
178 ret = es_veq_control_set(veq_control);
179 if (ret != 0) {
180 ALOGE("%s: es_veq_control_set(%d) failed with code: %d", __func__, veq_control, ret);
181 goto exit;
182 }
183
184exit:
185 return ret;
186}
187
188/*
189 * Disables the Audience earSmart IC.
190 */
191void es_stop_voice_session()
192{
193 /* This will cancel any pending workers, stop the stream and send the IC to sleep */
194 es_route_value_set(AUDIENCE_SLEEP);
195}