Add testcases for audio-hal-interfaces 62/255262/10
authorJaechul Lee <jcsing.lee@samsung.com>
Tue, 16 Mar 2021 04:24:47 +0000 (13:24 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Fri, 2 Apr 2021 04:24:56 +0000 (13:24 +0900)
[Version] 0.0.4
[Issue Type] Testcase

Change-Id: Id79ce8ef4c96b32dd874fb92bb8b5eb4364667a5
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
CMakeLists.txt
hal-api-audio-haltests.manifest [new file with mode: 0644]
packaging/hal-api-audio.spec
testcase/CMakeLists.txt [new file with mode: 0644]
testcase/audio_haltests.cpp [new file with mode: 0644]
testcase/parser.cpp [new file with mode: 0644]
testcase/parser.hh [new file with mode: 0644]
testcase/test_16le_44100_2ch.raw [new file with mode: 0644]

index 7ee91b08a41a4037342333597e085704841e568a..678f9557b59f257edaa09bd737f2efe8038748be 100644 (file)
@@ -1,5 +1,5 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(hal-api-audio C)
+PROJECT(hal-api-audio C CXX)
 
 SET(PREFIX ${CMAKE_INSTALL_PREFIX})
 SET(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}/bin")
@@ -46,3 +46,4 @@ INSTALL(DIRECTORY include/ DESTINATION include/hal
 
 INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIBDIR}/pkgconfig)
 
+ADD_SUBDIRECTORY(testcase)
diff --git a/hal-api-audio-haltests.manifest b/hal-api-audio-haltests.manifest
new file mode 100644 (file)
index 0000000..81ace0c
--- /dev/null
@@ -0,0 +1,6 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
+
index b7e729a466cf70a8d2c06128013c8f345f063d3f..632cf80bbb3904c2b0667fe69a705ac0d74e2007 100644 (file)
@@ -1,6 +1,6 @@
 Name:       hal-api-audio
 Summary:    TIZEN Audio HAL
-Version:    0.0.3
+Version:    0.0.4
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
@@ -9,6 +9,10 @@ Source0:    hal-api-audio-%{version}.tar.gz
 BuildRequires: cmake
 BuildRequires: pkgconfig(hal-api-common)
 BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(json-c)
+BuildRequires: pkgconfig(gmock)
 
 %description
 TIZEN Audio HAL
@@ -21,6 +25,14 @@ Requires:   %{name} = %{version}-%{release}
 %description devel
 %{name} interface development package for product vendor developer
 
+%package    haltests
+Summary:    gtest for audio HAL APIs
+Group:      Development/Tools
+Version:    %{version}
+
+%description    haltests
+haltests for audio HAL APIs.
+
 %prep
 %setup -q -n %{name}-%{version}
 %cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_LIBDIR_PREFIX=%{_libdir}
@@ -33,6 +45,8 @@ export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
 make %{?jobs:-j%jobs}
 
 %install
