[audio] fix for multiple target support by parsing device-map json configuration
[platform/core/multimedia/mm-hal-interface.git] / testcase / audio / parser.cpp
1 #include <iostream>
2 #include <json.h>
3 #include <assert.h>
4 #include <string.h>
5 #include <string>
6
7 #define DEVICE_FILE_OBJECT                  "device-files"
8 #define DEVICE_TYPE_PROP_PLAYBACK_DEVICES   "playback-devices"
9 #define DEVICE_TYPE_PROP_CAPTURE_DEVICES    "capture-devices"
10 #define DEVICE_TYPE_PROP_DEVICE_STRING      "device-string"
11 #define DEVICE_TYPE_PROP_ROLE               "role"
12
13 /* device-files example
14         device-files : {
15                 playback-devices : [
16                         {
17                                 device-string : alsa:sprdphone,0,
18                                 role : { normal : rate=44100 }
19                         }
20                         {
21                                 device-string : alsa:VIRTUALAUDIOW,0,
22                                 role : { call-voice : rate=16000 channels=1 tsched=0 alternate_rate=16000 }
23                         }
24                 ]
25                 capture-devices : [
26                         {
27                                 device-string : alsa:sprdphone,0,
28                                 role : { normal : rate=44100 }
29                         }
30                 ]
31         }
32 */
33
34 using namespace std;
35
36 class CDeviceMapParser
37 {
38 public:
39         CDeviceMapParser();
40         CDeviceMapParser(const char* map_file);
41         virtual ~CDeviceMapParser();
42
43         void dump_devices();
44
45         void get_playback(string& card, string& device_num, int& rate, int& channels);
46         void get_capture(string& card, string& device_num, int& rate, int& channels);
47
48 private:
49         void open_json(const char* json_file);
50         void close_json();
51         void parse_device_string_object(json_object *device_string_o, string& device_string);
52         void parse_device_role_object(json_object *device_role_o, string& device_params);
53         void parse_device_file_object(json_object *device_file_o, pair<string, string>& device);
54         void parse_device_file_array_object(json_object *device_file_array_o, pair<string, string>& device);
55
56         void parse_playback();
57         void parse_capture();
58         void get_device(string& s, string& card, string& device_num);
59         void get_params(string& s, int& rate, int& channels);
60         void get_single_param(string& s, int& rate, int& channels);
61
62         // FixMe, pair doens't define what is paired clearly....
63         pair<string, string> m_playback; // device_string, device_params
64         pair<string, string> m_capture;  // device_string, device_params
65
66         json_object *m_json_obj;
67         json_object *m_json_device_files_obj;
68 };
69
70 CDeviceMapParser::CDeviceMapParser()
71 {
72         open_json("/etc/pulse/device-map.json");
73 }
74
75 CDeviceMapParser::CDeviceMapParser(const char* map_file)
76 {
77         open_json(map_file);
78 }
79
80 CDeviceMapParser::~CDeviceMapParser()
81 {
82         close_json();
83 }
84
85 void CDeviceMapParser::open_json(const char* json_file)
86 {
87         m_json_obj = json_object_from_file(json_file);
88         if (!m_json_obj) {
89                 cout << "Read device-map " << json_file << " failed" << endl;
90                 return;
91         }
92
93         if (!json_object_object_get_ex(m_json_obj, DEVICE_FILE_OBJECT, &m_json_device_files_obj)) {
94                 cout << "Get device files object failed" << endl;
95                 return;
96         }
97         if (!json_object_is_type(m_json_device_files_obj, json_type_object)) {
98                 cout << "json object type failed" << endl;
99                 json_object_put(m_json_obj);
100                 m_json_obj = NULL;
101                 return;
102         }
103
104         cout << DEVICE_FILE_OBJECT << " : {" << endl;
105 }
106
107 void CDeviceMapParser::close_json()
108 {
109         if (!m_json_obj)
110                 return;
111
112         json_object_put(m_json_obj);
113
114         cout << "}" << endl;
115 }
116
117 void CDeviceMapParser::parse_playback()
118 {
119         json_object *playback_devices_o = NULL;
120
121         if (!json_object_object_get_ex(m_json_device_files_obj, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) {
122                 cout << "failed to get playback" << endl;
123                 return;
124         }
125
126         cout << "  " << DEVICE_TYPE_PROP_PLAYBACK_DEVICES << " : ["  << endl;
127         parse_device_file_array_object(playback_devices_o, m_playback);
128         cout << "  ]" << endl;
129 }
130
131 void CDeviceMapParser::parse_capture()
132 {
133         json_object *capture_devices_o = NULL;
134
135         if (!json_object_object_get_ex(m_json_device_files_obj, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) {
136                 cout << "failed to get capture" << endl;
137                 return;
138         }
139
140         cout << "  " << DEVICE_TYPE_PROP_CAPTURE_DEVICES << " : ["  << endl;
141         parse_device_file_array_object(capture_devices_o, m_capture);
142         cout << "  ]" << endl;
143 }
144
145 void CDeviceMapParser::get_device(string& s, string& card, string& device_num)
146 {
147         // eg. alsa:0,0
148         string delimiter = ",";
149         string s1(s.substr(s.find_last_of(':') + 1));
150
151         // eg. 0,0
152         size_t pos = s1.find(delimiter);
153         string token(s1.substr(0, pos));
154         s1.erase(0, pos + delimiter.length());
155
156         card.assign(token);
157         device_num.assign(s1);
158 }
159
160 void CDeviceMapParser::get_single_param(string& s, int& rate, int& channels)
161 {
162         // eg. rate=44100
163         string delimiter = "=";
164         size_t pos = s.find(delimiter);
165         string token = s.substr(0, pos);
166         s.erase(0, pos + delimiter.length());
167
168         if (token.compare("rate") == 0)
169                 rate = stoi(s);
170         else if (token.compare("channels") == 0)
171                 channels = stoi(s);
172 }
173
174 void CDeviceMapParser::get_params(string& s, int& rate, int& channels)
175 {
176         // eg. rate=44100 channels=1
177         string delimiter = " ";
178         size_t pos = 0;
179         string token;
180         string s1(s);
181
182         while ((pos = s1.find(delimiter)) != string::npos) {
183                 token = s1.substr(0, pos);
184                 get_single_param(token, rate, channels);
185                 s1.erase(0, pos + delimiter.length());
186         }
187         get_single_param(s1, rate, channels);
188 }
189
190
191 void CDeviceMapParser::dump_devices()
192 {
193         string card, device_num;
194         int rate = -1, channels = -1;
195
196         get_playback(card, device_num, rate, channels);
197         get_capture(card, device_num, rate, channels);
198 }
199
200 void CDeviceMapParser::get_playback(string& card, string& device_num, int& rate, int& channels)
201 {
202         parse_playback();
203
204         get_device(m_playback.first, card, device_num);
205         get_params(m_playback.second, rate, channels);
206         cout << "  1. PLAYBACK" << endl;
207         cout << "     > card=" << card << ", device=" << device_num << endl;
208         cout << "     > rate=" << rate << ", channels=" << channels << endl << endl;
209 }
210
211 void CDeviceMapParser::get_capture(string& card, string& device_num, int& rate, int& channels)
212 {
213         parse_capture();
214
215         get_device(m_capture.first, card, device_num);
216         get_params(m_capture.second, rate, channels);
217         cout << "  2. CAPTURE" << endl;
218         cout << "     > card=" << card << ", device=" << device_num << endl;
219         cout << "     > rate=" << rate << ", channels=" << channels << endl;
220 }
221
222 void CDeviceMapParser::parse_device_string_object(json_object *device_string_o, string& device_string)
223 {
224         assert(device_string_o);
225         assert(json_object_is_type(device_string_o, json_type_string));
226
227         // object example
228         //   device-string : alsa:sprdphone,0,
229
230         device_string.assign(json_object_get_string(device_string_o));
231
232         cout << "      " << DEVICE_TYPE_PROP_DEVICE_STRING << " : " << device_string << "," << endl;
233 }
234
235 void CDeviceMapParser::parse_device_role_object(json_object *device_role_o, string& device_params)
236 {
237         struct json_object_iterator it, it_end;
238
239         assert(device_role_o);
240         assert(json_object_is_type(device_role_o, json_type_object));
241
242         // <object example>
243         //   role : { normal : rate=44100 }
244
245         it = json_object_iter_begin(device_role_o);
246         it_end = json_object_iter_end(device_role_o);
247
248         while (!json_object_iter_equal(&it, &it_end)) {
249                 if (strcmp(json_object_iter_peek_name(&it), "normal") == 0) {
250                         device_params.assign(json_object_get_string(json_object_iter_peek_value(&it)));
251                         cout << "      " << DEVICE_TYPE_PROP_ROLE << " : {  normal : " << device_params << " }" << endl;
252                         break;
253                 }
254
255                 json_object_iter_next(&it);
256         }
257 }
258
259 void CDeviceMapParser::parse_device_file_object(json_object *device_file_o, pair<string, string>& device)
260 {
261         json_object *device_file_prop_o = NULL;
262         string device_string, device_param;
263
264         assert(device_file_o);
265         assert(json_object_is_type(device_file_o, json_type_object));
266
267         // <object example>
268         //      device-string : alsa:sprdphone,0,
269         //      role : { normal : rate=44100 }
270
271         // parse role
272         if (!json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) {
273                 cout << "Get device role object failed" << endl;
274                 return;
275         }
276         parse_device_role_object(device_file_prop_o, device_param);
277
278         if (device_param.empty()) {
279                 cout << "      " << "[E] This is not a normal device..skip" << endl;
280                 return;
281         }
282
283         // parse device-string
284         if (!json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_DEVICE_STRING, &device_file_prop_o)) {
285                 cout << "Get device-string object failed" << endl;
286                 return;
287         }
288         parse_device_string_object(device_file_prop_o, device_string);
289
290         // store device information
291         device = make_pair(device_string, device_param);
292 }
293
294 void CDeviceMapParser::parse_device_file_array_object(json_object *device_file_array_o, pair<string, string>& device)
295 {
296         int num, idx;
297         json_object *device_file_o = NULL;
298
299         assert(device_file_array_o);
300         assert(json_object_is_type(device_file_array_o, json_type_array));
301
302         // <object example>
303         //  {
304         //        device-string : alsa:sprdphone,0,
305         //        role : { normal : rate=44100 }
306         //  }
307
308         // ToDo : this might be replaced with iterator such as foreach?
309         num = json_object_array_length(device_file_array_o);
310         for (idx = 0; idx < num; idx++) {
311                 if (!(device_file_o = json_object_array_get_idx(device_file_array_o, idx))) {
312                         cout << "Get device file object failed" << endl;
313                         return;
314                 }
315
316                 cout << "    {" << endl;
317                 parse_device_file_object(device_file_o, device);
318                 cout << "    }" << endl;
319         }
320 }