From 5cfe54834f37db8a96a502b6191252534fc537b4 Mon Sep 17 00:00:00 2001 From: KimJeongYeon Date: Tue, 7 Jul 2015 16:46:14 +0900 Subject: [PATCH] apply new version of audio-io for tizen 3.0 [Version] 0.3.5 [Profile] Common [Issue Type] Add features [Dependency module] libmm-sound [Dependency commit] NA [Comment] 1. Completely re-written with C++. 2. Remove dependancy of sound server. 3. Support audio focus feature for backward compatibility. 4. merged from tizen_2.4_experimental branch(SPIN). Signed-off-by: KimJeongYeon Change-Id: Id915e895463de3f1e320559c9d17b59a5b66243f --- .gitignore | 27 + AUTHORS | 2 + CMakeLists.txt | 25 +- LICENSE.APLv2 => LICENSE | 412 ++++----- doc/audio_io_doc.h | 2 +- include/CAudioError.h | 102 +++ include/CAudioIO.h | 136 +++ include/CAudioIODef.h | 116 +++ include/CAudioInfo.h | 133 +++ include/CAudioInput.h | 86 ++ include/CAudioOutput.h | 79 ++ include/CAudioSessionHandler.h | 152 ++++ include/CPulseAudioClient.h | 117 +++ include/CPulseAudioPolicy.h | 72 ++ include/CPulseAudioVolume.h | 90 ++ include/CPulseStreamSpec.h | 78 ++ include/IAudioSessionEventListener.h | 58 ++ include/IPulseStreamListener.h | 44 + include/audio_io.h | 438 ++++++++-- include/audio_io_private.h | 88 -- include/cpp_audio_io.h | 84 ++ packaging/capi-media-audio-io.manifest | 6 +- packaging/capi-media-audio-io.spec | 18 +- src/audio_io.c | 498 ++--------- src/audio_io_private.c | 459 ---------- src/cpp/CAudioError.cpp | 144 +++ src/cpp/CAudioIO.cpp | 469 ++++++++++ src/cpp/CAudioInfo.cpp | 108 +++ src/cpp/CAudioInput.cpp | 498 +++++++++++ src/cpp/CAudioOutput.cpp | 403 +++++++++ src/cpp/CAudioSessionHandler.cpp | 504 +++++++++++ src/cpp/CPulseAudioClient.cpp | 747 ++++++++++++++++ src/cpp/CPulseAudioPolicy.cpp | 57 ++ src/cpp/CPulseAudioVolume.cpp | 53 ++ src/cpp/CPulseStreamSpec.cpp | 140 +++ src/cpp/cpp_audio_io.cpp | 1499 ++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 7 +- test/audio_io_test.c | 733 +++++++++++++++- 38 files changed, 7394 insertions(+), 1290 deletions(-) create mode 100644 .gitignore mode change 100755 => 100644 CMakeLists.txt rename LICENSE.APLv2 => LICENSE (98%) mode change 100755 => 100644 doc/audio_io_doc.h create mode 100644 include/CAudioError.h create mode 100644 include/CAudioIO.h create mode 100644 include/CAudioIODef.h create mode 100644 include/CAudioInfo.h create mode 100644 include/CAudioInput.h create mode 100644 include/CAudioOutput.h create mode 100644 include/CAudioSessionHandler.h create mode 100644 include/CPulseAudioClient.h create mode 100644 include/CPulseAudioPolicy.h create mode 100644 include/CPulseAudioVolume.h create mode 100644 include/CPulseStreamSpec.h create mode 100644 include/IAudioSessionEventListener.h create mode 100644 include/IPulseStreamListener.h delete mode 100644 include/audio_io_private.h create mode 100644 include/cpp_audio_io.h delete mode 100644 src/audio_io_private.c create mode 100644 src/cpp/CAudioError.cpp create mode 100644 src/cpp/CAudioIO.cpp create mode 100644 src/cpp/CAudioInfo.cpp create mode 100644 src/cpp/CAudioInput.cpp create mode 100644 src/cpp/CAudioOutput.cpp create mode 100644 src/cpp/CAudioSessionHandler.cpp create mode 100644 src/cpp/CPulseAudioClient.cpp create mode 100644 src/cpp/CPulseAudioPolicy.cpp create mode 100644 src/cpp/CPulseAudioVolume.cpp create mode 100644 src/cpp/CPulseStreamSpec.cpp create mode 100644 src/cpp/cpp_audio_io.cpp mode change 100755 => 100644 test/audio_io_test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03736b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +CMakeCache.txt +*/CMakeFiles/* +*.cmake +CMakeFiles* +*.a +*.so +Testing +cmake.depends +cmake.check_depends +cmake.check_cache +core +core.* +gmon.out +install_manifest.txt +*~ +.kdev_include_paths +src.kdev4 +.cproject +.project +tet_captured +tet_lock +*.pc +Makefile +*-test +*-test_* +*tester.c +.gitattributes diff --git a/AUTHORS b/AUTHORS index 56edb13..c41c666 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,5 @@ Kangho Hur Seungkeun Lee Seungbae Shin +SeonYoung Jeong +JeongYeon Kim diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index f2a7e53..af36fad --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ - CMAKE_MINIMUM_REQUIRED(VERSION 2.6) SET(fw_name "capi-media-audio-io") @@ -10,18 +9,22 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog mm-sound capi-base-common capi-media-sound-manager") +SET(dependents "dlog mm-sound capi-base-common capi-media-sound-manager mm-common mm-session libpulse vconf") SET(pc_dependents "capi-base-common capi-media-sound-manager") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) FOREACH(flag ${${fw_name}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror") SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror -std=c++0x") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") + IF("${ARCH}" STREQUAL "arm") ADD_DEFINITIONS("-DTARGET") ENDIF("${ARCH}" STREQUAL "arm") @@ -31,8 +34,12 @@ ADD_DEFINITIONS("-DTIZEN_DEBUG") SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") +aux_source_directory(src/cpp CPPSOURCES) aux_source_directory(src SOURCES) -ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +SET(ALL_SRC ${SOURCES} ${CPPSOURCES}) + +ADD_LIBRARY(${fw_name} SHARED ${ALL_SRC}) SET_TARGET_PROPERTIES(${fw_name} PROPERTIES @@ -55,6 +62,9 @@ INSTALL( DIRECTORY ${INC_DIR}/ DESTINATION include/media FILES_MATCHING PATTERN "*_private.h" EXCLUDE + PATTERN "*cpp*.h" EXCLUDE + PATTERN "C*.h" EXCLUDE + PATTERN "I*.h" EXCLUDE PATTERN "${INC_DIR}/*.h" ) @@ -70,16 +80,16 @@ CONFIGURE_FILE( ) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -ADD_SUBDIRECTORY(test) +#ADD_SUBDIRECTORY(test) IF(UNIX) ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) ADD_CUSTOM_COMMAND( - DEPENDS clean + DEPENDS clean COMMENT "distribution clean" COMMAND find - ARGS . + ARGS . -not -name config.cmake -and \( -name tester.c -or -name Testing -or @@ -102,4 +112,3 @@ ADD_CUSTOM_COMMAND( ) ENDIF(UNIX) - diff --git a/LICENSE.APLv2 b/LICENSE similarity index 98% rename from LICENSE.APLv2 rename to LICENSE index f94008a..bbe9d02 100644 --- a/LICENSE.APLv2 +++ b/LICENSE @@ -1,206 +1,206 @@ -Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - - - +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + diff --git a/doc/audio_io_doc.h b/doc/audio_io_doc.h old mode 100755 new mode 100644 index 4ca1422..ee80e81 --- a/doc/audio_io_doc.h +++ b/doc/audio_io_doc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. diff --git a/include/CAudioError.h b/include/CAudioError.h new file mode 100644 index 0000000..de1e1fb --- /dev/null +++ b/include/CAudioError.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CAUDIOERROR_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CAUDIOERROR_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * Audio Error + */ + class CAudioError { + public: + /* Constants Definition */ + static const unsigned int MSG_LENGTH = 512; + + enum EError { + ERROR_NONE, + + ERROR_INVALID_ARGUMENT, + ERROR_INVALID_HANDLE, + ERROR_INVALID_SAMPLERATE, + ERROR_INVALID_CHANNEL, + ERROR_INVALID_FORMAT, + ERROR_INVALID_POINTER, + ERROR_INVALID_OPERATION, + + ERROR_NOT_INITIALIZED, + ERROR_NOT_SUPPORTED, + + ERROR_PERMISSION_DENIED, + + ERROR_DEVICE_NOT_OPENED, + ERROR_DEVICE_NOT_CLOSED, + + ERROR_OUT_OF_MEMORY, + ERROR_INTERNAL_OPERATION, + ERROR_FAILED_OPERATION, + + ERROR_POLICY_BLOCKED, + ERROR_POLICY_INTERRUPTED, + ERROR_POLICY_DUPLICATED, + + ERROR_MAX + }; + + private: + /* Members */ + static EError mLastError; + static char mLastErrorMsg[MSG_LENGTH]; + + EError mError; + char mErrorMsg[MSG_LENGTH]; + + const char* _convertErrorToString(EError err); + + public: + /* Constructor & Destructor */ + CAudioError(EError err); + CAudioError(EError err, const char* fileName, const char* parentFunc, int lineNum); + CAudioError(EError err, const char* msg, const char* fileName, const char* parentFunc, int lineNum); + //CAudioError(CAudioError& err); + ~CAudioError(); + + /* Static Methods */ + static EError getLastError(); + static const char* getLastErrorMsg(); + + /* Setter & Getter */ + EError getError(); + const char* getErrorMsg(); + + /* Overrided Operation */ + CAudioError& operator = (const EError err); + CAudioError& operator = (const CAudioError& err); + bool operator != (const EError err); + bool operator == (const EError err); +// friend bool operator == (const CAudioError& src, const EError& err); + }; + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_CPP_OBJECTS_IO_H__ */ diff --git a/include/CAudioIO.h b/include/CAudioIO.h new file mode 100644 index 0000000..b920752 --- /dev/null +++ b/include/CAudioIO.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CAUDIO_IO_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CAUDIO_IO_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * Abstract Class + * You can't take this object directly. + */ + class IPulseStreamListener; + class IAudioSessionEventListener; + class CAudioIO : public IPulseStreamListener, public IAudioSessionEventListener { + public: + struct SStreamCallback { + void* mUserData; + void (*onStream)(size_t nbytes, void* user_data); + + SStreamCallback() : mUserData(NULL), onStream(NULL) + {/* Empty Body */} + }; + + struct SStateChangedCallback { + void* mUserData; + void (*onStateChanged)(CAudioInfo::EAudioIOState state, CAudioInfo::EAudioIOState statePrev, bool byPolicy, void* user_data); + + SStateChangedCallback() : mUserData(NULL), onStateChanged(NULL) + {/* Empty Body */} + }; + + struct SInterruptCallback { + void* mUserData; + void (*onInterrupt)(IAudioSessionEventListener::EInterruptCode code, void* user_data); + + SInterruptCallback() : mUserData(NULL), onInterrupt(NULL) + {/* Empty Body */} + }; + + private: + pthread_mutex_t mMutex; + pthread_cond_t mCond; + bool mIsInit; + bool mForceIgnore; + + protected: + CAudioSessionHandler* mpAudioSessionHandler; + CPulseAudioClient* mpPulseAudioClient; + CAudioInfo mAudioInfo; + + SStreamCallback mStreamCallback; + SStateChangedCallback mStateChangedCallback; + SInterruptCallback mInterruptCallback; + + CAudioInfo::EAudioIOState mState; + CAudioInfo::EAudioIOState mStatePrev; + bool mByPolicy; + + /* Protected Methods */ + virtual void setInit(bool flag); + virtual bool isInit(); + virtual bool IsReady(); + + void internalLock() throw (CAudioError); + void internalUnlock() throw (CAudioError); + void internalWait() throw (CAudioError); + void internalSignal() throw (CAudioError); + + bool isForceIgnore(); + + public: + /* Constructor & Destructor */ + CAudioIO(); + CAudioIO(CAudioInfo& audioInfo); + virtual ~CAudioIO(); + + /* Pure Virtual Methods */ + virtual void initialize() throw (CAudioError) = 0; + virtual void finalize() = 0; + + virtual void prepare() throw (CAudioError) = 0; + virtual void unprepare() throw (CAudioError) = 0; + + virtual void pause() throw (CAudioError) = 0; + virtual void resume() throw (CAudioError) = 0; + + virtual void drain() throw (CAudioError) = 0; + virtual void flush() throw (CAudioError) = 0; + + virtual int getBufferSize() throw (CAudioError) = 0; + + /* Implemented Handlers */ + virtual void onStream(CPulseAudioClient* pClient, size_t length); + virtual void onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy); + virtual void onStateChanged(CAudioInfo::EAudioIOState state); + virtual void onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info); + virtual void onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value); + + /* Methods */ + CAudioInfo getAudioInfo() throw (CAudioError); + + virtual void setStreamCallback(SStreamCallback callback) throw (CAudioError); + SStreamCallback getStreamCallback() throw (CAudioError); + + virtual void setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError); + SStateChangedCallback getStateChangedCallback() throw (CAudioError); + + void setInterruptCallback(SInterruptCallback callback) throw (CAudioError); + SInterruptCallback getInterruptCallback() throw (CAudioError); + + void ignoreSession() throw (CAudioError); + }; + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CAUDIO_IO_H__ */ diff --git a/include/CAudioIODef.h b/include/CAudioIODef.h new file mode 100644 index 0000000..74bb000 --- /dev/null +++ b/include/CAudioIODef.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CAUDIO_DEF_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CAUDIO_DEF_H__ + + +#ifdef __cplusplus + + +#include +#include +#include + +#include "CAudioError.h" +#include "CAudioInfo.h" +#include "IAudioSessionEventListener.h" +#include "CAudioSessionHandler.h" +#include "IPulseStreamListener.h" +#include "CPulseAudioVolume.h" +#include "CPulseAudioPolicy.h" +#include "CPulseStreamSpec.h" +#include "CPulseAudioClient.h" +#include "CAudioIO.h" +#include "CAudioInput.h" +#include "CAudioOutput.h" + +//#define _AUDIO_IO_DEBUG_TIMING_ + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "TIZEN_N_AUDIO_IO" + +#define AUDIO_IO_LOGD(_fmt_, arg...) { \ + LOGD(_fmt_, ##arg); \ +} + +#define AUDIO_IO_LOGW(_fmt_, arg...) { \ + LOGW(_fmt_, ##arg); \ +} + +#define AUDIO_IO_LOGE(_fmt_, arg...) { \ + LOGE(_fmt_, ##arg); \ +} + +#define _AUDIO_IO_SHELL_COLOR_ +#ifdef _AUDIO_IO_SHELL_COLOR_ +#define COLOR_BLACK "\033[0;30m" +#define COLOR_RED "\033[0;31m" +#define COLOR_GREEN "\033[0;32m" +#define COLOR_YELLOW "\033[0;33m" +#define COLOR_BLUE "\033[0;34m" +#define COLOR_MAGENTA "\033[0;35m" +#define COLOR_CYAN "\033[0;36m" +#define COLOR_GRAY "\033[0;37m" +#define COLOR_WHITE "\033[1;37m" +#define COLOR_END "\033[0m" +#else +#define COLOR_BLACK +#define COLOR_RED +#define COLOR_GREEN +#define COLOR_BLUE +#define COLOR_YELLOW +#define COLOR_MAGENTA +#define COLOR_CYAN +#define COLOR_WHITE +#define COLOR_END +#endif + + +#define RET_ERROR(_x_) {return CAudioError((_x_), __FILE__, __func__, __LINE__);}; +#define RET_ERROR_MSG(_x_, _msg_) {return CAudioError((_x_), (_msg_), __FILE__, __func__, __LINE__);}; + +#define RET_ERROR_MSG_FORMAT(_x_, _format_, ...) { \ + char _msg_[CAudioError::MSG_LENGTH] = {0, }; \ + snprintf(_msg_, CAudioError::MSG_LENGTH, _format_, ##__VA_ARGS__); \ + return CAudioError((_x_), (_msg_), __FILE__, __func__, __LINE__); \ +}; + + +#define THROW_ERROR(_x_) {throw CAudioError((_x_), __FILE__, __func__, __LINE__);}; +#define THROW_ERROR_MSG(_x_, _msg_) {throw CAudioError((_x_), (_msg_), __FILE__, __func__, __LINE__);}; + +#define THROW_ERROR_MSG_FORMAT(_x_, _format_, ...) { \ + char _msg_[CAudioError::MSG_LENGTH] = {0, }; \ + snprintf(_msg_, CAudioError::MSG_LENGTH, _format_, ##__VA_ARGS__); \ + throw CAudioError((_x_), (_msg_), __FILE__, __func__, __LINE__); \ +}; + +#define VALID_POINTER_START(_x_) { \ + if ((_x_) != NULL) { + +#define VALID_POINTER_END } \ +} + +#define SAFE_DELETE(_x_) {if ((_x_)) {delete (_x_); (_x_) = NULL;}}; +#define SAFE_FINALIZE(_x_) {if ((_x_)) {(_x_)->finalize();}}; +#define SAFE_REMOVE(_x_) {if ((_x_)) {(_x_)->finalize(); delete (_x_); (_x_) = NULL;}}; + + +#endif +#endif /* __TIZEN_MEDIA_CPP_OBJECTS_IO_H__ */ diff --git a/include/CAudioInfo.h b/include/CAudioInfo.h new file mode 100644 index 0000000..420042f --- /dev/null +++ b/include/CAudioInfo.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO__IO_CAUDIO_INFO_H__ +#define __TIZEN_MEDIA_AUDIO__IO_CAUDIO_INFO_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * Audio Information + */ + class CAudioInfo { + public: + const static unsigned int MIN_SYSTEM_SAMPLERATE = 8000; + const static unsigned int MAX_SYSTEM_SAMPLERATE = 48000; + + enum EChannel { + CHANNEL_MONO = 1, /**< 1 channel, mono */ + CHANNEL_STEREO, /**< 2 channel, stereo */ + CHANNEL_MAX + }; + + enum ESampleType { + SAMPLE_TYPE_U8 = 1, /**< Unsigned 8-bit audio samples */ + SAMPLE_TYPE_S16_LE, /**< Signed 16-bit audio samples */ + SAMPLE_TYPE_MAX + }; + + enum EAudioType { + /* Only Input */ + AUDIO_IN_TYPE_MEDIA = 0, + AUDIO_IN_TYPE_SYSTEM, + AUDIO_IN_TYPE_ALARM, + AUDIO_IN_TYPE_NOTIFICATION, + AUDIO_IN_TYPE_EMERGENCY, + AUDIO_IN_TYPE_VOICE_INFORMATION, + AUDIO_IN_TYPE_VOICE_RECOGNITION, + AUDIO_IN_TYPE_RINGTONE_VOIP, + AUDIO_IN_TYPE_VOIP, + AUDIO_IN_TYPE_LOOPBACK, /**< only for loopback */ + + /* Only Output */ + AUDIO_OUT_TYPE_MEDIA, + AUDIO_OUT_TYPE_SYSTEM, + AUDIO_OUT_TYPE_ALARM, + AUDIO_OUT_TYPE_NOTIFICATION, + AUDIO_OUT_TYPE_EMERGENCY, + AUDIO_OUT_TYPE_VOICE_INFORMATION, + AUDIO_OUT_TYPE_VOICE_RECOGNITION, + AUDIO_OUT_TYPE_RINGTONE_VOIP, + AUDIO_OUT_TYPE_VOIP, + + AUDIO_TYPE_MAX + }; + + enum EAudioIOState { + AUDIO_IO_STATE_NONE, /**< Audio-io handle is not created */ + AUDIO_IO_STATE_IDLE, /**< Audio-io handle is created, but not prepared */ + AUDIO_IO_STATE_RUNNING, /**< Audio-io handle is ready and the stream is running */ + AUDIO_IO_STATE_PAUSED, /**< Audio-io handle is ready and the stream is paused */ + }; + + private: + unsigned int mSampleRate; + EChannel mChannel; + ESampleType mSampleType; + EAudioType mAudioType; + int mAudioIndex; + + const char *StreamTypeTable[AUDIO_TYPE_MAX] = { + /* Only Input */ + "media", /**< AUDIO_IN_TYPE_MEDIA */ + "system", /**< AUDIO_IN_TYPE_SYSTEM */ + "alarm", /**< AUDIO_IN_TYPE_ALARM */ + "notification", /**< AUDIO_IN_TYPE_NOTIFICATION */ + "emergency", /**< AUDIO_IN_TYPE_EMERGENCY */ + "voice-information", /**< AUDIO_IN_TYPE_VOICE_INFORMATION */ + "voice-recognition", /**< AUDIO_IN_TYPE_VOICE_RECOGNITION */ + "ringtone-voip", /**< AUDIO_IN_TYPE_RINGTONE_VOIP */ + "voip", /**< AUDIO_IN_TYPE_VOIP */ + "loopback", /**< AUDIO_IN_TYPE_LOOPBACK */ /**< only for loopback */ + + /* Only Output */ + "media", /**< AUDIO_OUT_TYPE_MEDIA */ + "system", /**< AUDIO_OUT_TYPE_SYSTEM */ + "alarm", /**< AUDIO_OUT_TYPE_ALARM */ + "notification", /**< AUDIO_OUT_TYPE_NOTIFICATION */ + "emergency", /**< AUDIO_OUT_TYPE_EMERGENCY */ + "voice-information", /**< AUDIO_OUT_TYPE_VOICE_INFORMATION */ + "voice-recognition", /**< AUDIO_OUT_TYPE_VOICE_RECOGNITION */ + "ringtone-voip", /**< AUDIO_OUT_TYPE_RINGTONE_VOIP */ + "voip", /**< AUDIO_OUT_TYPE_VOIP */ + }; + + public: + /* Constructors */ + CAudioInfo(); + CAudioInfo(unsigned int sampleRate, EChannel channel, ESampleType sampleType, EAudioType audioType, int audioIndex) throw (CAudioError); + + /* Setter & Getter */ + unsigned int getSampleRate(); + EChannel getChannel(); + ESampleType getSampleType(); + EAudioType getAudioType(); + void setAudioType(EAudioType AudioType); + int getAudioIndex(); + void setAudioIndex(int AudioIndex); + void convertAudioType2StreamType (CAudioInfo::EAudioType audioType, char **streamType); + void convertStreamType2AudioType (char *streamType, CAudioInfo::EAudioType *audioType); + }; + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO__IO_CAUDIO_INFO_H__ */ diff --git a/include/CAudioInput.h b/include/CAudioInput.h new file mode 100644 index 0000000..3ecc898 --- /dev/null +++ b/include/CAudioInput.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CAUDIO_INPUT_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CAUDIO_INPUT_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * A class CAudioInput that inherited from CAudioIO + */ + class CAudioInput : public CAudioIO { + private: + + const void* mpSyncReadDataPtr; + size_t mSyncReadIndex; + size_t mSyncReadLength; + + bool mIsUsedSyncRead; + bool mIsInit; + + /* Private Methods */ + void setInit(bool flag); + bool IsInit(); + bool IsReady(); + + public: + /* Constructor & Destructor */ + CAudioInput(CAudioInfo& info); + CAudioInput( + unsigned int sampleRate, + CAudioInfo::EChannel channel, + CAudioInfo::ESampleType sampleType, + CAudioInfo::EAudioType audioType); + ~CAudioInput(); + + /* Overridden Handler */ + virtual void onStream(CPulseAudioClient* pClient, size_t length); + virtual void onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info); + virtual void onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value); + + /* Implemented Methods */ + virtual void initialize() throw (CAudioError); + virtual void finalize(); + + virtual void prepare() throw (CAudioError); + virtual void unprepare() throw (CAudioError); + + virtual void pause() throw (CAudioError); + virtual void resume() throw (CAudioError); + + virtual void drain() throw (CAudioError); + virtual void flush() throw (CAudioError); + + virtual int getBufferSize() throw (CAudioError); + + /* Overridden Methods */ + virtual void setStreamCallback(SStreamCallback callback) throw (CAudioError); + + /* Methods */ + int read(void* buffer, size_t length) throw (CAudioError); + int peek(const void** buffer, size_t* length) throw (CAudioError); + int drop() throw (CAudioError); + }; +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CAUDIO_INPUT_H__ */ diff --git a/include/CAudioOutput.h b/include/CAudioOutput.h new file mode 100644 index 0000000..59de7e3 --- /dev/null +++ b/include/CAudioOutput.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CAUDIO_OUTPUT_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CAUDIO_OUTPUT_H__ + + +#ifdef __cplusplus + +#include "CAudioIODef.h" + + +namespace tizen_media_audio { + + + /** + * A class CAudioOutput that inherited from CAudioIO + */ + class CAudioOutput : public CAudioIO { + private: + bool mIsUsedSyncWrite; + bool mIsInit; + + /* Private Methods */ + void setInit(bool flag); + bool IsInit(); + bool IsReady(); + + public: + /* Constructor & Destructor */ + CAudioOutput(CAudioInfo& info); + CAudioOutput( + unsigned int smapleRate, + CAudioInfo::EChannel channel, + CAudioInfo::ESampleType sampleType, + CAudioInfo::EAudioType type); + ~CAudioOutput(); + + /* Overridden Handler */ + virtual void onStream(CPulseAudioClient* pClient, size_t length); + virtual void onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info); + virtual void onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value); + + /* Implemented Methods */ + virtual void initialize() throw (CAudioError); + virtual void finalize(); + + virtual void prepare() throw (CAudioError); + virtual void unprepare() throw (CAudioError); + + virtual void pause() throw (CAudioError); + virtual void resume() throw (CAudioError); + + virtual void drain() throw (CAudioError); + virtual void flush() throw (CAudioError); + + virtual int getBufferSize() throw (CAudioError); + + /* Methods */ + int write(const void* buffer, unsigned int length) throw (CAudioError); + }; + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CAUDIO_OUTPUT_H__ */ diff --git a/include/CAudioSessionHandler.h b/include/CAudioSessionHandler.h new file mode 100644 index 0000000..7c4ab9a --- /dev/null +++ b/include/CAudioSessionHandler.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIOIO_IO_CAUDIO_SESSION_HANDLER_H__ +#define __TIZEN_MEDIA_AUDIOIO_IO_CAUDIO_SESSION_HANDLER_H__ + + +#ifdef __cplusplus + + +#include +#include +#include +#include +#include + +namespace tizen_media_audio { + + + /** + * ASM Thread + */ + class CAudioSessionHandler { + public: + enum EAudioSessionType { + AUDIO_SESSION_TYPE_CAPTURE, + AUDIO_SESSION_TYPE_PLAYBACK + }; + + private: + /* Static Member */ + static int sCaptureRef; + static int sFocusRef; + + /* Members */ + int mId; + int mOptions; + + EAudioSessionType mAudioSession; + MMSessionType mMultimediaSession; + + mm_sound_focus_type_e mFocusType; /* For audio focus */ + mm_sound_focus_state_e mState; /* For audio focus */ + char* mReasonForChange; /* For audio focus */ + char* mAdditionalInfo; /* For audio focus */ + + CAudioInfo mAudioInfo; /* Referenced from CAudioIO */ + + IAudioSessionEventListener* mpEventListener; + + bool mIsInit; + + bool mUseFocus; + int mSubscribeId; + + struct stream_type_table_s { + const char* name; + MMSessionType type; + }; + const struct stream_type_table_s stream_type_table_in[MM_SESSION_TYPE_NUM] = { + {"media", MM_SESSION_TYPE_MEDIA}, + {"media", MM_SESSION_TYPE_MEDIA_RECORD}, + {"media", MM_SESSION_TYPE_ALARM}, + {"media", MM_SESSION_TYPE_NOTIFY}, + {"media", MM_SESSION_TYPE_EMERGENCY}, + {"media", MM_SESSION_TYPE_CALL}, + {"media", MM_SESSION_TYPE_VIDEOCALL}, + {"voip", MM_SESSION_TYPE_VOIP}, + {"media", MM_SESSION_TYPE_VOICE_RECOGNITION}, + {"media", MM_SESSION_TYPE_RECORD_AUDIO}, + {"media", MM_SESSION_TYPE_RECORD_VIDEO} + }; + const struct stream_type_table_s stream_type_table_out[MM_SESSION_TYPE_NUM] = { + {"media", MM_SESSION_TYPE_MEDIA}, + {"media", MM_SESSION_TYPE_MEDIA_RECORD}, + {"alarm", MM_SESSION_TYPE_ALARM}, + {"notification", MM_SESSION_TYPE_NOTIFY}, + {"emergency", MM_SESSION_TYPE_EMERGENCY}, + {"media", MM_SESSION_TYPE_CALL}, + {"media", MM_SESSION_TYPE_VIDEOCALL}, + {"voip", MM_SESSION_TYPE_VOIP}, + {"media", MM_SESSION_TYPE_VOICE_RECOGNITION}, + {"media", MM_SESSION_TYPE_RECORD_AUDIO}, + {"media", MM_SESSION_TYPE_RECORD_VIDEO} + }; + + /* Private Static Methods */ + static int PCM_CAPTURE_COUNT_INC(); + static int PCM_CAPTURE_COUNT_DEC(); + static int PCM_CAPTURE_COUNT_GET(); + static int FOCUS_ID_COUNT_INC(); + static int FOCUS_ID_COUNT_DEC(); + static int FOCUS_ID_COUNT_GET(); + + static void _sound_pcm_signal_cb(mm_sound_signal_name_t signal, int value, void *user_data); + static ASM_cb_result_t _sound_pcm_asm_cb(int handle, ASM_event_sources_t eventSrc, ASM_sound_commands_t command, unsigned int soundState, void *cbData); + static void _sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data); + static void _sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data); + + /* Private Method */ + CAudioError _convertStreamType(EAudioSessionType type1, MMSessionType type2, int *index); + CAudioError _getAsmInformation(MMSessionType *type, int *options); + bool _isFocusRequired(MMSessionType type, int options); + + public: + /* Constructor & Destructor */ + CAudioSessionHandler(EAudioSessionType sessionType, CAudioInfo& audioInfo, IAudioSessionEventListener* listener); + virtual ~CAudioSessionHandler(); + + /* Methods */ + virtual void initialize() throw (CAudioError); + virtual void finalize(); + + bool isSkipSessionEvent() throw (CAudioError); + + void registerSound() throw (CAudioError); + void unregisterSound() throw (CAudioError); + + void updatePlaying() throw (CAudioError); + void updateStop() throw (CAudioError); + void disableSessionHandler() throw (CAudioError); + + /* Setter & Getter */ + int getId(); + int getOptions(); + + EAudioSessionType getAudioSession(); + MMSessionType getMultimediaSession(); + + int getSubscribeId(); + + CAudioInfo getAudioInfo(); + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIOIO_IO_CAUDIO_SESSION_HANDLER_H__ */ diff --git a/include/CPulseAudioClient.h b/include/CPulseAudioClient.h new file mode 100644 index 0000000..90a01fb --- /dev/null +++ b/include/CPulseAudioClient.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_CLIENT_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_CLIENT_H__ + + +#ifdef __cplusplus + + +#include +#include + + +namespace tizen_media_audio { + + + /** + * PULSE Thread + */ + class CPulseAudioVolume; + class CPulseAudioPolicy; + class CPulseStreamSpec; + class CPulseAudioClient { + public: + /* Constants */ + static const char* CLIENT_NAME; + + enum EStreamDirection { + STREAM_DIRECTION_RECORD, /**< Record stream */ + STREAM_DIRECTION_PLAYBACK /**< Playback stream */ + }; + + private: + /* Members */ + EStreamDirection mDirection; + CPulseStreamSpec mSpec; + IPulseStreamListener* mpListener; + + pa_threaded_mainloop* mpMainloop; + pa_context* mpContext; + pa_stream* mpStream; + pa_proplist* mpPropList; + + bool mIsInit; + bool mIsOperationSuccess; + + /* Static Methods */ + + /* Private Method */ + + /* Private Calblack Method */ + static void _contextStateChangeCb(pa_context* c, void* user_data); + static void _successContextCb(pa_context* c, int success, void* user_data); + + static void _streamStateChangeCb(pa_stream* s, void* user_data); + static void _streamCaptureCb(pa_stream* s, size_t length, void* user_data); + static void _streamPlaybackCb(pa_stream* s, size_t length, void* user_data); + static void _streamLatencyUpdateCb(pa_stream* s, void* user_data); + static void _successStreamCb(pa_stream* s, int success, void* user_data); + + public: + /* Constructor & Destructor */ + CPulseAudioClient(EStreamDirection direction, + CPulseStreamSpec& spec, + IPulseStreamListener* listener); + ~CPulseAudioClient(); + + /* Implemented Methods */ + void initialize() throw (CAudioError); + void finalize(); + + /* Methods */ + int peek(const void** data, size_t* length) throw (CAudioError); + int drop() throw (CAudioError); + int write(const void* data, size_t length) throw (CAudioError); + + void cork(bool cork) throw (CAudioError); + bool isCorked() throw (CAudioError); + + bool drain() throw (CAudioError); + bool flush() throw (CAudioError); + + void checkRunningState() throw (CAudioError); + bool isInThread() throw (CAudioError); + + size_t getWritableSize() throw (CAudioError); + size_t getReadableSize() throw (CAudioError); + + size_t getBufferSize() throw (CAudioError); + + pa_usec_t getLatency() throw (CAudioError); + pa_usec_t getFinalLatency() throw (CAudioError); + + /* Setter & Getter */ + EStreamDirection getStreamDirection(); + CPulseStreamSpec getStreamSpec(); + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_CLIENT_H__ */ diff --git a/include/CPulseAudioPolicy.h b/include/CPulseAudioPolicy.h new file mode 100644 index 0000000..ce941bc --- /dev/null +++ b/include/CPulseAudioPolicy.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + + +#if 0 +#ifndef __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_POLICY_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_POLICY_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * class CPulseAudioPolicy + */ + class CPulseAudioPolicy { + public: + /* Constants */ + enum EPolicy { + POLICY_DEFAULT, + POLICY_OUT_AUTO, + POLICY_OUT_PHONE, + POLICY_OUT_VOIP, + POLICY_OUT_ALL, + POLICY_IN_VOIP, + POLICY_IN_LOOPBACK, + POLICY_IN_MIRRORING, + POLICY_HIGH_LATENCY, + POLICY_MAX + }; + + private: + /* Members */ + EPolicy mPolicy; + + public: + /* Constructors */ + CPulseAudioPolicy(); + CPulseAudioPolicy(EPolicy policy); + ~CPulseAudioPolicy(); + + /* getter & setter */ + void setPolicy(EPolicy policy) throw (CAudioError); + EPolicy getPolicy(); + + /* Override */ + bool operator != (const EPolicy policy); + bool operator == (const EPolicy policy); + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_POLICY_H__ */ +#endif diff --git a/include/CPulseAudioVolume.h b/include/CPulseAudioVolume.h new file mode 100644 index 0000000..f4cbbf5 --- /dev/null +++ b/include/CPulseAudioVolume.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + + +#if 0 +#ifndef __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_VOLUME_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_VOLUME_H__ + + +#ifdef __cplusplus + + +namespace tizen_media_audio { + + + /** + * Audio Volume + */ + class CPulseAudioVolume { + public: + /* Constants */ + enum EVolume { + VOLUME_SYSTEM, /**< System volume type */ + VOLUME_NOTIFICATION, /**< Notification volume type */ + VOLUME_ALARM, /**< Alarm volume type */ + VOLUME_RINGTONE, /**< Ringtone volume type */ + VOLUME_MEDIA, /**< Media volume type */ + VOLUME_CALL, /**< Call volume type */ + VOLUME_VOIP, /**< VOIP volume type */ + VOLUME_VOICE, /**< VOICE volume type */ + VOLUME_FIXED, /**< Volume type for fixed acoustic level */ + VOLUME_EXT_ANDROID = VOLUME_FIXED, /**< External system volume for Android */ + VOLUME_MAX /**< Volume type count */ + }; + + enum EVolumeGain { + VOLUME_GAIN_DEFAULT, + VOLUME_GAIN_DIALER, + VOLUME_GAIN_TOUCH, + VOLUME_GAIN_AF, + VOLUME_GAIN_SHUTTER1, + VOLUME_GAIN_SHUTTER2, + VOLUME_GAIN_CAMCORDING, + VOLUME_GAIN_MIDI, + VOLUME_GAIN_BOOTING, + VOLUME_GAIN_VIDEO, + VOLUME_GAIN_TTS, + VOLUME_GAIN_MAX + }; + + private: + /* Members */ + EVolume mVolume; + EVolumeGain mVolumeGain; + + public: + /* Constructor & Destructor */ + CPulseAudioVolume(); + CPulseAudioVolume(EVolume volume, EVolumeGain gain); + ~CPulseAudioVolume(); + + /* Methods */ + + /* Setter & Getter */ + void setVolume(EVolume volume); + EVolume getVolume(); + + void setVolumeGain(EVolumeGain volumeGain); + EVolumeGain getVolumeGain(); + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CPULSEAUDIO_VOLUME_H__ */ +#endif diff --git a/include/CPulseStreamSpec.h b/include/CPulseStreamSpec.h new file mode 100644 index 0000000..ca3bcec --- /dev/null +++ b/include/CPulseStreamSpec.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_CPULSESTREAM_SPEC_H__ +#define __TIZEN_MEDIA_AUDIO_IO_CPULSESTREAM_SPEC_H__ + + +#ifdef __cplusplus + + +#include + + +namespace tizen_media_audio { + + + /** + * class CPulseStreamSpec + */ + class CPulseStreamSpec { + public: + /* Constants */ + enum EStreamLatency { + STREAM_LATENCY_INPUT_LOW, + STREAM_LATENCY_INPUT_MID, + STREAM_LATENCY_INPUT_HIGH, + STREAM_LATENCY_INPUT_VOIP, + STREAM_LATENCY_OUTPUT_LOW, + STREAM_LATENCY_OUTPUT_MID, + STREAM_LATENCY_OUTPUT_HIGH, + STREAM_LATENCY_OUTPUT_VOIP, + STREAM_LATENCY_MAX + }; + + private: + /* Members */ + EStreamLatency mLatency; + CAudioInfo mAudioInfo; + pa_sample_spec mSampleSpec; + pa_channel_map mChannelMap; + const char* mStreamName; + + /* private meethod */ + void _adjustSpec() throw (CAudioError); + + public: + /* Constructor & Destructor */ + CPulseStreamSpec() throw (CAudioError); + CPulseStreamSpec(EStreamLatency latency, CAudioInfo& audioInfo) throw (CAudioError); + CPulseStreamSpec(EStreamLatency latency, CAudioInfo& audioInfo, int customLatency) throw (CAudioError); + ~CPulseStreamSpec(); + + /* Setter & Getter */ + EStreamLatency getStreamLatency(); + CAudioInfo getAudioInfo(); + pa_sample_spec getSampleSpec(); + pa_channel_map getChannelMap(); + const char* getStreamName(); + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_CPULSESTREAM_SPEC_H__ */ diff --git a/include/IAudioSessionEventListener.h b/include/IAudioSessionEventListener.h new file mode 100644 index 0000000..8c425a9 --- /dev/null +++ b/include/IAudioSessionEventListener.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_IAUDIO_SESSION_EVENT_LISTENER_H__ +#define __TIZEN_MEDIA_AUDIO_IO_IAUDIO_SESSION_EVENT_LISTENER_H__ + + +#ifdef __cplusplus + + +#include +#include + + +namespace tizen_media_audio { + + + /** + * Called by ASM Thread + */ + class CAudioSessionHandler; + class IAudioSessionEventListener { + public: + enum EInterruptCode { + INTERRUPT_COMPLETED = 0, /**< Interrupt completed */ + INTERRUPT_BY_MEDIA, /**< Interrupted by a media application */ + INTERRUPT_BY_CALL, /**< Interrupted by an incoming call */ + INTERRUPT_BY_EARJACK_UNPLUG, /**< Interrupted by unplugging headphones */ + INTERRUPT_BY_RESOURCE_CONFLICT, /**< Interrupted by a resource conflict */ + INTERRUPT_BY_ALARM, /**< Interrupted by an alarm */ + INTERRUPT_BY_EMERGENCY, /**< Interrupted by an emergency */ + INTERRUPT_BY_NOTIFICATION, /**< Interrupted by a notification */ + INTERRUPT_MAX + }; + + static EInterruptCode convertInterruptedCode(int code, const char *reason_for_change); + virtual void onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) = 0; + virtual void onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) = 0; + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_IAUDIO_SESSION_EVENT_LISTENER_H__ */ diff --git a/include/IPulseStreamListener.h b/include/IPulseStreamListener.h new file mode 100644 index 0000000..3a2e75d --- /dev/null +++ b/include/IPulseStreamListener.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_AUDIO_IO_IPULSESTREAM_LISTENER_H__ +#define __TIZEN_MEDIA_AUDIO_IO_IPULSESTREAM_LISTENER_H__ + + +#ifdef __cplusplus + + +#include + + +namespace tizen_media_audio { + + + /** + * Called by PulseAudio Thread + */ + class CPulseAudioClient; + class IPulseStreamListener { + public: + virtual void onStream(CPulseAudioClient* pClient, size_t length) = 0; + virtual void onStateChanged(CAudioInfo::EAudioIOState state) = 0; + }; + + +} /* namespace tizen_media_audio */ + +#endif +#endif /* __TIZEN_MEDIA_AUDIO_IO_IPULSESTREAM_LISTENER_H__ */ diff --git a/include/audio_io.h b/include/audio_io.h index 067cddc..767011a 100644 --- a/include/audio_io.h +++ b/include/audio_io.h @@ -1,18 +1,18 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* 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. -*/ + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ #ifndef __TIZEN_MEDIA_AUDIO_IO_H__ #define __TIZEN_MEDIA_AUDIO_IO_H__ @@ -34,17 +34,17 @@ extern "C" /** * @addtogroup CAPI_MEDIA_AUDIO_IN_MODULE * @{ -*/ + */ /** * @brief The audio input handle. * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif */ -typedef struct audio_in_s *audio_in_h; +typedef struct audio_io_s *audio_in_h; /** * @} -*/ + */ /** * @addtogroup CAPI_MEDIA_AUDIO_OUT_MODULE @@ -55,7 +55,7 @@ typedef struct audio_in_s *audio_in_h; * @brief The audio output handle. * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif */ -typedef struct audio_out_s *audio_out_h; +typedef struct audio_io_s *audio_out_h; /** * @} @@ -86,6 +86,17 @@ typedef enum { } audio_channel_e; /** + * @brief Enumeration for audio input and output state. + * @since_tizen 3.0 + */ +typedef enum +{ + AUDIO_IO_STATE_IDLE, /**< Audio-io handle is created, but not prepared */ + AUDIO_IO_STATE_RUNNING, /**< Audio-io handle is ready and the stream is running */ + AUDIO_IO_STATE_PAUSED, /**< Audio-io handle is ready and the stream is paused */ +} audio_io_state_e; + +/** * @brief Enumeration for audio input and output error. * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif */ @@ -100,9 +111,11 @@ typedef enum{ AUDIO_IO_ERROR_DEVICE_NOT_CLOSED = TIZEN_ERROR_AUDIO_IO | 0x02, /**< Device close error */ AUDIO_IO_ERROR_INVALID_BUFFER = TIZEN_ERROR_AUDIO_IO | 0x03, /**< Invalid buffer pointer */ AUDIO_IO_ERROR_SOUND_POLICY = TIZEN_ERROR_AUDIO_IO | 0x04, /**< Sound policy error */ + AUDIO_IO_ERROR_INVALID_STATE = TIZEN_ERROR_AUDIO_IO | 0x05, /**< Invalid state (Since 3.0) */ } audio_io_error_e; /** + * @deprecated Deprecated since 3.0 * @brief Enumeration for audio IO interrupted messages. * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif */ @@ -119,6 +132,7 @@ typedef enum } audio_io_interrupted_code_e; /** + * @deprecated Deprecated since 3.0. Use sound_stream_focus_state_changed_cb instead. * @brief Called when audio input or output is interrupted. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -134,12 +148,12 @@ typedef void (*audio_io_interrupted_cb)(audio_io_interrupted_code_e code, void * /** * @} -*/ + */ /** * @addtogroup CAPI_MEDIA_AUDIO_IN_MODULE * @{ -*/ + */ // //AUDIO INPUT @@ -154,21 +168,37 @@ typedef void (*audio_io_interrupted_cb)(audio_io_interrupted_code_e code, void * * * @param[in] handle The handle to the audio input * @param[in] nbytes The amount of available audio in data which can be peeked. - * @param[in] userdata The user data passed from the callback registration function + * @param[in] user_data The user data passed from the callback registration function * * @see audio_in_set_stream_cb() */ -typedef void (*audio_in_stream_cb)(audio_in_h handle, size_t nbytes, void *userdata); +typedef void (*audio_in_stream_cb)(audio_in_h handle, size_t nbytes, void *user_data); + +/** + * @brief Called when the state of audio input is changed. + * + * @since_tizen 3.0 + * + * @param[in] handle The handle of the audio input + * @param[in] previous The previous state of the audio input + * @param[in] current The current state of the audio input + * @param[in] by_policy @c true if the state is changed by policy, otherwise @c false if the state is not changed by policy + * @param[in] user_data The user data passed from the callback registration function + * + * @see audio_in_set_state_changed_cb() + * @see audio_in_unset_state_changed_cb() + */ +typedef void (*audio_in_state_changed_cb)(audio_in_h handle, audio_io_state_e previous, audio_io_state_e current, bool by_policy, void *user_data); /** * @brief Creates an audio device instance and returns an input handle to record PCM (pulse-code modulation) data. * + * @details This function is used for audio input initialization. + * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @privlevel public * @privilege %http://tizen.org/privilege/recorder * - * @details This function is used for audio input initialization. - * * @remarks @a input must be released using audio_in_destroy(). * * @param[in] sample_rate The audio sample rate in 8000[Hz] ~ 48000[Hz] @@ -184,19 +214,23 @@ typedef void (*audio_in_stream_cb)(audio_in_h handle, size_t nbytes, void *userd * @retval #AUDIO_IO_ERROR_DEVICE_NOT_OPENED Device not opened * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * + * @post The state will be #AUDIO_IO_STATE_IDLE.\n + * audio_in_set_stream_info() is recommended to be called after this API. * @see audio_in_destroy() */ int audio_in_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_in_h *input); /** + * @deprecated Deprecated since 3.0. Use sound_manager_create_stream_information() instead. * @brief Creates an audio loopback device instance and returns an input handle to record PCM (pulse-code modulation) data. * + * @details This function is used for audio loopback input initialization. + * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @privlevel public * @privilege %http://tizen.org/privilege/recorder * - * @details This function is used for audio loopback input initialization. - * * @remarks @a input must be released using audio_in_destroy(). * * @param[in] sample_rate The audio sample rate in 8000[Hz] ~ 48000[Hz] @@ -212,6 +246,7 @@ int audio_in_create(int sample_rate, audio_channel_e channel, audio_sample_type_ * @retval #AUDIO_IO_ERROR_DEVICE_NOT_OPENED Device not opened * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * * @see audio_in_destroy() */ int audio_in_create_loopback(int sample_rate, audio_channel_e channel, audio_sample_type_e type , audio_in_h* input); @@ -228,12 +263,38 @@ int audio_in_create_loopback(int sample_rate, audio_channel_e channel, audio_sam * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_DEVICE_NOT_CLOSED Device not closed * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * * @see audio_in_create() */ int audio_in_destroy(audio_in_h input); /** - * @brief Prepares reading audio input by starting buffering of audio data from the device. + * @brief Sets the sound stream information to the audio input. + * + * @since_tizen 3.0 + * + * @remarks @a the sound stream information includes audio routing and volume type. + * For more details, you can refer to @ref CAPI_MEDIA_SOUND_MANAGER_MODULE + * + * @param[in] input The handle to the audio input + * @param[in] stream_info The handle of stream information + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_IDLE.\n + * Call audio_in_create() before calling this function. + * @post Call audio_in_prepare() after calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int audio_in_set_stream_info(audio_in_h input, sound_stream_info_h stream_info); + +/** + * @brief Prepares the audio input for reading audio data by starting buffering of audio data from the device. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @@ -243,13 +304,15 @@ int audio_in_destroy(audio_in_h input); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @post The state will be #AUDIO_IO_STATE_RUNNING. * @see audio_in_unprepare() */ int audio_in_prepare(audio_in_h input); /** - * @brief Unprepares reading audio input by stopping buffering the audio data from the device. + * @brief Unprepares the audio input. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @@ -259,11 +322,52 @@ int audio_in_prepare(audio_in_h input); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @post The state will be #AUDIO_IO_STATE_IDLE. * @see audio_in_prepare() */ int audio_in_unprepare(audio_in_h input); /** + * @brief Pauses buffering of audio data from the device. + * + * @since_tizen 3.0 + * + * @param[in] input The handle to the audio input + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. + * @post The state will be #AUDIO_IO_STATE_PAUSED. + * @see audio_in_resume() + */ +int audio_in_pause(audio_in_h input); + +/** + * @brief Resumes buffering audio data from the device. + * + * @since_tizen 3.0 + * + * @param[in] input The handle to the audio input + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_PAUSED. + * @post The state will be #AUDIO_IO_STATE_RUNNING. + * @see audio_in_pause() + */ +int audio_in_resume(audio_in_h input); + +/** * @brief Flushes and discards buffered audio data from the input stream. * * @since_tizen 2.4 @@ -274,6 +378,9 @@ int audio_in_unprepare(audio_in_h input); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_RUNNING or #AUDIO_IO_STATE_PAUSED. */ int audio_in_flush(audio_in_h input); @@ -292,8 +399,9 @@ int audio_in_flush(audio_in_h input); * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error * @retval #AUDIO_IO_ERROR_INVALID_OPERATION Invalid operation * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported - * @pre audio_in_start_recording(). -*/ + * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. + */ int audio_in_read(audio_in_h input, void *buffer, unsigned int length); /** @@ -309,7 +417,7 @@ int audio_in_read(audio_in_h input, void *buffer, unsigned int length); * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported * @see audio_in_read() -*/ + */ int audio_in_get_buffer_size(audio_in_h input, int *size); /** @@ -324,16 +432,16 @@ int audio_in_get_buffer_size(audio_in_h input, int *size); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported -*/ + */ int audio_in_get_sample_rate(audio_in_h input, int *sample_rate); /** * @brief Gets the channel type of the audio input data stream. * - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif - * * @details The audio channel type defines whether the audio is mono or stereo. * + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * * @param[in] input The handle to the audio input * @param[out] channel The audio channel type * @return @c 0 on success, @@ -341,7 +449,7 @@ int audio_in_get_sample_rate(audio_in_h input, int *sample_rate); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported -*/ + */ int audio_in_get_channel(audio_in_h input, audio_channel_e *channel); /** @@ -356,10 +464,11 @@ int audio_in_get_channel(audio_in_h input, audio_channel_e *channel); * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported -*/ + */ int audio_in_get_sample_type(audio_in_h input, audio_sample_type_e *type); /** + * @deprecated Deprecated since 3.0. Use sound_manager_create_stream_information() instead. * @brief Registers a callback function to be invoked when the audio input handle is interrupted or the interrupt is completed. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -381,6 +490,7 @@ int audio_in_get_sample_type(audio_in_h input, audio_sample_type_e *type); int audio_in_set_interrupted_cb(audio_in_h input, audio_io_interrupted_cb callback, void *user_data); /** + * @deprecated Deprecated since 3.0 * @brief Unregisters the callback function. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -398,6 +508,7 @@ int audio_in_set_interrupted_cb(audio_in_h input, audio_io_interrupted_cb callba int audio_in_unset_interrupted_cb(audio_in_h input); /** + * @deprecated Deprecated since 3.0 * @brief Ignores session for input. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -415,19 +526,19 @@ int audio_in_ignore_session(audio_in_h input); /** * @brief Sets an asynchronous(event) callback function to handle recording PCM (pulse-code modulation) data. * - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif - * * @details @a callback will be called when you can read a PCM data. * It might cause dead lock if change the state of audio handle in callback. * (ex: audio_in_destroy, audio_in_prepare, audio_in_unprepare) * Recommend to use as a VOIP only. * Recommend not to hold callback too long.(it affects latency) * + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * * @remarks @a input must be created using audio_in_create(). * * @param[in] input An audio input handle * @param[in] callback notify stream callback when user can read data (#audio_in_stream_cb) - * @param[in] userdata user data to be retrieved when callback is called + * @param[in] user_data user data to be retrieved when callback is called * @return @c 0 on success, * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful @@ -439,7 +550,7 @@ int audio_in_ignore_session(audio_in_h input); * * @see audio_out_set_stream_cb() */ -int audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* userdata); +int audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* user_data); /** * @brief Unregisters the callback function. @@ -461,10 +572,10 @@ int audio_in_unset_stream_cb(audio_in_h input); /** * @brief peek from audio in buffer * - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif - * * @details This function works correctly only with read, write callback. Otherwise it won't operate as intended. * + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * * @remarks @a Works only in asynchronous(event) mode. This will just retrieve buffer pointer from audio in buffer. Drop after use. * * @param[in] input The handle to the audio input @@ -476,7 +587,9 @@ int audio_in_unset_stream_cb(audio_in_h input); * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_INVALID_OPERATION Invalid operation * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. * @see audio_in_drop() */ int audio_in_peek(audio_in_h input, const void **buffer, unsigned int *length); @@ -496,22 +609,58 @@ int audio_in_peek(audio_in_h input, const void **buffer, unsigned int *length); * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_INVALID_OPERATION Invalid operation * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. * @see audio_in_peek() */ int audio_in_drop(audio_in_h input); +/** + * @brief Sets the state changed callback function to the audio input handle. + * + * @since_tizen 3.0 + * + * @remarks @a input must be created using audio_in_create(). + * + * @param[in] input The audio input handle + * @param[in] callback the state changed callback called when the state of the handle is changed (#audio_in_state_changed_cb) + * @param[in] user_data user data to be retrieved when callback is called + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * + * @see audio_in_unset_state_changed_cb() + */ +int audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb callback, void* user_data); + +/** + * @brief Unregisters the state changed callback function of the audio input handle. + * + * @since_tizen 3.0 + * + * @param[in] input The handle to the audio input + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * + * @see audio_in_set_state_changed_cb() + */ +int audio_in_unset_state_changed_cb(audio_in_h input); +/** + * @} + */ // // AUDIO OUTPUT // /** - * @} -*/ - -/** * @addtogroup CAPI_MEDIA_AUDIO_OUT_MODULE * @{ */ @@ -524,24 +673,41 @@ int audio_in_drop(audio_in_h input); * @remarks @a use audio_out_write() to write pcm data inside this callback. * @param[in] handle The handle to the audio output * @param[in] nbytes The amount of audio in data which can be written. - * @param[in] userdata The user data passed from the callback registration function + * @param[in] user_data The user data passed from the callback registration function * * @see audio_out_set_stream_cb() */ -typedef void (*audio_out_stream_cb)(audio_out_h handle, size_t nbytes, void *userdata); +typedef void (*audio_out_stream_cb)(audio_out_h handle, size_t nbytes, void *user_data); /** - * @brief Creates an audio device instance and returns an output handle to play PCM (pulse-code modulation) data. + * @brief Called when the state of audio output is changed. + * + * @since_tizen 3.0 + * + * @param[in] handle The handle of the audio output + * @param[in] previous The previous state of the audio output + * @param[in] current The current state of the audio output + * @param[in] by_policy @c true if the state is changed by policy, otherwise @c false if the state is not changed by policy + * @param[in] user_data The user data passed from the callback registration function + * + * @see audio_out_set_state_changed_cb() + * @see audio_out_unset_state_changed_cb() + */ +typedef void (*audio_out_state_changed_cb)(audio_out_h handle, audio_io_state_e previous, audio_io_state_e current, bool by_policy, void *user_data); - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif +/** + * @deprecated Deprecated since 3.0. Use audio_out_create_new() instead. + * @brief Creates an audio device instance and returns an output handle to play PCM (pulse-code modulation) data. * * @details This function is used for audio output initialization. * + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * * @remarks @a output must be released by audio_out_destroy(). * * @param[in] sample_rate The audio sample rate in 8000[Hz] ~ 48000[Hz] * @param[in] channel The audio channel type (mono or stereo) - * @param[in] type The type of audio sample (8- or 16-bit) + * @param[in] type The type of audio sample (8-bit or 16-bit) * @param[in] sound_type The type of sound (#sound_type_e) * @param[out] output An audio output handle is created on success * @return @c 0 on success, @@ -553,10 +719,38 @@ typedef void (*audio_out_stream_cb)(audio_out_h handle, size_t nbytes, void *use * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error * * @see audio_out_destroy() -*/ + */ int audio_out_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h *output); /** + * @brief Creates an audio device instance and returns an output handle to play PCM (pulse-code modulation) data. + * + * @details This function is used for audio output initialization. + * + * @since_tizen 3.0 + * + * @remarks @a output must be released by audio_out_destroy(). + * It is recommended to call audio_out_set_stream_info() after this API. + * + * @param[in] sample_rate The audio sample rate in 8000[Hz] ~ 48000[Hz] + * @param[in] channel The audio channel type (mono or stereo) + * @param[in] type The type of audio sample (8-bit or 16-bit) + * @param[out] output An audio output handle is created on success + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_OUT_OF_MEMORY Out of memory + * @retval #AUDIO_IO_ERROR_DEVICE_NOT_OPENED Device not opened + * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error + * + * @post The state will be #AUDIO_IO_STATE_IDLE.\n + * audio_out_set_stream_info() is recommended to be called after this API. + * @see audio_out_destroy() + */ +int audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output); + +/** * @brief Releases the audio output handle, along with all its resources. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -570,11 +764,36 @@ int audio_out_create(int sample_rate, audio_channel_e channel, audio_sample_type * @retval #AUDIO_IO_ERROR_DEVICE_NOT_CLOSED Device not closed * * @see audio_out_create() -*/ + */ int audio_out_destroy(audio_out_h output); /** - * @brief Prepares playing audio output, this must be called before audio_out_write(). + * @brief Sets the sound stream information to the audio output. + * + * @since_tizen 3.0 + * + * @remarks @a the sound stream information includes audio routing and volume type. + * For more details, you can refer to sound_manager.h + * + * @param[in] output The handle to the audio output + * @param[in] stream_info The handle of stream information + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_IDLE.\n + * Call audio_out_create_new() before calling this function. + * @post Call audio_out_prepare() after calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int audio_out_set_stream_info(audio_out_h output, sound_stream_info_h stream_info); + +/** + * @brief Prepares the audio output for playback, this must be called before audio_out_write(). * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @@ -583,13 +802,15 @@ int audio_out_destroy(audio_out_h output); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @post The state will be #AUDIO_IO_STATE_RUNNING. * @see audio_out_unprepare() */ int audio_out_prepare(audio_out_h output); /** - * @brief Unprepares playing audio output. + * @brief Unprepares the audio output. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif * @@ -598,12 +819,50 @@ int audio_out_prepare(audio_out_h output); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @post The state will be #AUDIO_IO_STATE_IDLE. * @see audio_out_prepare() */ int audio_out_unprepare(audio_out_h output); /** + * @brief Pauses feeding of audio data to the device. + * + * @since_tizen 3.0 + * + * @param[in] output The handle to the audio output + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. + * @post The state will be #AUDIO_IO_STATE_PAUSED. + * @see audio_out_resume() + */ +int audio_out_pause(audio_out_h output); + +/** + * @brief Resumes feeding of audio data to the device. + * + * @since_tizen 3.0 + * + * @param[in] output The handle to the audio output + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_PAUSED. + * @post The state will be #AUDIO_IO_STATE_RUNNING. + * @see audio_out_pause() + */ +int audio_out_resume(audio_out_h output); + +/** * @brief Drains buffered audio data from the output stream. * * @details This function waits until drains stream buffer completely. (e.g end of playback) @@ -615,7 +874,9 @@ int audio_out_unprepare(audio_out_h output); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @pre The state should be #AUDIO_IO_STATE_RUNNING or #AUDIO_IO_STATE_PAUSED. * @see audio_out_flush() */ int audio_out_drain(audio_out_h output); @@ -630,7 +891,9 @@ int audio_out_drain(audio_out_h output); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state * + * @pre The state should be #AUDIO_IO_STATE_RUNNING or #AUDIO_IO_STATE_PAUSED. * @see audio_out_drain() */ int audio_out_flush(audio_out_h output); @@ -648,7 +911,10 @@ int audio_out_flush(audio_out_h output); * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * @retval #AUDIO_IO_ERROR_INVALID_BUFFER Invalid buffer pointer * @retval #AUDIO_IO_ERROR_SOUND_POLICY Sound policy error -*/ + * @retval #AUDIO_IO_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #AUDIO_IO_STATE_RUNNING. + */ int audio_out_write(audio_out_h output, void *buffer, unsigned int length); /** @@ -664,7 +930,7 @@ int audio_out_write(audio_out_h output, void *buffer, unsigned int length); * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter * * @see audio_out_write() -*/ + */ int audio_out_get_buffer_size(audio_out_h output, int *size); /** @@ -678,11 +944,12 @@ int audio_out_get_buffer_size(audio_out_h output, int *size); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter -*/ + */ int audio_out_get_sample_rate(audio_out_h output, int *sample_rate); /** * @brief Gets the channel type of the audio output data stream. + * * @details The audio channel type defines whether the audio is mono or stereo. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -693,7 +960,7 @@ int audio_out_get_sample_rate(audio_out_h output, int *sample_rate); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter -*/ + */ int audio_out_get_channel(audio_out_h output, audio_channel_e *channel); /** @@ -707,10 +974,9 @@ int audio_out_get_channel(audio_out_h output, audio_channel_e *channel); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter -*/ + */ int audio_out_get_sample_type(audio_out_h output, audio_sample_type_e *type); - /** * @brief Gets the sound type supported by the audio output device. * @@ -722,10 +988,11 @@ int audio_out_get_sample_type(audio_out_h output, audio_sample_type_e *type); * otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter -*/ + */ int audio_out_get_sound_type(audio_out_h output, sound_type_e *type); /** + * @deprecated Deprecated since 3.0. Use sound_manager_create_stream_information() instead. * @brief Registers a callback function to be invoked when the audio output handle is interrupted or the interrupt is completed. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -746,6 +1013,7 @@ int audio_out_get_sound_type(audio_out_h output, sound_type_e *type); int audio_out_set_interrupted_cb(audio_out_h output, audio_io_interrupted_cb callback, void *user_data); /** + * @deprecated Deprecated since 3.0 * @brief Unregisters the callback function. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -762,6 +1030,7 @@ int audio_out_set_interrupted_cb(audio_out_h output, audio_io_interrupted_cb cal int audio_out_unset_interrupted_cb(audio_out_h output); /** + * @deprecated Deprecated since 3.0 * @brief Ignores session for output. * * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -778,19 +1047,19 @@ int audio_out_ignore_session(audio_out_h output); /** * @brief Sets an asynchronous(event) callback function to handle playing PCM (pulse-code modulation) data. * - * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif - * * @details @a callback will be called when you can write a PCM data. * It might cause dead lock if change the state of audio handle in callback. * (ex: audio_in_destroy, audio_in_prepare, audio_in_unprepare) * Recommend to use as a VOIP only. * Recommend not to hold callback too long.(it affects latency) * + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * * @remarks @a output must be created using audio_out_create(). * * @param[in] output An audio output handle * @param[in] callback notify stream callback when user can write data (#audio_out_stream_cb) - * @param[in] userdata user data to be retrieved when callback is called + * @param[in] user_data user data to be retrieved when callback is called * @return 0 on success, otherwise a negative error value * @retval #AUDIO_IO_ERROR_NONE Successful * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter @@ -800,7 +1069,7 @@ int audio_out_ignore_session(audio_out_h output); * * @see audio_in_set_stream_cb() */ -int audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* userdata); +int audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* user_data); /** * @brief Unregisters the callback function. @@ -816,9 +1085,44 @@ int audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, vo * @see audio_out_set_stream_cb() */ int audio_out_unset_stream_cb(audio_out_h output); + +/** + * @brief Sets the state changed callback function to the audio output handle. + * + * @since_tizen 3.0 + * + * @remarks @a input must be created using audio_out_create_new(). + * + * @param[in] output The audio output handle + * @param[in] callback the state changed callback called when the state of the handle is changed (#audio_out_state_changed_cb) + * @param[in] user_data user data to be retrieved when callback is called + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see audio_out_unset_state_changed_cb() + */ +int audio_out_set_state_changed_cb(audio_out_h output, audio_out_state_changed_cb callback, void* user_data); + +/** + * @brief Unregisters the state changed callback function of the audio output handle. + * + * @since_tizen 3.0 + * + * @param[in] output The handle to the audio output + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see audio_out_set_state_changed_cb() + */ +int audio_out_unset_state_changed_cb(audio_out_h output); + /** * @} -*/ + */ #ifdef __cplusplus } diff --git a/include/audio_io_private.h b/include/audio_io_private.h deleted file mode 100644 index 8ce9181..0000000 --- a/include/audio_io_private.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* 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. -*/ - -#ifndef __TIZEN_MEDIA_AUDIO_IO_PRIVATE_H__ -#define __TIZEN_MEDIA_AUDIO_IO_PRIVATE_H__ -#include -#include -#include "audio_io.h" - -/* -* Internal Macros -*/ - -#define AUDIO_IO_INTERRUPTED_BY_RESUMABLE_MEDIA (AUDIO_IO_INTERRUPTED_BY_NOTIFICATION + 1) -#define AUDIO_IO_INTERRUPTED_BY_RESUMABLE_CANCELED (AUDIO_IO_INTERRUPTED_BY_NOTIFICATION + 2) - -#define AUDIO_IO_CHECK_CONDITION(condition,error,msg) \ - if(condition) {} else \ - { LOGE("[%s] %s(0x%08x)",__FUNCTION__, msg,error); return error;}; \ - -#define AUDIO_IO_NULL_ARG_CHECK(arg) \ - AUDIO_IO_CHECK_CONDITION(arg != NULL, AUDIO_IO_ERROR_INVALID_PARAMETER, "AUDIO_IO_ERROR_INVALID_PARAMETER" ) - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _audio_in_s{ - MMSoundPcmHandle_t mm_handle; - int is_async; - int is_loopback; - int _buffer_size; - int _sample_rate; - audio_channel_e _channel; - audio_sample_type_e _type; - audio_io_interrupted_cb user_cb; - void* user_data; - audio_in_stream_cb stream_cb; - void* stream_userdata; -} audio_in_s; - -typedef struct _audio_out_s{ - MMSoundPcmHandle_t mm_handle; - int is_async; - int is_loopback; - int _buffer_size; - int _sample_rate; - audio_channel_e _channel; - audio_sample_type_e _type; - sound_type_e _sound_type; - audio_io_interrupted_cb user_cb; - void* user_data; - audio_out_stream_cb stream_cb; - void* stream_userdata; -} audio_out_s; - -int __convert_audio_io_error_code(int code, char *func_name); -int __check_parameter(int sample_rate, audio_channel_e channel, audio_sample_type_e type); -int __mm_sound_pcm_capture_msg_cb (int message, void *param, void *user_param); -audio_io_interrupted_code_e __translate_interrupted_code (int code); - -int audio_in_create_private(int sample_rate, audio_channel_e channel, audio_sample_type_e type , int source_type, audio_in_h* input); - -int audio_in_set_callback_private(audio_in_h input, audio_in_stream_cb callback, void* userdata); - -int audio_out_create_private(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h* output); - -int audio_out_set_callback_private(audio_out_h output, audio_out_stream_cb callback, void* userdata); - - -#ifdef __cplusplus -} -#endif - -#endif //__TIZEN_MEDIA_AUDIO_IO_PRIVATE_H__ diff --git a/include/cpp_audio_io.h b/include/cpp_audio_io.h new file mode 100644 index 0000000..fdaa8e7 --- /dev/null +++ b/include/cpp_audio_io.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#ifndef __TIZEN_MEDIA_CPP_AUDIO_IO_H__ +#define __TIZEN_MEDIA_CPP_AUDIO_IO_H__ + +#include "audio_io.h" + + +#ifdef __cplusplus + + +extern "C" +{ +#endif + +int cpp_audio_in_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_in_h *input); +int cpp_audio_in_create_loopback(int sample_rate, audio_channel_e channel, audio_sample_type_e type , audio_in_h* input); +int cpp_audio_in_destroy(audio_in_h input); +int cpp_audio_in_set_stream_info(audio_in_h input, sound_stream_info_h stream_info); +int cpp_audio_in_prepare(audio_in_h input); +int cpp_audio_in_unprepare(audio_in_h input); +int cpp_audio_in_pause(audio_in_h input); +int cpp_audio_in_resume(audio_in_h input); +int cpp_audio_in_drain(audio_in_h input); +int cpp_audio_in_flush(audio_in_h input); +int cpp_audio_in_read(audio_in_h input, void *buffer, unsigned int length); +int cpp_audio_in_get_buffer_size(audio_in_h input, int *size); +int cpp_audio_in_get_sample_rate(audio_in_h input, int *sample_rate); +int cpp_audio_in_get_channel(audio_in_h input, audio_channel_e *channel); +int cpp_audio_in_get_sample_type(audio_in_h input, audio_sample_type_e *type); +int cpp_audio_in_set_interrupted_cb(audio_in_h input, audio_io_interrupted_cb callback, void *user_data); +int cpp_audio_in_unset_interrupted_cb(audio_in_h input); +int cpp_audio_in_ignore_session(audio_in_h input); +int cpp_audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* user_data); +int cpp_audio_in_unset_stream_cb(audio_in_h input); +int cpp_audio_in_peek(audio_in_h input, const void **buffer, unsigned int *length); +int cpp_audio_in_drop(audio_in_h input); +int cpp_audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb callback, void* user_data); +int cpp_audio_in_unset_state_changed_cb(audio_in_h input); + + +int cpp_audio_out_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h *output); +int cpp_audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output); +int cpp_audio_out_destroy(audio_out_h output); +int cpp_audio_out_set_stream_info(audio_out_h output, sound_stream_info_h stream_info); +int cpp_audio_out_prepare(audio_out_h output); +int cpp_audio_out_unprepare(audio_out_h output); +int cpp_audio_out_pause(audio_out_h output); +int cpp_audio_out_resume(audio_out_h output); +int cpp_audio_out_drain(audio_out_h output); +int cpp_audio_out_flush(audio_out_h output); +int cpp_audio_out_write(audio_out_h output, void *buffer, unsigned int length); +int cpp_audio_out_get_buffer_size(audio_out_h output, int *size); +int cpp_audio_out_get_sample_rate(audio_out_h output, int *sample_rate); +int cpp_audio_out_get_channel(audio_out_h output, audio_channel_e *channel); +int cpp_audio_out_get_sample_type(audio_out_h output, audio_sample_type_e *type); +int cpp_audio_out_get_sound_type(audio_out_h output, sound_type_e *type); +int cpp_audio_out_set_interrupted_cb(audio_out_h output, audio_io_interrupted_cb callback, void *user_data); +int cpp_audio_out_unset_interrupted_cb(audio_out_h output); +int cpp_audio_out_ignore_session(audio_out_h output); +int cpp_audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* user_data); +int cpp_audio_out_unset_stream_cb(audio_out_h output); +int cpp_audio_out_set_state_changed_cb(audio_out_h output, audio_in_state_changed_cb callback, void* user_data); +int cpp_audio_out_unset_state_changed_cb(audio_out_h output); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CPP_AUDIO_IO_H__ */ diff --git a/packaging/capi-media-audio-io.manifest b/packaging/capi-media-audio-io.manifest index 017d22d..a76fdba 100644 --- a/packaging/capi-media-audio-io.manifest +++ b/packaging/capi-media-audio-io.manifest @@ -1,5 +1,5 @@ - - - + + + diff --git a/packaging/capi-media-audio-io.spec b/packaging/capi-media-audio-io.spec index f873d97..28a2454 100644 --- a/packaging/capi-media-audio-io.spec +++ b/packaging/capi-media-audio-io.spec @@ -1,6 +1,6 @@ Name: capi-media-audio-io Summary: An Audio Input & Audio Output library in Tizen Native API -Version: 0.2.3 +Version: 0.3.5 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -8,9 +8,14 @@ Source0: %{name}-%{version}.tar.gz Source1001: capi-media-audio-io.manifest BuildRequires: cmake BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(mm-session) BuildRequires: pkgconfig(mm-sound) +BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(capi-media-sound-manager) BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(libpulse) +Requires(post): libprivilege-control %description An Audio Input & Audio Output library in Tizen Native API @@ -27,7 +32,6 @@ An Audio Input & Audio Output library in Tizen Native API (DEV) %setup -q cp %{SOURCE1001} . - %build MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` %cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} @@ -36,15 +40,17 @@ make %{?jobs:-j%jobs} %install %make_install +mkdir -p %{buildroot}/usr/share/privilege-control -%post -p /sbin/ldconfig +%post +/sbin/ldconfig +/usr/bin/api_feature_loader --verbose --dir=/usr/share/privilege-control %postun -p /sbin/ldconfig - %files %manifest %{name}.manifest -%license LICENSE.APLv2 +%license LICENSE %{_libdir}/libcapi-media-audio-io.so.* %manifest capi-media-audio-io.manifest @@ -53,5 +59,5 @@ make %{?jobs:-j%jobs} %{_includedir}/media/audio_io.h %{_libdir}/pkgconfig/*.pc %{_libdir}/libcapi-media-audio-io.so - +#%{_prefix}/bin/audio_io_test diff --git a/src/audio_io.c b/src/audio_io.c index 54a7f1e..57eea3f 100644 --- a/src/audio_io.c +++ b/src/audio_io.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,565 +14,239 @@ * limitations under the License. */ -#include -#include -#include -#include -#include "audio_io_private.h" -#include - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "TIZEN_N_AUDIO_IO" -#include -/* -* Internal Implementation -*/ +#include +#include -/* -* Public Implementation -*/ - -/* Audio In */ int audio_in_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type , audio_in_h* input) { - return audio_in_create_private (sample_rate, channel, type, SUPPORT_SOURCE_TYPE_DEFAULT, input); + return cpp_audio_in_create(sample_rate, channel, type, input); } int audio_in_create_loopback(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_in_h* input) { - return audio_in_create_private (sample_rate, channel, type, SUPPORT_SOURCE_TYPE_LOOPBACK, input); + return cpp_audio_in_create_loopback(sample_rate, channel, type, input); } int audio_in_destroy(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s *handle = (audio_in_s *) input; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_capture_close_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_capture_close(handle->mm_handle); - } - if (ret != MM_ERROR_NONE) { - free(handle); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - free(handle); + return cpp_audio_in_destroy(input); +} - LOGI("[%s] mm_sound_pcm_capture_close() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; +int audio_in_set_stream_info(audio_in_h input, sound_stream_info_h stream_info) +{ + return cpp_audio_in_set_stream_info(input, stream_info); } int audio_in_prepare(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s *handle = (audio_in_s *) input; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_capture_start_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_capture_start(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_capture_start() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_prepare(input); } int audio_in_unprepare(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s *handle = (audio_in_s *) input; - int ret = MM_ERROR_NONE; + return cpp_audio_in_unprepare(input); +} - if (handle->is_async) { - ret = mm_sound_pcm_capture_stop_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_capture_stop(handle->mm_handle); - } - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } +int audio_in_pause(audio_in_h input) +{ + return cpp_audio_in_pause(input); +} - LOGI("[%s] mm_sound_pcm_capture_stop() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; +int audio_in_resume(audio_in_h input) +{ + return cpp_audio_in_resume(input); } int audio_in_flush(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s *handle = (audio_in_s *) input; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_capture_flush_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_capture_flush(handle->mm_handle); - } - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_capture_flush() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_flush(input); } int audio_in_read(audio_in_h input, void *buffer, unsigned int length ) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(buffer); - audio_in_s *handle = (audio_in_s *) input; - int ret = 0; - int result = 0; - - if (handle->is_async) { - LOGE ("audio_in_read doesn't operate in async mode!!!, use audio_in_peek/audio_in_drop instead"); - return AUDIO_IO_ERROR_INVALID_OPERATION; - } - - ret = mm_sound_pcm_capture_read(handle->mm_handle, (void*) buffer, length); - if (ret > 0) - return ret; - - switch(ret) - { - case MM_ERROR_SOUND_INVALID_STATE: - result = AUDIO_IO_ERROR_INVALID_OPERATION; - LOGE("[%s] (0x%08x) : Not recording started yet.",(char*)__FUNCTION__, AUDIO_IO_ERROR_INVALID_OPERATION); - break; - default: - result = __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - break; - } - return result; + return cpp_audio_in_read(input, buffer, length); } int audio_in_get_buffer_size(audio_in_h input, int *size) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(size); - audio_in_s *handle = (audio_in_s *) input; - - *size = handle->_buffer_size; - - LOGI("[%s] buffer size = %d",__FUNCTION__, *size); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_get_buffer_size(input, size); } int audio_in_get_sample_rate(audio_in_h input, int *sample_rate) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(sample_rate); - audio_in_s *handle = (audio_in_s *) input; - - *sample_rate = handle->_sample_rate; - - LOGI("[%s] sample rate = %d",__FUNCTION__, *sample_rate); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_get_sample_rate(input, sample_rate); } - int audio_in_get_channel(audio_in_h input, audio_channel_e *channel) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(channel); - audio_in_s *handle = (audio_in_s *) input; - - *channel = handle->_channel; - - LOGI("[%s] channel = %d",__FUNCTION__, *channel); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_get_channel(input, channel); } int audio_in_get_sample_type(audio_in_h input, audio_sample_type_e *type) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(type); - audio_in_s *handle = (audio_in_s *) input; - - *type = handle->_type; - - LOGI("[%s] sample type = %d",__FUNCTION__, *type); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_get_sample_type(input, type); } int audio_in_set_interrupted_cb(audio_in_h input, audio_io_interrupted_cb callback, void *user_data) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(callback); - audio_in_s *handle = (audio_in_s *) input; - - handle->user_cb = callback; - handle->user_data = user_data; - - LOGI("[%s] current interrupted cb (%p) / data (%p)",__FUNCTION__, handle->user_cb, handle->user_data); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_set_interrupted_cb(input, callback, user_data); } int audio_in_unset_interrupted_cb(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s * handle = (audio_in_s *) input; - - handle->user_cb = NULL; - handle->user_data = NULL; - - LOGI("[%s] current interrupted cb (%p) / data (%p)",__FUNCTION__, handle->user_cb, handle->user_data); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_unset_interrupted_cb(input); } int audio_in_ignore_session(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s * handle = (audio_in_s *) input; - int ret = 0; - - if (handle->is_async) { - LOGE ("Not supported in async mode"); - return AUDIO_IO_ERROR_INVALID_OPERATION; - } - - ret = mm_sound_pcm_capture_ignore_session(handle->mm_handle); - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_capture_ignore_session() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_in_ignore_session(input); } -int audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* userdata) +int audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* user_data) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(callback); - return audio_in_set_callback_private(input, callback, userdata); + return cpp_audio_in_set_stream_cb(input, callback, user_data); } int audio_in_unset_stream_cb(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - return audio_in_set_callback_private(input, NULL, NULL); + return cpp_audio_in_unset_stream_cb(input); } int audio_in_peek(audio_in_h input, const void **buffer, unsigned int *length) { - AUDIO_IO_NULL_ARG_CHECK(input); - AUDIO_IO_NULL_ARG_CHECK(buffer); - audio_in_s *handle = (audio_in_s *) input; - int ret = 0; - int result = 0; - LOGE("handle->is_async : %d", handle->is_async); - if (!handle->is_async) { - LOGE ("audio_in_peek doesn't operate in poll mode!!!, use audio_in_read instead"); - return AUDIO_IO_ERROR_INVALID_OPERATION; - } - - LOGE("before mm_sound_pcm_capture_peek(handle[%p], buffer[%p], length[%d])", handle->mm_handle, buffer, length); - ret = mm_sound_pcm_capture_peek(handle->mm_handle, buffer, length); - LOGE("after mm_sound_pcm_capture_peek() ret[%d]", ret); - switch(ret) - { - case MM_ERROR_SOUND_INVALID_STATE: - result = AUDIO_IO_ERROR_INVALID_OPERATION; - LOGE("[%s] (0x%08x) : Not recording started yet.",(char*)__FUNCTION__, AUDIO_IO_ERROR_INVALID_OPERATION); - break; - default: - result = __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - break; - } - return result; + return cpp_audio_in_peek(input, buffer, length); } int audio_in_drop(audio_in_h input) { - AUDIO_IO_NULL_ARG_CHECK(input); - audio_in_s *handle = (audio_in_s *) input; - int ret = 0; - int result = 0; - - if (!handle->is_async) { - LOGE ("audio_in_drop doesn't operate in poll mode!!!, use audio_in_read instead"); - return AUDIO_IO_ERROR_INVALID_OPERATION; - } + return cpp_audio_in_drop(input); +} - ret = mm_sound_pcm_capture_drop(handle->mm_handle); - if (ret == MM_ERROR_NONE) { - return ret; - } +int audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb callback, void* user_data) +{ + return cpp_audio_in_set_state_changed_cb(input, callback, user_data); +} - switch(ret) - { - case MM_ERROR_SOUND_INVALID_STATE: - result = AUDIO_IO_ERROR_INVALID_OPERATION; - LOGE("[%s] (0x%08x) : Not recording started yet.",(char*)__FUNCTION__, AUDIO_IO_ERROR_INVALID_OPERATION); - break; - default: - result = __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - break; - } - return result; +int audio_in_unset_state_changed_cb(audio_in_h input) +{ + return cpp_audio_in_unset_state_changed_cb(input); } /* Audio Out */ int audio_out_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h* output) { - return audio_out_create_private(sample_rate, channel, type, sound_type, output); + return cpp_audio_out_create(sample_rate, channel, type, sound_type, output); } -int audio_out_destroy(audio_out_h output) +int audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; + return cpp_audio_out_create_new(sample_rate, channel, type, output); +} - if (handle->is_async) { - ret = mm_sound_pcm_play_close_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_close(handle->mm_handle); - } - if (ret != MM_ERROR_NONE) { - free(handle); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - free(handle); +int audio_out_destroy(audio_out_h output) +{ + return cpp_audio_out_destroy(output); +} - LOGI("[%s] mm_sound_pcm_play_close() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; +int audio_out_set_stream_info(audio_out_h output, sound_stream_info_h stream_info) +{ + return cpp_audio_out_set_stream_info(output, stream_info); } int audio_out_prepare(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_play_start_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_start(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_play_start() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_prepare(output); } int audio_out_unprepare(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_play_stop_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_stop(handle->mm_handle); - } + return cpp_audio_out_unprepare(output); +} - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } +int audio_out_pause(audio_out_h output) +{ + return cpp_audio_out_pause(output); +} - LOGI("[%s] mm_sound_pcm_play_stop() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; +int audio_out_resume(audio_out_h output) +{ + return cpp_audio_out_resume(output); } int audio_out_drain(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_play_drain_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_drain(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_play_drain() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_drain(output); } int audio_out_flush(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_play_flush_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_flush(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - LOGI("[%s] mm_sound_pcm_play_flush() success",__FUNCTION__); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_flush(output); } int audio_out_write(audio_out_h output, void* buffer, unsigned int length) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(buffer); - audio_out_s *handle = (audio_out_s *) output; - int ret = MM_ERROR_NONE; - - if (handle->is_async) { - ret = mm_sound_pcm_play_write_async(handle->mm_handle, (void*) buffer, length); - } else { - ret = mm_sound_pcm_play_write(handle->mm_handle, (void*) buffer, length); - } - - if (ret > 0) - return ret; - - switch(ret) - { - case MM_ERROR_SOUND_INVALID_STATE: - ret = AUDIO_IO_ERROR_INVALID_OPERATION; - LOGE("[%s] (0x%08x) : Not playing started yet.",(char*)__FUNCTION__, AUDIO_IO_ERROR_INVALID_OPERATION); - break; - default: - ret = __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - break; - } - return ret; + return cpp_audio_out_write(output, buffer, length); } int audio_out_get_buffer_size(audio_out_h output, int *size) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(size); - audio_out_s *handle = (audio_out_s *) output; - - *size = handle->_buffer_size; - - LOGI("[%s] buffer size = %d",__FUNCTION__, *size); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_get_buffer_size(output, size); } int audio_out_get_sample_rate(audio_out_h output, int *sample_rate) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(sample_rate); - audio_out_s *handle = (audio_out_s *) output; - - *sample_rate = handle->_sample_rate; - - LOGI("[%s] sample rate = %d",__FUNCTION__, *sample_rate); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_get_sample_rate(output, sample_rate); } int audio_out_get_channel(audio_out_h output, audio_channel_e *channel) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(channel); - audio_out_s *handle = (audio_out_s *) output; - - *channel = handle->_channel; - - LOGI("[%s] channel = %d",__FUNCTION__, *channel); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_get_channel(output, channel); } int audio_out_get_sample_type(audio_out_h output, audio_sample_type_e *type) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(type); - audio_out_s *handle = (audio_out_s *) output; - - *type = handle->_type; - - LOGI("[%s] sample type = %d",__FUNCTION__, *type); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_get_sample_type(output, type); } int audio_out_get_sound_type(audio_out_h output, sound_type_e *type) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(type); - audio_out_s *handle = (audio_out_s *) output; - - *type = handle->_sound_type; - - LOGI("[%s] sound type = %d",__FUNCTION__, *type); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_get_sound_type(output, type); } int audio_out_set_interrupted_cb(audio_out_h output, audio_io_interrupted_cb callback, void *user_data) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(callback); - audio_out_s *handle = (audio_out_s *) output; - - handle->user_cb = callback; - handle->user_data = user_data; - - LOGI("[%s] current interrupted cb (%p) / data (%p)",__FUNCTION__, handle->user_cb, handle->user_data); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_set_interrupted_cb(output, callback, user_data); } int audio_out_unset_interrupted_cb(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - - handle->user_cb = NULL; - handle->user_data = NULL; - - LOGI("[%s] current interrupted cb (%p) / data (%p)",__FUNCTION__, handle->user_cb, handle->user_data); - return AUDIO_IO_ERROR_NONE; + return cpp_audio_out_unset_interrupted_cb(output); } int audio_out_ignore_session(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - audio_out_s *handle = (audio_out_s *) output; - int ret = 0; - - if (handle->is_async) { - LOGE ("Not supported in async mode"); - return AUDIO_IO_ERROR_INVALID_OPERATION; - } + return cpp_audio_out_ignore_session(output); +} - ret = mm_sound_pcm_play_ignore_session(handle->mm_handle); - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - LOGI("[%s] mm_sound_pcm_play_ignore_session() success",__FUNCTION__); +int audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* user_data) +{ + return cpp_audio_out_set_stream_cb(output, callback, user_data); +} - return AUDIO_IO_ERROR_NONE; +int audio_out_unset_stream_cb(audio_out_h output) +{ + return cpp_audio_out_unset_stream_cb(output); } -int audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* userdata) +int audio_out_set_state_changed_cb(audio_out_h output, audio_out_state_changed_cb callback, void* user_data) { - AUDIO_IO_NULL_ARG_CHECK(output); - AUDIO_IO_NULL_ARG_CHECK(callback); - return audio_out_set_callback_private(output, callback, userdata); + return cpp_audio_out_set_state_changed_cb(output, callback, user_data); } -int audio_out_unset_stream_cb(audio_out_h output) +int audio_out_unset_state_changed_cb(audio_out_h output) { - AUDIO_IO_NULL_ARG_CHECK(output); - return audio_out_set_callback_private(output, NULL, NULL); + return cpp_audio_out_unset_state_changed_cb(output); } diff --git a/src/audio_io_private.c b/src/audio_io_private.c deleted file mode 100644 index b56a6de..0000000 --- a/src/audio_io_private.c +++ /dev/null @@ -1,459 +0,0 @@ -/* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved -* -* 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 -#include -#include -#include -#include "audio_io_private.h" -#include - -#include - - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "TIZEN_N_AUDIO_IO" -/* -* Internal Implementation -*/ -int __convert_audio_io_error_code(int code, char *func_name) -{ - int ret = AUDIO_IO_ERROR_INVALID_OPERATION; - char* msg = "AUDIO_IO_ERROR_INVALID_OPERATION"; - - switch(code) - { - case MM_ERROR_NONE: - ret = AUDIO_IO_ERROR_NONE; - msg = "AUDIO_IO_ERROR_NONE"; - break; - case MM_ERROR_INVALID_ARGUMENT: - case MM_ERROR_SOUND_DEVICE_INVALID_SAMPLERATE: - case MM_ERROR_SOUND_DEVICE_INVALID_CHANNEL: - case MM_ERROR_SOUND_DEVICE_INVALID_FORMAT: - ret = AUDIO_IO_ERROR_INVALID_PARAMETER; - msg = "AUDIO_IO_ERROR_INVALID_PARAMETER"; - break; - case MM_ERROR_SOUND_DEVICE_NOT_OPENED: - ret = AUDIO_IO_ERROR_DEVICE_NOT_OPENED; - msg = "AUDIO_IO_ERROR_DEVICE_NOT_OPENED"; - break; - case MM_ERROR_SOUND_PERMISSION_DENIED: - ret = AUDIO_IO_ERROR_PERMISSION_DENIED; - msg = "AUDIO_IO_ERROR_PERMISSION_DENIED"; - break; - case MM_ERROR_SOUND_INTERNAL: - ret = AUDIO_IO_ERROR_INVALID_OPERATION; - msg = "AUDIO_IO_ERROR_INVALID_OPERATION"; - break; - case MM_ERROR_SOUND_INVALID_POINTER: - ret = AUDIO_IO_ERROR_INVALID_BUFFER; - msg = "AUDIO_IO_ERROR_INVALID_BUFFER"; - break; - case MM_ERROR_POLICY_BLOCKED: - case MM_ERROR_POLICY_INTERRUPTED: - case MM_ERROR_POLICY_INTERNAL: - case MM_ERROR_POLICY_DUPLICATED: - ret = AUDIO_IO_ERROR_SOUND_POLICY; - msg = "AUDIO_IO_ERROR_SOUND_POLICY"; - break; - } - LOGE("[%s] %s(0x%08x) : core fw error(0x%x)",func_name,msg, ret, code); - return ret; -} - -int __check_parameter(int sample_rate, audio_channel_e channel, audio_sample_type_e type) -{ - if(sample_rate<8000 || sample_rate > 48000) { - LOGE("[%s] AUDIO_IO_ERROR_INVALID_PARAMETER(0x%08x) : Invalid sample rate (8000~48000Hz) : %d",__FUNCTION__, AUDIO_IO_ERROR_INVALID_PARAMETER,sample_rate); - return AUDIO_IO_ERROR_INVALID_PARAMETER; - } - if (channel < AUDIO_CHANNEL_MONO || channel > AUDIO_CHANNEL_STEREO) { - LOGE("[%s] AUDIO_IO_ERROR_INVALID_PARAMETER(0x%08x) : Invalid audio channel : %d",__FUNCTION__, AUDIO_IO_ERROR_INVALID_PARAMETER,channel); - return AUDIO_IO_ERROR_INVALID_PARAMETER; - } - if (type < AUDIO_SAMPLE_TYPE_U8 || type > AUDIO_SAMPLE_TYPE_S16_LE) { - LOGE("[%s] AUDIO_IO_ERROR_INVALID_PARAMETER(0x%08x) : Invalid sample typel : %d",__FUNCTION__, AUDIO_IO_ERROR_INVALID_PARAMETER,type); - return AUDIO_IO_ERROR_INVALID_PARAMETER; - } - return AUDIO_IO_ERROR_NONE; -} - -//LCOV_EXCL_START -audio_io_interrupted_code_e __translate_interrupted_code (int code) -{ - audio_io_interrupted_code_e e = AUDIO_IO_INTERRUPTED_COMPLETED; - - switch(code) - { - case MM_MSG_CODE_INTERRUPTED_BY_CALL_END: - case MM_MSG_CODE_INTERRUPTED_BY_ALARM_END: - case MM_MSG_CODE_INTERRUPTED_BY_EMERGENCY_END: - case MM_MSG_CODE_INTERRUPTED_BY_NOTIFICATION_END: - e = AUDIO_IO_INTERRUPTED_COMPLETED; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_MEDIA: - case MM_MSG_CODE_INTERRUPTED_BY_OTHER_PLAYER_APP: - e = AUDIO_IO_INTERRUPTED_BY_MEDIA; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_CALL_START: - e = AUDIO_IO_INTERRUPTED_BY_CALL; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_EARJACK_UNPLUG: - e = AUDIO_IO_INTERRUPTED_BY_EARJACK_UNPLUG; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT: - e = AUDIO_IO_INTERRUPTED_BY_RESOURCE_CONFLICT; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_ALARM_START: - e = AUDIO_IO_INTERRUPTED_BY_ALARM; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_NOTIFICATION_START: - e = AUDIO_IO_INTERRUPTED_BY_NOTIFICATION; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_EMERGENCY_START: - e = AUDIO_IO_INTERRUPTED_BY_EMERGENCY; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_RESUMABLE_MEDIA: - e = AUDIO_IO_INTERRUPTED_BY_RESUMABLE_MEDIA; - break; - - case MM_MSG_CODE_INTERRUPTED_BY_RESUMABLE_CANCELED: - e = AUDIO_IO_INTERRUPTED_BY_RESUMABLE_CANCELED; - break; - } - - return e; -} - -int __mm_sound_pcm_capture_msg_cb (int message, void *param, void *user_param) -{ - audio_io_interrupted_code_e e = AUDIO_IO_INTERRUPTED_COMPLETED; - audio_in_s *handle = (audio_in_s *) user_param; - MMMessageParamType *msg = (MMMessageParamType*)param; - - LOGI("[%s] Got message type : 0x%x with code : %d" ,__FUNCTION__, message, msg->code); - - if (handle->user_cb == NULL) { - LOGI("[%s] No interrupt callback is set. Skip this" ,__FUNCTION__); - return 0; - } - - if (message == MM_MESSAGE_SOUND_PCM_INTERRUPTED) { - e = __translate_interrupted_code (msg->code); - } else if (message == MM_MESSAGE_SOUND_PCM_CAPTURE_RESTRICTED) { - /* TODO : handling restricted code is needed */ - /* e = _translate_restricted_code (msg->code); */ - } - - handle->user_cb (e, handle->user_data); - - return 0; -} - -static int __mm_sound_pcm_playback_msg_cb (int message, void *param, void *user_param) -{ - audio_io_interrupted_code_e e = AUDIO_IO_INTERRUPTED_COMPLETED; - audio_out_s *handle = (audio_out_s *) user_param; - MMMessageParamType *msg = (MMMessageParamType*)param; - - LOGI("[%s] Got message type : 0x%x with code : %d" ,__FUNCTION__, message, msg->code); - - if (handle->user_cb == NULL) { - LOGI("[%s] No interrupt callback is set. Skip this" ,__FUNCTION__); - return 0; - } - - if (message == MM_MESSAGE_SOUND_PCM_INTERRUPTED) { - e = __translate_interrupted_code (msg->code); - } - - handle->user_cb (e, handle->user_data); - - return 0; -} -//LCOV_EXCL_STOP - -static int __audio_in_stream_cb (void* p, int nbytes, void* userdata) -{ - audio_in_s *handle = (audio_in_s *) userdata; - - LOGI("<< p=%p, nbytes=%d, userdata=%p", p, nbytes, userdata); - - if (handle && handle->stream_cb) { - handle->stream_cb ((audio_in_h)handle, nbytes, handle->stream_userdata); - LOGI("<< handle->stream_cb(handle:%p, nbytes:%d, handle->stream_userdata:%p)", p, nbytes, userdata); - } else { - LOGI("No stream callback is set. Skip this"); - } - return 0; -} - -static int __audio_out_stream_cb (void* p, int nbytes, void* userdata) -{ - audio_out_s *handle = (audio_out_s *) userdata; - bool is_started = false; - char * dummy = NULL; - - LOGI(">> p=%p, nbytes=%d, userdata=%p", p, nbytes, userdata); - - if (handle) { - mm_sound_pcm_is_started_async(handle->mm_handle, &is_started); - if (is_started) { - if (handle->stream_cb) { - handle->stream_cb ((audio_out_h)handle, nbytes, handle->stream_userdata); - } else { - LOGI("Started state but No stream callback is set. Skip this"); - } - } else { - LOGI("Not started....write dummy data"); - if ((dummy = (char*)malloc(nbytes)) != NULL) { - memset (dummy, 0, nbytes); - mm_sound_pcm_play_write_async(handle->mm_handle, (void*) dummy, nbytes); - free (dummy); - LOGI("write done!!!"); - } else { - LOGE("ERROR : AUDIO_IO_ERROR_OUT_OF_MEMORY(0x%08x)", AUDIO_IO_ERROR_OUT_OF_MEMORY); - } - } - } else { - LOGE("Handle is invalid..."); - } - - return 0; -} - -int audio_in_create_private(int sample_rate, audio_channel_e channel, audio_sample_type_e type , int source_type, audio_in_h* input) -{ - int ret = 0; - audio_in_s *handle = NULL; - - /* input condition check */ - AUDIO_IO_NULL_ARG_CHECK(input); - if(__check_parameter(sample_rate, channel, type) != AUDIO_IO_ERROR_NONE) - return AUDIO_IO_ERROR_INVALID_PARAMETER; - - /* Create Handle & Fill information */ - if ((handle = (audio_in_s*)malloc( sizeof(audio_in_s))) == NULL) { - LOGE("ERROR : AUDIO_IO_ERROR_OUT_OF_MEMORY(0x%08x)", AUDIO_IO_ERROR_OUT_OF_MEMORY); - return AUDIO_IO_ERROR_OUT_OF_MEMORY; - } - memset(handle, 0, sizeof(audio_in_s)); - - - /* Capture open */ - if ((ret = mm_sound_pcm_capture_open_ex(&handle->mm_handle, sample_rate, channel, type, source_type)) < 0) { - LOGE("mm_sound_pcm_capture_open_ex() failed [0x%x]", ret); - goto ERROR; - } - LOGI("mm_sound_pcm_capture_open_ex() success"); - - - if (source_type == SUPPORT_SOURCE_TYPE_LOOPBACK) - { - handle->is_loopback = 1; - } - - handle->_buffer_size = ret; /* return by pcm_open */ - handle->_sample_rate = sample_rate; - handle->_channel = channel; - handle->_type = type; - - /* Set message interrupt callback */ - if ((ret = mm_sound_pcm_set_message_callback(handle->mm_handle, __mm_sound_pcm_capture_msg_cb, handle)) < 0) { - LOGE("mm_sound_pcm_set_message_callback() failed [0x%x]", ret); - goto ERROR; - } - LOGI("mm_sound_pcm_set_message_callback() success"); - - /* Handle assign */ - *input = (audio_in_h)handle; - - return AUDIO_IO_ERROR_NONE; - -ERROR: - if (handle) - free (handle); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); -} - -int audio_in_set_callback_private(audio_in_h input, audio_in_stream_cb callback, void* userdata) -{ - AUDIO_IO_NULL_ARG_CHECK(input); - - int ret = AUDIO_IO_ERROR_NONE; - int source_type = SUPPORT_SOURCE_TYPE_DEFAULT; - audio_in_s* handle = (audio_in_s*)input; - - // at first, release existing audio handle - if (handle->is_async) { - ret = mm_sound_pcm_capture_close_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_capture_close(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - // Initialize flags - handle->stream_cb = NULL; - handle->stream_userdata = NULL; - handle->is_async = 0; - - // Checks loopback type - if (handle->is_loopback == 1) { - source_type = SUPPORT_SOURCE_TYPE_LOOPBACK; - } - - /* Async (callback exists) or Sync (otherwise) */ - if (callback != NULL) { - handle->stream_cb = callback; - handle->stream_userdata = userdata; - handle->is_async = 1; - - /* Capture open */ - if ((ret = mm_sound_pcm_capture_open_async(&handle->mm_handle, handle->_sample_rate, handle->_channel, handle->_type, source_type, - (mm_sound_pcm_stream_cb_t)__audio_in_stream_cb, handle)) < 0) { - LOGE("mm_sound_pcm_capture_open_async() failed [0x%x]", ret); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - LOGI("mm_sound_pcm_capture_open_async() success"); - } else { - /* Capture open */ - if ((ret = mm_sound_pcm_capture_open_ex(&handle->mm_handle, handle->_sample_rate, handle->_channel, handle->_type, source_type)) < 0) { - LOGE("mm_sound_pcm_capture_open_ex() failed [0x%x]", ret); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - LOGI("mm_sound_pcm_capture_open_ex() success"); - } - - handle->_buffer_size = ret; /* return by pcm_open */ - - return AUDIO_IO_ERROR_NONE; -} - -int audio_out_create_private(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h* output) -{ - audio_out_s *handle = NULL; - int ret = 0; - - /* input condition check */ - AUDIO_IO_NULL_ARG_CHECK(output); - if(__check_parameter(sample_rate, channel, type)!=AUDIO_IO_ERROR_NONE) - return AUDIO_IO_ERROR_INVALID_PARAMETER; - if(sound_type < SOUND_TYPE_SYSTEM || sound_type > SOUND_TYPE_VOICE) { - LOGE("ERROR : AUDIO_IO_ERROR_INVALID_PARAMETER(0x%08x) : Invalid sample sound type : %d", - AUDIO_IO_ERROR_INVALID_PARAMETER,sound_type ); - return AUDIO_IO_ERROR_INVALID_PARAMETER; - } - - /* Create Handle & Fill information */ - if ((handle = (audio_out_s*)malloc( sizeof(audio_out_s))) == NULL) { - LOGE("ERROR : AUDIO_IO_ERROR_OUT_OF_MEMORY(0x%08x)", AUDIO_IO_ERROR_OUT_OF_MEMORY); - return AUDIO_IO_ERROR_OUT_OF_MEMORY; - } - memset(handle, 0 , sizeof(audio_out_s)); - - - if ((ret = mm_sound_pcm_play_open(&handle->mm_handle,sample_rate, channel, type, sound_type)) < 0) { - LOGE("mm_sound_pcm_play_open() failed [0x%x]", ret); - goto ERROR; - } - LOGI("mm_sound_pcm_play_open() success"); - - - handle->_buffer_size = ret; /* return by pcm_open */ - handle->_sample_rate = sample_rate; - handle->_channel = channel; - handle->_type = type; - handle->_sound_type = sound_type; - - /* Set message interrupt callback */ - if ((ret = mm_sound_pcm_set_message_callback(handle->mm_handle, __mm_sound_pcm_playback_msg_cb, handle)) < 0) { - LOGE("mm_sound_pcm_set_message_callback() failed [0x%x]", ret); - goto ERROR; - } - LOGI("mm_sound_pcm_set_message_callback() success"); - - /* Handle assign */ - *output = (audio_out_h)handle; - - return AUDIO_IO_ERROR_NONE; - -ERROR: - if (handle) - free (handle); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); -} - -int audio_out_set_callback_private(audio_out_h output, audio_out_stream_cb callback, void* userdata) -{ - AUDIO_IO_NULL_ARG_CHECK(output); - - int ret = AUDIO_IO_ERROR_NONE; - audio_out_s* handle = (audio_out_s*)output; - - // at first, release existing mm handle - if (handle->is_async) { - ret = mm_sound_pcm_play_close_async(handle->mm_handle); - } else { - ret = mm_sound_pcm_play_close(handle->mm_handle); - } - - if (ret != MM_ERROR_NONE) { - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - - // Initialize flags - handle->stream_cb = NULL; - handle->stream_userdata = NULL; - handle->is_async = 0; - - /* Async (callback exists) or Sync (otherwise) */ - if (callback != NULL) { - handle->stream_cb = callback; - handle->stream_userdata = userdata; - handle->is_async = 1; - - /* Playback open */ - if ((ret = mm_sound_pcm_play_open_async(&handle->mm_handle, handle->_sample_rate, handle->_channel, handle->_type, handle->_sound_type, - (mm_sound_pcm_stream_cb_t)__audio_out_stream_cb, handle)) < 0) { - LOGE("mm_sound_pcm_play_open_async() failed [0x%x]", ret); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - LOGI("mm_sound_pcm_play_open_async() success"); - } else { - if ((ret = mm_sound_pcm_play_open(&handle->mm_handle, handle->_sample_rate, handle->_channel, handle->_type, handle->_sound_type)) < 0) { - LOGE("mm_sound_pcm_play_open() failed [0x%x]", ret); - return __convert_audio_io_error_code(ret, (char*)__FUNCTION__); - } - LOGI("mm_sound_pcm_play_open() success"); - } - handle->_buffer_size = ret; /* return by pcm_open */ - - return AUDIO_IO_ERROR_NONE; -} diff --git a/src/cpp/CAudioError.cpp b/src/cpp/CAudioError.cpp new file mode 100644 index 0000000..b0bbfdb --- /dev/null +++ b/src/cpp/CAudioError.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include +#include +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioError + */ +CAudioError::EError CAudioError::mLastError = CAudioError::ERROR_NONE; +char CAudioError::mLastErrorMsg[CAudioError::MSG_LENGTH]; + +CAudioError::CAudioError(EError err) : mError(err) { + mLastError = mError; +} + +CAudioError::CAudioError(EError err, const char* fileName, const char* parentFunc, int lineNum) : mError(err) { + mLastError = mError; + + const char* findFileName = strrchr(fileName, '/'); + findFileName++; + const char* errStr = _convertErrorToString(mError); + + snprintf(mErrorMsg, CAudioError::MSG_LENGTH, "[" + COLOR_RED "THROW" COLOR_END ":%s|" + COLOR_YELLOW "ERR" COLOR_END ":%s|" + COLOR_YELLOW "FUNC" COLOR_END ":%s(%d)]", findFileName, errStr, parentFunc, lineNum); + + snprintf(mLastErrorMsg, CAudioError::MSG_LENGTH, "LastError:%s", mErrorMsg); +} + +CAudioError::CAudioError(EError err, const char* msg, const char* fileName, const char* parentFunc, int lineNum) : mError(err) { + mLastError = mError; + + const char* findFileName = strrchr(fileName, '/'); + findFileName++; + const char* errStr = _convertErrorToString(mError); + + snprintf(mErrorMsg, CAudioError::MSG_LENGTH, "[" + COLOR_RED "THROW" COLOR_END ":%s|" + COLOR_YELLOW "ERR" COLOR_END ":%s|" + COLOR_YELLOW "FUNC" COLOR_END ":%s(%d)]" + COLOR_YELLOW "MSG" COLOR_END ":" + COLOR_CYAN "%s" COLOR_END, findFileName, errStr, parentFunc, lineNum, msg); + + snprintf(mLastErrorMsg, CAudioError::MSG_LENGTH, "LastError:%s", mErrorMsg); +} + +//CAudioError::CAudioError(CAudioError& err) { +// mError = err.mError; +// strncpy(mErrorMsg, err.mErrorMsg, MSG_LENGTH); +//} + +CAudioError::~CAudioError() { +} + +const char* CAudioError::_convertErrorToString(EError err) { + switch (err) { + + default: + case ERROR_NONE: return COLOR_GREEN "ERROR_NONE" COLOR_END; + case ERROR_INVALID_ARGUMENT: return COLOR_RED "ERROR_INVALID_ARGUMENT" COLOR_END; + case ERROR_INVALID_HANDLE: return COLOR_RED "ERROR_INVALID_HANDLE" COLOR_END; + case ERROR_INVALID_SAMPLERATE: return COLOR_RED "ERROR_INVALID_SAMPLERATE" COLOR_END; + case ERROR_INVALID_CHANNEL: return COLOR_RED "ERROR_INVALID_CHANNEL" COLOR_END; + case ERROR_INVALID_FORMAT: return COLOR_RED "ERROR_INVALID_FORMAT" COLOR_END; + case ERROR_INVALID_POINTER: return COLOR_RED "ERROR_INVALID_POINTER" COLOR_END; + case ERROR_INVALID_OPERATION: return COLOR_RED "ERROR_INVALID_OPERATION" COLOR_END; + case ERROR_NOT_INITIALIZED: return COLOR_RED "ERROR_NOT_INITIALIZED" COLOR_END; + case ERROR_NOT_SUPPORTED: return COLOR_RED "ERROR_NOT_SUPPORTED" COLOR_END; + case ERROR_PERMISSION_DENIED: return COLOR_RED "ERROR_PERMISSION_DENIED" COLOR_END; + case ERROR_DEVICE_NOT_OPENED: return COLOR_RED "ERROR_DEVICE_NOT_OPENED" COLOR_END; + case ERROR_DEVICE_NOT_CLOSED: return COLOR_RED "ERROR_DEVICE_NOT_CLOSED" COLOR_END; + case ERROR_OUT_OF_MEMORY: return COLOR_RED "ERROR_OUT_OF_MEMORY" COLOR_END; + case ERROR_INTERNAL_OPERATION: return COLOR_RED "ERROR_INTERNAL_OPERATION" COLOR_END; + case ERROR_FAILED_OPERATION: return COLOR_RED "ERROR_FAILED_OPERATION" COLOR_END; + case ERROR_POLICY_BLOCKED: return COLOR_RED "ERROR_POLICY_BLOCKED" COLOR_END; + case ERROR_POLICY_INTERRUPTED: return COLOR_RED "ERROR_POLICY_INTERRUPTED" COLOR_END; + case ERROR_POLICY_DUPLICATED: return COLOR_RED "ERROR_POLICY_DUPLICATED" COLOR_END; + } +} + +CAudioError::EError CAudioError::getLastError() { + return mLastError; +} + +const char* CAudioError::getLastErrorMsg() { + return mLastErrorMsg; +} + +CAudioError::EError CAudioError::getError() { + return mError; +} + +const char* CAudioError::getErrorMsg() { + return mErrorMsg; +} + +CAudioError& CAudioError::operator = (const EError err) { + mError = err; + mLastError = mError; + return *this; +} + +CAudioError& CAudioError::operator = (const CAudioError& err) { + mError = err.mError; + mLastError = mError; + memcpy(mErrorMsg, err.mErrorMsg, MSG_LENGTH); + memcpy(mLastErrorMsg, mErrorMsg, MSG_LENGTH); + return *this; +} + +bool CAudioError::operator != (const EError err) { + return (mError != err); +} + +bool CAudioError::operator == (const EError err) { + return (mError == err); +} + +//bool operator == (const CAudioError& src, const CAudioError::EError& err) { +// //return (src.mLastError == err); +// return true; +//} diff --git a/src/cpp/CAudioIO.cpp b/src/cpp/CAudioIO.cpp new file mode 100644 index 0000000..94bed76 --- /dev/null +++ b/src/cpp/CAudioIO.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include +#include +#include +#include "CAudioIODef.h" + +#define AUDIO_IO_DEBUG + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioIO + */ +CAudioIO::CAudioIO() : mIsInit(false), mForceIgnore(false), mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL) { + mState = CAudioInfo::AUDIO_IO_STATE_NONE; + mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE; + mByPolicy = false; +} + +CAudioIO::CAudioIO(CAudioInfo& audioInfo) : mIsInit(false), mForceIgnore(false), mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL) { + mAudioInfo = audioInfo; + mState = CAudioInfo::AUDIO_IO_STATE_NONE; + mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE; + mByPolicy = false; +} + +CAudioIO::~CAudioIO() { +} + +void CAudioIO::setInit(bool flag) { + mIsInit = flag; +} + +bool CAudioIO::isInit() { + return mIsInit; +} + +bool CAudioIO::IsReady() { + return ((mState == CAudioInfo::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::AUDIO_IO_STATE_PAUSED)? true : false); +} + +void CAudioIO::internalLock() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + if (pthread_mutex_lock(&mMutex) != 0) { + THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); + } +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD(COLOR_RED"LOCK"COLOR_END); +#endif +} + +void CAudioIO::internalUnlock() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + if (pthread_mutex_unlock(&mMutex) != 0) { + THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()"); + } +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD(COLOR_GREEN"UNLOCK"COLOR_END); +#endif +} + +void CAudioIO::internalWait() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD(COLOR_RED"WAIT"COLOR_END); +#endif + + pthread_cond_wait(&mCond, &mMutex); +} + +void CAudioIO::internalSignal() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD(COLOR_GREEN"SIGNAL"COLOR_END); +#endif + + pthread_cond_signal(&mCond); +} + +bool CAudioIO::isForceIgnore() { + return mForceIgnore; +} + +void CAudioIO::initialize() throw (CAudioError) { + if (mIsInit == true) { + return; + } + + AUDIO_IO_LOGD("initialize"); + + int ret = pthread_mutex_init(&mMutex, NULL); + if (ret != 0) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()"); + } + + ret = pthread_cond_init(&mCond, NULL); + if (ret != 0) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()"); + } + + mIsInit = true; +} + +void CAudioIO::finalize() { + if (mIsInit == false) { + return; + } + + AUDIO_IO_LOGD("finalize"); + + int ret = pthread_mutex_destroy(&mMutex); + if (ret != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret); + } + + ret = pthread_cond_destroy(&mCond); + if (ret != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret); + } + + mIsInit = false; +} + +void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) { + assert(mIsInit == true); + assert(pClient != NULL); + assert(length > 0); + + if (mStreamCallback.onStream != NULL) { + mStreamCallback.onStream(length, mStreamCallback.mUserData); + } +} + +void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) { + assert(mIsInit == true); + assert(state > 0); + + mStatePrev = mState; + mState = state; + mByPolicy = byPolicy; + + AUDIO_IO_LOGD("current(%d), previous(%d), by_policy(%d)", mState, mStatePrev, mByPolicy); + + if (mStateChangedCallback.onStateChanged != NULL) { + mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData); + } +} + +void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) { + onStateChanged(state, false); +} + +void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) { + assert(pHandler); + + int session_option = pHandler->getOptions(); + + if (id == -1) { + /////////////////////////////////////// + // Triggered by 'focus watch callback' + /////////////////////////////////////// + + if (session_option & (ASM_SESSION_OPTION_PAUSE_OTHERS | ASM_SESSION_OPTION_UNINTERRUPTIBLE)) { + AUDIO_IO_LOGD("Session option is pausing others or uninterruptible, skip..."); + return; + } + + if (state == FOCUS_IS_RELEASED) { + // Focus handle(id) of the other application was released, do resume if possible + internalLock(); + + mpPulseAudioClient->cork(false); + onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); + + internalUnlock(); + + // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience + state = FOCUS_IS_ACQUIRED; + } else if (state == FOCUS_IS_ACQUIRED) { + // Focus handle(id) of the other application was acquired, do pause if possible + internalLock(); + if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) { + if (mpPulseAudioClient->drain() == false) { + AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()"); + } + } + + mpPulseAudioClient->cork(true); + onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); + + internalUnlock(); + + // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience + state = FOCUS_IS_RELEASED; + } + } else { + /////////////////////////////////////// + // Triggered by 'focus callback' + /////////////////////////////////////// + + if (pHandler->getId() != id) { + AUDIO_IO_LOGW("Id is different, why? [mId : %d]", pHandler->getId()); + } + + if (session_option & ASM_SESSION_OPTION_UNINTERRUPTIBLE) { + AUDIO_IO_LOGD("Session option is uninterruptible, skip..."); + return; + } + + if (state == FOCUS_IS_RELEASED) { + // Focus handle(id) was released, do pause here + internalLock(); + if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) { + if (mpPulseAudioClient->drain() == false) { + AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()"); + } + } + + mpPulseAudioClient->cork(true); + onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); + + internalUnlock(); + } else if (state == FOCUS_IS_ACQUIRED) { + // Focus handle(id) was acquired again, + // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...) + // do resume here and call interrupt completed callback to application. + internalLock(); + + mpPulseAudioClient->cork(false); + onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); + + internalUnlock(); + } + } + + if (mInterruptCallback.onInterrupt != NULL) { + IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::INTERRUPT_COMPLETED; + e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change); + mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData); + } +} + +void CAudioIO::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) { + assert(pHandler); + + if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) { + if (value == 1 && pHandler->getSubscribeId() >= 0) { + // Unregister focus watch callback & disable session handler + pHandler->disableSessionHandler(); + AUDIO_IO_LOGD("Session handler disabled by signal"); + } else if (value == 0) { + // Currently do nothing... + } + } +} + +void CAudioIO::prepare() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("prepare"); + /* Do nothing */ + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioIO::unprepare() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("unprepare"); + /* Do nothing */ + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioIO::pause() throw (CAudioError) { + if (mIsInit == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("pause"); + mpPulseAudioClient->cork(true); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioIO::resume() throw (CAudioError) { + if (mIsInit == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("resume"); + mpPulseAudioClient->cork(false); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioIO::drain() throw (CAudioError) { + if (mIsInit == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("drain"); + mpPulseAudioClient->drain(); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioIO::flush() throw (CAudioError) { + if (mIsInit == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO"); + } + + try { + internalLock(); + AUDIO_IO_LOGD("flush"); + mpPulseAudioClient->flush(); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +CAudioInfo CAudioIO::getAudioInfo() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + return mAudioInfo; +} + +void CAudioIO::setStreamCallback(SStreamCallback callback) throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + internalLock(); + mStreamCallback = callback; + internalUnlock(); +} + +CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + return mStreamCallback; +} + +void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + internalLock(); + mStateChangedCallback = callback; + internalUnlock(); +} + +CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + return mStateChangedCallback; +} + +void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + mInterruptCallback = callback; +} + +CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + return mInterruptCallback; +} + + +void CAudioIO::ignoreSession() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO"); + } + + internalLock(); + + try { + if (mpPulseAudioClient != NULL && mpPulseAudioClient->isCorked() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started"); + } + + bool isSkip = mpAudioSessionHandler->isSkipSessionEvent(); + if (isSkip == false && mpAudioSessionHandler->getId() >= 0) { + mpAudioSessionHandler->unregisterSound(); + mForceIgnore = true; + } + } catch (CAudioError e) { + internalUnlock(); + + throw e; + } + + internalUnlock(); +} diff --git a/src/cpp/CAudioInfo.cpp b/src/cpp/CAudioInfo.cpp new file mode 100644 index 0000000..0c18bf4 --- /dev/null +++ b/src/cpp/CAudioInfo.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioInfo + */ +CAudioInfo::CAudioInfo() + : mSampleRate(MAX_SYSTEM_SAMPLERATE), mChannel(CHANNEL_MONO), + mSampleType(SAMPLE_TYPE_U8), mAudioType(AUDIO_IN_TYPE_MEDIA), + mAudioIndex(-1) { +} + +CAudioInfo::CAudioInfo(unsigned int sampleRate, EChannel channel, ESampleType sampleType, EAudioType audioType, int audioIndex) throw (CAudioError) + : mSampleRate(sampleRate), mChannel(channel), mSampleType(sampleType), mAudioType(audioType), mAudioIndex(audioIndex) { + // Check to invalid AudioInfo + if (sampleRate < CAudioInfo::MIN_SYSTEM_SAMPLERATE || sampleRate > CAudioInfo::MAX_SYSTEM_SAMPLERATE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The sampleRate is invalid [sampleRate:%d]", sampleRate); + } + + if (channel < CAudioInfo::CHANNEL_MONO || channel >= CAudioInfo::CHANNEL_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The channel is invalid [channel:%d]", channel); + } + + if (sampleType < CAudioInfo::SAMPLE_TYPE_U8 || sampleType >= CAudioInfo::SAMPLE_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The sampleType is invalid [sampleType:%d]", sampleType); + } + + if (audioType < CAudioInfo::AUDIO_IN_TYPE_MEDIA || audioType >= CAudioInfo::AUDIO_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [audioType:%d]", audioType); + } +} + +unsigned int CAudioInfo::getSampleRate() { + return mSampleRate; +} + +CAudioInfo::EChannel CAudioInfo::getChannel() { + return mChannel; +} + +CAudioInfo::ESampleType CAudioInfo::getSampleType() { + return mSampleType; +} + +CAudioInfo::EAudioType CAudioInfo::getAudioType() { + return mAudioType; +} + +void CAudioInfo::setAudioType(CAudioInfo::EAudioType AudioType) { + mAudioType = AudioType; + return; +} + +int CAudioInfo::getAudioIndex() { + return mAudioIndex; +} + +void CAudioInfo::setAudioIndex(int AudioIndex) { + mAudioIndex = AudioIndex; + return; +} + +void CAudioInfo::convertAudioType2StreamType (CAudioInfo::EAudioType audioType, char **streamType) +{ + if (audioType < CAudioInfo::AUDIO_IN_TYPE_MEDIA || audioType >= CAudioInfo::AUDIO_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [audioType:%d]", audioType); + } + *streamType = (char *)StreamTypeTable[audioType]; + return; +} + +void CAudioInfo::convertStreamType2AudioType (char *streamType, CAudioInfo::EAudioType *audioType) +{ + unsigned int i; + for (i = 0 ; i < CAudioInfo::AUDIO_TYPE_MAX ; i++) { + if (!strcmp((char *)StreamTypeTable[i], streamType)) { + break; + } + } + if (i < CAudioInfo::AUDIO_IN_TYPE_MEDIA || i >= CAudioInfo::AUDIO_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The streamType is invalid [streamType:%s]", streamType); + } + *audioType = (CAudioInfo::EAudioType)i; + return; +} + diff --git a/src/cpp/CAudioInput.cpp b/src/cpp/CAudioInput.cpp new file mode 100644 index 0000000..9440bc2 --- /dev/null +++ b/src/cpp/CAudioInput.cpp @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioInput inherited by CAudioIO + */ +CAudioInput::CAudioInput(CAudioInfo& info) + : CAudioIO(info), + mpSyncReadDataPtr(NULL), + mSyncReadIndex(0), + mSyncReadLength(0), + mIsUsedSyncRead(true) { +} + +CAudioInput::CAudioInput( + unsigned int sampleRate, + CAudioInfo::EChannel channel, + CAudioInfo::ESampleType type, + CAudioInfo::EAudioType audioType) + : mpSyncReadDataPtr(NULL), + mSyncReadIndex(0), + mSyncReadLength(0), + mIsUsedSyncRead(true) { + mAudioInfo = CAudioInfo(sampleRate, channel, type, audioType, -1); +} + +CAudioInput::~CAudioInput() { +} + +void CAudioInput::onStream(CPulseAudioClient* pClient, size_t length) { + assert(pClient); + + /* + * Does not call CAudioIO::onStream() for synchronization + * if a user is using read() + */ + if (mIsUsedSyncRead == true) { +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("Sync Read Mode! - signal! - pClient:[%p], length:[%d]", pClient, length); +#endif + internalSignal(); + return; + } + + /* + * Accrues callback function + */ +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("pClient:[%p], length:[%d]", pClient, length); +#endif + CAudioIO::onStream(pClient, length); +} + +void CAudioInput::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) { + assert(pHandler); + AUDIO_IO_LOGD("[pHandler:0x%x], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s]", pHandler, focus_type, state, reason_for_change, additional_info); + CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info); +} + +void CAudioInput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) { + assert(pHandler); + AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value); + CAudioIO::onSignal(pHandler, signal, value); +} + +void CAudioInput::setInit(bool flag) { + mIsInit = flag; +} + +bool CAudioInput::IsInit() { + return (CAudioIO::isInit() == true && mIsInit == true); +} + +bool CAudioInput::IsReady() { + return CAudioIO::IsReady(); +} + +void CAudioInput::initialize() throw (CAudioError) { + if (IsInit() == true) { + return; + } + + try { + CAudioIO::initialize(); + + // Create ASM Handler + mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::AUDIO_SESSION_TYPE_CAPTURE, mAudioInfo, this); + if (mpAudioSessionHandler == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object"); + } + + // Initialize ASM Handler + mpAudioSessionHandler->initialize(); + + setInit(true); + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); + } catch (CAudioError err) { + finalize(); + throw err; + } +} + +void CAudioInput::finalize() { + if (IsInit() == false) { + AUDIO_IO_LOGD("Did not initialize"); + return; + } + + SAFE_FINALIZE(mpAudioSessionHandler); + SAFE_DELETE(mpAudioSessionHandler); + + CAudioIO::finalize(); + + setInit(false); +} + +void CAudioInput::prepare() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioInput"); + } + + if (IsReady() == true) { + AUDIO_IO_LOGD("Already prepared CAudioInput"); + return; + } + + try { + internalLock(); + + // Check to invalid AudioType + CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType(); + if (audioType < CAudioInfo::AUDIO_IN_TYPE_MEDIA || audioType > CAudioInfo::AUDIO_IN_TYPE_LOOPBACK) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [type:%d]", static_cast(audioType)); + } + + if (mpAudioSessionHandler->getId() < 0) { //Did not registerSound() + // Check session to skip registration + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + // Register ASM Listener + AUDIO_IO_LOGD("Register ASM Listener"); + mpAudioSessionHandler->registerSound(); + } + } + + // Init StreamSpec + AUDIO_IO_LOGD("Set Strem Spec : CPulseStreamSpec::STREAM_LATENCY_INPUT_MID"); + CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::STREAM_LATENCY_INPUT_MID; + CPulseStreamSpec spec(streamSpec, mAudioInfo); + + // Create PulseAudio Handler + mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::STREAM_DIRECTION_RECORD, spec, this); + if (mpPulseAudioClient == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object"); + } + + // Initialize PulseAudio Handler + mpPulseAudioClient->initialize(); + + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + /* Updates ASM to PLAYING */ + mpAudioSessionHandler->updatePlaying(); + } + + internalUnlock(); + + // Do Prepare + CAudioIO::prepare(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioInput::unprepare() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioInput"); + } + + if (IsReady() == false) { + AUDIO_IO_LOGD("Already unprepared"); + return; + } + + try{ + // Do unprepare + CAudioIO::unprepare(); + + internalLock(); + + SAFE_FINALIZE(mpPulseAudioClient); + SAFE_DELETE(mpPulseAudioClient); + + if (mpAudioSessionHandler->getId() >= 0) { + /* Updates ASM to STOP */ + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + mpAudioSessionHandler->updateStop(); + } + + bool isSkip = mpAudioSessionHandler->isSkipSessionEvent(); + if (isSkip == false) { + mpAudioSessionHandler->unregisterSound(); + } + } + + internalUnlock(); + + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioInput::pause() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + try{ + CAudioIO::pause(); + + internalLock(); + + /* Updates ASM to STOP */ + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + mpAudioSessionHandler->updateStop(); + } + + internalUnlock(); + + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioInput::resume() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + try { + internalLock(); + + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + + /* Updates ASM to PLAYING */ + mpAudioSessionHandler->updatePlaying(); + } + + internalUnlock(); + + CAudioIO::resume(); + + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioInput::drain() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + try{ + CAudioIO::drain(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioInput::flush() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + try { + CAudioIO::flush(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +int CAudioInput::getBufferSize() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioInput"); + } + + if (IsReady() == false) { + AUDIO_IO_LOGD("Warning: Did not prepare CAudioInput, then return zero"); + return 0; + } + + int size = 0; + + try { + internalLock(); + size = mpPulseAudioClient->getBufferSize(); + internalUnlock(); + } catch (CAudioError err) { + internalUnlock(); + throw err; + } + + return size; +} + +void CAudioInput::setStreamCallback(SStreamCallback callback) throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioInput"); + } + + internalLock(); + if (callback.onStream == NULL) { + AUDIO_IO_LOGD("mIsUsedSyncRead = true"); + mIsUsedSyncRead = true; + } else { + AUDIO_IO_LOGD("mIsUsedSyncRead = false"); + mIsUsedSyncRead = false; + } + internalUnlock(); + + CAudioIO::setStreamCallback(callback); +} + +int CAudioInput::read(void* buffer, unsigned int length) throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + if (buffer == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%d", buffer, length); + } + + /* Checks synchronous flag */ + if (mIsUsedSyncRead == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "Does not support read() if receive stream callback"); + } + + internalLock(); + + unsigned int lengthIter = length; + int ret = 0; + + try { + while (lengthIter > 0) { + size_t l; + + while (mpSyncReadDataPtr == NULL) { + ret = mpPulseAudioClient->peek(&mpSyncReadDataPtr, &mSyncReadLength); + if (ret != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "Failed CPulseAudioClient::peek() ret:[%d]", ret); + } + + if (mSyncReadLength <= 0) { +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("readLength(%d byte) is not valid.. wait..", mSyncReadLength); +#endif + internalWait(); + } else if (mpSyncReadDataPtr == NULL) { + /* There's a hole in the stream, skip it. We could generate + * silence, but that wouldn't work for compressed streams. + */ + ret = mpPulseAudioClient->drop(); + if (ret != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "Failed CPulseAudioClient::drop() ret:[%d]", ret); + } + } else { + mSyncReadIndex = 0; + } + }//end of while (pReadData == NULL) + + if (mSyncReadLength < lengthIter) { + l = mSyncReadLength; + } else { + l = lengthIter; + } + + // Copy partial pcm data on out parameter +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("memcpy() that a peeked buffer(%p), index(%d), length(%d), on out buffer", (const uint8_t*)(mpSyncReadDataPtr) + mSyncReadIndex, mSyncReadIndex, l); +#endif + memcpy(buffer, (const uint8_t*)mpSyncReadDataPtr + mSyncReadIndex, l); + + // Move next position + buffer = (uint8_t*)buffer + l; + lengthIter -= l; + + // Adjusts the rest length + mSyncReadIndex += l; + mSyncReadLength -= l; + + if (mSyncReadLength == 0) { +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("mSyncReadLength is zero - Do drop()"); +#endif + ret = mpPulseAudioClient->drop(); + if (ret != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "Failed CPulseAudioClient::drop() ret:[%d]", ret); + } + + // Reset the internal pointer + mpSyncReadDataPtr = NULL; + mSyncReadLength = 0; + mSyncReadIndex = 0; + } + }//end of while (length > 0) + } catch (CAudioError e) { + internalUnlock(); + throw e; + } + + internalUnlock(); + + return length; +} + +int CAudioInput::peek(const void** buffer, unsigned int* length) throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + if (buffer == NULL || length == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL buffer:%p, length:%p", buffer, length); + } + + /* Checks synchronous flag */ + internalLock(); + if (mIsUsedSyncRead == true) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "Does not support peek() if does not receive a stream callback"); + } + internalUnlock(); + + int ret = 0; + + try { + internalLock(); + ret = mpPulseAudioClient->peek(buffer, length); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } + + return ret; +} + +int CAudioInput::drop() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioInput"); + } + + /* Checks synchronous flag */ + internalLock(); + if (mIsUsedSyncRead == true) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "Does not support drop() if does not receive a stream callback"); + } + internalUnlock(); + + int ret = 0; + + try { + internalLock(); + ret = mpPulseAudioClient->drop(); + internalUnlock(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } + + return ret; +} diff --git a/src/cpp/CAudioOutput.cpp b/src/cpp/CAudioOutput.cpp new file mode 100644 index 0000000..f050401 --- /dev/null +++ b/src/cpp/CAudioOutput.cpp @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include "CAudioIODef.h" + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioOutput + */ +CAudioOutput::CAudioOutput(CAudioInfo& info) : CAudioIO(info), mIsUsedSyncWrite(false) { +} + +CAudioOutput::CAudioOutput( + unsigned int sampleRate, + CAudioInfo::EChannel channel, + CAudioInfo::ESampleType sampleType, + CAudioInfo::EAudioType audioType) : mIsUsedSyncWrite(false) { + mAudioInfo = CAudioInfo(sampleRate, channel, sampleType, audioType, -1); +} + +CAudioOutput::~CAudioOutput() { + +} + +void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) { + assert(pClient); + + /* + * Does not call CAudioIO::onStream() for synchronization + * if a user is using write() + */ + if (mIsUsedSyncWrite == true) { +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%d]", pClient, length); +#endif + internalSignal(); + return; + } + + /* + * Accrues callback function + */ +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("pClient:[%p], length:[%d]", pClient, length); +#endif + CAudioIO::onStream(pClient, length); +} + +void CAudioOutput::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) { + assert(pHandler); + AUDIO_IO_LOGD("[pHandler:0x%x], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s]", pHandler, focus_type, state, reason_for_change, additional_info); + CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info); +} + +void CAudioOutput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) { + assert(pHandler); + AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value); + CAudioIO::onSignal(pHandler, signal, value); +} + +void CAudioOutput::setInit(bool flag) { + mIsInit = flag; +} + +bool CAudioOutput::IsInit() { + return (CAudioIO::isInit() == true && mIsInit == true); +} + +bool CAudioOutput::IsReady() { + return CAudioIO::IsReady(); +} + +void CAudioOutput::initialize() throw (CAudioError) { + if (IsInit() == true) { + return; + } + + try { + CAudioIO::initialize(); + + // Create ASM Handler + mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this); + if (mpAudioSessionHandler == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object"); + } + + // Initialize ASM Handler + mpAudioSessionHandler->initialize(); + + setInit(true); + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); + } catch (CAudioError err) { + finalize(); + throw err; + } +} + +void CAudioOutput::finalize() { + if (IsInit() == false) { + AUDIO_IO_LOGD("Did not initialize"); + return; + } + + SAFE_FINALIZE(mpAudioSessionHandler); + SAFE_DELETE(mpAudioSessionHandler); + + CAudioIO::finalize(); + + setInit(false); +} + +void CAudioOutput::prepare() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); + } + + if (IsReady() == true) { + AUDIO_IO_LOGD("Already prepared CAudioOutput"); + return; + } + + try { + internalLock(); + + // Check to invalid AudioType + CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType(); + if (audioType < CAudioInfo::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::AUDIO_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [type:%d]", static_cast(audioType)); + } + + if (mpAudioSessionHandler->getId() < 0) { //Did not registerSound() + if (isForceIgnore() == false) { + // Register ASM Listener + AUDIO_IO_LOGD("Register ASM Listener"); + mpAudioSessionHandler->registerSound(); + } + } + + // Init StreamSpec + AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID"); + CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID; + CPulseStreamSpec spec(streamSpec, mAudioInfo); + + // Create PulseAudio Handler + mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::STREAM_DIRECTION_PLAYBACK, spec, this); + if (mpPulseAudioClient == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object"); + } + + // Initialize PulseAudio Handler + mpPulseAudioClient->initialize(); + + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + /* Updates ASM to PLAYING */ + mpAudioSessionHandler->updatePlaying(); + } + + internalUnlock(); + + CAudioIO::prepare(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioOutput::unprepare() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); + } + + if (IsReady() == false) { + AUDIO_IO_LOGD("Already unprepared"); + return; + } + + try { + CAudioIO::unprepare(); + + internalLock(); + + SAFE_FINALIZE(mpPulseAudioClient); + SAFE_DELETE(mpPulseAudioClient); + + if (mpAudioSessionHandler->getId() >= 0) { + /* Updates ASM to STOP */ + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + mpAudioSessionHandler->updateStop(); + } + + bool isSkip = mpAudioSessionHandler->isSkipSessionEvent(); + if (isSkip == false) { + mpAudioSessionHandler->unregisterSound(); + } + } + + internalUnlock(); + + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioOutput::pause() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); + } + + try { + CAudioIO::pause(); + + internalLock(); + + /* Updates ASM to STOP */ + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + mpAudioSessionHandler->updateStop(); + } + + internalUnlock(); + + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioOutput::resume() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); + } + + try { + internalLock(); + + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + + /* Updates ASM to PLAYING */ + mpAudioSessionHandler->updatePlaying(); + } + + internalUnlock(); + + CAudioIO::resume(); + CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioOutput::drain() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); + } + + try { + CAudioIO::drain(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +void CAudioOutput::flush() throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); + } + + try { + CAudioIO::flush(); + } catch (CAudioError e) { + internalUnlock(); + throw e; + } +} + +int CAudioOutput::getBufferSize() throw (CAudioError) { + if (IsInit() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); + } + + if (IsReady() == false) { + AUDIO_IO_LOGD("Warning: Did not prepare CAudioOutput, then return zero"); + return 0; + } + + int size = 0; + + try { + internalLock(); + size = mpPulseAudioClient->getBufferSize(); + internalUnlock(); + } catch (CAudioError err) { + internalUnlock(); + throw err; + } + + return size; +} + +int CAudioOutput::write(const void* buffer, unsigned int length) throw (CAudioError) { + if (IsInit() == false || IsReady() == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); + } + + if (buffer == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%d", buffer, length); + } + + /* + * Check skip condition. + * If accessibility screen reader (VOICE type with NoSession), no need to check, always do write. + */ + if (mpAudioSessionHandler->isSkipSessionEvent() == false) { + /* Check whether voicerecorder is running */ + int vrState = 0; + + vconf_get_int(VCONFKEY_RECORDER_STATE, &vrState); + if (vrState == VCONFKEY_RECORDER_STATE_RECORDING) { + THROW_ERROR_MSG(CAudioError::ERROR_POLICY_BLOCKED, "During Voicerecording --> MUTE"); + } + } + + /* When write() is called in PulseAudio callback, bypass a pcm data to PulseAudioClient (For Asynchronous) */ + if (mpPulseAudioClient->isInThread() == true) { + int ret = mpPulseAudioClient->write(buffer, length); + if (ret == 0) { + return length; + } + } + + /* For synchronization */ + internalLock(); + + // Sets synchronous flag + mIsUsedSyncWrite = true; + + unsigned int lengthIter = length; + try { + while (lengthIter > 0) { + int l, r; + + while ((l = mpPulseAudioClient->getWritableSize()) == 0) { +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("writableSize is [%d].. wait", l); +#endif + internalWait(); + } + + if (l == -1) { + THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "The Writable size is invalid"); + } + + if (static_cast(l) > lengthIter) { + l = lengthIter; + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("PulseAudioClient->write(buffer:%p, length:%d)", buffer, l); +#endif + + r = mpPulseAudioClient->write(buffer, l); + if (r < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", r); + } + + buffer = static_cast(buffer) + l; + lengthIter -= l; + }//end of while (length > 0) + } catch (CAudioError e) { + // Unsets synchronous flag + mIsUsedSyncWrite = false; + internalUnlock(); + throw e; + } + + // Unsets synchronous flag + mIsUsedSyncWrite = false; + internalUnlock(); + + return length; +} diff --git a/src/cpp/CAudioSessionHandler.cpp b/src/cpp/CAudioSessionHandler.cpp new file mode 100644 index 0000000..f6a37b1 --- /dev/null +++ b/src/cpp/CAudioSessionHandler.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CAudioSessionHandler + */ +int CAudioSessionHandler::sCaptureRef = 0; + +int CAudioSessionHandler::PCM_CAPTURE_COUNT_INC() { + int actual; + do { + actual = sCaptureRef; + } while (!__sync_bool_compare_and_swap(&sCaptureRef, actual, actual + 1)); + AUDIO_IO_LOGD("CaptureRefCount+1 > [%d]", sCaptureRef); + return sCaptureRef; +} + +int CAudioSessionHandler::PCM_CAPTURE_COUNT_DEC() { + int actual; + do { + actual = sCaptureRef; + } while (!__sync_bool_compare_and_swap(&sCaptureRef, actual, actual - 1)); + AUDIO_IO_LOGD("CaptureRefCount-1 > [%d]", sCaptureRef); + if (sCaptureRef < 0) { + AUDIO_IO_LOGE("A CaptureRef[%d] is not valid! Something is wrong!", sCaptureRef); + sCaptureRef = 0; + } + return sCaptureRef; +} + +int CAudioSessionHandler::PCM_CAPTURE_COUNT_GET() { + AUDIO_IO_LOGD("CaptureRefCount > [%d]", sCaptureRef); + return sCaptureRef; +} + +int CAudioSessionHandler::sFocusRef = 0; + +int CAudioSessionHandler::FOCUS_ID_COUNT_INC() { + int actual; + do { + actual = sFocusRef; + } while (!__sync_bool_compare_and_swap(&sFocusRef, actual, actual + 1)); + AUDIO_IO_LOGD("FocusRefCount+1 > [%d]", sFocusRef); + return sFocusRef; +} + +int CAudioSessionHandler::FOCUS_ID_COUNT_DEC() { + int actual; + do { + actual = sFocusRef; + } while (!__sync_bool_compare_and_swap(&sFocusRef, actual, actual - 1)); + AUDIO_IO_LOGD("FocusRefCount-1 > [%d]", sFocusRef); + return sFocusRef; +} + +int CAudioSessionHandler::FOCUS_ID_COUNT_GET() { + /* AUDIO_IO_LOGD("FocusRefCount > [%d]", sFocusRef); */ + return sFocusRef; +} + +CAudioSessionHandler::CAudioSessionHandler(EAudioSessionType sessionType, CAudioInfo& audioInfo, IAudioSessionEventListener* listener) +: mId(-1), + mOptions(0), + mAudioSession(sessionType), + mMultimediaSession(MM_SESSION_TYPE_MEDIA), + mpEventListener(listener), + mIsInit(false), + mUseFocus(false), + mSubscribeId(-1) { + mAudioInfo = audioInfo; +} + +CAudioSessionHandler::~CAudioSessionHandler() { +} + +CAudioError CAudioSessionHandler::_convertStreamType(EAudioSessionType type1, MMSessionType type2, int *index) { + unsigned int i; + int idx = -1; + + assert(index != NULL); + + if (type1 == AUDIO_SESSION_TYPE_CAPTURE) { + for (i = 0 ; i < sizeof(stream_type_table_in) / sizeof(stream_type_table_in[0]) ; i++) { + if (stream_type_table_in[i].type == type2) { + idx = i; + break; + } + } + } else { + for (i = 0 ; i < sizeof(stream_type_table_out) / sizeof(stream_type_table_out[0]) ; i++) { + if (stream_type_table_out[i].type == type2) { + idx = i; + break; + } + } + } + + if (idx < 0) { + RET_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "Does not support session type."); + } + *index = idx; + RET_ERROR(CAudioError::ERROR_NONE); +} + +CAudioError CAudioSessionHandler::_getAsmInformation(MMSessionType *type, int *options) { + assert(type != NULL); + assert(options != NULL); + + MMSessionType currentSession = MM_SESSION_TYPE_MEDIA; + int sessionOptions = 0; + + /* Read session information */ + int ret = 0; + if ((ret = _mm_session_util_read_information(-1, (int*)¤tSession, &sessionOptions)) < 0) { + if(ret == (int) MM_ERROR_INVALID_HANDLE) { + RET_ERROR_MSG(CAudioError::ERROR_INVALID_HANDLE, "Failed _mm_session_util_read_information(). Invalid handle"); + } else { + RET_ERROR_MSG(CAudioError::ERROR_FAILED_OPERATION, "Failed _mm_session_util_read_information(). Not exist"); + } + } + + *type = currentSession; + *options = sessionOptions; + + RET_ERROR(CAudioError::ERROR_NONE); +} + +bool CAudioSessionHandler::_isFocusRequired(MMSessionType type, int options) { + if((options & ASM_SESSION_OPTION_PAUSE_OTHERS) + || ((type != MM_SESSION_TYPE_MEDIA) && (type != MM_SESSION_TYPE_MEDIA_RECORD))) + return true; + else + return false; +} + +int CAudioSessionHandler::getId() { + return mId; +} + +int CAudioSessionHandler::getOptions() { + return mOptions; +} + +CAudioSessionHandler::EAudioSessionType CAudioSessionHandler::getAudioSession() { + return mAudioSession; +} + +MMSessionType CAudioSessionHandler::getMultimediaSession() { + return mMultimediaSession; +} + +int CAudioSessionHandler::getSubscribeId() { + return mSubscribeId; +} + +CAudioInfo CAudioSessionHandler::getAudioInfo() { + return mAudioInfo; +} + +void CAudioSessionHandler::_sound_pcm_signal_cb(mm_sound_signal_name_t signal, int value, void *user_data) { + assert(user_data); + + AUDIO_IO_LOGD("[signal:%d], [value:%d], [user_data:0x%x]", signal, value, user_data); + + CAudioSessionHandler* pHandler = static_cast(user_data); + if (pHandler->mpEventListener != NULL) { + pHandler->mpEventListener->onSignal(pHandler, signal, value); + } +} + +void CAudioSessionHandler::initialize() throw (CAudioError) { + AUDIO_IO_LOGD(""); + if (mIsInit == true) { + return; + } + + MMSessionType currentSession = MM_SESSION_TYPE_MEDIA; + int sessionOptions = 0; // Mix with others by default + + CAudioError err = _getAsmInformation(¤tSession, &sessionOptions); + if (err == CAudioError::ERROR_NONE) { + // Session was configured before, use focus callback + mUseFocus = true; + AUDIO_IO_LOGD("Use audio focus concept internally!"); + } else { + if (err == CAudioError::ERROR_INVALID_HANDLE) { + int value = 0; + unsigned int subscribe_id; + + int errorCode = mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &value); + if (errorCode != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_get_signal_value() err:0x%x", errorCode); + } + + if (value == 1) { + // stream_info was created or focus watch callback was configured before + mUseFocus = false; + AUDIO_IO_LOGD("Skip audio focus concept!"); + } else if (value == 0) { + // No session, No stream_info, No focus watch callback before + // Use focus watch callback with signal subscribe + errorCode = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &subscribe_id, _sound_pcm_signal_cb, static_cast(this)); + if (errorCode != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_get_signal_value() err:0x%x", errorCode); + } + + mSubscribeId = (int)subscribe_id; + AUDIO_IO_LOGD("Subscribed mm_sound signal"); + + sessionOptions = 0; // Mix with others by default + mUseFocus = true; + AUDIO_IO_LOGD("Use audio focus(watch) concept internally!"); + } + } else { + mUseFocus = false; + AUDIO_IO_LOGD("Skip audio focus concept!"); + } + + if (mAudioSession == AUDIO_SESSION_TYPE_CAPTURE) { + AUDIO_IO_LOGD("Set default \"Media_Record\" type"); + currentSession = MM_SESSION_TYPE_MEDIA_RECORD; + } else { + AUDIO_IO_LOGD("Set default \"Media\" type"); + currentSession = MM_SESSION_TYPE_MEDIA; + } + } + + // Updates session information + mMultimediaSession = currentSession; + mOptions = sessionOptions; + + if (this->mAudioSession == AUDIO_SESSION_TYPE_CAPTURE) { + PCM_CAPTURE_COUNT_INC(); + } + + mIsInit = true; +} + +void CAudioSessionHandler::finalize() { + AUDIO_IO_LOGD(""); + if (mIsInit == false) { + return; + } + + if (mAudioSession == AUDIO_SESSION_TYPE_CAPTURE) { + PCM_CAPTURE_COUNT_DEC(); + } + + if (mSubscribeId >= 0) { + mm_sound_unsubscribe_signal(mSubscribeId); + } + + mIsInit = false; +} + +bool CAudioSessionHandler::isSkipSessionEvent() throw (CAudioError) { + bool ret = false; + + // To be regarded... +#if 0 + /* Only Support below Event */ + if (mEvent != ASM_EVENT_CALL && mEvent != ASM_EVENT_VOIP && + mEvent != ASM_EVENT_VIDEOCALL && mEvent != ASM_EVENT_VOICE_RECOGNITION && + mEvent != ASM_EVENT_MMCAMCORDER_AUDIO && mEvent != ASM_EVENT_MMCAMCORDER_VIDEO) { + + // Check AudioType + switch (mAudioInfo.getAudioType()) { + case CAudioInfo::AUDIO_IN_TYPE_MEDIA: + case CAudioInfo::AUDIO_IN_TYPE_VOICECONTROL: + ret = false; + break; + + case CAudioInfo::AUDIO_IN_TYPE_MIRRORING: + case CAudioInfo::AUDIO_IN_TYPE_LOOPBACK: + ret = true; + break; + + default: + return false; + } + + if (ret == true) { + int captureCount = CAudioSessionHandler::PCM_CAPTURE_COUNT_GET(); + if (captureCount == 1) {/* If this is last one */ + /* Recover session information to MEDIA */ + int sessionResult = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA, mOptions); + if (sessionResult != 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "Failed _mm_session_util_write_information() ret:%d", sessionResult); + } + } + } + } +#endif + + return ret; +} + +void CAudioSessionHandler::_sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) { + assert(user_data); + + AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:0x%x]", id, focus_type, state, reason_for_change, additional_info, user_data); + + CAudioSessionHandler* pHandler = static_cast(user_data); + pHandler->mFocusType = focus_type; + pHandler->mState = state; + pHandler->mReasonForChange = (char *)reason_for_change; + pHandler->mAdditionalInfo = (char *)additional_info; + + if (pHandler->mpEventListener != NULL) { + pHandler->mpEventListener->onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info); + } + + return; +} + +void CAudioSessionHandler::_sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) { + AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:0x%x]", id, focus_type, state, reason_for_change, additional_info, user_data); + + CAudioSessionHandler::_sound_pcm_focus_cb(-1, focus_type, state, reason_for_change, additional_info, user_data); + + return; +} + +void CAudioSessionHandler::registerSound() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler"); + } + + if (mUseFocus == true) { + if (mId >= 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Already registered [id:%d]", mId); + } + + int errorCode = 0; + + if (_isFocusRequired(mMultimediaSession, mOptions)) { + int index = 0; + CAudioError err = _convertStreamType(mAudioSession, mMultimediaSession, &index); + if (err != CAudioError::ERROR_NONE) { + throw err; + } + + errorCode = mm_sound_focus_get_id(&mId); + if (errorCode != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_focus_get_id() err:0x%x", errorCode); + } + + // Register focus callback + errorCode = mm_sound_register_focus(mId, + mAudioSession == AUDIO_SESSION_TYPE_CAPTURE ? stream_type_table_in[index].name : stream_type_table_out[index].name, + _sound_pcm_focus_cb, + static_cast(this)); + if (errorCode != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_register_focus() err:0x%x", errorCode); + } + + FOCUS_ID_COUNT_INC(); + + AUDIO_IO_LOGD("Focus callback registered successfully [id:%d]", mId); + } else if (!(mOptions & ASM_SESSION_OPTION_UNINTERRUPTIBLE)) { + // Register focus watch callback + errorCode = mm_sound_set_focus_watch_callback(FOCUS_FOR_BOTH, _sound_pcm_focus_watch_cb, static_cast(this), &mId); + if (errorCode < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_set_focus_watch_callback() err:0x%x", errorCode); + } + + FOCUS_ID_COUNT_INC(); + + AUDIO_IO_LOGD("Focus watch callback registered successfully [id:%d]", mId); + } + } +} + +void CAudioSessionHandler::unregisterSound() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler"); + } + + if (mUseFocus == true) { + if (mId < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Did not register [id:%d]", mId); + } + + int errorCode = 0; + + if (_isFocusRequired(mMultimediaSession, mOptions)) { + // Unregister focus callback + errorCode = mm_sound_unregister_focus(mId); + if (errorCode != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_unregister_focus() err:0x%x", errorCode); + } + + FOCUS_ID_COUNT_DEC(); + + AUDIO_IO_LOGD("Focus callback unregistered successfully [id:%d]", mId); + mId = -1; + } else if (!(mOptions & ASM_SESSION_OPTION_UNINTERRUPTIBLE)) { + // Unregister focus watch callback. + errorCode = mm_sound_unset_focus_watch_callback(mId); + if (errorCode < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_unset_focus_watch_callback() err:0x%x", errorCode); + } + + FOCUS_ID_COUNT_DEC(); + + AUDIO_IO_LOGD("Focus watch callback unregistered successfully [id:%d]", mId); + mId = -1; + } + } +} + +void CAudioSessionHandler::updatePlaying() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler"); + } + + if (mUseFocus && _isFocusRequired(mMultimediaSession, mOptions)) { + if (mId >= 0) { + int ret = mm_sound_acquire_focus(mId, FOCUS_FOR_BOTH, "audio-io acquire focus"); + if (ret != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_acquire_focus() err:0x%x", ret); + } + AUDIO_IO_LOGD("Focus acquired successfully [id:%d]", mId); + } + } +} + +void CAudioSessionHandler::updateStop() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler"); + } + + if (mUseFocus && _isFocusRequired(mMultimediaSession, mOptions)) { + if (mId >= 0) { + int ret = mm_sound_release_focus(mId, FOCUS_FOR_BOTH, "audio-io release focus"); + if (ret != MM_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_POLICY_BLOCKED, "Failed mm_sound_release_focus() err:0x%x", ret); + } + AUDIO_IO_LOGD("Focus released successfully [id:%d]", mId); + } + } +} + +void CAudioSessionHandler::disableSessionHandler() throw (CAudioError) { + CAudioSessionHandler::updateStop(); + CAudioSessionHandler::unregisterSound(); + + CAudioSessionHandler::mUseFocus = false; +} + +/** + * class IAudioSessionEventListener + */ +IAudioSessionEventListener::EInterruptCode IAudioSessionEventListener::convertInterruptedCode(int code, const char *reason_for_change) { + EInterruptCode e = INTERRUPT_COMPLETED; + + switch (code) + { + case FOCUS_IS_ACQUIRED: + e = INTERRUPT_COMPLETED; + break; + + case FOCUS_IS_RELEASED: + if (!strcmp(reason_for_change, "media")) e = INTERRUPT_BY_MEDIA; + if (!strcmp(reason_for_change, "radio")) e = INTERRUPT_BY_MEDIA; + if (!strcmp(reason_for_change, "loopback")) e = INTERRUPT_BY_MEDIA; + if (!strcmp(reason_for_change, "system")) e = INTERRUPT_BY_MEDIA; + if (!strcmp(reason_for_change, "alarm")) e = INTERRUPT_BY_ALARM; + if (!strcmp(reason_for_change, "notification")) e = INTERRUPT_BY_NOTIFICATION; + if (!strcmp(reason_for_change, "emergency")) e = INTERRUPT_BY_EMERGENCY; + if (!strcmp(reason_for_change, "voice-information")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "voice-recognition")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "ringtone-voip")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "ringtone-call")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "voip")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "call-voice")) e = INTERRUPT_BY_MEDIA; //for what? + if (!strcmp(reason_for_change, "call-video")) e = INTERRUPT_BY_MEDIA; //for what? + break; + } + + return e; +} diff --git a/src/cpp/CPulseAudioClient.cpp b/src/cpp/CPulseAudioClient.cpp new file mode 100644 index 0000000..55d2f39 --- /dev/null +++ b/src/cpp/CPulseAudioClient.cpp @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CPulseAudioClient + */ +const char* CPulseAudioClient::CLIENT_NAME = "AUDIO_IO_PA_CLIENT"; + +CPulseAudioClient::CPulseAudioClient(EStreamDirection direction, + CPulseStreamSpec& spec, + IPulseStreamListener* listener) + : mDirection(direction), mSpec(spec), mpListener(listener), + mpMainloop(NULL), mpContext(NULL), mpStream(NULL), + mpPropList(NULL), mIsInit(false), mIsOperationSuccess(false) { +} + +CPulseAudioClient::~CPulseAudioClient() { + finalize(); +} + +void CPulseAudioClient::_contextStateChangeCb(pa_context* c, void* user_data) { + CPulseAudioClient* pClient = static_cast(user_data); + assert(pClient); + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + AUDIO_IO_LOGD("The context is ready!"); + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + pa_threaded_mainloop_signal(pClient->mpMainloop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + +void CPulseAudioClient::_successContextCb(pa_context* c, int success, void* user_data) { + AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data); + assert(c); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + pClient->mIsOperationSuccess = static_cast(success); + + pa_threaded_mainloop_signal(pClient->mpMainloop, 0); +} + +void CPulseAudioClient::_streamStateChangeCb(pa_stream* s, void* user_data) { + assert(s); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_READY: + AUDIO_IO_LOGD("The stream is ready!"); + pClient->mpListener->onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(pClient->mpMainloop, 0); + break; + + case PA_STREAM_UNCONNECTED: + break; + case PA_STREAM_CREATING: + break; + } +} + +void CPulseAudioClient::_streamCaptureCb(pa_stream* s, size_t length, void* user_data) { + assert(s); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + assert(pClient->mpListener); + + pClient->mpListener->onStream(pClient, length); +} + +void CPulseAudioClient::_streamPlaybackCb(pa_stream* s, size_t length, void* user_data) { + //AUDIO_IO_LOGD("_streamPlaybackCb()"); + assert(s); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + assert(pClient->mpListener); + + if (pClient->mIsInit == false) { + AUDIO_IO_LOGD("Occurred this listener when an out stream is on the way to create - Dummy write[length:%d]", length); + + char* dummy = new char[length]; + memset(dummy, 0, length); + pa_stream_write(s, dummy, length, NULL, 0LL, PA_SEEK_RELATIVE); + delete [] dummy; + + return; + } + + pClient->mpListener->onStream(pClient, length); +} + +void CPulseAudioClient::_streamLatencyUpdateCb(pa_stream* s, void* user_data) { + assert(s); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + + pa_threaded_mainloop_signal(pClient->mpMainloop, 0); +} + +void CPulseAudioClient::_successStreamCb(pa_stream* s, int success, void* user_data) { + AUDIO_IO_LOGD("pa_stream[%p], success[%d], user_data[%p]", s, success, user_data); + assert(s); + assert(user_data); + + CPulseAudioClient* pClient = static_cast(user_data); + pClient->mIsOperationSuccess = static_cast(success); + + pa_threaded_mainloop_signal(pClient->mpMainloop, 0); +} + +void CPulseAudioClient::initialize() throw (CAudioError) { + AUDIO_IO_LOGD(""); + if (mIsInit == true) { + return; + } + + int ret = 0; + int err = 0; + + try { + // Allocates PA proplist + mpPropList = pa_proplist_new(); + if (mpPropList == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pa_proplist_new()"); + } + + // Adds values on proplist for delivery to PULSEAUDIO + char *streamType = NULL; + CAudioInfo::EAudioType audioType = mSpec.getAudioInfo().getAudioType(); + mSpec.getAudioInfo().convertAudioType2StreamType(audioType, &streamType); + pa_proplist_sets(mpPropList, PA_PROP_MEDIA_ROLE, streamType); + + int index = mSpec.getAudioInfo().getAudioIndex(); + if (index >= 0) { + pa_proplist_setf(mpPropList, PA_PROP_MEDIA_PARENT_ID, "%u", (unsigned int) index); + } + + // Adds latency on proplist for delivery to PULSEAUDIO + CPulseStreamSpec::EStreamLatency latency = mSpec.getStreamLatency(); + AUDIO_IO_LOGD("LATENCY : %d", latency); + + pa_proplist_setf(mpPropList, PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY, "%d", latency); + + // Allocates PA mainloop + mpMainloop = pa_threaded_mainloop_new(); + if (mpMainloop == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pa_threaded_mainloop_new()"); + } + + // Allocates PA context + mpContext = pa_context_new(pa_threaded_mainloop_get_api(mpMainloop), CLIENT_NAME); + if (mpContext == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pa_context_new()"); + } + + // Sets context state changed callback + pa_context_set_state_callback(mpContext, _contextStateChangeCb, this); + + // Connects this client with PA server + if (pa_context_connect(mpContext, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pa_context_connect()"); + } + + // LOCK for synchronous connection + pa_threaded_mainloop_lock(mpMainloop); + + // Start mainloop + if (pa_threaded_mainloop_start(mpMainloop) < 0) { + pa_threaded_mainloop_unlock(mpMainloop); + THROW_ERROR_MSG(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_threaded_mainloop_start()"); + } + + // Connection process is asynchronously + // So, this function will be waited when occurred context state change event + // If I got a signal, do next processing + while (true) { + pa_context_state_t state; + state = pa_context_get_state(mpContext); + + if (state == PA_CONTEXT_READY) { + break; + } + + if (!PA_CONTEXT_IS_GOOD(state)) { + err = pa_context_errno(mpContext); + pa_threaded_mainloop_unlock(mpMainloop); + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "pa_context's state is not good err:[%d]", err); + } + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(mpMainloop); + } + + // Allocates PA stream + pa_sample_spec ss = mSpec.getSampleSpec(); + pa_channel_map map = mSpec.getChannelMap(); + + mpStream = pa_stream_new_with_proplist(mpContext, mSpec.getStreamName(), &ss, &map, mpPropList); + if (mpStream == NULL) { + pa_threaded_mainloop_unlock(mpMainloop); + THROW_ERROR_MSG(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_new_with_proplist()()"); + } + + // Sets stream callbacks + pa_stream_set_state_callback(mpStream, _streamStateChangeCb, this); + pa_stream_set_read_callback(mpStream, _streamCaptureCb, this); + pa_stream_set_write_callback(mpStream, _streamPlaybackCb, this); + pa_stream_set_latency_update_callback(mpStream, _streamLatencyUpdateCb, this); + + // Connect stream with PA Server + + if (mDirection == STREAM_DIRECTION_PLAYBACK) { + pa_stream_flags_t flags = static_cast( + PA_STREAM_INTERPOLATE_TIMING | + PA_STREAM_ADJUST_LATENCY | + PA_STREAM_AUTO_TIMING_UPDATE); + + ret = pa_stream_connect_playback(mpStream, NULL, NULL, flags, NULL, NULL); + } else { + pa_stream_flags_t flags = static_cast( + PA_STREAM_INTERPOLATE_TIMING | + PA_STREAM_ADJUST_LATENCY | + PA_STREAM_AUTO_TIMING_UPDATE); + + ret = pa_stream_connect_record(mpStream, NULL, NULL, flags); + } + + if (ret != 0) { + err = pa_context_errno(mpContext); + pa_threaded_mainloop_unlock(mpMainloop); + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_connect() err:[%d]", err); + } + + while (true) { + pa_stream_state_t state; + state = pa_stream_get_state(mpStream); + + if (state == PA_STREAM_READY) { + AUDIO_IO_LOGD("STREAM READY"); + break; + } + + if (!PA_STREAM_IS_GOOD(state)) { + err = pa_context_errno(mpContext); + pa_threaded_mainloop_unlock(mpMainloop); + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "pa_stream's state is not good err:[%d]", err); + } + + /* Wait until the stream is ready */ + pa_threaded_mainloop_wait(mpMainloop); + } + + // End of synchronous + pa_threaded_mainloop_unlock(mpMainloop); + + mIsInit = true; + } catch (CAudioError e) { + finalize(); + throw e; + } +} + +void CPulseAudioClient::finalize() { + AUDIO_IO_LOGD(""); + if (mIsInit == false) { + return; + } + + if (mpMainloop != NULL) { + pa_threaded_mainloop_stop(mpMainloop); + } + if (mpStream != NULL) { + pa_stream_disconnect(mpStream); + mpStream = NULL; + } + + if (mpContext != NULL) { + pa_context_disconnect(mpContext); + pa_context_unref(mpContext); + mpContext = NULL; + } + + if (mpMainloop != NULL) { + pa_threaded_mainloop_free(mpMainloop); + mpMainloop = NULL; + } + + if (mpPropList != NULL) { + pa_proplist_free(mpPropList); + mpPropList = NULL; + } + + mIsInit = false; +} + +int CPulseAudioClient::peek(const void** data, size_t* length) throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("data:[%p], length:[%p]", data, length); +#endif + + checkRunningState(); + + if (data == NULL || length == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The parameter is invalid - data:%p, length:%p", data, length); + } + + if (mDirection == STREAM_DIRECTION_PLAYBACK) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function"); + } + + int ret = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + ret = pa_stream_peek(mpStream, data, length); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + ret = pa_stream_peek(mpStream, data, length); + } + + if (ret < 0) { + THROW_ERROR_MSG(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_peek()"); + } + + return ret; +} + +int CPulseAudioClient::drop() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD(""); +#endif + + checkRunningState(); + + if (mDirection == STREAM_DIRECTION_PLAYBACK) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function"); + } + + int ret = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + ret = pa_stream_drop(mpStream); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + ret = pa_stream_drop(mpStream); + } + + if (ret < 0) { + THROW_ERROR_MSG(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_drop()"); + } + + return ret; +} + +int CPulseAudioClient::write(const void* data, size_t length) throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("data[%p], length:[%d]", data, length); +#endif + + checkRunningState(); + + if (data == NULL || length < 0) { + THROW_ERROR_MSG(CAudioError::ERROR_INVALID_ARGUMENT, "The parameter is invalid"); + } + + if (mDirection == STREAM_DIRECTION_RECORD) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "The Playback client couldn't use this function"); + } + + int ret = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + ret = pa_stream_write(mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + ret = pa_stream_write(mpStream, data, length, NULL, 0LL, PA_SEEK_RELATIVE); + } + + if (ret < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_write() err:%d", ret); + } + + return ret; +} + +void CPulseAudioClient::cork(bool cork) throw (CAudioError) { + AUDIO_IO_LOGD("bool cork:%d", cork); + + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + if (isInThread() == true) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "This operation is not supported in callback"); + } + + checkRunningState(); + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + pa_operation_unref(pa_stream_cork(mpStream, static_cast(cork), _successStreamCb, this)); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + pa_operation_unref(pa_stream_cork(mpStream, static_cast(cork), _successStreamCb, this)); + } + + return; +} + +bool CPulseAudioClient::isCorked() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + int isCork = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + isCork = pa_stream_is_corked(mpStream); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + isCork = pa_stream_is_corked(mpStream); + } + + AUDIO_IO_LOGD("isCork:%d", isCork); + return static_cast(isCork); +} + +bool CPulseAudioClient::drain() throw (CAudioError) { + AUDIO_IO_LOGD("drain"); + + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + pa_operation_unref(pa_stream_drain(mpStream, _successStreamCb, this)); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + pa_operation_unref(pa_stream_drain(mpStream, _successStreamCb, this)); + } + + return true; +} + +bool CPulseAudioClient::flush() throw (CAudioError) { + AUDIO_IO_LOGD("flush"); + + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + pa_operation_unref(pa_stream_flush(mpStream, _successStreamCb, this)); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + pa_operation_unref(pa_stream_flush(mpStream, _successStreamCb, this)); + } + + return true; +} + +size_t CPulseAudioClient::getWritableSize() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + if (mDirection != STREAM_DIRECTION_PLAYBACK) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "This client is used for Playback"); + } + + size_t ret = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + ret = pa_stream_writable_size(mpStream); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + ret = pa_stream_writable_size(mpStream); + } + + return ret; +} + +void CPulseAudioClient::checkRunningState() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + if (mpContext == NULL || PA_CONTEXT_IS_GOOD(pa_context_get_state(mpContext)) == 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_NOT_INITIALIZED, "The context[%p] is not created or not good state", mpContext); + } + if (mpStream == NULL || PA_STREAM_IS_GOOD(pa_stream_get_state(mpStream)) == 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_NOT_INITIALIZED, "The stream[%p] is not created or not good state", mpStream); + } + if (pa_context_get_state(mpContext) != PA_CONTEXT_READY || pa_stream_get_state(mpStream) != PA_STREAM_READY) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_NOT_INITIALIZED, "The context[%p] or stream[%p] state is not ready", mpContext, mpStream); + } + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("This client is running"); +#endif +} + +bool CPulseAudioClient::isInThread() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + int ret = pa_threaded_mainloop_in_thread(mpMainloop); + +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("isInThread : [%d][TRUE:1][FALSE:0]", ret); +#endif + return static_cast(ret); +} + +size_t CPulseAudioClient::getReadableSize() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + if (mDirection != STREAM_DIRECTION_RECORD) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_SUPPORTED, "This client is used for Capture"); + } + + size_t ret = 0; + + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + ret = pa_stream_writable_size(mpStream); + pa_threaded_mainloop_unlock(mpMainloop); + } else { + ret = pa_stream_writable_size(mpStream); + } + + return ret; +} + +size_t CPulseAudioClient::getBufferSize() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + size_t ret = 0; + + try { + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + } + + const pa_buffer_attr* attr = pa_stream_get_buffer_attr(mpStream); + if (attr == NULL) { + int _err = pa_context_errno(mpContext); + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_buffer_attr() err:%d", _err); + } + + if (mDirection == STREAM_DIRECTION_PLAYBACK) { + ret = attr->tlength; + AUDIO_IO_LOGD("PLAYBACK buffer size : %d", ret); + } else { + ret = attr->fragsize; + AUDIO_IO_LOGD("RECORD buffer size : %d", ret); + } + } catch (CAudioError err) { + if (isInThread() == false) { + pa_threaded_mainloop_unlock(mpMainloop); + } + throw err; + } + + if (isInThread() == false) { + pa_threaded_mainloop_unlock(mpMainloop); + } + + return ret; +} + +pa_usec_t CPulseAudioClient::getLatency() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + pa_usec_t ret = 0; + int negative = 0; + + if (isInThread() == false) { + if (pa_stream_get_latency(mpStream, &ret, &negative) < 0) { + int _err = pa_context_errno(mpContext); + if (_err != PA_ERR_NODATA) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() err:%d", _err); + } + } + return negative ? 0 : ret; + } + + pa_threaded_mainloop_lock(mpMainloop); + + try { + while (true) { + if (pa_stream_get_latency(mpStream, &ret, &negative) >= 0) { + break; + } + + int _err = pa_context_errno(mpContext); + if (_err != PA_ERR_NODATA) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_FAILED_OPERATION, "Failed pa_stream_get_latency() err:%d", _err); + } + + /* Wait until latency data is available again */ + pa_threaded_mainloop_wait(mpMainloop); + } + } catch (CAudioError e) { + pa_threaded_mainloop_unlock(mpMainloop); + throw e; + } + + pa_threaded_mainloop_unlock(mpMainloop); + + return negative ? 0 : ret; +} + +pa_usec_t CPulseAudioClient::getFinalLatency() throw (CAudioError) { + if (mIsInit == false) { + THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + } + + checkRunningState(); + + pa_usec_t ret = 0; + uint32_t ver = 0; + + try { + if (isInThread() == false) { + pa_threaded_mainloop_lock(mpMainloop); + } + + ver = pa_context_get_server_protocol_version(mpContext); + if (ver >= 13) { + const pa_buffer_attr* buffer_attr = pa_stream_get_buffer_attr(mpStream); + const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(mpStream); + const pa_timing_info* timing_info = pa_stream_get_timing_info(mpStream); + + if (buffer_attr == NULL || sample_spec == NULL || timing_info == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to get buffer_attr[%p] or sample_spec[%p] or timing_info[%p] from a pa_stream", + buffer_attr, sample_spec, timing_info); + } + + if (mDirection == STREAM_DIRECTION_PLAYBACK) { + ret = (pa_bytes_to_usec(buffer_attr->tlength, sample_spec) + timing_info->configured_sink_usec); + AUDIO_IO_LOGD("FINAL PLAYBACK LATENCY : %d", ret); + } else { + ret = (pa_bytes_to_usec(buffer_attr->fragsize, sample_spec) + timing_info->configured_source_usec); + AUDIO_IO_LOGD("FINAL RECORD LATENCY : %d", ret); + } + } else { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_NOT_SUPPORTED, "This version(ver.%d) is not supported", ver); + } + + if (isInThread() == false) { + pa_threaded_mainloop_unlock(mpMainloop); + } + } catch (CAudioError e) { + if (isInThread() == false) { + pa_threaded_mainloop_unlock(mpMainloop); + } + throw e; + } + + return ret; +} + +CPulseAudioClient::EStreamDirection CPulseAudioClient::getStreamDirection() { + return mDirection; +} + +CPulseStreamSpec CPulseAudioClient::getStreamSpec() { + return mSpec; +} diff --git a/src/cpp/CPulseAudioPolicy.cpp b/src/cpp/CPulseAudioPolicy.cpp new file mode 100644 index 0000000..0c96f84 --- /dev/null +++ b/src/cpp/CPulseAudioPolicy.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + + +#if 0 +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CPulseAudioPolicy + */ +CPulseAudioPolicy::CPulseAudioPolicy() : mPolicy(POLICY_DEFAULT) { +} + +CPulseAudioPolicy::CPulseAudioPolicy(EPolicy policy) : mPolicy(policy) { +} + +CPulseAudioPolicy::~CPulseAudioPolicy() { +} + +void CPulseAudioPolicy::setPolicy(EPolicy policy) throw (CAudioError) { + if (policy < POLICY_DEFAULT || policy >= POLICY_MAX) { + THROW_ERROR_MSG(CAudioError::ERROR_INVALID_ARGUMENT, "The argument is out of range"); + } + + mPolicy = policy; +} + +CPulseAudioPolicy::EPolicy CPulseAudioPolicy::getPolicy() { + return mPolicy; +} + +bool CPulseAudioPolicy::operator != (const EPolicy policy) { + return (mPolicy != policy); +} + +bool CPulseAudioPolicy::operator == (const EPolicy policy) { + return (mPolicy == policy); +} +#endif diff --git a/src/cpp/CPulseAudioVolume.cpp b/src/cpp/CPulseAudioVolume.cpp new file mode 100644 index 0000000..12aaf05 --- /dev/null +++ b/src/cpp/CPulseAudioVolume.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + + +#if 0 +#include "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * class CPulseAudioVolume + */ +CPulseAudioVolume::CPulseAudioVolume() : mVolume(VOLUME_MEDIA), mVolumeGain(VOLUME_GAIN_DEFAULT) { +} + +CPulseAudioVolume::CPulseAudioVolume(EVolume volume, EVolumeGain gain) : mVolume(volume), mVolumeGain(gain) { +} + +CPulseAudioVolume::~CPulseAudioVolume() { +} + +void CPulseAudioVolume::setVolume(EVolume volume) { + mVolume = volume; +} + +CPulseAudioVolume::EVolume CPulseAudioVolume::getVolume() { + return mVolume; +} + +void CPulseAudioVolume::setVolumeGain(EVolumeGain volumeGain) { + mVolumeGain = volumeGain; +} + +CPulseAudioVolume::EVolumeGain CPulseAudioVolume::getVolumeGain() { + return mVolumeGain; +} +#endif diff --git a/src/cpp/CPulseStreamSpec.cpp b/src/cpp/CPulseStreamSpec.cpp new file mode 100644 index 0000000..c564944 --- /dev/null +++ b/src/cpp/CPulseStreamSpec.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "CAudioIODef.h" + + +using namespace std; +using namespace tizen_media_audio; + + +static const char* STREAM_NAME_INPUT = "CAPTURE"; +static const char* STREAM_NAME_INPUT_LOW_LATENCY = "LOW LATENCY CAPTURE"; +static const char* STREAM_NAME_INPUT_HIGH_LATENCY = "HIGH LATENCY CAPTURE"; +static const char* STREAM_NAME_INPUT_VOIP = "VOIP CAPTURE"; + +static const char* STREAM_NAME_OUTPUT = "PLAYBACK"; +static const char* STREAM_NAME_OUTPUT_LOW_LATENCY = "LOW LATENCY PLAYBACK"; +static const char* STREAM_NAME_OUTPUT_HIGH_LATENCY = "HIGH LATENCY PLAYBACK"; +static const char* STREAM_NAME_OUTPUT_VOIP = "VOIP PLAYBACK"; + + +CPulseStreamSpec::CPulseStreamSpec() throw (CAudioError) + : mLatency(STREAM_LATENCY_INPUT_MID), mStreamName(NULL) { + _adjustSpec(); +} + +CPulseStreamSpec::CPulseStreamSpec(EStreamLatency latency, CAudioInfo& audioInfo) throw (CAudioError) + : mLatency(latency), mAudioInfo(audioInfo), mStreamName(NULL) { + _adjustSpec(); +} + +CPulseStreamSpec::CPulseStreamSpec(EStreamLatency latency, CAudioInfo& audioInfo, int customLatency) throw (CAudioError) + : mLatency(latency), mAudioInfo(audioInfo), mStreamName(NULL) { + _adjustSpec(); +} + +CPulseStreamSpec::~CPulseStreamSpec() { +} + +void CPulseStreamSpec::_adjustSpec() throw (CAudioError) { + // Sets a sampleRate + mSampleSpec.rate = mAudioInfo.getSampleRate(); + + // Convert channels for PA + switch (mAudioInfo.getChannel()) { + case CAudioInfo::CHANNEL_MONO: + mSampleSpec.channels = 1; + break; + + case CAudioInfo::CHANNEL_STEREO: + default: + mSampleSpec.channels = 2; + break; + } + + // Convert format for PA + switch (mAudioInfo.getSampleType()) { + case CAudioInfo::SAMPLE_TYPE_U8: + mSampleSpec.format = PA_SAMPLE_U8; + break; + + case CAudioInfo::SAMPLE_TYPE_S16_LE: + default: + mSampleSpec.format = PA_SAMPLE_S16LE; + break; + } + + // Sets channelmap + pa_channel_map_init_auto(&mChannelMap, mSampleSpec.channels, PA_CHANNEL_MAP_ALSA); + + // Sets stream name + switch (mLatency) { + case STREAM_LATENCY_OUTPUT_MID: + mStreamName = STREAM_NAME_OUTPUT; + break; + + case STREAM_LATENCY_OUTPUT_HIGH: + mStreamName = STREAM_NAME_OUTPUT_HIGH_LATENCY; + break; + + case STREAM_LATENCY_OUTPUT_LOW: + mStreamName = STREAM_NAME_OUTPUT_LOW_LATENCY; + break; + + case STREAM_LATENCY_OUTPUT_VOIP: + mStreamName = STREAM_NAME_OUTPUT_VOIP; + break; + + case STREAM_LATENCY_INPUT_HIGH: + mStreamName = STREAM_NAME_INPUT_HIGH_LATENCY; + break; + + case STREAM_LATENCY_INPUT_LOW: + mStreamName = STREAM_NAME_INPUT_LOW_LATENCY; + break; + + case STREAM_LATENCY_INPUT_VOIP: + mStreamName = STREAM_NAME_INPUT_VOIP; + break; + + case STREAM_LATENCY_INPUT_MID: + default: + mStreamName = STREAM_NAME_INPUT; + break; + } +} + +CPulseStreamSpec::EStreamLatency CPulseStreamSpec::getStreamLatency() { + return mLatency; +} + +CAudioInfo CPulseStreamSpec::getAudioInfo() { + return mAudioInfo; +} + +pa_sample_spec CPulseStreamSpec::getSampleSpec() { + return mSampleSpec; +} + +pa_channel_map CPulseStreamSpec::getChannelMap() { + return mChannelMap; +} + +const char* CPulseStreamSpec::getStreamName() { + return mStreamName; +} diff --git a/src/cpp/cpp_audio_io.cpp b/src/cpp/cpp_audio_io.cpp new file mode 100644 index 0000000..6f2f5fb --- /dev/null +++ b/src/cpp/cpp_audio_io.cpp @@ -0,0 +1,1499 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "audio_io.h" +#include "cpp_audio_io.h" +#include "CAudioIODef.h" +#include + + +using namespace std; +using namespace tizen_media_audio; + + +/** + * Defines Structures + * type : struct + * Name : audio_io_interrupted_cb_s + * Declaration : Keeps user callback pointer and user data for delivering an interrupt event + */ +typedef struct audio_io_interrupted_cb_s { + void* user_data; + audio_io_interrupted_cb onInterrupt; + + audio_io_interrupted_cb_s() : user_data(NULL), onInterrupt(NULL) + {/* Empty Body */} +} audio_io_interrupted_cb_s; + +/** + * Defines Structures + * type : struct + * Name : audio_io_stream_cb_s + * Declaration : Keeps user callback pointer and user data for delivering an stream event + */ +typedef struct audio_io_stream_cb_s { + void* user_data; + audio_in_stream_cb onStream; + + audio_io_stream_cb_s() : user_data(NULL), onStream(NULL) + {/* Empty Body */} +} audio_io_stream_cb_s; + +/** + * Defines Structures + * type : struct + * Name : audio_io_state_changed_cb_s + * Declaration : Keeps user callback pointer and user data for delivering an state changed event + */ +typedef struct audio_io_state_changed_cb_s { + void* user_data; + audio_in_state_changed_cb onStateChanged; + + audio_io_state_changed_cb_s() : user_data(NULL), onStateChanged(NULL) + {/* Empty Body */} +} audio_io_state_changed_cb_s; + +/** + * Defines Structures + * type : struct + * Name : audio_io_s + * Declaration : An handle of AudioIO + * The handle has two struct for user callback + * And the handle has a pointer of private audioIO object + * The CAudioIO is a abstract class object about Input and Output + */ +typedef struct audio_io_s { + CAudioIO* audioIoHandle; + audio_io_interrupted_cb_s interrupt_callback; + audio_io_stream_cb_s stream_callback; + audio_io_state_changed_cb_s state_changed_callback; + + audio_io_s() : audioIoHandle(NULL) + {/* Empty Body */} +} audio_io_s; + + +/** + * Internal functions + */ +static audio_io_error_e _convert_CAudioError(CAudioError& error) { + audio_io_error_e ret = AUDIO_IO_ERROR_NONE; + CAudioError::EError err = error.getError(); + + switch(err) + { + case CAudioError::ERROR_NONE: + ret = AUDIO_IO_ERROR_NONE; + break; + + case CAudioError::ERROR_INVALID_ARGUMENT: + case CAudioError::ERROR_INVALID_HANDLE: + case CAudioError::ERROR_INVALID_SAMPLERATE: + case CAudioError::ERROR_INVALID_CHANNEL: + case CAudioError::ERROR_INVALID_FORMAT: + ret = AUDIO_IO_ERROR_INVALID_PARAMETER; + break; + + case CAudioError::ERROR_DEVICE_NOT_OPENED: + ret = AUDIO_IO_ERROR_DEVICE_NOT_OPENED; + break; + + case CAudioError::ERROR_DEVICE_NOT_CLOSED: + ret = AUDIO_IO_ERROR_DEVICE_NOT_CLOSED; + break; + + case CAudioError::ERROR_PERMISSION_DENIED: + ret = AUDIO_IO_ERROR_PERMISSION_DENIED; + break; + + case CAudioError::ERROR_NOT_SUPPORTED: + ret = AUDIO_IO_ERROR_NOT_SUPPORTED; + break; + + case CAudioError::ERROR_MAX: + case CAudioError::ERROR_INTERNAL_OPERATION: + case CAudioError::ERROR_NOT_INITIALIZED: + case CAudioError::ERROR_FAILED_OPERATION: + case CAudioError::ERROR_INVALID_OPERATION: + ret = AUDIO_IO_ERROR_INVALID_OPERATION; + break; + + case CAudioError::ERROR_OUT_OF_MEMORY: + case CAudioError::ERROR_INVALID_POINTER: + ret = AUDIO_IO_ERROR_INVALID_BUFFER; + break; + + case CAudioError::ERROR_POLICY_BLOCKED: + case CAudioError::ERROR_POLICY_INTERRUPTED: + case CAudioError::ERROR_POLICY_DUPLICATED: + ret = AUDIO_IO_ERROR_SOUND_POLICY; + break; + } + return ret; + +} + +static void _convert_channel_2_audio_info_channel(const audio_channel_e& src_channel, CAudioInfo::EChannel& dst_channel) { + switch (src_channel) { + case AUDIO_CHANNEL_MONO: + dst_channel = CAudioInfo::CHANNEL_MONO; + break; + case AUDIO_CHANNEL_STEREO: + dst_channel = CAudioInfo::CHANNEL_STEREO; + break; + default: + dst_channel = CAudioInfo::CHANNEL_MONO; + } +} + +static void _convert_audio_info_channel_2_channel(const CAudioInfo::EChannel& src_channel, audio_channel_e& dst_channel) { + switch (src_channel) { + case CAudioInfo::CHANNEL_MONO: + dst_channel = AUDIO_CHANNEL_MONO; + break; + case CAudioInfo::CHANNEL_STEREO: + dst_channel = AUDIO_CHANNEL_STEREO; + break; + default: + dst_channel = AUDIO_CHANNEL_MONO; + } +} + +static void _convert_sample_type_2_audio_info_sample_type(const audio_sample_type_e& src_type, CAudioInfo::ESampleType& dst_type) { + switch (src_type) { + case AUDIO_SAMPLE_TYPE_U8: + dst_type = CAudioInfo::SAMPLE_TYPE_U8; + break; + case AUDIO_SAMPLE_TYPE_S16_LE: + dst_type = CAudioInfo::SAMPLE_TYPE_S16_LE; + break; + default: + dst_type = CAudioInfo::SAMPLE_TYPE_U8; + } +} + +static void _convert_audio_info_sample_type_2_sample_type(const CAudioInfo::ESampleType& src_type, audio_sample_type_e& dst_type) { + switch (src_type) { + case CAudioInfo::SAMPLE_TYPE_U8: + dst_type = AUDIO_SAMPLE_TYPE_U8; + break; + case CAudioInfo::SAMPLE_TYPE_S16_LE: + dst_type = AUDIO_SAMPLE_TYPE_S16_LE; + break; + default: + dst_type = AUDIO_SAMPLE_TYPE_U8; + } +} + +static void _convert_sound_type_2_audio_info_audio_type(const sound_type_e& src_type, CAudioInfo::EAudioType& dst_type) { + switch (src_type) { + case SOUND_TYPE_SYSTEM: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_SYSTEM; + break; + case SOUND_TYPE_NOTIFICATION: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_NOTIFICATION; + break; + case SOUND_TYPE_ALARM: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_ALARM; + break; + case SOUND_TYPE_RINGTONE: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_RINGTONE_VOIP; + break; + case SOUND_TYPE_MEDIA: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_MEDIA; + break; + case SOUND_TYPE_CALL: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_SYSTEM; + break; + case SOUND_TYPE_VOIP: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_VOIP; + break; + case SOUND_TYPE_VOICE: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_VOICE_INFORMATION; + break; + default: + dst_type = CAudioInfo::AUDIO_OUT_TYPE_MEDIA; + break; + } +} + +static void _convert_audio_info_audio_type_2_sound_type(const CAudioInfo::EAudioType& src_type, sound_type_e& dst_type) { + switch (src_type) { + case CAudioInfo::AUDIO_OUT_TYPE_MEDIA: + dst_type = SOUND_TYPE_MEDIA; + break; + case CAudioInfo::AUDIO_OUT_TYPE_SYSTEM: + dst_type = SOUND_TYPE_SYSTEM; + break; + case CAudioInfo::AUDIO_OUT_TYPE_ALARM: + dst_type = SOUND_TYPE_ALARM; + break; + case CAudioInfo::AUDIO_OUT_TYPE_NOTIFICATION: + case CAudioInfo::AUDIO_OUT_TYPE_EMERGENCY: + dst_type = SOUND_TYPE_NOTIFICATION; + break; + case CAudioInfo::AUDIO_OUT_TYPE_VOICE_INFORMATION: + case CAudioInfo::AUDIO_OUT_TYPE_VOICE_RECOGNITION: + dst_type = SOUND_TYPE_VOICE; + break; + case CAudioInfo::AUDIO_OUT_TYPE_RINGTONE_VOIP: + dst_type = SOUND_TYPE_RINGTONE; + break; + case CAudioInfo::AUDIO_OUT_TYPE_VOIP: + dst_type = SOUND_TYPE_VOIP; + break; + default: + dst_type = SOUND_TYPE_MEDIA; + break; + } +} + +static audio_io_state_e _convert_state_type(const CAudioInfo::EAudioIOState src_state) { + audio_io_state_e dst_state; + switch (src_state) { + case CAudioInfo::AUDIO_IO_STATE_NONE: + dst_state = AUDIO_IO_STATE_IDLE; + break; + case CAudioInfo::AUDIO_IO_STATE_IDLE: + dst_state = AUDIO_IO_STATE_IDLE; + break; + case CAudioInfo::AUDIO_IO_STATE_RUNNING: + dst_state = AUDIO_IO_STATE_RUNNING; + break; + case CAudioInfo::AUDIO_IO_STATE_PAUSED: + dst_state = AUDIO_IO_STATE_PAUSED; + break; + default: + dst_state = AUDIO_IO_STATE_IDLE; + } + return dst_state; +} + +static CAudioInfo _generate_audio_input_info(int sampleRate, audio_channel_e channel, audio_sample_type_e sample_type) throw (CAudioError) { + CAudioInfo::EChannel dstChannel; + CAudioInfo::ESampleType dstSampleType; + CAudioInfo::EAudioType dstAudioType = CAudioInfo::AUDIO_IN_TYPE_MEDIA; + + _convert_channel_2_audio_info_channel(channel, dstChannel); + _convert_sample_type_2_audio_info_sample_type(sample_type, dstSampleType); + + return CAudioInfo(sampleRate, dstChannel, dstSampleType, dstAudioType, -1); +} + +static CAudioInfo _generate_audio_input_loopback_info(int sampleRate, audio_channel_e channel, audio_sample_type_e sample_type) throw (CAudioError) { + CAudioInfo::EChannel dstChannel; + CAudioInfo::ESampleType dstSampleType; + CAudioInfo::EAudioType dstAudioType = CAudioInfo::AUDIO_IN_TYPE_LOOPBACK; + + _convert_channel_2_audio_info_channel(channel, dstChannel); + _convert_sample_type_2_audio_info_sample_type(sample_type, dstSampleType); + + return CAudioInfo(sampleRate, dstChannel, dstSampleType, dstAudioType, -1); +} + +static CAudioInfo _generate_audio_output_info(int sampleRate, audio_channel_e channel, audio_sample_type_e sample_type, sound_type_e sound_type) throw (CAudioError) { + CAudioInfo::EChannel dstChannel; + CAudioInfo::ESampleType dstSampleType; + CAudioInfo::EAudioType dstAudioType; + + _convert_channel_2_audio_info_channel(channel, dstChannel); + _convert_sample_type_2_audio_info_sample_type(sample_type, dstSampleType); + _convert_sound_type_2_audio_info_audio_type(sound_type, dstAudioType); + + return CAudioInfo(sampleRate, dstChannel, dstSampleType, dstAudioType, -1); +} + +static audio_io_interrupted_code_e _convert_interrupted_code(IAudioSessionEventListener::EInterruptCode code) { + switch (code) { + case IAudioSessionEventListener::INTERRUPT_COMPLETED: + return AUDIO_IO_INTERRUPTED_COMPLETED; + case IAudioSessionEventListener::INTERRUPT_BY_CALL: + return AUDIO_IO_INTERRUPTED_BY_CALL; + case IAudioSessionEventListener::INTERRUPT_BY_EARJACK_UNPLUG: + return AUDIO_IO_INTERRUPTED_BY_EARJACK_UNPLUG; + case IAudioSessionEventListener::INTERRUPT_BY_RESOURCE_CONFLICT: + return AUDIO_IO_INTERRUPTED_BY_RESOURCE_CONFLICT; + case IAudioSessionEventListener::INTERRUPT_BY_ALARM: + return AUDIO_IO_INTERRUPTED_BY_ALARM; + case IAudioSessionEventListener::INTERRUPT_BY_EMERGENCY: + return AUDIO_IO_INTERRUPTED_BY_EMERGENCY; + case IAudioSessionEventListener::INTERRUPT_BY_NOTIFICATION: + return AUDIO_IO_INTERRUPTED_BY_NOTIFICATION; + case IAudioSessionEventListener::INTERRUPT_BY_MEDIA: + case IAudioSessionEventListener::INTERRUPT_MAX: + default: + return AUDIO_IO_INTERRUPTED_BY_MEDIA; + } +} + +/** + * Implements CAPI functions + */ +int cpp_audio_in_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_in_h *input) { + audio_io_s* handle = NULL; + try { + if (input == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + handle = new audio_io_s; + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation handle"); + } + + CAudioInfo audioInfo = _generate_audio_input_info(sample_rate, channel, type); + + handle->audioIoHandle = new CAudioInput(audioInfo); + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation internal handle"); + } + + handle->audioIoHandle->initialize(); + + *input = handle; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + + VALID_POINTER_START(handle) + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + VALID_POINTER_END + + VALID_POINTER_START(input) + *input = NULL; + VALID_POINTER_END + + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; + +} + +int cpp_audio_in_create_loopback(int sample_rate, audio_channel_e channel, audio_sample_type_e type , audio_in_h* input) { + audio_io_s* handle = NULL; + try { + if (input == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + handle = new audio_io_s; + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation handle"); + } + + CAudioInfo audioInfo = _generate_audio_input_loopback_info(sample_rate, channel, type); + + handle->audioIoHandle = new CAudioInput(audioInfo); + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation internal handle"); + } + + handle->audioIoHandle->initialize(); + + *input = handle; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + + VALID_POINTER_START(handle) + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + VALID_POINTER_END + + VALID_POINTER_START(input) + *input = NULL; + VALID_POINTER_END + + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_destroy(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_set_stream_info(audio_in_h input, sound_stream_info_h stream_info) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || stream_info == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, stream_info:%p", input, stream_info); + } + + assert(handle->audioIoHandle); + + int errorCode = SOUND_MANAGER_ERROR_NONE; + CAudioInfo::EAudioType AudioType = CAudioInfo::AUDIO_IN_TYPE_MEDIA; + char *type = NULL; + int index = -1; + + if ((errorCode = sound_manager_get_type_from_stream_information (stream_info, &type)) != SOUND_MANAGER_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); + } + handle->audioIoHandle->getAudioInfo().convertStreamType2AudioType(type, &AudioType); + handle->audioIoHandle->getAudioInfo().setAudioType(AudioType); + + if ((errorCode = sound_manager_get_index_from_stream_information (stream_info, &index)) != SOUND_MANAGER_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); + } + handle->audioIoHandle->getAudioInfo().setAudioIndex(index); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_prepare(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->prepare(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_unprepare(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->unprepare(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_pause(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->pause(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_resume(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->resume(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_drain(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->drain(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_flush(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->flush(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_read(audio_in_h input, void *buffer, unsigned int length) { + audio_io_s* handle = static_cast(input); + int ret = 0; + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + CAudioInput* inputHandle = dynamic_cast(handle->audioIoHandle); + ret = inputHandle->read(buffer, length); +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("ret:%d", ret); +#endif + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return ret; +} + +int cpp_audio_in_get_buffer_size(audio_in_h input, int *size) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || size == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, size:%p", input, size); + } + + assert(handle->audioIoHandle); + + CAudioIO* inputHandle = dynamic_cast(handle->audioIoHandle); + *size = inputHandle->getBufferSize(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_get_sample_rate(audio_in_h input, int *sample_rate) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || sample_rate == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, sample_rate:%p", input, sample_rate); + } + + assert(handle->audioIoHandle); + *sample_rate = handle->audioIoHandle->getAudioInfo().getSampleRate(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_get_channel(audio_in_h input, audio_channel_e *channel) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || channel == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, channel:%p", input, channel); + } + + assert(handle->audioIoHandle); + + const CAudioInfo::EChannel srcChannel = handle->audioIoHandle->getAudioInfo().getChannel(); + audio_channel_e dstChannel = AUDIO_CHANNEL_MONO; + _convert_audio_info_channel_2_channel(srcChannel, dstChannel); + + *channel = dstChannel; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_get_sample_type(audio_in_h input, audio_sample_type_e *type) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || type == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, type:%p", input, type); + } + + assert(handle->audioIoHandle); + + const CAudioInfo::ESampleType srcSampleType = handle->audioIoHandle->getAudioInfo().getSampleType(); + audio_sample_type_e dstSampleType = AUDIO_SAMPLE_TYPE_U8; + _convert_audio_info_sample_type_2_sample_type(srcSampleType, dstSampleType); + + *type = dstSampleType; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +static void _interrupt_cb_internal(IAudioSessionEventListener::EInterruptCode _code, void* user_data) { + audio_io_s* handle = static_cast(user_data); + audio_io_interrupted_code_e code = _convert_interrupted_code(_code); + + assert(handle); + + if (handle->interrupt_callback.onInterrupt != NULL) { + handle->interrupt_callback.onInterrupt(code, handle->interrupt_callback.user_data); + } +} + +int cpp_audio_in_set_interrupted_cb(audio_in_h input, audio_io_interrupted_cb callback, void *user_data) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || callback == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, callback:%p", input, callback); + } + + assert(handle->audioIoHandle); + + handle->interrupt_callback.onInterrupt = callback; + handle->interrupt_callback.user_data = user_data; + + CAudioIO::SInterruptCallback cb = handle->audioIoHandle->getInterruptCallback(); + cb.mUserData = static_cast(handle); + cb.onInterrupt = _interrupt_cb_internal; + + handle->audioIoHandle->setInterruptCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_unset_interrupted_cb(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->interrupt_callback.onInterrupt = NULL; + handle->interrupt_callback.user_data = NULL; + + CAudioIO::SInterruptCallback cb = handle->audioIoHandle->getInterruptCallback(); + cb.mUserData = NULL; + cb.onInterrupt = NULL; + + handle->audioIoHandle->setInterruptCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_ignore_session(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->ignoreSession(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +static void _stream_cb_internal(size_t nbytes, void *user_data) { + audio_io_s* audioIo = static_cast(user_data); + assert(audioIo); + + if (audioIo->stream_callback.onStream != NULL) { + audioIo->stream_callback.onStream(audioIo, nbytes, audioIo->stream_callback.user_data); + } +} + +static void _state_changed_cb_internal(CAudioInfo::EAudioIOState state, CAudioInfo::EAudioIOState state_prev, bool by_policy, void *user_data) { + audio_io_s* audioIo = static_cast(user_data); + assert(audioIo); + + if (audioIo->state_changed_callback.onStateChanged != NULL) { + audioIo->state_changed_callback.onStateChanged(audioIo, _convert_state_type(state_prev), _convert_state_type(state), by_policy, audioIo->state_changed_callback.user_data); + } +} + +int cpp_audio_in_set_stream_cb(audio_in_h input, audio_in_stream_cb callback, void* user_data) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL || callback == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p, callback:%p", input, callback); + } + + assert(handle->audioIoHandle); + + handle->stream_callback.onStream = callback; + handle->stream_callback.user_data = user_data; + + CAudioIO::SStreamCallback cb = handle->audioIoHandle->getStreamCallback(); + cb.mUserData = static_cast(handle); + cb.onStream = _stream_cb_internal; + + handle->audioIoHandle->setStreamCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_unset_stream_cb(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + assert(handle->audioIoHandle); + + handle->stream_callback.onStream = NULL; + handle->stream_callback.user_data = NULL; + + CAudioIO::SStreamCallback cb = handle->audioIoHandle->getStreamCallback(); + cb.mUserData = NULL; + cb.onStream = NULL; + + handle->audioIoHandle->setStreamCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_peek(audio_in_h input, const void **buffer, unsigned int *length) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + CAudioInput* inputHandle = dynamic_cast(handle->audioIoHandle); + assert(inputHandle); + + inputHandle->peek(buffer, length); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_drop(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL input:%p", input); + } + + CAudioInput* inputHandle = dynamic_cast(handle->audioIoHandle); + assert(inputHandle); + + inputHandle->drop(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb callback, void* user_data) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, callback:%p", input, callback); + } + + assert(handle->audioIoHandle); + + handle->state_changed_callback.onStateChanged = callback; + handle->state_changed_callback.user_data = user_data; + + CAudioIO::SStateChangedCallback cb = handle->audioIoHandle->getStateChangedCallback(); + cb.mUserData = static_cast(handle); + cb.onStateChanged = _state_changed_cb_internal; + + handle->audioIoHandle->setStateChangedCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_unset_state_changed_cb(audio_in_h input) { + audio_io_s* handle = static_cast(input); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p", input); + } + + assert(handle->audioIoHandle); + + handle->state_changed_callback.onStateChanged = NULL; + handle->state_changed_callback.user_data = NULL; + + CAudioIO::SStateChangedCallback cb = handle->audioIoHandle->getStateChangedCallback(); + cb.mUserData = NULL; + cb.onStateChanged = NULL; + + handle->audioIoHandle->setStateChangedCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + + +/** + * Audio Out + */ +int cpp_audio_out_create(int sample_rate, audio_channel_e channel, audio_sample_type_e type, sound_type_e sound_type, audio_out_h *output) { + audio_io_s* handle = NULL; + try { + handle = new audio_io_s; + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation handle"); + } + + CAudioInfo audioInfo = _generate_audio_output_info(sample_rate, channel, type, sound_type); + + handle->audioIoHandle = new CAudioOutput(audioInfo); + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation internal handle"); + } + + handle->audioIoHandle->initialize(); + + *output = handle; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + + VALID_POINTER_START(handle) + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + VALID_POINTER_END + + VALID_POINTER_START(output) + *output = NULL; + VALID_POINTER_END + + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output) { + audio_io_s* handle = NULL; + try { + handle = new audio_io_s; + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation handle"); + } + + CAudioInfo audioInfo = _generate_audio_output_info(sample_rate, channel, type, SOUND_TYPE_MEDIA /* default sound_tyoe */); + + handle->audioIoHandle = new CAudioOutput(audioInfo); + if (handle == NULL) { + THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed allocation internal handle"); + } + + handle->audioIoHandle->initialize(); + + *output = handle; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + + VALID_POINTER_START(handle) + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + VALID_POINTER_END + + VALID_POINTER_START(output) + *output = NULL; + VALID_POINTER_END + + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_destroy(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + SAFE_FINALIZE(handle->audioIoHandle); + SAFE_DELETE(handle->audioIoHandle); + SAFE_DELETE(handle); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_set_stream_info(audio_out_h output, sound_stream_info_h stream_info) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || stream_info == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, stream_info:%p", output, stream_info); + } + + assert(handle->audioIoHandle); + + int errorCode = SOUND_MANAGER_ERROR_NONE; + CAudioInfo::EAudioType AudioType = CAudioInfo::AUDIO_OUT_TYPE_MEDIA; + char *type = NULL; + int index = -1; + + if ((errorCode = sound_manager_get_type_from_stream_information (stream_info, &type)) != SOUND_MANAGER_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode); + } + handle->audioIoHandle->getAudioInfo().convertStreamType2AudioType(type, &AudioType); + handle->audioIoHandle->getAudioInfo().setAudioType(AudioType); + + if ((errorCode = sound_manager_get_index_from_stream_information (stream_info, &index)) != SOUND_MANAGER_ERROR_NONE) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode); + } + handle->audioIoHandle->getAudioInfo().setAudioIndex(index); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_prepare(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->prepare(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_unprepare(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->unprepare(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_pause(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->pause(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_resume(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->resume(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_drain(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->drain(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_flush(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->flush(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_write(audio_out_h output, void *buffer, unsigned int length) { + audio_io_s* handle = static_cast(output); + int ret = 0; + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameter is NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + CAudioOutput* outputHandle = dynamic_cast(handle->audioIoHandle); + ret = outputHandle->write(buffer, length); +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("ret:%d", ret); +#endif + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return ret; +} + +int cpp_audio_out_get_buffer_size(audio_out_h output, int *size) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || size == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, size:%p", output, size); + } + + assert(handle->audioIoHandle); + + CAudioOutput* outputHandle = dynamic_cast(handle->audioIoHandle); + *size = outputHandle->getBufferSize(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_get_sample_rate(audio_out_h output, int *sample_rate) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || sample_rate == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, sample_rate:%p", output, sample_rate); + } + + assert(handle->audioIoHandle); + *sample_rate = handle->audioIoHandle->getAudioInfo().getSampleRate(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_get_channel(audio_out_h output, audio_channel_e *channel) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || channel == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, channel:%p", output, channel); + } + + assert(handle->audioIoHandle); + + const CAudioInfo::EChannel srcChannel = handle->audioIoHandle->getAudioInfo().getChannel(); + audio_channel_e dstChannel = AUDIO_CHANNEL_MONO; + _convert_audio_info_channel_2_channel(srcChannel, dstChannel); + + *channel = dstChannel; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_get_sample_type(audio_out_h output, audio_sample_type_e *type) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || type == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, type:%p", output, type); + } + + assert(handle->audioIoHandle); + + const CAudioInfo::ESampleType srcSampleType = handle->audioIoHandle->getAudioInfo().getSampleType(); + audio_sample_type_e dstSampleType = AUDIO_SAMPLE_TYPE_U8; + _convert_audio_info_sample_type_2_sample_type(srcSampleType, dstSampleType); + + *type = dstSampleType; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_get_sound_type(audio_out_h output, sound_type_e *type) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || type == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, type:%p", output, type); + } + + assert(handle->audioIoHandle); + + const CAudioInfo::EAudioType srcAudioType = handle->audioIoHandle->getAudioInfo().getAudioType(); + sound_type_e dstSoundType = SOUND_TYPE_MEDIA; + _convert_audio_info_audio_type_2_sound_type(srcAudioType, dstSoundType); + + *type = dstSoundType; + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_set_interrupted_cb(audio_out_h output, audio_io_interrupted_cb callback, void *user_data) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL || callback == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, callback:%p", output, callback); + } + + assert(handle->audioIoHandle); + + handle->interrupt_callback.onInterrupt = callback; + handle->interrupt_callback.user_data = user_data; + + CAudioIO::SInterruptCallback cb = handle->audioIoHandle->getInterruptCallback(); + cb.mUserData = static_cast(handle); + cb.onInterrupt = _interrupt_cb_internal; + + handle->audioIoHandle->setInterruptCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_unset_interrupted_cb(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->interrupt_callback.onInterrupt = NULL; + handle->interrupt_callback.user_data = NULL; + + CAudioIO::SInterruptCallback cb = handle->audioIoHandle->getInterruptCallback(); + cb.mUserData = NULL; + cb.onInterrupt = NULL; + + handle->audioIoHandle->setInterruptCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_ignore_session(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->audioIoHandle->ignoreSession(); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_set_stream_cb(audio_out_h output, audio_out_stream_cb callback, void* user_data) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, callback:%p", output, callback); + } + + assert(handle->audioIoHandle); + + handle->stream_callback.onStream = callback; + handle->stream_callback.user_data = user_data; + + CAudioIO::SStreamCallback cb = handle->audioIoHandle->getStreamCallback(); + cb.mUserData = static_cast(handle); + cb.onStream = _stream_cb_internal; + + handle->audioIoHandle->setStreamCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_unset_stream_cb(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->stream_callback.onStream = NULL; + handle->stream_callback.user_data = NULL; + + CAudioIO::SStreamCallback cb = handle->audioIoHandle->getStreamCallback(); + cb.mUserData = NULL; + cb.onStream = NULL; + + handle->audioIoHandle->setStreamCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_set_state_changed_cb(audio_out_h output, audio_in_state_changed_cb callback, void* user_data) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p, callback:%p", output, callback); + } + + assert(handle->audioIoHandle); + + handle->state_changed_callback.onStateChanged = callback; + handle->state_changed_callback.user_data = user_data; + + CAudioIO::SStateChangedCallback cb = handle->audioIoHandle->getStateChangedCallback(); + cb.mUserData = static_cast(handle); + cb.onStateChanged = _state_changed_cb_internal; + + handle->audioIoHandle->setStateChangedCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_out_unset_state_changed_cb(audio_out_h output) { + audio_io_s* handle = static_cast(output); + + try { + if (handle == NULL) { + THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are NULL output:%p", output); + } + + assert(handle->audioIoHandle); + + handle->state_changed_callback.onStateChanged = NULL; + handle->state_changed_callback.user_data = NULL; + + CAudioIO::SStateChangedCallback cb = handle->audioIoHandle->getStateChangedCallback(); + cb.mUserData = NULL; + cb.onStateChanged = NULL; + + handle->audioIoHandle->setStateChangedCallback(cb); + } catch (CAudioError e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return _convert_CAudioError(e); + } + + return AUDIO_IO_ERROR_NONE; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d11160..67cedc2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,3 @@ - SET(fw_test "${fw_name}-test") INCLUDE(FindPkgConfig) @@ -6,13 +5,15 @@ FOREACH(flag ${${fw_test}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror -pie") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror -std=c++0x -pie") aux_source_directory(. sources) FOREACH(src ${sources}) GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) MESSAGE("${src_name}") ADD_EXECUTABLE(${src_name} ${src}) - TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS}) + TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS} -lm) ENDFOREACH() +INSTALL(TARGETS audio_io_test DESTINATION bin) diff --git a/test/audio_io_test.c b/test/audio_io_test.c old mode 100755 new mode 100644 index 9aba129..c96771b --- a/test/audio_io_test.c +++ b/test/audio_io_test.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,49 +11,708 @@ * 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. +* limitations under the License. */ - + #include #include #include -#include - -int audio_io_test() -{ - int ret, size; - audio_in_h input; - if ((ret = audio_in_create(44100, AUDIO_CHANNEL_STEREO ,AUDIO_SAMPLE_TYPE_S16_LE, &input)) == AUDIO_IO_ERROR_NONE) { - ret = audio_in_ignore_session(input); - if (ret != 0) { - printf ("ERROR, set session mix\n"); - audio_in_destroy(input); - return 0; - } - - audio_in_prepare(input); - if ((ret = audio_in_get_buffer_size(input, &size)) == AUDIO_IO_ERROR_NONE) { - size = 500000; - char *buffer = alloca(size); - if ((ret = audio_in_read(input, (void*)buffer, size)) > AUDIO_IO_ERROR_NONE) { - FILE* fp = fopen ("/root/test.raw", "wb+"); - fwrite (buffer, size, sizeof(char), fp); - fclose (fp); - printf ("PASS, size=%d, ret=%d\n", size, ret); - } - else { - printf ("FAIL, size=%d, ret=%d\n", size, ret); - } - } - audio_in_destroy(input); - } - - return 1; +#include +#include +#include +#include + +//#define _NEW_SOUND_MANAGER_API_ +#define _SESSION_SOUND_MANAGER_API_ + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_channel; + int right_channel; +} test_wav_t; +test_wav_t test_wav; + +static int ch_table[3] = { 0, AUDIO_CHANNEL_MONO, AUDIO_CHANNEL_STEREO }; + +void play_file(char *file, int length, int ch) +{ + audio_out_h output; + FILE* fp = fopen (file, "r"); + if (fp == NULL) { + printf ("fopen failed\n"); + return; + } + + char * buf = malloc (length); + if (buf == NULL) { + printf ("malloc failed\n"); + fclose (fp); + return; + } + + printf ("start to play [%s][%d][%d]\n", file, length, ch); + //audio_out_create(44100, ch_table[ch] ,AUDIO_SAMPLE_TYPE_S16_LE, SOUND_TYPE_MEDIA, &output); + audio_out_create_new(44100, ch_table[ch] ,AUDIO_SAMPLE_TYPE_S16_LE, &output); + if (fread (buf, 1, length, fp) != length) { + printf ("error!!!!\n"); + } + + audio_out_prepare(output); + audio_out_write(output, buf, length); + audio_out_unprepare(output); + + audio_out_destroy (output); + + fclose (fp); + + printf ("play done\n"); +} + +#define DUMP_FILE "/root/test.raw" + + +void play_file_sample(char *file, int frequency, int ch, int type) +{ + audio_out_h output; + int file_size = 0; + int read_bytes = 0; + int buffer_size = 0; + char * buf = NULL; + + if(ch < 0 || ch > 2) { + ch = 0; + } + + FILE* fp = fopen (file, "r"); + if (fp == NULL) { + printf("open failed\n"); + return; + } + /*Get the size*/ + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + printf ("start to play [%s] of size [%d] with [%d][%d][%d]\n", file, file_size, frequency, ch, type); + if (type) { + //audio_out_create(frequency, ch_table[ch] ,AUDIO_SAMPLE_TYPE_S16_LE, SOUND_TYPE_MEDIA, &output); + audio_out_create_new(frequency, ch_table[ch] ,AUDIO_SAMPLE_TYPE_S16_LE, &output); + } else { + //audio_out_create(frequency, ch_table[ch] ,AUDIO_SAMPLE_TYPE_U8, SOUND_TYPE_MEDIA, &output); + audio_out_create_new(frequency, ch_table[ch] ,AUDIO_SAMPLE_TYPE_U8, &output); + } + audio_out_prepare(output); + audio_out_get_buffer_size(output, &buffer_size); + + buf = (char *) malloc(buffer_size); + if (buf == NULL) { + printf ("malloc failed\n"); + audio_out_unprepare(output); + audio_out_destroy(output); + fclose (fp); + return; + } + //audio_out_prepare(output); + + while (file_size > 0) { + read_bytes = fread (buf, 1, buffer_size, fp); + printf ("Read %d Requested - %d\n", read_bytes, buffer_size); + audio_out_write(output, buf, read_bytes); + file_size = file_size - read_bytes; + } + + audio_out_unprepare(output); + audio_out_destroy (output); + + free(buf); + fclose (fp); + printf ("play done\n"); +} + +int audio_io_test(int length, int num, int ch) +{ + int ret, size, i; + audio_in_h input; + if ((ret = audio_in_create(44100, ch_table[ch] ,AUDIO_SAMPLE_TYPE_S16_LE, &input)) == AUDIO_IO_ERROR_NONE) { + ret = audio_in_ignore_session(input); + if (ret != 0) { + printf ("ERROR, set session mix\n"); + audio_in_destroy(input); + return 0; + } + + ret = audio_in_prepare(input); + if (ret != 0) { + printf ("ERROR, prepare\n"); + audio_in_destroy(input); + return 0; + } + + FILE* fp = fopen (DUMP_FILE, "wb+"); + + if (fp == NULL) { + printf ("ERROR, file open failed\n"); + audio_in_destroy(input); + return 0; + } + + if ((ret = audio_in_get_buffer_size(input, &size)) == AUDIO_IO_ERROR_NONE) { + size = length; + char *buffer = alloca(size); + + for (i=0; i AUDIO_IO_ERROR_NONE) { + fwrite (buffer, size, sizeof(char), fp); + printf ("PASS, size=%d, ret=%d\n", size, ret); + } else { + printf ("FAIL, size=%d, ret=%d\n", size, ret); + } + } + } + + fclose (fp); + + audio_in_destroy(input); + } + + play_file (DUMP_FILE, length*num, ch); + + return 1; +} + +int audio_io_loopback_in_test() +{ + int ret, size; + audio_in_h input; + FILE* fp = fopen ("/tmp/dump_test.raw", "wb+"); + + if(fp == NULL) { + printf("open failed \n"); + return 0; + } + + if ((ret = audio_in_create(16000, AUDIO_CHANNEL_MONO , AUDIO_SAMPLE_TYPE_S16_LE, &input)) == AUDIO_IO_ERROR_NONE) { + ret = audio_in_ignore_session(input); + if (ret != 0) { + printf ("ERROR, set session mix\n"); + goto exit; + } + + ret = audio_in_prepare(input); + if (ret != 0) { + printf ("ERROR, prepare\n"); + goto exit; + } + + ret = audio_in_get_buffer_size(input, &size); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_in_get_buffer_size failed.\n"); + goto exit; + } + + while(1) { + char *buffer = alloca(size); + if ((ret = audio_in_read(input, (void*)buffer, size)) > AUDIO_IO_ERROR_NONE) { + fwrite (buffer, size, sizeof(char), fp); + printf ("PASS, size=%d, ret=%d\n", size, ret); + } else { + printf ("FAIL, size=%d, ret=%d\n", size, ret); + } + } + } + +exit: + audio_in_destroy(input); + + fclose (fp); + + return ret; + +} + +int audio_io_loopback_test() +{ + int ret, size; + audio_in_h input; + audio_out_h output; + char *buffer = NULL; + + ret = audio_in_create(16000, AUDIO_CHANNEL_MONO , AUDIO_SAMPLE_TYPE_S16_LE, &input); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_in_create_ex failed. \n"); + return 0; + } + + //ret = audio_out_create(16000, AUDIO_CHANNEL_MONO , AUDIO_SAMPLE_TYPE_S16_LE, SOUND_TYPE_CALL, &output); + ret = audio_out_create_new(16000, AUDIO_CHANNEL_MONO , AUDIO_SAMPLE_TYPE_S16_LE, &output); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_out_create failed. \n"); + return 0; + } + + ret = audio_in_prepare(input); + if (ret != 0) { + printf ("audio_in_prepare failed.\n"); + audio_in_destroy(input); + return 0; + } else { + ret = audio_in_get_buffer_size(input, &size); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_in_get_buffer_size failed.\n"); + return 0; + } else { + printf("size(%d)\n", size); + buffer = alloca(size); + } + } + + ret = audio_out_prepare(output); + if (ret != 0) { + printf ("audio_out_prepare failed.\n"); + audio_out_destroy(output); + return 0; + } + + if(buffer == NULL) { + printf("buffer is null\n"); + return 0; + } + + while(1) { + ret = audio_in_read(input, (void*)buffer, size); + if(ret > AUDIO_IO_ERROR_NONE) { + ret = audio_out_write(output, buffer, size); + if(ret > AUDIO_IO_ERROR_NONE) { + printf("audio read/write success. buffer(%p), size(%d)\n", buffer, size); + } else { + printf("audio read success, write failed. buffer(%p), size(%d)\n", buffer, size); + } + } else + printf("audio read/write failed. buffer(%p), size(%d)\n", buffer, size); + } + +} + +audio_in_h input; +audio_out_h output; + +FILE* fp_w = NULL; + +#ifdef _NEW_SOUND_MANAGER_API_ +sound_stream_info_h g_stream_info_read_h = NULL; +sound_stream_info_h g_stream_info_write_h = NULL; + +static void focus_callback_read (sound_stream_info_h stream_info, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data) { + int ret = 0; + sound_stream_focus_state_e playback_focus_state; + sound_stream_focus_state_e recording_focus_state; + printf ("*** focus_callback_read is called, stream_info(%p) ***\n", stream_info); + printf (" - reason_for_change(%d), additional_info(%s), user_data(%p)\n", reason_for_change, additional_info, user_data); + ret = sound_manager_get_focus_state (stream_info, &playback_focus_state, &recording_focus_state); + if (!ret) + printf (" - focus_state(playback_focus:%d, recording_focus:%d)\n", playback_focus_state, recording_focus_state); + if (playback_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + printf (" -- PLAYBACK_FOCUS acquired\n"); + } + if (recording_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + printf (" -- FOCUS_RECORDING acquired\n"); + } + printf ("*** focus_callback_read is ended, stream_info(%p) ****\n", stream_info); + return; +} + +static void focus_callback_write (sound_stream_info_h stream_info, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data) { + int ret = 0; + sound_stream_focus_state_e playback_focus_state; + sound_stream_focus_state_e recording_focus_state; + printf ("*** focus_callback_write is called, stream_info(%p) ***\n", stream_info); + printf (" - reason_for_change(%d), additional_info(%s), user_data(%p)\n", reason_for_change, additional_info, user_data); + ret = sound_manager_get_focus_state (stream_info, &playback_focus_state, &recording_focus_state); + if (!ret) + printf (" - focus_state(playback_focus:%d, recording_focus:%d)\n", playback_focus_state, recording_focus_state); + if (playback_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + printf (" -- PLAYBACK_FOCUS acquired\n"); + } + if (recording_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + printf (" -- FOCUS_RECORDING acquired\n"); + } + printf ("*** focus_callback_write is ended, stream_info(%p) ****\n", stream_info); + return; +} +#endif + +static void interrupted_callback_read(audio_io_interrupted_code_e code, void *user_data) { + printf ("*** interrupted_callback_read is called, code(%d), user_data(%p) ***\n", code, user_data); +} + +static void interrupted_callback_write(audio_io_interrupted_code_e code, void *user_data) { + printf ("*** interrupted_callback_write is called, code(%d), user_data(%p) ***\n", code, user_data); +} + +static void _audio_io_stream_read_cb (audio_in_h handle, size_t nbytes, void *user_data) +{ + const void * buffer = NULL; + +// printf("_audio_io_stream_read_cb : handle=%p, nbytes=%d, user_data=%p\n", handle, nbytes, user_data); + + if (nbytes > 0) { + audio_in_peek (handle, &buffer, &nbytes); + if (fp_w) { + fwrite(buffer, sizeof(char), nbytes, fp_w); + } + audio_in_drop (handle); + } +} + +static void _audio_io_stream_write_cb (audio_out_h handle, size_t nbytes, void *user_data) +{ + short* buffer = NULL; + int ret = 0; + int i = 0; + +// printf("_audio_io_stream_write_cb : handle=%p, nbytes=%d, user_data=%p\n", handle, nbytes, user_data); + + if (nbytes > 0) { + buffer = (short *) malloc(nbytes); + if (buffer == NULL) { + printf ("malloc failed\n"); + return; + } + memset (buffer, 0, nbytes); + + for(i=0; i= TABLE_SIZE ) test_wav.left_channel -= TABLE_SIZE; + test_wav.right_channel += 3; + if( test_wav.right_channel >= TABLE_SIZE ) test_wav.right_channel -= TABLE_SIZE; + } + + ret = audio_out_write(handle, buffer, nbytes); + if(ret > AUDIO_IO_ERROR_NONE) { +// printf("audio write success. buffer(%p), nbytes(%d)\n", buffer, nbytes); + } + + free (buffer); + } +} + +static void _audio_in_state_cb (audio_in_h handle, audio_io_state_e previous, audio_io_state_e current, bool by_policy, void *user_data) +{ + printf(">>> _audio_in_state_cb() : handle(%p), current(%d), previous(%d), by_policy(%d), user_data(%p)\n", handle, current, previous, by_policy, user_data); +} + +static void _audio_out_state_cb (audio_in_h handle, audio_io_state_e previous, audio_io_state_e current, bool by_policy, void *user_data) +{ + printf(">>> _audio_out_state_cb() : handle(%p), current(%d), previous(%d), by_policy(%d), user_data(%p)\n", handle, current, previous, by_policy, user_data); +} + +int _convert_cmd_and_run(char cmd, int mode) { + int ret = 0; + switch (cmd) { + case 'P': + if(mode & 0x01) ret = audio_out_prepare(output); + if(mode & 0x02) ret = audio_in_prepare(input); + break; + case 'u': + if(mode & 0x01) ret = audio_out_unprepare(output); + if(mode & 0x02) ret = audio_in_unprepare(input); + break; + case 'p': + if(mode & 0x01) ret = audio_out_pause(output); + if(mode & 0x02) ret = audio_in_pause(input); + break; + case 'r': + if(mode & 0x01) ret = audio_out_resume(output); + if(mode & 0x02) ret = audio_in_resume(input); + break; + case 'd': + if(mode & 0x01) ret = audio_out_drain(output); + //if(mode & 0x02) ret = audio_in_drain(input); + break; + case 'f': + if(mode & 0x01) ret = audio_out_flush(output); + if(mode & 0x02) ret = audio_in_flush(input); + break; + case 'i': +#ifdef _NEW_SOUND_MANAGER_API_ + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, focus_callback_write, NULL, &g_stream_info_write_h); + if (ret) { + printf ("fail to sound_manager_create_stream_information(), ret(0x%x)\n", ret); + } +#endif +#ifdef _SESSION_SOUND_MANAGER_API_ + ret = sound_manager_set_session_type(SOUND_SESSION_TYPE_MEDIA); + if (ret) { + printf ("fail to sound_manager_set_session_type(), ret(0x%x)\n", ret); + } + ret = sound_manager_set_media_session_option (SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START, SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY); + if (ret) { + printf ("fail to sound_manager_set_media_session_option(), ret(0x%x)\n", ret); + } +#endif + break; + case 'q': /* quit */ + ret = 1; + break; + default: + ret = 1; + break; + } + return ret; +} + +int audio_io_async_test(int mode) +{ + int ret, size; + char *buffer = NULL; + int i=0; + + char cmd = 0; + int cmd_ret; + + int write_mode = (mode & 0x01); + int read_mode = (mode & 0x02); + + if((write_mode == 0) && (read_mode == 0)) { + printf ("not vaild mode.\n"); + return 0; + } + + if (read_mode) { + +#ifdef _SESSION_SOUND_MANAGER_API_ + printf ("set session for capture.\n"); + + ret = sound_manager_set_session_type(SOUND_SESSION_TYPE_MEDIA); + if (ret) { + printf ("fail to sound_manager_set_session_type(), ret(0x%x)\n", ret); + } + + ret = sound_manager_set_media_session_option (SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START, SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY); + if (ret) { + printf ("fail to sound_manager_set_media_session_option(), ret(0x%x)\n", ret); + } +#endif + + printf ("audio_in_create\n"); + ret = audio_in_create(44100, AUDIO_CHANNEL_STEREO , AUDIO_SAMPLE_TYPE_S16_LE, &input); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_in_create_ex failed. \n"); + return 0; + } + printf ("audio_in_create success!!! [%p]\n", input); + + ret = audio_in_set_stream_cb(input, _audio_io_stream_read_cb, NULL); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_in_set_stream_cb failed. \n"); + return 0; + } + printf ("audio_in_set_stream_cb success!!! [%p]\n", input); + + ret = audio_in_set_state_changed_cb(input, _audio_in_state_cb, NULL); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_out_set_state_changed_cb failed. \n"); + return 0; + } + printf ("audio_out_set_state_changed_cb success!!! [%p]\n", input); + + fp_w = fopen( "/tmp/pcm_w.raw", "w"); + +#ifdef _NEW_SOUND_MANAGER_API_ + //set stream type as SOUND_STREAM_TYPE_MEDIA + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, focus_callback_read, NULL, &g_stream_info_read_h); + if (ret) { + printf ("fail to sound_manager_create_stream_information(), ret(0x%x)\n", ret); + } + ret = audio_in_set_stream_info(input, g_stream_info_read_h); +#endif + + ret = audio_in_set_interrupted_cb(input, interrupted_callback_read, NULL); + } + + if (write_mode) { + printf ("before audio_out_create\n"); + getchar(); + +#ifdef _SESSION_SOUND_MANAGER_API_ + printf ("set session for playback.\n"); + + ret = sound_manager_set_session_type(SOUND_SESSION_TYPE_MEDIA); + if (ret) { + printf ("fail to sound_manager_set_session_type(), ret(0x%x)\n", ret); + } + + ret = sound_manager_set_media_session_option (SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START, SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY); + if (ret) { + printf ("fail to sound_manager_set_media_session_option(), ret(0x%x)\n", ret); + } +#endif + + printf ("audio_out_create\n"); + //ret = audio_out_create(44100, AUDIO_CHANNEL_STEREO , AUDIO_SAMPLE_TYPE_S16_LE, SOUND_TYPE_MEDIA, &output); + ret = audio_out_create_new(44100, AUDIO_CHANNEL_STEREO , AUDIO_SAMPLE_TYPE_S16_LE, &output); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_out_create failed. \n"); + return 0; + } + printf ("audio_out_create success!!! [%p]\n", output); + + ret = audio_out_set_stream_cb(output, _audio_io_stream_write_cb, NULL); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_out_set_stream_cb failed. \n"); + return 0; + } + printf ("audio_out_set_stream_cb success!!! [%p]\n", output); + + ret = audio_out_set_state_changed_cb(output, _audio_out_state_cb, NULL); + if(ret != AUDIO_IO_ERROR_NONE) { + printf ("audio_out_set_state_changed_cb failed. \n"); + return 0; + } + printf ("audio_out_set_state_changed_cb success!!! [%p]\n", output); + +#ifdef _NEW_SOUND_MANAGER_API_ + //set stream type as SOUND_STREAM_TYPE_MEDIA + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, focus_callback_write, NULL, &g_stream_info_write_h); + if (ret) { + printf ("fail to sound_manager_create_stream_information(), ret(0x%x)\n", ret); + } + ret = audio_out_set_stream_info(output, g_stream_info_write_h); +#endif + + ret = audio_out_set_interrupted_cb(output, interrupted_callback_write, NULL); + + //generate wave data + for(i=0; i