14a5a4f7f9e38f9f5e7d2fa71df7ddaf47fd01d0
[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
33 /* Avoid the build error related to vconf.h's dependency */
34 #ifndef VCONFKEY_BT_AVC_MODE
35 #define VCONFKEY_BT_AVC_MODE "db/bluetooth/avc_mode"
36 #endif
37
38 #ifndef VCONFKEY_BT_AVC_OFF
39 #define VCONFKEY_BT_AVC_OFF false
40 #endif
41
42 #define ABSOLUTE_VOLUME_MAX 150
43 #define BT_VOLUME_MAX 127
44
45 static unsigned int absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
46 static unsigned int bt_volume = BT_VOLUME_MAX + 1;
47 static unsigned int avc_mode = BT_AVC_OFF;
48
49 static int __bt_audio_get_active_headset_volume(void)
50 {
51         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
52         gboolean connected = FALSE;
53         int volume = -1;
54
55         /* 1. Get active A2DP headset path */
56
57         /* We should modify this function to get the active headset in later */
58         connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
59
60         if (connected == FALSE) {
61                 BT_DBG("There is no active A2DP headset");
62                 return -1;
63         }
64
65         /* 2. Get volume info for active transport for the path */
66
67         /*
68                 _bt_avrcp_transport_get_property(VOLUME, &volume)
69         */
70
71         return volume;
72 }
73
74 static void __bt_audio_notify_avc_mode_changed(unsigned int avc_mode)
75 {
76         GVariant *param = g_variant_new("(u)", avc_mode);
77
78         _bt_send_event(BT_AUDIO_AVC_EVENT,
79                         BLUETOOTH_EVENT_AUDIO_AVC_MODE_CHANGED,
80                         param);
81 }
82
83 static void __bt_audio_set_avc_mode(unsigned int mode)
84 {
85         unsigned int prev_mode = avc_mode;
86
87         if (prev_mode == mode) {
88                 BT_DBG("No avc mode change");
89                 return;
90         }
91
92         BT_ERR("Previous mode [%d], New mode [%d]", prev_mode, mode);
93
94         __bt_audio_notify_avc_mode_changed(mode);
95
96         avc_mode = mode;
97 }
98
99 static void __bt_audio_set_user_avc_value(bool mode)
100 {
101         int volume = 0;
102
103         if (mode == false) {
104                 __bt_audio_set_avc_mode(BT_AVC_OFF);
105                 return;
106         }
107
108         volume = __bt_audio_get_active_headset_volume();
109
110         if (volume == -1) {
111                 __bt_audio_set_avc_mode(BT_AVC_OFF);
112                 return;
113         }
114
115         BT_INFO("The current transport supports AVC : volume [%d]", volume);
116
117         if (volume == 0) {
118                 __bt_audio_set_avc_mode(BT_AVC_NULL);
119         } else {
120                 BT_DBG("BT volume: %d", volume);
121                 __bt_audio_set_avc_mode(BT_AVC_MAX);
122         }
123
124         if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
125                 BT_DBG("synchronize the system and bt volume");
126
127                 /* Add Sync volumes */
128         }
129 }
130
131 static void __bt_audio_user_avc_mode_cb(keynode_t *node, void *data)
132 {
133         int type;
134         bool mode = VCONFKEY_BT_AVC_OFF;
135
136         DBG_SECURE("key=%s", vconf_keynode_get_name(node));
137         type = vconf_keynode_get_type(node);
138
139         if (type == VCONF_TYPE_BOOL) {
140                 mode = vconf_keynode_get_bool(node);
141                 __bt_audio_set_user_avc_value(mode);
142         } else {
143                 BT_ERR("Invaild vconf key type : %d", type);
144         }
145 }
146
147 int _bt_audio_init_absolute_volume_control(void)
148 {
149         absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
150         bt_volume = BT_VOLUME_MAX + 1;
151         avc_mode = BT_AVC_OFF;
152
153         if (vconf_notify_key_changed(VCONFKEY_BT_AVC_MODE,
154                 (vconf_callback_fn)__bt_audio_user_avc_mode_cb, NULL) < 0) {
155                         BT_ERR("Unable to register key handler");
156                         return BLUETOOTH_ERROR_INTERNAL;
157         }
158
159         return BLUETOOTH_ERROR_NONE;
160 }
161
162 void _bt_audio_deinit_absolute_volume_control(void)
163 {
164         absolute_volume = ABSOLUTE_VOLUME_MAX + 1;
165         bt_volume = BT_VOLUME_MAX + 1;
166         avc_mode = BT_AVC_OFF;
167
168         vconf_ignore_key_changed(VCONFKEY_BT_AVC_MODE,
169                         (vconf_callback_fn)__bt_audio_user_avc_mode_cb);
170 }
171
172 int _bt_audio_set_absolute_volume(unsigned int volume)
173 {
174         int result = BLUETOOTH_ERROR_NONE;
175
176         if (avc_mode == BT_AVC_OFF) {
177                 BT_ERR("AVC mode is off");
178                 return BLUETOOTH_ERROR_INTERNAL;
179         }
180
181         /* 1. Translate the absolute volume to bt volume */
182
183         /* Convert system gain to BT
184                 BT volume range : 0 ~ 127
185                 system volume range : 0 ~ 150 */
186
187         bt_volume = 127 * volume / 150;
188
189         /* volume table
190                 system volume : 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150
191                 avrcp_ volume : 0  9 17 26 34 43 51 60 68 77  85  94 102 111 119 127 */
192
193         if (bt_volume > 0 && bt_volume < 127)
194                 bt_volume++;
195
196         /* 2. Notify the bt_volume to transport (BT Headset) */
197
198         /*
199                 _bt_avrcp_transport_set_property(VOLUME, bt_volume)
200         */
201
202         /* 3. Notify the avc mode to the pulseaudio if it is needed */
203         if (volume == 0) {
204                 __bt_audio_set_avc_mode(BT_AVC_NULL);
205         } else {
206                 BT_DBG("BT volume: %d", volume);
207                 __bt_audio_set_avc_mode(BT_AVC_MAX);
208         }
209
210         return result;
211 }
212
213 /* Just return the absolute_volume value */
214 int _bt_audio_get_absolute_volume(unsigned int *volume)
215 {
216         int result = BLUETOOTH_ERROR_NONE;
217
218         if (avc_mode == BT_AVC_OFF) {
219                 BT_ERR("AVC mode is off");
220                 return BLUETOOTH_ERROR_INTERNAL;
221         }
222
223         *volume = absolute_volume;
224
225         return result;
226 }
227
228 int _bt_audio_is_avc_activated(bool *activated)
229 {
230         unsigned int mode = BT_AVC_OFF;
231
232         if (_bt_audio_get_avc_mode(&mode) != BLUETOOTH_ERROR_NONE)
233                 BT_ERR("Fail to get the avc mode");
234
235         *activated = (mode == BT_AVC_OFF) ? false : true;
236
237         return BLUETOOTH_ERROR_NONE;
238 }
239
240 int _bt_audio_get_avc_mode(unsigned int *mode)
241 {
242         int state = 0;
243         int volume = 0;
244
245         /* 1. Get AVC mode in the vconf value */
246         if (vconf_get_bool(VCONFKEY_BT_AVC_MODE, &state) != 0) {
247                 BT_ERR("vconf_get_bool failed");
248                 *mode = BT_AVC_OFF;
249                 return BLUETOOTH_ERROR_INTERNAL;
250         }
251
252         if (state == VCONFKEY_BT_AVC_OFF) {
253                 *mode = BT_AVC_OFF;
254                 return BLUETOOTH_ERROR_NONE;
255         }
256
257         volume = __bt_audio_get_active_headset_volume();
258
259         if (volume == -1) {
260                 *mode = BT_AVC_OFF;
261                 return BLUETOOTH_ERROR_NONE;
262         }
263
264         BT_INFO("The current transport supports AVC : volume [%d]", volume);
265
266         if (volume == 0) {
267                 *mode = BT_AVC_NULL;
268         } else {
269                 BT_DBG("BT volume: %d", volume);
270                 *mode = BT_AVC_MAX;
271         }
272
273         if (absolute_volume > ABSOLUTE_VOLUME_MAX || bt_volume > BT_VOLUME_MAX) {
274                 BT_DBG("synchronize the system and bt volume");
275
276                 /* Add Sync volumes */
277         }
278
279         return BLUETOOTH_ERROR_NONE;
280 }
281
282 /* 1. When a2dp headset is connected, we should set 'AVC' mode internaly */
283 /* 2. If the avc mode is changed, we should inform 'AVC' mode to pulseaudio */
284 /* 3. If BT is off, we should send 'AVC' off mode event for application */
285 /* 4. If BT A2DP is disconnected, we should send 'AVC' off mode event for application */
286