+install -d -m 755 %{buildroot}%{_datadir}/testcase/res/audio/
+install -m 644 testcase/*.raw %{buildroot}%{_datadir}/testcase/res/audio/
 
 %make_install
 
@@ -53,3 +67,10 @@ make %{?jobs:-j%jobs}
 %defattr(-,root,root,-)
 %{_includedir}/hal/*.h
 %{_libdir}/pkgconfig/*.pc
+
+%files haltests
+%defattr(-,root,root,-)
+%manifest %{name}-haltests.manifest
+%{_bindir}/hal/audio-haltests
+%{_datadir}/testcase/res/audio/*
+
diff --git a/testcase/CMakeLists.txt b/testcase/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3de3682
--- /dev/null
@@ -0,0 +1,16 @@
+SET(target "audio-haltests")
+
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(${target} REQUIRED dlog json-c capi-system-info gmock)
+FOREACH(flag ${${target}_CFLAGS})
+    SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}")
+ENDFOREACH()
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror -std=c++0x -pie")
+
+AUX_SOURCE_DIRECTORY(. sources)
+ADD_EXECUTABLE(${target} ${sources})
+TARGET_LINK_LIBRARIES(${target} ${${target}_LDFLAGS} ${PROJECT_NAME} -lpthread)
+
+INSTALL(TARGETS ${target} DESTINATION /usr/bin/hal)
+
diff --git a/testcase/audio_haltests.cpp b/testcase/audio_haltests.cpp
new file mode 100644 (file)
index 0000000..7e6da81
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Seungbae Shin <seungbae.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <array>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+#include <system_info.h>
+
+#include <hal-audio-interface.h>
+#include <hal-audio.h>
+
+#include "parser.hh"
+
+using namespace std;
+
+#define USE_IFSTREAM
+#define DISABLE_DEBUG_LOG
+
+typedef void *pcm_handle;
+
+typedef enum audio_sample_format {
+       AUDIO_SAMPLE_U8,
+       AUDIO_SAMPLE_ALAW,
+       AUDIO_SAMPLE_ULAW,
+       AUDIO_SAMPLE_S16LE,
+       AUDIO_SAMPLE_S16BE,
+       AUDIO_SAMPLE_FLOAT32LE,
+       AUDIO_SAMPLE_FLOAT32BE,
+       AUDIO_SAMPLE_S32LE,
+       AUDIO_SAMPLE_S32BE,
+       AUDIO_SAMPLE_S24LE,
+       AUDIO_SAMPLE_S24BE,
+       AUDIO_SAMPLE_S24_32LE,
+       AUDIO_SAMPLE_S24_32BE,
+       AUDIO_SAMPLE_MAX,
+       AUDIO_SAMPLE_INVALID = -1
+} audio_sample_format_t;
+
+typedef struct {
+       audio_sample_format_t format;
+       uint32_t rate;
+       uint8_t channels;
+} audio_pcm_sample_spec_t;
+
+/*
+ * TestSuite Class
+ */
+class AudioHalTest : public testing::Test
+{
+       public:
+               virtual void SetUp();
+               virtual void TearDown();
+
+       protected:
+               void SetRouteToSpeaker();
+               void SetRouteToMicrophone();
+               int32_t WritePcmFromFile(pcm_handle pcm_h);
+               int32_t ReadPcmFromDevice(pcm_handle pcm_h);
+               uint32_t BytesToFrames(uint32_t bytes, audio_pcm_sample_spec_t *spec);
+               uint32_t BytesToFrames(uint32_t bytes);
+               uint32_t FramesToBytes(uint32_t frames, audio_pcm_sample_spec_t *spec);
+               uint32_t FramesToBytes(uint32_t frames);
+               uint32_t GetDefaultFrames();
+
+               static void HalMessageCallback(const char *name, int value, void *user_data);
+
+               void *m_h;
+               audio_pcm_sample_spec_t m_spec;
+
+               // Todo : following value may vary depends on targets
+               const int default_frames = 6400;
+               const int default_periods = 5;
+               const int default_rate = 44100;
+               const int default_channels = 2;
+
+               // ToDo : following types may need to be fixed.
+               const array<string, 8> vol_types = { "system", "notification", "alarm", "ringtone",
+                                                                                       "media", "call", "voip", "voice" };
+
+};
+
+void AudioHalTest::SetUp()
+{
+       m_h = nullptr;
+
+       int32_t ret = hal_audio_init(&m_h);
+       if (ret != AUDIO_RET_OK)
+               cout << "audio hal init failed : " << ret << endl;
+}
+
+void AudioHalTest::TearDown()
+{
+       if (m_h == nullptr)
+               return;
+
+       int32_t ret = hal_audio_deinit(m_h);
+       if (ret != AUDIO_RET_OK)
+               cout << "audio hal deinit failed : " << ret << endl;
+
+       m_h = nullptr;
+}
+
+void AudioHalTest::SetRouteToSpeaker()
+{
+       audio_route_info info;
+       int32_t num_of_devices = 1;
+
+       memset(&info, 0, sizeof(audio_route_info));
+
+       info.role = "media";
+       info.device_infos = (device_info_s*)malloc(sizeof(device_info_s) * num_of_devices);
+       if (info.device_infos == nullptr) {
+               cout << "malloc error!!! : " << errno << endl;
+               return;
+       }
+       info.device_infos[0].direction = AUDIO_DIRECTION_OUT;
+       info.device_infos[0].type = "builtin-speaker";
+       info.device_infos[0].id = 100;
+       info.num_of_devices = num_of_devices;
+
+       int32_t ret = hal_audio_update_route(m_h, &info);
+       cout << "update route : " << ret << endl;
+
+       free(info.device_infos);
+}
+
+void AudioHalTest::SetRouteToMicrophone()
+{
+       audio_route_info info;
+       int32_t num_of_devices = 1;
+
+       memset(&info, 0, sizeof(audio_route_info));
+
+       info.role = "media";
+       info.device_infos = (device_info_s*)malloc(sizeof(device_info_s) * num_of_devices);
+       if (info.device_infos == nullptr) {
+               cout << "malloc error!!! : " << errno << endl;
+               return;
+       }
+       info.device_infos[0].direction = AUDIO_DIRECTION_IN;
+       info.device_infos[0].type = "builtin-mic";
+       info.device_infos[0].id = 100;
+       info.num_of_devices = num_of_devices;
+
+       int32_t ret = hal_audio_update_route(m_h, &info);
+       cout << "update route : " << ret << endl;
+
+       free(info.device_infos);
+}
+
+int32_t AudioHalTest::WritePcmFromFile(pcm_handle pcm_h)
+{
+       int32_t ret = AUDIO_RET_OK;
+       uint32_t avail_frames = 0;
+       int bytes_read;
+       char buffer[65536];
+
+       const char res_path[] = "/usr/share/testcase/res/audio/test_16le_44100_2ch.raw";
+#ifdef USE_IFSTREAM
+       ifstream fs;
+       fs.open(res_path, fstream::in | fstream::binary);
+       if (fs.fail()) {
+               cout << "Failed to open : " << res_path << endl;
+               return AUDIO_ERR_INTERNAL;
+       }
+#else
+       int fd = open(res_path, O_RDONLY);
+       if (fd == -1) {
+               cout << "Failed to open : " << res_path << ", " << errno << endl;
+               return AUDIO_ERR_INTERNAL;
+       }
+#endif
+
+       cout << "start to play dtmf+noise sounds ( " << res_path << " ) for 5 sec. " << endl;
+
+       while (1) {
+               ret = hal_audio_pcm_avail(m_h, pcm_h, &avail_frames);
+               if (ret == AUDIO_ERR_INTERNAL)
+                       break;
+
+               if (avail_frames == 0) {
+                       usleep(20000); // 20ms
+                       continue;
+               }
+
+#ifdef USE_IFSTREAM
+               fs.read(buffer, FramesToBytes(avail_frames));
+               bytes_read = fs.gcount();
+#else
+               bytes_read = read(fd, buffer, FramesToBytes(avail_frames));
+#endif
+
+               cout << "avail frames : " << avail_frames << ", read_n : " << bytes_read << endl;
+
+               ret = hal_audio_pcm_write(m_h, pcm_h, buffer, BytesToFrames(bytes_read));
+               if (ret == AUDIO_ERR_INTERNAL)
+                       break;
+
+#ifdef USE_IFSTREAM
+               if (!fs.good()) {
+                       if (fs.eof())
+                               cout << "EOS!!!" << endl;
+                       else if (fs.fail() || fs.bad())
+                               cout << "Error..." << endl;
+                       break;
+               }
+#else
+               if (bytes_read < static_cast<int>(FramesToBytes(avail_frames))) {
+                       cout << "EOS!!!" << endl;
+                       break;
+               }
+#endif
+       }
+
+#ifdef USE_IFSTREAM
+       fs.close();
+#else
+       close(fd);
+#endif
+
+       cout << "Done!!!" << endl;
+
+       return ret;
+}
+
+int32_t AudioHalTest::ReadPcmFromDevice(pcm_handle pcm_h)
+{
+       int32_t ret = AUDIO_RET_OK;
+       uint32_t avail_frames = 0;
+       char buffer[65536];
+       int iter_left = 100;
+
+       cout << "start to record for few seconds..." << endl;
+
+       do {
+               ret = hal_audio_pcm_avail(m_h, pcm_h, &avail_frames);
+               if (ret == AUDIO_ERR_INTERNAL)
+                       break;
+
+               if (avail_frames == 0) {
+                       usleep(20000); // 20ms
+                       continue;
+               }
+
+               ret = hal_audio_pcm_read(m_h, pcm_h, buffer, avail_frames);
+               if (ret == AUDIO_ERR_INTERNAL)
+                       break;
+
+               cout << iter_left << ", read success, avail frames : " << avail_frames << endl;
+       } while (--iter_left);
+
+       cout << "Done!!!" << endl;
+
+       return ret;
+}
+
+uint32_t AudioHalTest::BytesToFrames(uint32_t bytes, audio_pcm_sample_spec_t *spec)
+{
+       // ToDo : support various sample format
+       return (spec->format == AUDIO_SAMPLE_S16LE) ? bytes / spec->channels / 2 : 0;
+}
+
+uint32_t AudioHalTest::BytesToFrames(uint32_t bytes)
+{
+       // ToDo : support various sample format
+       return (m_spec.format == AUDIO_SAMPLE_S16LE) ? bytes / m_spec.channels / 2 : 0;
+}
+
+uint32_t AudioHalTest::FramesToBytes(uint32_t frames, audio_pcm_sample_spec_t *spec)
+{
+       // ToDo : support various sample format
+       return (spec->format == AUDIO_SAMPLE_S16LE) ? frames * spec->channels * 2 : 0;
+}
+
+uint32_t AudioHalTest::FramesToBytes(uint32_t frames)
+{
+       // ToDo : support various sample format
+       return (m_spec.format == AUDIO_SAMPLE_S16LE) ? frames * m_spec.channels * 2 : 0;
+}
+
+uint32_t AudioHalTest::GetDefaultFrames()
+{
+       return BytesToFrames(default_frames);
+}
+
+void AudioHalTest::HalMessageCallback(const char *name, int value, void *user_data)
+{
+       cout << name << "," << value << "," << user_data << endl;
+}
+
+/**
+ * @testcase           InitP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Initialize audio HAL handle
+ * @apicovered         audio_init, audio_deinit
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST(AudioHalPreTest, InitP)
+{
+       void *h = nullptr;
+
+       int32_t ret = hal_audio_init(&h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+       ASSERT_NE(h, nullptr);
+
+       ret = hal_audio_deinit(h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           InitN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Initialize audio HAL handle
+ * @apicovered         audio_init
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST(AudioHalPreTest, InitN)
+{
+       int32_t ret = hal_audio_init(nullptr);
+       ASSERT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           DeinitP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Deinitialize audio HAL handle
+ * @apicovered         audio_init, audio_deinit
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST(AudioHalPreTest, DeinitP)
+{
+       void *h = nullptr;
+
+       int32_t ret = hal_audio_init(&h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+       ASSERT_NE(h, nullptr);
+
+       ret = hal_audio_deinit(h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           GetVolumeLevelMaxP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Get maximum volume level of each volume types
+ * @apicovered         audio_get_volume_level_max
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeLevelMaxP)
+{
+       uint32_t level_max;
+       audio_volume_info_s info = { NULL, NULL, AUDIO_DIRECTION_OUT };
+
+       for (const auto& i : vol_types) {
+               info.type = i.c_str();
+               int32_t ret = hal_audio_get_volume_level_max(m_h, &info, &level_max);
+               cout << i << " : " << level_max << endl;
+               EXPECT_EQ(ret, AUDIO_RET_OK);
+       }
+}
+
+/**
+ * @testcase           GetVolumeLevelMaxN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Get maximum volume level of each volume types
+ * @apicovered         audio_get_volume_level_max
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeLevelMaxN)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_get_volume_level_max(m_h, &info, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           GetVolumeLevelP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Get volume level of each volume types
+ * @apicovered         audio_get_volume_level
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeLevelP)
+{
+       uint32_t level;
+       int32_t ret;
+       audio_volume_info_s info = { NULL, NULL, AUDIO_DIRECTION_OUT };
+
+       for (const auto& i : vol_types) {
+               info.type = i.c_str();
+               ret = hal_audio_get_volume_level(m_h, &info, &level);
+               cout << i << " : " << level << endl;
+               EXPECT_EQ(ret, AUDIO_RET_OK);
+       }
+}
+
+/**
+ * @testcase           GetVolumeLevelN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Get volume level of each volume types
+ * @apicovered         audio_get_volume_level
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeLevelN)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_get_volume_level(m_h, &info, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           SetVolumeLevelP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Set volume level of each volume types
+ * @apicovered         audio_set_volume_level
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, SetVolumeLevelP)
+{
+       /* FIXME : need to revise */
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_set_volume_level(m_h, &info, 15);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_set_volume_level(m_h, &info, 7);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+
+/**
+ * @testcase           SetVolumeLevelN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Set volume level of each volume types
+ * @apicovered         audio_set_volume_level
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, SetVolumeLevelN)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_set_volume_level(m_h, &info, 10000);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+
+/**
+ * @testcase           GetVolumeValueP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Get volume value of each volume types with given volume level
+ * @apicovered         audio_get_volume_value
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeValueP)
+{
+       double value;
+       uint32_t level_max;
+       int32_t ret;
+       audio_volume_info_s info = { NULL, NULL, AUDIO_DIRECTION_OUT };
+
+       for (const auto& i : vol_types) {
+               info.type = i.c_str();
+               ret = hal_audio_get_volume_level_max(m_h, &info, &level_max);
+               EXPECT_EQ(ret, AUDIO_RET_OK);
+
+               for (uint32_t l = 0; l < level_max ; l++) {
+                       info.type = i.c_str();
+                       ret = hal_audio_get_volume_value(m_h, &info, l, &value);
+                       EXPECT_EQ(ret, AUDIO_RET_OK);
+                       cout << i << ", level " << l << ", value : " << value << endl;
+               }
+       }
+}
+
+/**
+ * @testcase           GetVolumeValueN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Get volume value of each volume types with given volume level
+ * @apicovered         audio_get_volume_value
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeValueN)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_get_volume_value(m_h, &info, 0, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           GetVolumeMuteP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Get volume mute of each volume types.
+ * @apicovered         audio_get_volume_mute
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeMuteP)
+{
+       uint32_t mute = 0;
+       int32_t ret;
+       audio_volume_info_s info = { NULL, NULL, AUDIO_DIRECTION_OUT };
+
+       for (const auto& i : vol_types) {
+               info.type = i.c_str();
+               ret = hal_audio_get_volume_mute(m_h, &info, &mute);
+               EXPECT_EQ(ret, AUDIO_RET_OK);
+               cout << i << " mute : " << mute << endl;
+       }
+}
+
+/**
+ * @testcase           GetVolumeMuteN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Get volume mute of each volume types.
+ * @apicovered         audio_get_volume_mute
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, GetVolumeMuteN)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_get_volume_mute(m_h, &info, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           SetVolumeMuteP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Set volume mute of each volume types.
+ * @apicovered         audio_set_volume_mute
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, SetVolumeMuteP)
+{
+       audio_volume_info_s info = { "media", NULL, AUDIO_DIRECTION_OUT };
+       int32_t ret = hal_audio_set_volume_mute(m_h, &info, 1);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_set_volume_mute(m_h, &info, 0);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+#if 0 // can't test because mute is not implemented yet...
+TEST_F(AudioHalTest, SetVolumeMuteN)
+{
+       int32_t ret = hal_audio_set_volume_mute(m_h, "media", AUDIO_DIRECTION_OUT, 10000);
+       EXPECT_EQ(ret, AUDIO_ERR_INTERNAL);
+}
+#endif
+
+/**
+ * @testcase           UpdateRouteP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Update route
+ * @apicovered         audio_update_route
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, UpdateRouteP)
+{
+       audio_route_info info;
+       int32_t num_of_devices = 1;
+
+       memset(&info, 0, sizeof(audio_route_info));
+
+       info.role = "media";
+       info.device_infos = (device_info_s*)malloc(sizeof(device_info_s) * num_of_devices);
+       ASSERT_NE(info.device_infos, nullptr);
+       info.device_infos[0].direction = AUDIO_DIRECTION_OUT;
+       info.device_infos[0].type = "builtin-speaker";
+       info.device_infos[0].id = 100;
+       info.num_of_devices = num_of_devices;
+
+       int32_t ret = hal_audio_update_route(m_h, &info);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       free(info.device_infos);
+}
+
+
+/**
+ * @testcase           UpdateRouteN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Update route
+ * @apicovered         audio_update_route
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, UpdateRouteN)
+{
+       int32_t ret = hal_audio_update_route(m_h, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       audio_route_info info;
+       memset(&info, 0, sizeof(audio_route_info));
+       info.role = nullptr;
+       ret = hal_audio_update_route(m_h, &info);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           UpdateRouteOptionP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Update route option
+ * @apicovered         audio_update_route_option
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, UpdateRouteOptionP)
+{
+       audio_route_option_s option;
+
+       int32_t ret = hal_audio_update_route_option(m_h, &option);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+
+/**
+ * @testcase           UpdateRouteOptionN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Update route option
+ * @apicovered         audio_update_route_option
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, UpdateRouteOptionN)
+{
+       int32_t ret = hal_audio_update_route_option(m_h, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           NotifyStreamConnectionChangedP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, Notify stream connection changed
+ * @apicovered         audio_notify_stream_connection_changed
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, NotifyStreamConnectionChangedP)
+{
+       audio_stream_info_s info;
+
+       memset(&info, 0, sizeof(audio_stream_info_s));
+       info.role = "media";
+       info.direction = AUDIO_DIRECTION_OUT;
+       info.idx = 100;
+
+       int32_t ret = hal_audio_notify_stream_connection_changed(m_h, &info, 1);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           NotifyStreamConnectionChangedN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, Notify stream connection changed
+ * @apicovered         audio_notify_stream_connection_changed
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, NotifyStreamConnectionChangedN)
+{
+       // check for nullptr ptr
+       int32_t ret = hal_audio_notify_stream_connection_changed(m_h, nullptr, 1);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       // check for invalid role
+       audio_stream_info_s info;
+       memset(&info, 0, sizeof(audio_stream_info_s));
+       info.role = nullptr;
+       info.direction = AUDIO_DIRECTION_OUT;
+       info.idx = 100;
+
+       ret = hal_audio_notify_stream_connection_changed(m_h, &info, 1);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           MessageCallbackP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, add/remove message callback
+ * @apicovered         audio_add_message_cb, audio_remove_message_cb
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, MessageCallbackP)
+{
+       int32_t ret = hal_audio_add_message_cb(m_h, HalMessageCallback, nullptr);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_remove_message_cb(m_h, HalMessageCallback);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           MessageCallbackN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, add/remove message callback
+ * @apicovered         audio_add_message_cb, audio_remove_message_cb
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, MessageCallbackN)
+{
+       int32_t ret = hal_audio_add_message_cb(m_h, nullptr, nullptr);
+       ASSERT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       ret = hal_audio_remove_message_cb(m_h, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+
+/**
+ * @testcase           PcmGetFdP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, get fd from the pcm handle
+ * @apicovered         audio_pcm_get_fd, audio_pcm_open, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                                       AUDIO_DIRECTION_OUT, &m_spec,
+                                       GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       int pcm_fd = -1;
+       ret = hal_audio_pcm_get_fd(m_h, pcm_h, &pcm_fd);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+       cout << "pcm fd : " << pcm_fd << endl;
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmGetFdN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, get fd from the pcm handle
+ * @apicovered         audio_pcm_get_fd, audio_pcm_open, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, PcmGetFdN)
+{
+       // check for pcm handle
+       int pcm_fd = -1;
+       int32_t ret = hal_audio_pcm_get_fd(m_h, nullptr, &pcm_fd);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       // 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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                               AUDIO_DIRECTION_OUT, &m_spec,
+                               GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_get_fd(m_h, pcm_h, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmOpenWriteCloseP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, open pcm handle, start pcm handle, write pcm buffers, stop pcm handle and close pcm_handle
+ * @apicovered         audio_pcm_open, audio_pcm_start, audio_pcm_avail, audio_pcm_write, audio_pcm_stop, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                                       AUDIO_DIRECTION_OUT, &m_spec,
+                                       GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_start(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = WritePcmFromFile(pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_stop(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmOpenReadCloseP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, open pcm handle, start pcm handle, read pcm buffers, stop pcm handle and close pcm_handle
+ * @apicovered         audio_pcm_open, audio_pcm_start, audio_pcm_avail, audio_pcm_read, audio_pcm_stop, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                               AUDIO_DIRECTION_IN, &m_spec,
+                               GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_start(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = ReadPcmFromDevice(pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_stop(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmRecoverN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, pcm recovery
+ * @apicovered         audio_pcm_recover
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, PcmRecoverN)
+{
+       int32_t ret = hal_audio_pcm_recover(m_h, nullptr, 0);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+/**
+ * @testcase           PcmSetParamP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, set audio parameters
+ * @apicovered         audio_pcm_pcm_set_param, audio_pcm_open, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                                       AUDIO_DIRECTION_OUT, &m_spec,
+                                       GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_set_params(m_h, pcm_h, AUDIO_DIRECTION_OUT, &m_spec,
+                                       GetDefaultFrames(), default_periods);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmSetParamN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, set audio parameters
+ * @apicovered         audio_pcm_pcm_set_param, audio_pcm_open, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                                                                                       AUDIO_DIRECTION_OUT, &m_spec,   GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       ret = hal_audio_pcm_set_params(m_h, nullptr, AUDIO_DIRECTION_OUT, &m_spec, GetDefaultFrames(), default_periods);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmGetParamP
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Positive, get audio parameters
+ * @apicovered         audio_pcm_pcm_get_param, audio_pcm_open, audio_pcm_close
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+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 = hal_audio_pcm_open(m_h, card.c_str(), dev.c_str(),
+                                       AUDIO_DIRECTION_OUT, &m_spec,
+                                       GetDefaultFrames(), default_periods, &pcm_h);
+       ASSERT_EQ(ret, AUDIO_RET_OK);
+
+       // Test Body
+       audio_pcm_sample_spec_t local_spec;
+       audio_pcm_sample_spec_t * p_spec = &local_spec;
+       uint32_t period_size = 0;
+       uint32_t periods = 0;
+
+       memset(p_spec, 0, sizeof(audio_pcm_sample_spec_t));
+       ret = hal_audio_pcm_get_params(m_h, pcm_h, AUDIO_DIRECTION_OUT, (void**)&p_spec, &period_size, &periods);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+
+       cout << p_spec->format << "," <<
+                       p_spec->rate << "," <<
+                       static_cast<int>(p_spec->channels) << "," <<
+                       period_size << "," <<
+                       periods << endl;
+
+       // Cleanup
+       ret = hal_audio_pcm_close(m_h, pcm_h);
+       EXPECT_EQ(ret, AUDIO_RET_OK);
+}
+
+/**
+ * @testcase           PcmGetParamN
+ * @since_tizen                4.0
+ * @author                     SR(seungbae.shin)
+ * @reviewer           SR(sc11.lee)
+ * @type                       auto
+ * @description                Negative, get audio parameters
+ * @apicovered         audio_pcm_pcm_get_param
+ * @passcase           XXX
+ * @failcase           YYY
+ * @precondition       None
+ * @postcondition      None
+ */
+TEST_F(AudioHalTest, PcmGetParamN)
+{
+       int32_t ret = hal_audio_pcm_get_params(m_h, nullptr, AUDIO_DIRECTION_OUT, nullptr, nullptr, nullptr);
+       EXPECT_EQ(ret, AUDIO_ERR_PARAMETER);
+}
+
+int main(int argc, char **argv)
+{
+#ifdef DISABLE_DEBUG_LOG
+       cout.rdbuf(NULL);
+#endif
+
+       testing::InitGoogleTest(&argc, argv);
+
+       return RUN_ALL_TESTS();
+}
diff --git a/testcase/parser.cpp b/testcase/parser.cpp
new file mode 100644 (file)
index 0000000..608ed3a
--- /dev/null
@@ -0,0 +1,290 @@
+#include <iostream>
+#include <json.h>
+#include <assert.h>
+#include <string.h>
+#include <string>
+
+#include "parser.hh"
+
+#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;
+
+CDeviceMapParser::CDeviceMapParser()
+       : m_json_obj(nullptr), m_json_device_files_obj(nullptr)
+{
+       open_json("/etc/pulse/device-map.json");
+}
+
+CDeviceMapParser::CDeviceMapParser(const char* map_file)
+       : m_json_obj(nullptr), m_json_device_files_obj(nullptr)
+{
+       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 = nullptr;
+               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 = nullptr;
+
+       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 = nullptr;
+
+       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));
+
+       // <object example>
+       //   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<string, string>& device)
+{
+       json_object *device_file_prop_o = nullptr;
+       string device_string, device_param;
+
+       assert(device_file_o);
+       assert(json_object_is_type(device_file_o, json_type_object));
+
+       // <object example>
+       //      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<string, string>& device)
+{
+       int num, idx;
+       json_object *device_file_o = nullptr;
+
+       assert(device_file_array_o);
+       assert(json_object_is_type(device_file_array_o, json_type_array));
+
+       // <object example>
+       //  {
+       //        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/parser.hh b/testcase/parser.hh
new file mode 100644 (file)
index 0000000..34b7f14
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Seungbae Shin <seungbae.shin@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <string>
+#include <json.h>
+
+using namespace std;
+
+class CDeviceMapParser
+{
+public:
+       CDeviceMapParser();
+       explicit 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<string, string>& device);
+       void parse_device_file_array_object(json_object *device_file_array_o, pair<string, string>& 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 doesn't define what is paired clearly....
+       pair<string, string> m_playback; // device_string, device_params
+       pair<string, string> m_capture;  // device_string, device_params
+
+       json_object *m_json_obj;
+       json_object *m_json_device_files_obj;
+};
+
+
diff --git a/testcase/test_16le_44100_2ch.raw b/testcase/test_16le_44100_2ch.raw
new file mode 100644 (file)
index 0000000..cbc25eb
Binary files /dev/null and b/testcase/test_16le_44100_2ch.raw differ