From: Seungbae Shin Date: Fri, 31 Aug 2018 11:24:08 +0000 (+0900) Subject: [audio] fix for multiple target support by parsing device-map json configuration X-Git-Tag: accepted/tizen/unified/20180904.180637^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=910c47d1aac9c0c497698f2c71456fabcfca4a7b;p=platform%2Fcore%2Fmultimedia%2Fmm-hal-interface.git [audio] fix for multiple target support by parsing device-map json configuration [Version] 0.0.16 [Profile] Common [Issue Type] Add [Dependency module] N/A Change-Id: I66909ac9942212536c5a88410ace58773536b401 --- diff --git a/configure.ac b/configure.ac index 330e936..e5c30b7 100755 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,8 @@ AC_SUBST(TBM_LIBS) PKG_CHECK_MODULES([GST_ALLOCATORS], [gstreamer-allocators-1.0]) +PKG_CHECK_MODULES(LIBJSON, [ json-c >= 0.11 ]) + # Checks for library functions. AC_CONFIG_FILES([ Makefile diff --git a/packaging/mm-hal-interface.spec b/packaging/mm-hal-interface.spec index 9bd31b1..5592c56 100755 --- a/packaging/mm-hal-interface.spec +++ b/packaging/mm-hal-interface.spec @@ -1,6 +1,6 @@ Name: mm-hal-interface Summary: Multimedia HAL Interface -Version: 0.0.15 +Version: 0.0.16 Release: 0 Group: Multimedia/Development License: Apache-2.0 @@ -15,6 +15,7 @@ BuildRequires: pkgconfig(libtbm) BuildRequires: pkgconfig(gstreamer-1.0) BuildRequires: pkgconfig(gstreamer-plugins-base-1.0) BuildRequires: pkgconfig(iniparser) +BuildRequires: pkgconfig(json-c) %description Multimedia framework hardware abstraction layer interface package. diff --git a/testcase/audio/Makefile.am b/testcase/audio/Makefile.am index 779de11..9bbb5e0 100644 --- a/testcase/audio/Makefile.am +++ b/testcase/audio/Makefile.am @@ -2,11 +2,13 @@ bin_PROGRAMS = audio_haltests audio_haltests_SOURCES = \ - audio_haltests.cpp + audio_haltests.cpp \ + parser.cpp audio_haltests_CPPFLAGS = \ $(DLOG_CFLAGS)\ $(SYSTEM_INFO_CFLAGS)\ + $(LIBJSON_CFLAGS)\ -I$(srcdir)/../../include/audio audio_haltests_LDADD = \ @@ -14,5 +16,6 @@ audio_haltests_LDADD = \ -lgtest\ $(top_builddir)/src/audio/libaudio_hal_interface.la\ $(DLOG_LIBS)\ + $(LIBJSON_LIBS)\ $(SYSTEM_INFO_LIBS) diff --git a/testcase/audio/audio_haltests.cpp b/testcase/audio/audio_haltests.cpp index 4a9f628..0e21ad3 100644 --- a/testcase/audio/audio_haltests.cpp +++ b/testcase/audio/audio_haltests.cpp @@ -31,6 +31,8 @@ #include #include +#include "parser.hh" + using namespace std; #define USE_IFSTREAM @@ -88,10 +90,8 @@ class AudioHalTest : public testing::Test // Todo : following value may vary depends on targets const int default_frames = 6400; const int default_periods = 5; - - // ToDo : following should be changed in runtime - const string default_card = "sprdphone"; - const string default_device = "0"; + const int default_rate = 44100; + const int default_channels = 2; // ToDo : following types may need to be fixed. const array vol_types = { "system", "notification", "alarm", "ringtone", @@ -103,10 +103,6 @@ void AudioHalTest::SetUp() { m_h = nullptr; - m_spec.format = AUDIO_SAMPLE_S16LE; - m_spec.rate = 44100; - m_spec.channels = 2; - int32_t ret = audio_hal_interface_init(&m_h); if (ret != AUDIO_HAL_SUCCESS) cout << "audio hal init failed : " << ret << endl; @@ -857,9 +853,19 @@ TEST_F(AudioHalTest, PcmGetFdP) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; + SetRouteToSpeaker(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -894,10 +900,19 @@ TEST_F(AudioHalTest, PcmGetFdN) // check for fd pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; SetRouteToSpeaker(); - ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -924,10 +939,19 @@ TEST_F(AudioHalTest, PcmGetFdN) TEST_F(AudioHalTest, PcmOpenWriteCloseP) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; SetRouteToSpeaker(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -960,10 +984,19 @@ TEST_F(AudioHalTest, PcmOpenWriteCloseP) TEST_F(AudioHalTest, PcmOpenReadCloseP) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_capture(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; SetRouteToMicrophone(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_IN, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -1015,10 +1048,19 @@ TEST_F(AudioHalTest, PcmRecoverN) TEST_F(AudioHalTest, PcmSetParamP) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; SetRouteToSpeaker(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -1046,10 +1088,19 @@ TEST_F(AudioHalTest, PcmSetParamP) TEST_F(AudioHalTest, PcmSetParamN) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; SetRouteToSpeaker(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); @@ -1076,10 +1127,19 @@ TEST_F(AudioHalTest, PcmSetParamN) TEST_F(AudioHalTest, PcmGetParamP) { pcm_handle pcm_h = nullptr; + string card, dev; + int rate = default_rate, channels = default_channels; + + CDeviceMapParser parser; + parser.get_playback(card, dev, rate, channels); + + m_spec.format = AUDIO_SAMPLE_S16LE; + m_spec.rate = rate; + m_spec.channels = channels; // Precondition SetRouteToSpeaker(); - int32_t ret = audio_hal_interface_pcm_open(m_h, default_card.c_str(), default_device.c_str(), + int32_t ret = audio_hal_interface_pcm_open(m_h, card.c_str(), dev.c_str(), DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods, &pcm_h); ASSERT_EQ(ret, AUDIO_HAL_SUCCESS); diff --git a/testcase/audio/parser.cpp b/testcase/audio/parser.cpp new file mode 100644 index 0000000..05099ee --- /dev/null +++ b/testcase/audio/parser.cpp @@ -0,0 +1,320 @@ +#include +#include +#include +#include +#include + +#define DEVICE_FILE_OBJECT "device-files" +#define DEVICE_TYPE_PROP_PLAYBACK_DEVICES "playback-devices" +#define DEVICE_TYPE_PROP_CAPTURE_DEVICES "capture-devices" +#define DEVICE_TYPE_PROP_DEVICE_STRING "device-string" +#define DEVICE_TYPE_PROP_ROLE "role" + +/* device-files example + device-files : { + playback-devices : [ + { + device-string : alsa:sprdphone,0, + role : { normal : rate=44100 } + } + { + device-string : alsa:VIRTUALAUDIOW,0, + role : { call-voice : rate=16000 channels=1 tsched=0 alternate_rate=16000 } + } + ] + capture-devices : [ + { + device-string : alsa:sprdphone,0, + role : { normal : rate=44100 } + } + ] + } +*/ + +using namespace std; + +class CDeviceMapParser +{ +public: + CDeviceMapParser(); + CDeviceMapParser(const char* map_file); + virtual ~CDeviceMapParser(); + + void dump_devices(); + + void get_playback(string& card, string& device_num, int& rate, int& channels); + void get_capture(string& card, string& device_num, int& rate, int& channels); + +private: + void open_json(const char* json_file); + void close_json(); + void parse_device_string_object(json_object *device_string_o, string& device_string); + void parse_device_role_object(json_object *device_role_o, string& device_params); + void parse_device_file_object(json_object *device_file_o, pair& device); + void parse_device_file_array_object(json_object *device_file_array_o, pair& device); + + void parse_playback(); + void parse_capture(); + void get_device(string& s, string& card, string& device_num); + void get_params(string& s, int& rate, int& channels); + void get_single_param(string& s, int& rate, int& channels); + + // FixMe, pair doens't define what is paired clearly.... + pair m_playback; // device_string, device_params + pair m_capture; // device_string, device_params + + json_object *m_json_obj; + json_object *m_json_device_files_obj; +}; + +CDeviceMapParser::CDeviceMapParser() +{ + open_json("/etc/pulse/device-map.json"); +} + +CDeviceMapParser::CDeviceMapParser(const char* map_file) +{ + open_json(map_file); +} + +CDeviceMapParser::~CDeviceMapParser() +{ + close_json(); +} + +void CDeviceMapParser::open_json(const char* json_file) +{ + m_json_obj = json_object_from_file(json_file); + if (!m_json_obj) { + cout << "Read device-map " << json_file << " failed" << endl; + return; + } + + if (!json_object_object_get_ex(m_json_obj, DEVICE_FILE_OBJECT, &m_json_device_files_obj)) { + cout << "Get device files object failed" << endl; + return; + } + if (!json_object_is_type(m_json_device_files_obj, json_type_object)) { + cout << "json object type failed" << endl; + json_object_put(m_json_obj); + m_json_obj = NULL; + return; + } + + cout << DEVICE_FILE_OBJECT << " : {" << endl; +} + +void CDeviceMapParser::close_json() +{ + if (!m_json_obj) + return; + + json_object_put(m_json_obj); + + cout << "}" << endl; +} + +void CDeviceMapParser::parse_playback() +{ + json_object *playback_devices_o = NULL; + + if (!json_object_object_get_ex(m_json_device_files_obj, DEVICE_TYPE_PROP_PLAYBACK_DEVICES, &playback_devices_o)) { + cout << "failed to get playback" << endl; + return; + } + + cout << " " << DEVICE_TYPE_PROP_PLAYBACK_DEVICES << " : [" << endl; + parse_device_file_array_object(playback_devices_o, m_playback); + cout << " ]" << endl; +} + +void CDeviceMapParser::parse_capture() +{ + json_object *capture_devices_o = NULL; + + if (!json_object_object_get_ex(m_json_device_files_obj, DEVICE_TYPE_PROP_CAPTURE_DEVICES, &capture_devices_o)) { + cout << "failed to get capture" << endl; + return; + } + + cout << " " << DEVICE_TYPE_PROP_CAPTURE_DEVICES << " : [" << endl; + parse_device_file_array_object(capture_devices_o, m_capture); + cout << " ]" << endl; +} + +void CDeviceMapParser::get_device(string& s, string& card, string& device_num) +{ + // eg. alsa:0,0 + string delimiter = ","; + string s1(s.substr(s.find_last_of(':') + 1)); + + // eg. 0,0 + size_t pos = s1.find(delimiter); + string token(s1.substr(0, pos)); + s1.erase(0, pos + delimiter.length()); + + card.assign(token); + device_num.assign(s1); +} + +void CDeviceMapParser::get_single_param(string& s, int& rate, int& channels) +{ + // eg. rate=44100 + string delimiter = "="; + size_t pos = s.find(delimiter); + string token = s.substr(0, pos); + s.erase(0, pos + delimiter.length()); + + if (token.compare("rate") == 0) + rate = stoi(s); + else if (token.compare("channels") == 0) + channels = stoi(s); +} + +void CDeviceMapParser::get_params(string& s, int& rate, int& channels) +{ + // eg. rate=44100 channels=1 + string delimiter = " "; + size_t pos = 0; + string token; + string s1(s); + + while ((pos = s1.find(delimiter)) != string::npos) { + token = s1.substr(0, pos); + get_single_param(token, rate, channels); + s1.erase(0, pos + delimiter.length()); + } + get_single_param(s1, rate, channels); +} + + +void CDeviceMapParser::dump_devices() +{ + string card, device_num; + int rate = -1, channels = -1; + + get_playback(card, device_num, rate, channels); + get_capture(card, device_num, rate, channels); +} + +void CDeviceMapParser::get_playback(string& card, string& device_num, int& rate, int& channels) +{ + parse_playback(); + + get_device(m_playback.first, card, device_num); + get_params(m_playback.second, rate, channels); + cout << " 1. PLAYBACK" << endl; + cout << " > card=" << card << ", device=" << device_num << endl; + cout << " > rate=" << rate << ", channels=" << channels << endl << endl; +} + +void CDeviceMapParser::get_capture(string& card, string& device_num, int& rate, int& channels) +{ + parse_capture(); + + get_device(m_capture.first, card, device_num); + get_params(m_capture.second, rate, channels); + cout << " 2. CAPTURE" << endl; + cout << " > card=" << card << ", device=" << device_num << endl; + cout << " > rate=" << rate << ", channels=" << channels << endl; +} + +void CDeviceMapParser::parse_device_string_object(json_object *device_string_o, string& device_string) +{ + assert(device_string_o); + assert(json_object_is_type(device_string_o, json_type_string)); + + // object example + // device-string : alsa:sprdphone,0, + + device_string.assign(json_object_get_string(device_string_o)); + + cout << " " << DEVICE_TYPE_PROP_DEVICE_STRING << " : " << device_string << "," << endl; +} + +void CDeviceMapParser::parse_device_role_object(json_object *device_role_o, string& device_params) +{ + struct json_object_iterator it, it_end; + + assert(device_role_o); + assert(json_object_is_type(device_role_o, json_type_object)); + + // + // role : { normal : rate=44100 } + + it = json_object_iter_begin(device_role_o); + it_end = json_object_iter_end(device_role_o); + + while (!json_object_iter_equal(&it, &it_end)) { + if (strcmp(json_object_iter_peek_name(&it), "normal") == 0) { + device_params.assign(json_object_get_string(json_object_iter_peek_value(&it))); + cout << " " << DEVICE_TYPE_PROP_ROLE << " : { normal : " << device_params << " }" << endl; + break; + } + + json_object_iter_next(&it); + } +} + +void CDeviceMapParser::parse_device_file_object(json_object *device_file_o, pair& device) +{ + json_object *device_file_prop_o = NULL; + string device_string, device_param; + + assert(device_file_o); + assert(json_object_is_type(device_file_o, json_type_object)); + + // + // device-string : alsa:sprdphone,0, + // role : { normal : rate=44100 } + + // parse role + if (!json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_ROLE, &device_file_prop_o)) { + cout << "Get device role object failed" << endl; + return; + } + parse_device_role_object(device_file_prop_o, device_param); + + if (device_param.empty()) { + cout << " " << "[E] This is not a normal device..skip" << endl; + return; + } + + // parse device-string + if (!json_object_object_get_ex(device_file_o, DEVICE_TYPE_PROP_DEVICE_STRING, &device_file_prop_o)) { + cout << "Get device-string object failed" << endl; + return; + } + parse_device_string_object(device_file_prop_o, device_string); + + // store device information + device = make_pair(device_string, device_param); +} + +void CDeviceMapParser::parse_device_file_array_object(json_object *device_file_array_o, pair& device) +{ + int num, idx; + json_object *device_file_o = NULL; + + assert(device_file_array_o); + assert(json_object_is_type(device_file_array_o, json_type_array)); + + // + // { + // device-string : alsa:sprdphone,0, + // role : { normal : rate=44100 } + // } + + // ToDo : this might be replaced with iterator such as foreach? + num = json_object_array_length(device_file_array_o); + for (idx = 0; idx < num; idx++) { + if (!(device_file_o = json_object_array_get_idx(device_file_array_o, idx))) { + cout << "Get device file object failed" << endl; + return; + } + + cout << " {" << endl; + parse_device_file_object(device_file_o, device); + cout << " }" << endl; + } +} diff --git a/testcase/audio/parser.hh b/testcase/audio/parser.hh new file mode 100644 index 0000000..b53ba89 --- /dev/null +++ b/testcase/audio/parser.hh @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +using namespace std; + +class CDeviceMapParser +{ +public: + CDeviceMapParser(); + CDeviceMapParser(const char* map_file); + virtual ~CDeviceMapParser(); + + void dump_devices(); + + void get_playback(string& card, string& device_num, int& rate, int& channels); + void get_capture(string& card, string& device_num, int& rate, int& channels); + +private: + void open_json(const char* json_file); + void close_json(); + void parse_device_string_object(json_object *device_string_o, string& device_string); + void parse_device_role_object(json_object *device_role_o, string& device_params); + void parse_device_file_object(json_object *device_file_o, pair& device); + void parse_device_file_array_object(json_object *device_file_array_o, pair& device); + + void parse_playback(); + void parse_capture(); + void get_device(string& s, string& card, string& device_num); + void get_params(string& s, int& rate, int& channels); + void get_single_param(string& s, int& rate, int& channels); + + // FixMe, pair doens't define what is paired clearly.... + pair m_playback; // device_string, device_params + pair m_capture; // device_string, device_params + + json_object *m_json_obj; + json_object *m_json_device_files_obj; +}; + +