54e2e46617d99299c4ee041eac8debb7e9cc6295
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / audio / bt-service-absolute-volume.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Dohyun Pyun <dh79.pyun@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <vconf.h>
23 #include <vconf-internal-keys.h>
24
25 #include <oal-event.h>
26 #include <oal-hardware.h>
27 #include <oal-audio-src.h>
28
29 #include "bt-service-common.h"
30 #include "bt-service-audio-common.h"
31 #include "bt-service-event.h"
32 #include "bt-service-avrcp-tg.h"
33
34 /* Avoid the build error related to vconf.h's dependency */
35 #ifndef VCONFKEY_BT_AVC_MODE
36 #define VCONFKEY_BT_AVC_MODE "db/bluetooth/avc_mode"
37 #endif
38
39 #ifndef VCONFKEY_BT_AVC_OFF
40 #define VCONFKEY_BT_AVC_OFF false
41 #endif
42
43 #define ABSOLUTE_VOLUME_MAX 150
44 #define BT_VOLUME_MAX 127
45
46 static unsigned int absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
47 static unsigned int bt_volume = BT_VOLUME_MAX + 1;
48 static unsigned int avc_mode = BT_AVC_OFF;
49
50 static void __bt_audio_covert_system_to_bt_volume(unsigned int sys_vol, unsigned int *bt_vol)
51 {
52         /* Convert system gain to BT
53                 BT volume range : 0 ~ 127
54                 system volume range : 0 ~ 150 */
55
56         *bt_vol = 127 * ((float)sys_vol / 150);
57
58         /* volume table
59                 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
60                 avrcp  volume : 0  9 17 26 34 43 51 60 68 77  85  94 102 111 119 127 */
61
62         if (*bt_vol > 0 && *bt_vol < 127)
63                 *bt_vol = *bt_vol + 1;
64
65         BT_DBG("System volume [%d], BT volume [%d]", sys_vol, *bt_vol);
66 }
67
68 static void __bt_audio_covert_bt_to_system_volume(unsigned int bt_vol, unsigned int *sys_vol)
69 {
70         /* Convert BT gain to system
71                 BT volume range : 0 ~ 127
72                 system volume range : 0 ~ 150 */
73
74         *sys_vol = 150 * ((float)bt_vol / 127);
75
76         /* volume table
77                 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
78                 avrcp  volume : 0  9 17 26 34 43 51 60 68 77  85  94 102 111 119 127 */
79
80         if (*sys_vol > 0 && *sys_vol < 150)
81                 *sys_vol = *sys_vol + 1;
82
83         BT_DBG("System volume [%d], BT volume [%d]", *sys_vol, bt_vol);
84 }
85
86 static int __bt_audio_get_active_headset_volume(void)
87 {
88         int result = BLUETOOTH_ERROR_NONE;
89         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
90         bluetooth_device_address_t device_address;
91         gboolean connected = FALSE;
92         unsigned int volume = BT_VOLUME_MAX + 1;
93
94         /* 1. Get active A2DP headset path */
95
96         /* We should modify this function to get the active headset in later */
97         connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
98
99         if (connected == FALSE) {
100                 BT_DBG("There is no active A2DP headset");
101                 return -1;
102         }
103
104         _bt_convert_addr_string_to_type(device_address.addr, connected_address);
105
106         /* 2. Get volume info for active transport for the path */
107         result = _bt_avrcp_target_get_volume(&device_address, &volume);
108         if (result != BLUETOOTH_ERROR_NONE) {
109                 BT_ERR("Fail to notify BT volume to headset");
110                 return -1;
111         }
112
113         if (volume > BT_VOLUME_MAX) {
114                 BT_DBG("Absolute Volume is not set in transport");
115                 return -1;
116         }
117
118         return volume;
119 }
120
121 static void __bt_audio_notify_avc_mode_changed(unsigned int avc_mode)
122 {
123         GVariant *param = g_variant_new("(u)", avc_mode);
124
125         _bt_send_event(BT_AUDIO_AVC_EVENT,
126                         BLUETOOTH_EVENT_AUDIO_AVC_MODE_CHANGED,
127                         param);
128 }
129
130 static void __bt_audio_set_avc_mode(unsigned int mode)
131 {
132         unsigned int prev_mode = avc_mode;
133
134         if (prev_mode == mode) {
135                 BT_DBG("No avc mode change");
136                 return;
137         }
138
139         BT_ERR("Previous mode [%d], New mode [%d]", prev_mode, mode);
140
141         __bt_audio_notify_avc_mode_changed(mode);
142
143         avc_mode = mode;
144 }
145
146 static void __bt_audio_sync_absolute_volume(unsigned int bt_vol)
147 {
148         if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
149                 unsigned int sys_vol = 0;
150
151                 BT_DBG("synchronize the system and bt volume");
152
153                 __bt_audio_covert_bt_to_system_volume(bt_vol, &sys_vol);
154
155                 bt_volume = bt_vol;
156                 absolute_volume = sys_vol;
157         }
158 }
159
160 static void __bt_audio_set_user_avc_value(bool mode)
161 {
162         int volume = 0;
163
164         if (mode == false) {
165                 __bt_audio_set_avc_mode(BT_AVC_OFF);
166                 return;
167         }
168
169         volume = __bt_audio_get_active_headset_volume();
170
171         if (volume == -1) {
172                 __bt_audio_set_avc_mode(BT_AVC_OFF);
173                 return;
174         }
175
176         BT_INFO("The current transport supports AVC : volume [%d]", volume);
177
178         if (volume == 0) {
179                 __bt_audio_set_avc_mode(BT_AVC_NULL);
180         } else {
181                 BT_DBG("BT volume: %d", volume);
182                 __bt_audio_set_avc_mode(BT_AVC_MAX);
183         }
184
185         __bt_audio_sync_absolute_volume(volume);
186 }
187
188 static void __bt_audio_user_avc_mode_cb(keynode_t *node, void *data)
189 {
190         int type;
191         bool mode = VCONFKEY_BT_AVC_OFF;
192
193         DBG_SECURE("key=%s", vconf_keynode_get_name(node));
194         type = vconf_keynode_get_type(node);
195
196         if (type == VCONF_TYPE_BOOL) {
197                 mode = vconf_keynode_get_bool(node);
198                 __bt_audio_set_user_avc_value(mode);
199         } else {
200                 BT_ERR("Invaild vconf key type : %d", type);
201         }
202 }
203
204 int _bt_audio_init_absolute_volume_control(void)
205 {
206         absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
207         bt_volume = BT_VOLUME_MAX + 1;
208         avc_mode = BT_AVC_OFF;
209
210         if (vconf_notify_key_changed(VCONFKEY_BT_AVC_MODE,
211                 (vconf_callback_fn)__bt_audio_user_avc_mode_cb, NULL) < 0) {
212                         BT_ERR("Unable to register key handler");
213                         return BLUETOOTH_ERROR_INTERNAL;
214         }
215
216         return BLUETOOTH_ERROR_NONE;
217 }
218
219 void _bt_audio_deinit_absolute_volume_control(void)
220 {
221         absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
222         bt_volume = BT_VOLUME_MAX + 1;
223         avc_mode = BT_AVC_OFF;
224
225         vconf_ignore_key_changed(VCONFKEY_BT_AVC_MODE,
226                         (vconf_callback_fn)__bt_audio_user_avc_mode_cb);
227 }
228
229 int _bt_audio_set_absolute_volume(unsigned int volume)
230 {
231         int result = BLUETOOTH_ERROR_NONE;
232         unsigned int bt_vol = 0;
233         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
234         bluetooth_device_address_t device_address;
235         gboolean connected = FALSE;
236
237         if (volume > 150) {
238                 BT_ERR("The volume exceeded 150");
239                 return BLUETOOTH_ERROR_INVALID_PARAM;
240         }
241
242         if (avc_mode == BT_AVC_OFF) {
243                 BT_ERR("AVC mode is off");
244                 return BLUETOOTH_ERROR_INTERNAL;
245         }
246
247         /* We should modify this function to get the active headset in later */
248         connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
249
250         if (connected == FALSE) {
251                 BT_DBG("There is no active A2DP headset");
252                 return BLUETOOTH_ERROR_NOT_CONNECTED;
253         }
254
255         _bt_convert_addr_string_to_type(device_address.addr, connected_address);
256
257         /* 1. Translate the absolute volume to bt volume */
258         __bt_audio_covert_system_to_bt_volume(volume, &bt_vol);
259
260         bt_volume = bt_vol;
261         absolute_volume = volume;
262
263         /* 2. Notify the bt_volume to transport (BT Headset) */
264         result = _bt_avrcp_target_notify_volume(&device_address, bt_volume);
265         if (result != BLUETOOTH_ERROR_NONE)
266                 BT_ERR("Fail to notify BT volume to headset");
267
268         /* 3. Notify the avc mode to the pulseaudio if it is needed */
269         if (volume == 0) {
270                 __bt_audio_set_avc_mode(BT_AVC_NULL);
271         } else {
272                 BT_DBG("System volume: %d", volume);
273                 __bt_audio_set_avc_mode(BT_AVC_MAX);
274         }
275
276         return result;
277 }
278
279 /* Just return the absolute_volume value */
280 int _bt_audio_get_absolute_volume(unsigned int *volume)
281 {
282         int result = BLUETOOTH_ERROR_NONE;
283
284         if (avc_mode == BT_AVC_OFF) {
285                 BT_ERR("AVC mode is off");
286                 return BLUETOOTH_ERROR_INTERNAL;
287         }
288
289         *volume = absolute_volume;
290
291         return result;
292 }
293
294 int _bt_audio_is_avc_activated(bool *activated)
295 {
296         unsigned int mode = BT_AVC_OFF;
297
298         if (_bt_audio_get_avc_mode(&mode) != BLUETOOTH_ERROR_NONE)
299                 BT_ERR("Fail to get the avc mode");
300
301         *activated = (mode == BT_AVC_OFF) ? false : true;
302
303         return BLUETOOTH_ERROR_NONE;
304 }
305
306 int _bt_audio_get_avc_mode(unsigned int *mode)
307 {
308         int state = 0;
309         int volume = 0;
310
311         /* 1. Get AVC mode in the vconf value */
312         if (vconf_get_bool(VCONFKEY_BT_AVC_MODE, &state) != 0) {
313                 BT_ERR("vconf_get_bool failed");
314                 *mode = BT_AVC_OFF;
315                 return BLUETOOTH_ERROR_INTERNAL;
316         }
317
318         if (state == VCONFKEY_BT_AVC_OFF) {
319                 *mode = BT_AVC_OFF;
320                 return BLUETOOTH_ERROR_NONE;
321         }
322
323         volume = __bt_audio_get_active_headset_volume();
324
325         if (volume == -1) {
326                 *mode = BT_AVC_OFF;
327                 return BLUETOOTH_ERROR_NONE;
328         }
329
330         BT_INFO("The current transport supports AVC : volume [%d]", volume);
331
332         if (volume == 0) {
333                 *mode = BT_AVC_NULL;
334         } else {
335                 BT_DBG("BT volume: %d", volume);
336                 *mode = BT_AVC_MAX;
337         }
338
339         __bt_audio_sync_absolute_volume(volume);
340
341         return BLUETOOTH_ERROR_NONE;
342 }
343
344 /* 1. When a2dp headset is connected, we should set 'AVC' mode internaly */
345 /* 2. If the avc mode is changed, we should inform 'AVC' mode to pulseaudio */
346 /* 3. If BT is off, we should send 'AVC' off mode event for application */
347 /* 4. If BT A2DP is disconnected, we should send 'AVC' off mode event for application */
348 /* 5. When we recieve the volume changed, we shuld sync up the volume */
349