From 711ae6049d57e9cae15fa7b319a3ff057ef4e2b2 Mon Sep 17 00:00:00 2001 From: Murali S R Date: Sat, 26 Jun 2021 18:18:08 +0530 Subject: [PATCH 01/32] Audio framework with pulseaudio integration Signed-off-by: Muralidhar S R Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- BUILD.gn | 2 + .../innerkitsimpl/audiocapturer/BUILD.gn | 57 + .../include/audio_capturer_source.h | 86 + .../include/audio_capturer_source_intf.h | 42 + .../audiocapturer/include/audio_encoder.h | 2 +- .../audiocapturer/include/audio_source.h | 2 +- .../audiocapturer/src/audio_capturer_impl.cpp | 1 + .../src/audio_capturer_source.cpp | 473 ++++++ .../audiocapturer/src/audio_encoder.cpp | 1 + .../audiocapturer/src/audio_source.cpp | 1 + .../audiorecorder/src/audio_recorder.cpp | 152 ++ .../innerkitsimpl/audiorenderer/BUILD.gn | 61 + .../include/audio_renderer_sink.h | 67 + .../include/audio_renderer_sink_intf.h | 39 + .../audiorenderer/src/audio_renderer.cpp | 152 ++ .../audiorenderer/src/audio_renderer_sink.cpp | 396 +++++ .../{media_errors.h => audio_errors.h} | 223 +-- .../src/audio_device_descriptor_napi.cpp | 78 +- .../audio_manager/src/audio_manager_napi.cpp | 1265 ++++++++++++--- .../native/audiocommon/include/audio_info.h | 229 +++ .../innerkits/native/audiomanager/BUILD.gn | 82 +- ...o_svc_manager.h => audio_system_manager.h} | 39 +- .../innerkits/native/audiopolicy/BUILD.gn | 95 ++ .../include/audio_policy_manager.h | 61 + .../innerkits/native/audiorecorder/BUILD.gn | 91 ++ .../audiorecorder/include/audio_recorder.h | 202 +++ .../innerkits/native/audiorenderer/BUILD.gn | 71 + .../audiorenderer/include/audio_renderer.h | 201 +++ .../audiosession/include/audio_session.h | 51 + .../native/audiostream/include/audio_stream.h | 86 + .../audio_manager/@ohos.multimedia.audio.d.ts | 1416 +++++++++++++++-- .../include/audio_device_descriptor_napi.h | 16 +- .../include/audio_manager_napi.h | 29 +- libsnd/BUILD.gn | 132 ++ libsnd/include/config.h | 320 ++++ libsnd/include/sndfile.h | 817 ++++++++++ ohos.build | 48 +- pulseaudio/BUILD.gn | 49 + pulseaudio/conf/daemon.conf | 91 ++ pulseaudio/conf/default.pa | 34 + pulseaudio/include/config.h | 285 ++++ pulseaudio/include/ltdl.h | 28 + pulseaudio/include/pulse/version.h | 70 + pulseaudio/ohos_paconfig.sh | 75 + pulseaudio/src/BUILD.gn | 140 ++ pulseaudio/src/daemon/BUILD.gn | 63 + pulseaudio/src/daemon/ohos_daemon-conf.c | 872 ++++++++++ pulseaudio/src/daemon/ohos_pa_main.c | 1274 +++++++++++++++ pulseaudio/src/modules/BUILD.gn | 182 +++ pulseaudio/src/modules/hdi/BUILD.gn | 96 ++ pulseaudio/src/modules/hdi/hdi_sink.c | 440 +++++ pulseaudio/src/modules/hdi/hdi_source.c | 342 ++++ pulseaudio/src/modules/hdi/hdi_source.h | 51 + pulseaudio/src/modules/hdi/module_hdi_sink.c | 100 ++ .../src/modules/hdi/module_hdi_source.c | 100 ++ pulseaudio/src/pulse/BUILD.gn | 113 ++ pulseaudio/src/pulse/ohos_glib-mainloop.c | 661 ++++++++ pulseaudio/src/pulsecore/BUILD.gn | 182 +++ pulseaudio/src/pulsecore/ltdl-stub.c | 47 + pulseaudio/src/utils/BUILD.gn | 85 + sa_profile/3001.xml | 2 +- sa_profile/3009.xml | 28 + sa_profile/BUILD.gn | 6 + services/BUILD.gn | 113 +- .../etc/{audio_service.rc => audio_policy.rc} | 9 +- services/etc/pulseaudio.rc | 27 + services/include/audio_device_descriptor.h | 192 +-- services/include/audio_error.h | 27 + services/include/audio_manager_base.h | 62 +- .../audio_policy/client/audio_policy_base.h | 60 + .../audio_policy/client/audio_policy_proxy.h | 51 + .../audio_policy/common/audio_policy_types.h | 37 + .../audio_policy/server/audio_policy_server.h | 65 + services/include/client/audio_manager_proxy.h | 15 +- .../include/client/audio_service_client.h | 319 ++++ services/include/server/audio_server.h | 25 +- services/src/audio_device_descriptor.cpp | 108 +- .../client/audio_policy_manager.cpp} | 87 +- .../client/audio_policy_proxy.cpp | 164 ++ .../server/audio_policy_manager_stub.cpp | 115 ++ .../server/audio_policy_server.cpp | 100 ++ .../server/etc/audio_policy_config.xml | 35 + .../service/include/audio_policy_service.h | 104 ++ .../service/include/common/audio_config.h | 108 ++ .../server/service/include/config/parser.h | 31 + .../service/include/config/parser_factory.h | 43 + .../service/include/config/xml_parser.h | 68 + .../service/include/interface/iaudio_policy.h | 57 + .../include/interface/iport_observer.h | 33 + .../manager/audio_policy_manager_factory.h | 34 + .../manager/pulseaudio_policy_manager.h | 126 ++ .../service/src/audio_policy_service.cpp | 221 +++ .../server/service/src/config/xml_parser.cpp | 239 +++ .../src/manager/pulseaudio_policy_manager.cpp | 734 +++++++++ services/src/client/audio_manager_proxy.cpp | 99 +- services/src/client/audio_service_client.cpp | 850 ++++++++++ services/src/client/audio_session.cpp | 16 + services/src/client/audio_stream.cpp | 362 +++++ services/src/client/audio_system_manager.cpp | 234 +++ services/src/server/audio_manager_stub.cpp | 76 +- services/src/server/audio_server.cpp | 135 +- services/test/audio_policy_test.cpp | 172 ++ services/test/audio_recorder_test.cpp | 184 +++ services/test/audio_renderer_test.cpp | 184 +++ services/test/pcm2wav.h | 36 + services/test/playback_test.cpp | 130 ++ services/test/record_test.cpp | 121 ++ 107 files changed, 17622 insertions(+), 888 deletions(-) mode change 100755 => 100644 BUILD.gn create mode 100644 frameworks/innerkitsimpl/audiocapturer/BUILD.gn create mode 100644 frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h create mode 100644 frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source_intf.h create mode 100644 frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp create mode 100644 frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp create mode 100644 frameworks/innerkitsimpl/audiorenderer/BUILD.gn create mode 100644 frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h create mode 100644 frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h create mode 100644 frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp create mode 100644 frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp rename frameworks/innerkitsimpl/common/include/{media_errors.h => audio_errors.h} (39%) mode change 100755 => 100644 mode change 100755 => 100644 frameworks/kitsimpl/audio_manager/src/audio_device_descriptor_napi.cpp mode change 100755 => 100644 frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp create mode 100644 interfaces/innerkits/native/audiocommon/include/audio_info.h mode change 100755 => 100644 interfaces/innerkits/native/audiomanager/BUILD.gn rename interfaces/innerkits/native/audiomanager/include/{audio_svc_manager.h => audio_system_manager.h} (60%) mode change 100755 => 100644 create mode 100644 interfaces/innerkits/native/audiopolicy/BUILD.gn create mode 100644 interfaces/innerkits/native/audiopolicy/include/audio_policy_manager.h create mode 100644 interfaces/innerkits/native/audiorecorder/BUILD.gn create mode 100644 interfaces/innerkits/native/audiorecorder/include/audio_recorder.h create mode 100644 interfaces/innerkits/native/audiorenderer/BUILD.gn create mode 100644 interfaces/innerkits/native/audiorenderer/include/audio_renderer.h create mode 100644 interfaces/innerkits/native/audiosession/include/audio_session.h create mode 100644 interfaces/innerkits/native/audiostream/include/audio_stream.h mode change 100755 => 100644 interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts mode change 100755 => 100644 interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h mode change 100755 => 100644 interfaces/kits/js/audio_manager/include/audio_manager_napi.h create mode 100644 libsnd/BUILD.gn create mode 100644 libsnd/include/config.h create mode 100755 libsnd/include/sndfile.h mode change 100755 => 100644 ohos.build create mode 100644 pulseaudio/BUILD.gn create mode 100644 pulseaudio/conf/daemon.conf create mode 100644 pulseaudio/conf/default.pa create mode 100644 pulseaudio/include/config.h create mode 100644 pulseaudio/include/ltdl.h create mode 100644 pulseaudio/include/pulse/version.h create mode 100644 pulseaudio/ohos_paconfig.sh create mode 100644 pulseaudio/src/BUILD.gn create mode 100644 pulseaudio/src/daemon/BUILD.gn create mode 100644 pulseaudio/src/daemon/ohos_daemon-conf.c create mode 100644 pulseaudio/src/daemon/ohos_pa_main.c create mode 100644 pulseaudio/src/modules/BUILD.gn create mode 100644 pulseaudio/src/modules/hdi/BUILD.gn create mode 100644 pulseaudio/src/modules/hdi/hdi_sink.c create mode 100644 pulseaudio/src/modules/hdi/hdi_source.c create mode 100644 pulseaudio/src/modules/hdi/hdi_source.h create mode 100644 pulseaudio/src/modules/hdi/module_hdi_sink.c create mode 100644 pulseaudio/src/modules/hdi/module_hdi_source.c create mode 100644 pulseaudio/src/pulse/BUILD.gn create mode 100644 pulseaudio/src/pulse/ohos_glib-mainloop.c create mode 100644 pulseaudio/src/pulsecore/BUILD.gn create mode 100644 pulseaudio/src/pulsecore/ltdl-stub.c create mode 100644 pulseaudio/src/utils/BUILD.gn mode change 100755 => 100644 sa_profile/3001.xml create mode 100644 sa_profile/3009.xml mode change 100755 => 100644 services/BUILD.gn rename services/etc/{audio_service.rc => audio_policy.rc} (81%) create mode 100644 services/etc/pulseaudio.rc mode change 100755 => 100644 services/include/audio_device_descriptor.h create mode 100644 services/include/audio_error.h mode change 100755 => 100644 services/include/audio_manager_base.h create mode 100644 services/include/audio_policy/client/audio_policy_base.h create mode 100644 services/include/audio_policy/client/audio_policy_proxy.h create mode 100644 services/include/audio_policy/common/audio_policy_types.h create mode 100644 services/include/audio_policy/server/audio_policy_server.h mode change 100755 => 100644 services/include/client/audio_manager_proxy.h create mode 100644 services/include/client/audio_service_client.h mode change 100755 => 100644 services/include/server/audio_server.h mode change 100755 => 100644 services/src/audio_device_descriptor.cpp rename services/src/{client/audio_svc_manager.cpp => audio_policy/client/audio_policy_manager.cpp} (34%) mode change 100755 => 100644 create mode 100644 services/src/audio_policy/client/audio_policy_proxy.cpp create mode 100644 services/src/audio_policy/server/audio_policy_manager_stub.cpp create mode 100644 services/src/audio_policy/server/audio_policy_server.cpp create mode 100644 services/src/audio_policy/server/etc/audio_policy_config.xml create mode 100644 services/src/audio_policy/server/service/include/audio_policy_service.h create mode 100644 services/src/audio_policy/server/service/include/common/audio_config.h create mode 100644 services/src/audio_policy/server/service/include/config/parser.h create mode 100644 services/src/audio_policy/server/service/include/config/parser_factory.h create mode 100644 services/src/audio_policy/server/service/include/config/xml_parser.h create mode 100644 services/src/audio_policy/server/service/include/interface/iaudio_policy.h create mode 100644 services/src/audio_policy/server/service/include/interface/iport_observer.h create mode 100644 services/src/audio_policy/server/service/include/manager/audio_policy_manager_factory.h create mode 100644 services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h create mode 100644 services/src/audio_policy/server/service/src/audio_policy_service.cpp create mode 100644 services/src/audio_policy/server/service/src/config/xml_parser.cpp create mode 100644 services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp mode change 100755 => 100644 services/src/client/audio_manager_proxy.cpp create mode 100644 services/src/client/audio_service_client.cpp create mode 100644 services/src/client/audio_session.cpp create mode 100644 services/src/client/audio_stream.cpp create mode 100644 services/src/client/audio_system_manager.cpp mode change 100755 => 100644 services/src/server/audio_manager_stub.cpp mode change 100755 => 100644 services/src/server/audio_server.cpp create mode 100644 services/test/audio_policy_test.cpp create mode 100644 services/test/audio_recorder_test.cpp create mode 100644 services/test/audio_renderer_test.cpp create mode 100644 services/test/pcm2wav.h create mode 100644 services/test/playback_test.cpp create mode 100644 services/test/record_test.cpp diff --git a/BUILD.gn b/BUILD.gn old mode 100755 new mode 100644 index f39feefe86..5d33a819a6 --- a/BUILD.gn +++ b/BUILD.gn @@ -16,6 +16,8 @@ import("//build/ohos.gni") group("audio_packages") { public_deps = [ "interfaces/innerkits/native/audiocapturer:audio_capturer", + "interfaces/innerkits/native/audiorenderer:audio_renderer", + "interfaces/innerkits/native/audiorecorder:audio_recorder", "services:audio_service", "interfaces/innerkits/native/audiomanager:audio_client", ] diff --git a/frameworks/innerkitsimpl/audiocapturer/BUILD.gn b/frameworks/innerkitsimpl/audiocapturer/BUILD.gn new file mode 100644 index 0000000000..2b73a0d411 --- /dev/null +++ b/frameworks/innerkitsimpl/audiocapturer/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") +import("//drivers/adapter/uhdf2/uhdf.gni") + +ohos_shared_library("audio_capturer_source") { + install_enable = true + sources = [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp", + ] + cflags = [ "-fPIC" ] + cflags += [ "-Wall" ] + cflags_cc = cflags + + include_dirs = [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/media_standard/interfaces/innerkits/native/media/include", + "//utils/native/base/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//drivers/peripheral/audio/interfaces/include", + "//third_party/bounds_checking_function/include", + ] + public_configs = [ ":audio_external_library_config" ] + + deps = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//third_party/bounds_checking_function:libsec_static", + "$hdf_uhdf_path/config:libhdf_hcs", + "$hdf_uhdf_path/hcs:hdf_default.hcb", + "$hdf_uhdf_path/hdi:libhdi", + "$hdf_uhdf_path/host:hdf_devhost", + "$hdf_uhdf_path/host:libhdf_host", + "$hdf_uhdf_path/ipc:libhdf_ipc_adapter", + "$hdf_uhdf_path/manager:hdf_devmgr", + "$hdf_uhdf_path/manager:hdf_devmgr.rc", + "$hdf_uhdf_path/osal:libhdf_utils", + ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +config("audio_external_library_config") { + include_dirs = ["//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include"] +} diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h new file mode 100644 index 0000000000..3620af3860 --- /dev/null +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_CAPTURER_SOURCE_H +#define AUDIO_CAPTURER_SOURCE_H + +#include "audio_manager.h" + +#include + +namespace OHOS { +namespace AudioStandard { +#define AUDIO_CHANNELCOUNT 2 +#define AUDIO_SAMPLE_RATE_48K 48000 +#define DEEP_BUFFER_RENDER_PERIOD_SIZE 4096 +#define INT_32_MAX 0x7fffffff +#define PERIOD_SIZE 1024 +#define PATH_LEN 256 + +typedef struct { + AudioFormat format; + uint32_t sampleFmt; + uint32_t sampleRate; + uint32_t channel; + float volume; +} AudioSourceAttr; + +class AudioCapturerSource { +public: + int32_t Init(AudioSourceAttr &atrr); + void DeInit(void); + + int32_t Start(void); + int32_t Stop(void); + int32_t Flush(void); + int32_t Reset(void); + int32_t Pause(void); + int32_t Resume(void); + int32_t CaptureFrame(char *frame, uint64_t requestBytes, uint64_t &replyBytes); + int32_t SetVolume(float left, float right); + int32_t GetVolume(float &left, float &right); + int32_t SetMute(bool isMute); + int32_t GetMute(bool &isMute); + + static AudioCapturerSource* GetInstance(void); + bool capturerInited_; + +private: + const int32_t HALF_FACTOR = 2; + const int32_t MAX_AUDIO_ADAPTER_NUM = 3; + const float MAX_VOLUME_LEVEL = 100.0f; + + AudioSourceAttr attr_; + bool started_; + bool paused_; + float leftVolume_; + float rightVolume_; + + struct AudioManager *audioManager_; + struct AudioAdapter *audioAdapter_; + struct AudioCapture *audioCapture_; + + void *handle_; + +#ifdef CAPTURE_DUMP + FILE *pfd; +#endif + + AudioCapturerSource(); + ~AudioCapturerSource(); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_CAPTURER_SOURCE_H diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source_intf.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source_intf.h new file mode 100644 index 0000000000..a7e89c3617 --- /dev/null +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source_intf.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_CAPTURER_SINK_INTF_H +#define AUDIO_CAPTURER_SINK_INTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + enum AudioFormat format; + uint32_t sampleFmt; + uint32_t sampleRate; + uint32_t channel; + float volume; +} AudioSourceAttr; + +int32_t AudioCapturerSourceInit(AudioSourceAttr *); +void AudioCapturerSourceDeInit(void); +int32_t AudioCapturerSourceStart(void); +int32_t AudioCapturerSourceStop(void); +int32_t AudioCapturerSourceFrame(char *, uint64_t, uint64_t *); +int32_t AudioCapturerSourceSetVolume(float, float); +int32_t AudioCapturerSourceGetVolume(float *left, float *right); +#ifdef __cplusplus +} +#endif + +#endif // AUDIO_CAPTURER_SINK_INTF_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_encoder.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_encoder.h index 68afee6392..4c0a2b832e 100755 --- a/frameworks/innerkitsimpl/audiocapturer/include/audio_encoder.h +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_encoder.h @@ -21,7 +21,7 @@ #include #include #include -#include "media_errors.h" +#include "audio_errors.h" #include "media_info.h" #include "format.h" #include "codec_interface.h" diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_source.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_source.h index 1b03fa5a5a..a540a0542b 100755 --- a/frameworks/innerkitsimpl/audiocapturer/include/audio_source.h +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_source.h @@ -22,7 +22,7 @@ #include #include -#include "media_errors.h" +#include "audio_errors.h" #include "media_info.h" #include "format.h" #include "audio_manager.h" diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_impl.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_impl.cpp index 902047351b..7035b166b9 100755 --- a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_impl.cpp +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_impl.cpp @@ -23,6 +23,7 @@ namespace OHOS { namespace Audio { using namespace OHOS::Media; +using namespace OHOS::AudioStandard; const unsigned long long TIME_CONVERSION_US_S = 1000000ULL; /* us to s */ const unsigned long long TIME_CONVERSION_NS_US = 1000ULL; /* ns to us */ diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp new file mode 100644 index 0000000000..466b7ae4f0 --- /dev/null +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_capturer_source.h" +#include "audio_errors.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +#ifdef CAPTURE_DUMP +const char *g_audioOutTestFilePath = "/data/local/tmp/audio_capture.pcm"; +#endif // CAPTURE_DUMP + +AudioCapturerSource::AudioCapturerSource() + : capturerInited_(false), started_(false), paused_(false), leftVolume_(MAX_VOLUME_LEVEL), rightVolume_(MAX_VOLUME_LEVEL), + audioManager_(nullptr), audioAdapter_(nullptr), audioCapture_(nullptr) +{ + attr_ = {}; +#ifdef CAPTURE_DUMP + pfd = nullptr; +#endif // CAPTURE_DUMP +} + +AudioCapturerSource::~AudioCapturerSource() +{ + DeInit(); +} + +AudioCapturerSource* AudioCapturerSource::GetInstance() +{ + static AudioCapturerSource audioCapturer_; + return &audioCapturer_; +} + +void AudioCapturerSource::DeInit() +{ + started_ = false; + capturerInited_ = false; + + if ((audioCapture_ != nullptr) && (audioAdapter_ != nullptr)) { + audioAdapter_->DestroyCapture(audioAdapter_, audioCapture_); + } + audioCapture_ = nullptr; + + if ((audioManager_ != nullptr) && (audioAdapter_ != nullptr)) { + audioManager_->UnloadAdapter(audioManager_, audioAdapter_); + } + audioAdapter_ = nullptr; + audioManager_ = nullptr; + dlclose(handle_); +#ifdef CAPTURE_DUMP + if (pfd) { + fclose(pfd); + pfd = nullptr; + } +#endif // CAPTURE_DUMP +} + +int32_t InitAttrsCapture(struct AudioSampleAttributes *attrs) +{ + /* Initialization of audio parameters for playback */ + attrs->format = AUDIO_FORMAT_PCM_16_BIT; + attrs->channelCount = AUDIO_CHANNELCOUNT; + attrs->sampleRate = AUDIO_SAMPLE_RATE_48K; + attrs->interleaved = 0; + attrs->type = AUDIO_IN_MEDIA; + attrs->period = DEEP_BUFFER_RENDER_PERIOD_SIZE; + /* PERIOD_SIZE * 16 * attrs->channelCount / 8,Byte */ + attrs->frameSize = 16 * attrs->channelCount / 8; + attrs->isBigEndian = false; + attrs->isSignedData = true; + /* DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ + attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8); + attrs->stopThreshold = INT_32_MAX; + /* 16 * 1024 */ + attrs->silenceThreshold = 16 * 1024; + + return SUCCESS; +} + +int32_t SwitchAdapterCapture(struct AudioAdapterDescriptor *descs, const char *adapterNameCase, + enum AudioPortDirection portFlag, struct AudioPort *capturePort, const int32_t size) +{ + for (int32_t index = 0; index < size; index++) { + struct AudioAdapterDescriptor *desc = &descs[index]; + if (desc == nullptr) { + MEDIA_ERR_LOG("SwitchAdapter Fail AudioAdapterDescriptor desc NULL"); + return ERR_INVALID_INDEX; // note: return invalid index not invalid handle + } + if (!strcmp(desc->adapterName, adapterNameCase)) { + for (uint32_t port = 0; ((desc != NULL) && (port < desc->portNum)); port++) { + // Only find out the port of out in the sound card + if (desc->ports[port].dir == portFlag) { + *capturePort = desc->ports[port]; + return index; + } + } + } + } + MEDIA_ERR_LOG("SwitchAdapter Fail"); + + return ERR_INVALID_INDEX; +} + +int32_t AudioCapturerSource::Init(AudioSourceAttr &attr) +{ + attr_ = attr; + int32_t ret; + int32_t index; + int32_t size = 0; + char resolvedPath[100] = "/system/lib/libhdi_audio.z.so"; + struct AudioPort audioPort; + struct AudioAdapterDescriptor *descs = nullptr; + struct AudioPort capturePort; + struct AudioManager *(*getAudioManager)() = nullptr; + audioPort.dir = PORT_IN; + audioPort.portId = 0; + audioPort.portName = "AOP"; + + handle_ = dlopen(resolvedPath, 1); + if (handle_ == nullptr) { + MEDIA_ERR_LOG("Open Capturer so Fail"); + return ERR_INVALID_HANDLE; + } + getAudioManager = (struct AudioManager *(*)())(dlsym(handle_, "GetAudioManagerFuncs")); + audioManager_ = getAudioManager(); + if (audioManager_ == nullptr) { + return ERR_INVALID_HANDLE; + } + + ret = audioManager_->GetAllAdapters(audioManager_, &descs, &size); + // adapters is 0~3 + if (size > MAX_AUDIO_ADAPTER_NUM || size == 0 || descs == nullptr || ret < 0) { + MEDIA_ERR_LOG("Get adapters Fail"); + return ERR_NOT_STARTED; + } + + // Get qualified sound card and port + char adapterNameCase[PATH_LEN] = "internal"; + index = SwitchAdapterCapture(descs, adapterNameCase, audioPort.dir, &capturePort, size); + if (index < 0) { + MEDIA_ERR_LOG("Switch Adapter Fail"); + return ERR_NOT_STARTED; + } + + struct AudioAdapterDescriptor *desc = &descs[index]; + if (audioManager_->LoadAdapter(audioManager_, desc, &audioAdapter_) != 0) { + MEDIA_ERR_LOG("Load Adapter Fail"); + return ERR_NOT_STARTED; + } + if (audioAdapter_ == nullptr) { + MEDIA_ERR_LOG("Load audio device failed"); + return ERR_NOT_STARTED; + } + // Initialization port information, can fill through mode and other parameters + ret = audioAdapter_->InitAllPorts(audioAdapter_); + if (ret != 0) { + MEDIA_ERR_LOG("InitAllPorts failed"); + return ERR_DEVICE_INIT; + } + + struct AudioSampleAttributes param; + // User needs to set + InitAttrsCapture(¶m); + param.sampleRate = attr_.sampleRate; + param.format = attr_.format; + param.channelCount = attr_.channel; + + struct AudioDeviceDescriptor deviceDesc; + deviceDesc.portId = capturePort.portId; + deviceDesc.pins = PIN_IN_MIC; + deviceDesc.desc = nullptr; + + ret = audioAdapter_->CreateCapture(audioAdapter_, &deviceDesc, ¶m, &audioCapture_); + if (audioCapture_ == nullptr || ret < 0) { + MEDIA_ERR_LOG("Create capture failed"); + return ERR_NOT_STARTED; + } + + capturerInited_ = true; + +#ifdef CAPTURE_DUMP + pfd = fopen(g_audioOutTestFilePath, "wb+"); + if (pfd == nullptr) { + MEDIA_ERR_LOG("Error opening pcm test file!"); + } +#endif // CAPTURE_DUMP + + return SUCCESS; +} + +int32_t AudioCapturerSource::CaptureFrame(char *frame, uint64_t requestBytes, uint64_t &replyBytes) +{ + int32_t ret; + if (audioCapture_ == nullptr) { + MEDIA_ERR_LOG("Audio capture Handle is nullptr!"); + return ERR_INVALID_HANDLE; + } + + ret = audioCapture_->CaptureFrame(audioCapture_, frame, requestBytes, &replyBytes); + if (ret < 0) { + MEDIA_ERR_LOG("Capture Frame Fail"); + return ERR_READ_FAILED; + } + +#ifdef CAPTURE_DUMP + size_t writeResult = fwrite(frame, replyBytes, 1, pfd); + if (writeResult != replyBytes) { + MEDIA_ERR_LOG("Failed to write the file."); + } +#endif // CAPTURE_DUMP + + return SUCCESS; +} + +int32_t AudioCapturerSource::Start(void) +{ + int32_t ret; + if (!started_ && audioCapture_ != nullptr) { + ret = audioCapture_->control.Start((AudioHandle)audioCapture_); + if (ret < 0) { + return ERR_NOT_STARTED; + } + started_ = true; + audioCapture_->volume.SetVolume(reinterpret_cast(audioCapture_), MAX_VOLUME_LEVEL); + } + + return SUCCESS; +} + +int32_t AudioCapturerSource::SetVolume(float left, float right) +{ + float volume; + if (audioCapture_ == nullptr) { + MEDIA_ERR_LOG("AudioCapturerSource::SetVolume failed audioCapture_ null"); + return ERR_INVALID_HANDLE; + } + + leftVolume_ = left; + rightVolume_ = right; + if ((leftVolume_ == 0) && (rightVolume_ != 0)) { + volume = rightVolume_; + } else if ((leftVolume_ != 0) && (rightVolume_ == 0)) { + volume = leftVolume_; + } else { + volume = (leftVolume_ + rightVolume_) / HALF_FACTOR; + } + + audioCapture_->volume.SetVolume(reinterpret_cast(audioCapture_), volume); + + return SUCCESS; +} + +int32_t AudioCapturerSource::GetVolume(float &left, float &right) +{ + float val = 0.0; + audioCapture_->volume.GetVolume((AudioHandle)audioCapture_, &val); + left = val; + right = val; + + return SUCCESS; +} + +int32_t AudioCapturerSource::SetMute(bool isMute) +{ + int32_t ret; + if (audioCapture_ == nullptr) { + MEDIA_ERR_LOG("AudioCapturerSource::SetMute failed audioCapture_ handle is null!"); + return ERR_INVALID_HANDLE; + } + + ret = audioCapture_->volume.SetMute((AudioHandle)audioCapture_, isMute); + if (ret != 0) { + MEDIA_ERR_LOG("AudioCapturerSource::SetMute failed"); + return ERR_OPERATION_FAILED; + } + + return SUCCESS; +} + +int32_t AudioCapturerSource::GetMute(bool &isMute) +{ + int32_t ret; + if (audioCapture_ == nullptr) { + MEDIA_ERR_LOG("AudioCapturerSource::GetMute failed audioCapture_ handle is null!"); + return ERR_INVALID_HANDLE; + } + + ret = audioCapture_->volume.GetMute((AudioHandle)audioCapture_, &isMute); + if (ret != 0) { + MEDIA_ERR_LOG("AudioCapturerSource::GetMute failed"); + return ERR_OPERATION_FAILED; + } + + return SUCCESS; +} + +int32_t AudioCapturerSource::Stop(void) +{ + int32_t ret; + if (started_ && audioCapture_ != nullptr) { + ret = audioCapture_->control.Stop(reinterpret_cast(audioCapture_)); + if (ret < 0) { + MEDIA_ERR_LOG("Stop capture Failed"); + return ERR_OPERATION_FAILED; + } + } + started_ = false; + + return SUCCESS; +} + +int32_t AudioCapturerSource::Pause(void) +{ + int32_t ret; + if (started_ && audioCapture_ != nullptr) { + ret = audioCapture_->control.Pause(reinterpret_cast(audioCapture_)); + if (ret != 0) { + MEDIA_ERR_LOG("pause capture Failed"); + return ERR_OPERATION_FAILED; + } + } + paused_ = true; + + return SUCCESS; +} + +int32_t AudioCapturerSource::Resume(void) +{ + int32_t ret; + if (paused_ && audioCapture_ != nullptr) { + ret = audioCapture_->control.Resume(reinterpret_cast(audioCapture_)); + if (ret != 0) { + MEDIA_ERR_LOG("resume capture Failed"); + return ERR_OPERATION_FAILED; + } + } + paused_ = false; + + return SUCCESS; +} + +int32_t AudioCapturerSource::Reset(void) +{ + if (started_ && audioCapture_ != nullptr) { + audioCapture_->control.Flush(reinterpret_cast(audioCapture_)); + } + + return SUCCESS; +} + +int32_t AudioCapturerSource::Flush(void) +{ + if (started_ && audioCapture_ != nullptr) { + audioCapture_->control.Flush(reinterpret_cast(audioCapture_)); + } + + return SUCCESS; +} +} // namespace AudioStandard +} // namesapce OHOS + +#ifdef __cplusplus +extern "C" { +#endif + +using namespace OHOS::AudioStandard; + +AudioCapturerSource* g_audioCaptureSourceInstance = AudioCapturerSource::GetInstance(); + +int32_t AudioCapturerSourceInit(AudioSourceAttr *attr) +{ + int32_t ret; + + if (g_audioCaptureSourceInstance->capturerInited_) + return SUCCESS; + + ret = g_audioCaptureSourceInstance->Init(*attr); + + return ret; +} + +void AudioCapturerSourceDeInit() +{ + if (g_audioCaptureSourceInstance->capturerInited_) + g_audioCaptureSourceInstance->DeInit(); +} + +int32_t AudioCapturerSourceStop() +{ + int32_t ret; + + if (!g_audioCaptureSourceInstance->capturerInited_) + return SUCCESS; + + ret = g_audioCaptureSourceInstance->Stop(); + + return ret; +} + +int32_t AudioCapturerSourceStart() +{ + int32_t ret; + + if (!g_audioCaptureSourceInstance->capturerInited_) { + MEDIA_ERR_LOG("audioCapturer Not Inited! Init the capturer first\n"); + return ERR_DEVICE_INIT; + } + + ret = g_audioCaptureSourceInstance->Start(); + + return ret; +} + +int32_t AudioCapturerSourceFrame(char *frame, uint64_t requestBytes, uint64_t &replyBytes) +{ + int32_t ret; + + if (!g_audioCaptureSourceInstance->capturerInited_) { + MEDIA_ERR_LOG("audioCapturer Not Inited! Init the capturer first\n"); + return ERR_DEVICE_INIT; + } + + ret = g_audioCaptureSourceInstance->CaptureFrame(frame, requestBytes, replyBytes); + + return ret; +} + +int32_t AudioCapturerSourceSetVolume(float left, float right) +{ + int32_t ret; + + if (!g_audioCaptureSourceInstance->capturerInited_) { + MEDIA_ERR_LOG("audioCapturer Not Inited! Init the capturer first\n"); + return ERR_DEVICE_INIT; + } + + ret = g_audioCaptureSourceInstance->SetVolume(left, right); + + return ret; +} + +int32_t AudioCapturerSourceGetVolume(float *left, float *right) +{ + int32_t ret; + + if (!g_audioCaptureSourceInstance->capturerInited_) { + MEDIA_ERR_LOG("audioCapturer Not Inited! Init the capturer first\n"); + return ERR_DEVICE_INIT; + } + ret = g_audioCaptureSourceInstance->GetVolume(*left, *right); + + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_encoder.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_encoder.cpp index e84726f2cd..fa9fed58ed 100755 --- a/frameworks/innerkitsimpl/audiocapturer/src/audio_encoder.cpp +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_encoder.cpp @@ -20,6 +20,7 @@ namespace OHOS { namespace Audio { using namespace OHOS::Media; +using namespace OHOS::AudioStandard; constexpr uint32_t AUDIO_READ_STREAM_TIME_OUT_MS = 1000; /* 1S */ diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_source.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_source.cpp index 92be601e06..d17860fe8a 100755 --- a/frameworks/innerkitsimpl/audiocapturer/src/audio_source.cpp +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_source.cpp @@ -27,6 +27,7 @@ namespace Audio { } while (0) using namespace OHOS::Media; +using namespace OHOS::AudioStandard; static AudioManager *g_audioManager = nullptr; AudioSource::AudioSource() : initialized_(false), diff --git a/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp new file mode 100644 index 0000000000..ce7ec0ca60 --- /dev/null +++ b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_errors.h" +#include "audio_recorder.h" +#include "audio_stream.h" + +namespace OHOS { +namespace AudioStandard { + +class AudioRecorderPrivate : public AudioRecorder { +public: + int32_t GetFrameCount(uint32_t &frameCount) override; + int32_t SetParams(const AudioRecorderParams params) override; + int32_t GetParams(AudioRecorderParams ¶ms) override; + bool Start() override; + int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) override; + RecorderState GetStatus() override; + bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) override; + bool Stop() override; + bool Flush() override; + bool Release() override; + int32_t GetBufferSize(size_t &bufferSize) override; + std::vector GetSupportedFormats() override; + std::vector GetSupportedChannels() override; + std::vector GetSupportedEncodingTypes() override; + std::vector GetSupportedSamplingRates() override; + + std::unique_ptr audioRecorder; + + AudioRecorderPrivate(AudioStreamType audioStreamType); + virtual ~AudioRecorderPrivate(); +}; + +AudioRecorder::~AudioRecorder() = default; +AudioRecorderPrivate::~AudioRecorderPrivate() = default; + +std::unique_ptr AudioRecorder::Create(AudioStreamType audioStreamType) +{ + return std::make_unique(audioStreamType); +} + +AudioRecorderPrivate::AudioRecorderPrivate(AudioStreamType audioStreamType) +{ + audioRecorder = std::make_unique(audioStreamType, AUDIO_MODE_RECORD); +} + +int32_t AudioRecorderPrivate::GetFrameCount(uint32_t &frameCount) +{ + return audioRecorder->GetFrameCount(frameCount); +} + +int32_t AudioRecorderPrivate::SetParams(const AudioRecorderParams params) +{ + AudioStreamParams audioStreamParams; + audioStreamParams.format = params.audioSampleFormat; + audioStreamParams.samplingRate = params.samplingRate; + audioStreamParams.channels = params.audioChannel; + audioStreamParams.encoding = params.audioEncoding; + + return audioRecorder->SetAudioStreamInfo(audioStreamParams); +} + +int32_t AudioRecorderPrivate::GetParams(AudioRecorderParams ¶ms) +{ + AudioStreamParams audioStreamParams; + int32_t result = audioRecorder->GetAudioStreamInfo(audioStreamParams); + if (SUCCESS == result) { + params.audioSampleFormat = static_cast(audioStreamParams.format); + params.samplingRate = static_cast(audioStreamParams.samplingRate); + params.audioChannel = static_cast(audioStreamParams.channels); + params.audioEncoding = static_cast(audioStreamParams.encoding); + } + + return result; +} + +bool AudioRecorderPrivate::Start() +{ + return audioRecorder->StartAudioStream(); +} + +int32_t AudioRecorderPrivate::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) +{ + return audioRecorder->Read(buffer, userSize, isBlockingRead); +} + +RecorderState AudioRecorderPrivate::GetStatus() +{ + return (RecorderState)audioRecorder->GetState(); +} + +bool AudioRecorderPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) +{ + return audioRecorder->GetAudioTime(timestamp,base); +} + +bool AudioRecorderPrivate::Stop() +{ + return audioRecorder->StopAudioStream(); +} + +bool AudioRecorderPrivate::Flush() +{ + return audioRecorder->FlushAudioStream(); +} + +bool AudioRecorderPrivate::Release() +{ + return audioRecorder->ReleaseAudioStream(); +} + +int32_t AudioRecorderPrivate::GetBufferSize(size_t &bufferSize) +{ + return audioRecorder->GetBufferSize(bufferSize); +} + +std::vector AudioRecorderPrivate::GetSupportedFormats() +{ + return audioRecorder->GetSupportedFormats(); +} + +std::vector AudioRecorderPrivate::GetSupportedChannels() +{ + return audioRecorder->GetSupportedChannels(); +} + +std::vector AudioRecorderPrivate::GetSupportedEncodingTypes() +{ + return audioRecorder->GetSupportedEncodingTypes(); +} + +std::vector AudioRecorderPrivate::GetSupportedSamplingRates() +{ + return audioRecorder->GetSupportedSamplingRates(); +} +} // namespace AudioStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiorenderer/BUILD.gn b/frameworks/innerkitsimpl/audiorenderer/BUILD.gn new file mode 100644 index 0000000000..002a9e5c26 --- /dev/null +++ b/frameworks/innerkitsimpl/audiorenderer/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") +import("//drivers/adapter/uhdf2/uhdf.gni") + +ohos_shared_library("audio_renderer_sink") { + install_enable = true + + sources = [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp", + ] + + cflags = ["-fPIC"] + cflags += ["-Wall"] + cflags_cc = cflags + + include_dirs = [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/media_standard/interfaces/innerkits/native/media/include", + "//utils/native/base/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//drivers/peripheral/audio/interfaces/include", + "//utils/native/base/include", + ] + + public_configs = [":audio_external_library_config"] + + deps = [ + "//third_party/bounds_checking_function:libsec_static", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//utils/native/base:utils", + "$hdf_uhdf_path/ipc:libhdf_ipc_adapter", + "$hdf_uhdf_path/hcs:hdf_default.hcb", + "$hdf_uhdf_path/hdi:libhdi", + "$hdf_uhdf_path/host:hdf_devhost", + "$hdf_uhdf_path/host:libhdf_host", + "$hdf_uhdf_path/config:libhdf_hcs", + "$hdf_uhdf_path/manager:hdf_devmgr.rc", + "$hdf_uhdf_path/manager:hdf_devmgr", + "$hdf_uhdf_path/osal:libhdf_utils", + ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +config("audio_external_library_config") { + include_dirs = ["//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include"] +} diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h new file mode 100644 index 0000000000..1c1cd64ecb --- /dev/null +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_RENDERER_SINK_H +#define AUDIO_RENDERER_SINK_H + +#include "audio_manager.h" + +#include + +namespace OHOS { +namespace AudioStandard { +typedef struct { + AudioFormat format; + uint32_t sampleFmt; + uint32_t sampleRate; + uint32_t channel; + float volume; +} AudioSinkAttr; + +class AudioRendererSink { +public: + int32_t Init(AudioSinkAttr &atrr); + void DeInit(void); + int32_t Start(void); + int32_t Stop(void); + int32_t Flush(void); + int32_t Reset(void); + int32_t Pause(void); + int32_t Resume(void); + int32_t RenderFrame(char &frame, uint64_t len, uint64_t &writeLen); + int32_t SetVolume(float left, float right); + int32_t GetVolume(float &left, float &right); + static AudioRendererSink* GetInstance(void); + bool rendererInited_; +private: + AudioRendererSink(); + ~AudioRendererSink(); + AudioSinkAttr attr_; + bool started_; + bool paused_; + float leftVolume_; + float rightVolume_; + struct AudioManager *audioManager_; + struct AudioAdapter *audioAdapter_; + struct AudioRender *audioRender_; + void *handle_; +#ifdef DUMPFILE + FILE *pfd; +#endif // DUMPFILE +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // AUDIO_RENDERER_SINK_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h new file mode 100644 index 0000000000..ba37198524 --- /dev/null +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * 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 AUDIO_RENDERER_SINK_INTF_H +#define AUDIO_RENDERER_SINK_INTF_H + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct { + enum AudioFormat format; + uint32_t sampleFmt; + uint32_t sampleRate; + uint32_t channel; + float volume; +} AudioSinkAttr; + +int32_t AudioRendererSinkInit(AudioSinkAttr *); +void AudioRendererSinkDeInit(void); +int32_t AudioRendererSinkStart(void); +int32_t AudioRendererSinkStop(void); +int32_t AudioRendererRenderFrame(char*, uint64_t, uint64_t*); +int32_t AudioRendererSinkSetVolume(float, float); +#ifdef __cplusplus +} +#endif +#endif // AUDIO_RENDERER_SINK_INTF_H \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp new file mode 100644 index 0000000000..75807233c4 --- /dev/null +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_errors.h" +#include "audio_renderer.h" +#include "audio_stream.h" + +namespace OHOS { +namespace AudioStandard { + +class AudioRendererPrivate : public AudioRenderer { +public: + int32_t GetFrameCount(uint32_t &frameCount) override; + int32_t SetParams(const AudioRendererParams params) override; + int32_t GetParams(AudioRendererParams ¶ms) override; + bool Start() override; + int32_t Write(uint8_t *buffer, size_t bufferSize) override; + RendererState GetStatus() override; + bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) override; + bool Drain() override; + bool Stop() override; + bool Release() override; + int32_t GetBufferSize(size_t &bufferSize) override; + std::vector GetSupportedFormats() override; + std::vector GetSupportedChannels() override; + std::vector GetSupportedEncodingTypes() override; + std::vector GetSupportedSamplingRates() override; + + std::unique_ptr audioRenderer; + + AudioRendererPrivate(AudioStreamType audioStreamType); + virtual ~AudioRendererPrivate(); +}; + +AudioRenderer::~AudioRenderer() = default; +AudioRendererPrivate::~AudioRendererPrivate() = default; + +std::unique_ptr AudioRenderer::Create(AudioStreamType audioStreamType) +{ + return std::make_unique(audioStreamType); +} + +AudioRendererPrivate::AudioRendererPrivate(AudioStreamType audioStreamType) +{ + audioRenderer = std::make_unique(audioStreamType, AUDIO_MODE_PLAYBACK); +} + +int32_t AudioRendererPrivate::GetFrameCount(uint32_t &frameCount) +{ + return audioRenderer->GetFrameCount(frameCount); +} + +int32_t AudioRendererPrivate::SetParams(const AudioRendererParams params) +{ + AudioStreamParams audioStreamParams; + audioStreamParams.format = params.sampleFormat; + audioStreamParams.samplingRate = params.sampleRate; + audioStreamParams.channels = params.channelCount; + audioStreamParams.encoding = params.encodingType; + + return audioRenderer->SetAudioStreamInfo(audioStreamParams); +} + +int32_t AudioRendererPrivate::GetParams(AudioRendererParams ¶ms) +{ + AudioStreamParams audioStreamParams; + int32_t result = audioRenderer->GetAudioStreamInfo(audioStreamParams); + if(!result) { + params.sampleFormat = static_cast(audioStreamParams.format); + params.sampleRate = static_cast(audioStreamParams.samplingRate); + params.channelCount = static_cast(audioStreamParams.channels); + params.encodingType = static_cast(audioStreamParams.encoding); + } + + return result; +} + +bool AudioRendererPrivate::Start() +{ + return audioRenderer->StartAudioStream(); +} + +int32_t AudioRendererPrivate::Write(uint8_t *buffer, size_t bufferSize) +{ + return audioRenderer->Write(buffer, bufferSize); +} + +RendererState AudioRendererPrivate::GetStatus() +{ + return static_cast(audioRenderer->GetState()); +} + +bool AudioRendererPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) +{ + return audioRenderer->GetAudioTime(timestamp,base); +} + +bool AudioRendererPrivate::Drain() +{ + return audioRenderer->DrainAudioStream(); +} + +bool AudioRendererPrivate::Stop() +{ + return audioRenderer->StopAudioStream(); +} + +bool AudioRendererPrivate::Release() +{ + return audioRenderer->ReleaseAudioStream(); +} + +int32_t AudioRendererPrivate::GetBufferSize(size_t &bufferSize) +{ + return audioRenderer->GetBufferSize(bufferSize); +} + +std::vector AudioRendererPrivate::GetSupportedFormats() +{ + return audioRenderer->GetSupportedFormats(); +} + +std::vector AudioRendererPrivate::GetSupportedSamplingRates() +{ + return audioRenderer->GetSupportedSamplingRates(); +} + +std::vector AudioRendererPrivate::GetSupportedChannels() +{ + return audioRenderer->GetSupportedChannels(); +} + +std::vector AudioRendererPrivate::GetSupportedEncodingTypes() +{ + return audioRenderer->GetSupportedEncodingTypes(); +} +} // namespace AudioStandard +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp new file mode 100644 index 0000000000..5d2d4423ee --- /dev/null +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_errors.h" +#include "audio_renderer_sink.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +#define AUDIO_CHANNELCOUNT 2 +#define AUDIO_SAMPLE_RATE_48K 48000 +#define DEEP_BUFFER_RENDER_PERIOD_SIZE 4096 +#define INT_32_MAX 0x7fffffff +#define PERIOD_SIZE 1024 + +namespace { +const int32_t HALF_FACTOR = 2; +const int32_t MAX_AUDIO_ADAPTER_NUM = 3; +const float DEFAULT_VOLUME_LEVEL = 1.0f; +} + +#ifdef DUMPFILE +const char *g_audioOutTestFilePath = "/data/local/tmp/audioout_test.pcm"; +#endif // DUMPFILE + +AudioRendererSink::AudioRendererSink() + : rendererInited_(false), started_(false), paused_(false), leftVolume_(DEFAULT_VOLUME_LEVEL), + rightVolume_(DEFAULT_VOLUME_LEVEL), audioManager_(nullptr), audioAdapter_(nullptr), audioRender_(nullptr) +{ + attr_ = {}; +#ifdef DUMPFILE + pfd = nullptr; +#endif // DUMPFILE +} + +AudioRendererSink::~AudioRendererSink() +{ + DeInit(); +} + +AudioRendererSink* AudioRendererSink::GetInstance() +{ + static AudioRendererSink audioRenderer_; + + return &audioRenderer_; +} + +void AudioRendererSink::DeInit() +{ + started_ = false; + rendererInited_ = false; + if ((audioRender_ != nullptr) && (audioAdapter_ != nullptr)) { + audioAdapter_->DestroyRender(audioAdapter_, audioRender_); + } + audioRender_ = nullptr; + + if ((audioManager_ != nullptr) && (audioAdapter_ != nullptr)) { + audioManager_->UnloadAdapter(audioManager_, audioAdapter_); + } + audioAdapter_ = nullptr; + audioManager_ = nullptr; + + dlclose(handle_); + +#ifdef DUMPFILE + if (pfd) { + fclose(pfd); + pfd = nullptr; + } +#endif // DUMPFILE +} + +int32_t InitAttrs(struct AudioSampleAttributes *attrs) +{ + /* Initialization of audio parameters for playback */ + attrs->format = AUDIO_FORMAT_PCM_16_BIT; + attrs->channelCount = AUDIO_CHANNELCOUNT; + attrs->sampleRate = AUDIO_SAMPLE_RATE_48K; + attrs->interleaved = 0; + attrs->type = AUDIO_IN_MEDIA; + attrs->period = DEEP_BUFFER_RENDER_PERIOD_SIZE; + /* PERIOD_SIZE * 16 * attrs->channelCount / 8 */ + attrs->frameSize = PERIOD_SIZE * 16 * attrs->channelCount / 8; + attrs->isBigEndian = false; + attrs->isSignedData = true; + /* DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ + attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8); + attrs->stopThreshold = INT_32_MAX; + attrs->silenceThreshold = 0; + + return SUCCESS; +} + +static int32_t SwitchAdapter(struct AudioAdapterDescriptor *descs, + const char *adapterNameCase, enum AudioPortDirection portFlag, + struct AudioPort *renderPort, int32_t size) +{ + for (int32_t index = 0; index < size; index++) { + struct AudioAdapterDescriptor *desc = &descs[index]; + if (desc == nullptr) { + MEDIA_ERR_LOG("SwitchAdapter Fail AudioAdapterDescriptor desc NULL"); + return ERR_INVALID_INDEX; // note: return invalid index not invalid handle + } + if (!strcmp(desc->adapterName, adapterNameCase)) { + for (uint32_t port = 0; ((desc != NULL) && (port < desc->portNum)); port++) { + // Only find out the port of out in the sound card + if (desc->ports[port].dir == portFlag) { + *renderPort = desc->ports[port]; + return index; + } + } + } + } + MEDIA_ERR_LOG("SwitchAdapter Fail"); + + return ERR_INVALID_INDEX; +} + +int32_t AudioRendererSink::Init(AudioSinkAttr &attr) +{ + attr_ = attr; + struct AudioPort renderPort; + const char *adapterNameCase = "usb"; // Set sound card information + enum AudioPortDirection port = PORT_OUT; // Set port information + char resolvedPath[100] = "/system/lib/libhdi_audio.z.so"; + struct AudioManager *(*getAudioManager)() = nullptr; + + handle_ = dlopen(resolvedPath, 1); + if (handle_ == nullptr) { + MEDIA_ERR_LOG("Open so Fail"); + return ERR_INVALID_HANDLE; + } + getAudioManager = (struct AudioManager* (*)())(dlsym(handle_, "GetAudioManagerFuncs")); + audioManager_ = getAudioManager(); + if (audioManager_ == nullptr) { + return ERR_INVALID_HANDLE; + } + + int32_t ret = 0; + int32_t size = -1; + struct AudioAdapterDescriptor *descs = nullptr; + audioManager_->GetAllAdapters(audioManager_, &descs, &size); + if (size > MAX_AUDIO_ADAPTER_NUM || size == 0 || descs == nullptr || ret < 0) { + MEDIA_ERR_LOG("Get adapters Fail"); + return ERR_NOT_STARTED; + } + + // Get qualified sound card and port + int32_t index = SwitchAdapter(descs, adapterNameCase, port, &renderPort, size); + if (index < 0) { + MEDIA_ERR_LOG("Switch Adapter Fail"); + return ERR_NOT_STARTED; + } + + struct AudioAdapterDescriptor *desc = &descs[index]; + if (audioManager_->LoadAdapter(audioManager_, desc, &audioAdapter_) != 0) { + MEDIA_ERR_LOG("Load Adapter Fail"); + return ERR_NOT_STARTED; + } + if (audioAdapter_ == nullptr) { + MEDIA_ERR_LOG("Load audio device failed"); + return ERR_NOT_STARTED; + } + + // Initialization port information, can fill through mode and other parameters + ret = audioAdapter_->InitAllPorts(audioAdapter_); + if (ret != 0) { + MEDIA_ERR_LOG("InitAllPorts failed"); + return ERR_NOT_STARTED; + } + + struct AudioSampleAttributes param; + InitAttrs(¶m); + param.sampleRate = attr_.sampleRate; + param.channelCount = attr_.channel; + + struct AudioDeviceDescriptor deviceDesc; + deviceDesc.portId = renderPort.portId; + deviceDesc.pins = PIN_OUT_SPEAKER; + deviceDesc.desc = nullptr; + ret = audioAdapter_->CreateRender(audioAdapter_, &deviceDesc, ¶m, &audioRender_); + if (ret != 0 || audioRender_ == nullptr) { + MEDIA_ERR_LOG("AudioDeviceCreateRender failed"); + audioManager_->UnloadAdapter(audioManager_, audioAdapter_); + return ERR_NOT_STARTED; + } + rendererInited_ = true; + +#ifdef DUMPFILE + pfd = fopen(g_audioOutTestFilePath, "wb+"); + if (pfd == nullptr) { + MEDIA_ERR_LOG("Error opening pcm test file!"); + } +#endif // DUMPFILE + + return SUCCESS; +} + +int32_t AudioRendererSink::RenderFrame(char &data, uint64_t len, uint64_t &writeLen) +{ + int32_t ret; + if (audioRender_ == nullptr) { + MEDIA_ERR_LOG("Audio Render Handle is nullptr!"); + return ERR_INVALID_HANDLE; + } + +#ifdef DUMPFILE + size_t writeResult = fwrite((void*)&data, 1, len, pfd); + if (writeResult != len) { + MEDIA_ERR_LOG("Failed to write the file."); + } +#endif // DUMPFILE + + ret = audioRender_->RenderFrame(audioRender_, (void*)&data, len, &writeLen); + if (ret != 0) { + MEDIA_ERR_LOG("RenderFrame failed ret: %{public}x", ret); + return ERR_WRITE_FAILED; + } + + return SUCCESS; +} + +int32_t AudioRendererSink::Start(void) +{ + if (!started_ && audioRender_ != nullptr) { + audioRender_->control.Start((AudioHandle)audioRender_); + started_ = true; + } + return SUCCESS; +} + +int32_t AudioRendererSink::SetVolume(float left, float right) +{ + float volume; + if (audioRender_ == nullptr) { + MEDIA_ERR_LOG("AudioRendererSink::SetVolume failed audioRender_ null"); + return ERR_INVALID_HANDLE; + } + + leftVolume_ = left; + rightVolume_ = right; + if ((leftVolume_ == 0) && (rightVolume_ != 0)) { + volume = rightVolume_; + } else if ((leftVolume_ != 0) && (rightVolume_ == 0)) { + volume = leftVolume_; + } else { + volume = (leftVolume_ + rightVolume_) / HALF_FACTOR; + } + audioRender_->volume.SetVolume(reinterpret_cast(audioRender_), volume); + return SUCCESS; +} + +int32_t AudioRendererSink::GetVolume(float &left, float &right) +{ + left = leftVolume_; + right = rightVolume_; + return SUCCESS; +} + +int32_t AudioRendererSink::Stop(void) +{ + if (started_ && audioRender_ != nullptr) { + audioRender_->control.Stop(reinterpret_cast(audioRender_)); + } + started_ = false; + return SUCCESS; +} + +int32_t AudioRendererSink::Pause(void) +{ + if (started_ && audioRender_ != nullptr) { + audioRender_->control.Pause(reinterpret_cast(audioRender_)); + } + paused_ = true; + return SUCCESS; +} + +int32_t AudioRendererSink::Resume(void) +{ + audioRender_->control.Resume(reinterpret_cast(audioRender_)); + paused_ = false; + return SUCCESS; +} + +int32_t AudioRendererSink::Reset(void) +{ + if (started_ && audioRender_ != nullptr) { + audioRender_->control.Flush(reinterpret_cast(audioRender_)); + } + return SUCCESS; +} + +int32_t AudioRendererSink::Flush(void) +{ + if (started_ && audioRender_ != nullptr) { + audioRender_->control.Flush(reinterpret_cast(audioRender_)); + } + return SUCCESS; +} +} // namespace AudioStandard +} // namespace OHOS + +#ifdef __cplusplus +extern "C" { +#endif + +using namespace OHOS::AudioStandard; + +AudioRendererSink* g_audioRendrSinkInstance = AudioRendererSink::GetInstance(); + +int32_t AudioRendererSinkInit(AudioSinkAttr *attr) +{ + int32_t ret; + + if (g_audioRendrSinkInstance->rendererInited_) + return SUCCESS; + + ret = g_audioRendrSinkInstance->Init(*attr); + return ret; +} + +void AudioRendererSinkDeInit() +{ + if (g_audioRendrSinkInstance->rendererInited_) + g_audioRendrSinkInstance->DeInit(); +} + +int32_t AudioRendererSinkStop() +{ + int32_t ret; + + if (!g_audioRendrSinkInstance->rendererInited_) + return SUCCESS; + + ret = g_audioRendrSinkInstance->Stop(); + return ret; +} + +int32_t AudioRendererSinkStart() +{ + int32_t ret; + + if (!g_audioRendrSinkInstance->rendererInited_) { + MEDIA_ERR_LOG("audioRenderer Not Inited! Init the renderer first\n"); + return ERR_NOT_STARTED; + } + + ret = g_audioRendrSinkInstance->Start(); + return ret; +} + +int32_t AudioRendererRenderFrame(char &data, uint64_t len, uint64_t &writeLen) +{ + int32_t ret; + + if (!g_audioRendrSinkInstance->rendererInited_) { + MEDIA_ERR_LOG("audioRenderer Not Inited! Init the renderer first\n"); + return ERR_NOT_STARTED; + } + + ret = g_audioRendrSinkInstance->RenderFrame(data, len, writeLen); + return ret; +} + +int32_t AudioRendererSinkSetVolume(float left, float right) +{ + int32_t ret; + + if (!g_audioRendrSinkInstance->rendererInited_) { + MEDIA_ERR_LOG("audioRenderer Not Inited! Init the renderer first\n"); + return ERR_NOT_STARTED; + } + + ret = g_audioRendrSinkInstance->SetVolume(left, right); + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/frameworks/innerkitsimpl/common/include/media_errors.h b/frameworks/innerkitsimpl/common/include/audio_errors.h old mode 100755 new mode 100644 similarity index 39% rename from frameworks/innerkitsimpl/common/include/media_errors.h rename to frameworks/innerkitsimpl/common/include/audio_errors.h index 3e4da13ed8..bd076132c6 --- a/frameworks/innerkitsimpl/common/include/media_errors.h +++ b/frameworks/innerkitsimpl/common/include/audio_errors.h @@ -1,104 +1,119 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * 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. - */ - -/** - * @addtogroup MultiMedia_MediaCommon - * @{ - * - * @brief Provides data types and media formats required for recording and playing audio and videos. - * - * - * @since 1.0 - * @version 1.0 - */ - -/** - * @file media_errors.h - * - * @brief Declares the media_errors class to define errors that may occur during media operations. - * - * - * @since 1.0 - * @version 1.0 - */ - -#ifndef MEDIA_ERRORS_H -#define MEDIA_ERRORS_H - -#include - -namespace OHOS { -namespace Media { -constexpr int MODULE_MEDIA = 1; -constexpr int SUBSYS_MEDIA = 30; - -using ErrCode = int32_t; -constexpr int SUBSYSTEM_BIT_NUM = 21; -constexpr int MODULE_BIT_NUM = 16; - -/** - * @brief Generates a start error code with a unique identifier based on specified subsystem and module bit numbers. - * - * @param subsystem Indicates the subsystem bit number. - * @param module Indicates the module bit number. - * @return - * @since 1.0 - * @version 1.0 - */ -constexpr ErrCode ErrCodeOffset(unsigned int subsystem, unsigned int module = 0) -{ - return (subsystem << SUBSYSTEM_BIT_NUM) | (module << MODULE_BIT_NUM); -} - -constexpr int32_t BASE_MEDIA_ERR_OFFSET = ErrCodeOffset(SUBSYS_MEDIA, MODULE_MEDIA); - -/** Invalid data size that has been read */ -const int32_t ERR_INVALID_READ = -1; - -/** Success */ -const int32_t SUCCESS = 0; - -/** Fail */ -const int32_t ERROR = BASE_MEDIA_ERR_OFFSET; - -/** Status error */ -const int32_t ERR_ILLEGAL_STATE = BASE_MEDIA_ERR_OFFSET + 1; - -/** Invalid parameter */ -const int32_t ERR_INVALID_PARAM = BASE_MEDIA_ERR_OFFSET + 2; - -/** Early media preparation */ -const int32_t ERR_EARLY_PREPARE = BASE_MEDIA_ERR_OFFSET + 3; - -/** No media source */ -const int32_t ERR_SOURCE_NOT_SET = BASE_MEDIA_ERR_OFFSET + 4; - -/** Invalid operation */ -const int32_t ERR_INVALID_OPERATION = BASE_MEDIA_ERR_OFFSET + 5; - -/** No idle channel */ -const int32_t ERR_NOFREE_CHANNEL = BASE_MEDIA_ERR_OFFSET + 6; - -/** Buffer reading failed */ -const int32_t ERR_READ_BUFFER = BASE_MEDIA_ERR_OFFSET + 7; - -/** Device not started */ -const int32_t ERR_NOT_STARTED = BASE_MEDIA_ERR_OFFSET + 8; - -/** Unknown error */ -const int32_t ERR_UNKNOWN = BASE_MEDIA_ERR_OFFSET + 200; -} // namespace Media -} // namespace OHOS -#endif // MEDIA_ERRORS_H +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +/** + * @addtogroup MultiMedia_AudioCommon + * @{ + * + * @brief Provides data types and audio formats required for recording and playing and recording audio. + * + * + * @since 1.0 + * @version 1.0 + */ + +/** + * @file audio_errors.h + * + * @brief Declares the audio_errors class to define errors that may occur during audio operations. + * + * + * @since 1.0 + * @version 1.0 + */ + +#ifndef AUDIO_ERRORS_H +#define AUDIO_ERRORS_H + +#include + +namespace OHOS { +namespace AudioStandard { +constexpr int MODULE_AUDIO = 1; +constexpr int SUBSYS_AUDIO = 30; + +using ErrCode = int32_t; +constexpr int SUBSYSTEM_BIT_NUM = 21; +constexpr int MODULE_BIT_NUM = 16; + +constexpr ErrCode ErrCodeOffset(unsigned int subsystem, unsigned int module = 0) +{ + return (subsystem << SUBSYSTEM_BIT_NUM) | (module << MODULE_BIT_NUM); +} + +constexpr int32_t BASE_AUDIO_ERR_OFFSET = -ErrCodeOffset(SUBSYS_AUDIO, MODULE_AUDIO); + +/** Success */ +const int32_t SUCCESS = 0; + +/** Fail */ +const int32_t ERROR = BASE_AUDIO_ERR_OFFSET; + +/** Status error */ +const int32_t ERR_ILLEGAL_STATE = BASE_AUDIO_ERR_OFFSET - 1; + +/** Invalid parameter */ +const int32_t ERR_INVALID_PARAM = BASE_AUDIO_ERR_OFFSET - 2; + +/** Early media preparation */ +const int32_t ERR_EARLY_PREPARE = BASE_AUDIO_ERR_OFFSET - 3; + +/** Invalid operation */ +const int32_t ERR_INVALID_OPERATION = BASE_AUDIO_ERR_OFFSET - 4; + +/** error operation failed */ +const int32_t ERR_OPERATION_FAILED = BASE_AUDIO_ERR_OFFSET - 5; + +/** Buffer reading failed */ +const int32_t ERR_READ_BUFFER = BASE_AUDIO_ERR_OFFSET - 6; + +/** Buffer writing failed */ +const int32_t ERR_WRITE_BUFFER = BASE_AUDIO_ERR_OFFSET - 7; + +/** Device not started */ +const int32_t ERR_NOT_STARTED = BASE_AUDIO_ERR_OFFSET - 8; + +/** Invalid Device handle */ +const int32_t ERR_INVALID_HANDLE = BASE_AUDIO_ERR_OFFSET - 9; + +/** unsupported operation */ +const int32_t ERR_NOT_SUPPORTED = BASE_AUDIO_ERR_OFFSET - 10; + +/** unsupported device */ +const int32_t ERR_DEVICE_NOT_SUPPORTED = BASE_AUDIO_ERR_OFFSET - 11; + +/** write operation failed */ +const int32_t ERR_WRITE_FAILED = BASE_AUDIO_ERR_OFFSET - 12; + +/** read operation failed */ +const int32_t ERR_READ_FAILED = BASE_AUDIO_ERR_OFFSET - 13; + +/** device init failed */ +const int32_t ERR_DEVICE_INIT = BASE_AUDIO_ERR_OFFSET - 14; + +/** Invalid data size that has been read */ +const int32_t ERR_INVALID_READ = BASE_AUDIO_ERR_OFFSET - 15; + +/** Invalid data size that has been written */ +const int32_t ERR_INVALID_WRITE = BASE_AUDIO_ERR_OFFSET - 16; + +/** set invalid index < 0 */ +const int32_t ERR_INVALID_INDEX = BASE_AUDIO_ERR_OFFSET - 17; + +/** Unknown error */ +const int32_t ERR_UNKNOWN = BASE_AUDIO_ERR_OFFSET - 200; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_ERRORS_H diff --git a/frameworks/kitsimpl/audio_manager/src/audio_device_descriptor_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_device_descriptor_napi.cpp old mode 100755 new mode 100644 index 4ef41de62e..2ee0823282 --- a/frameworks/kitsimpl/audio_manager/src/audio_device_descriptor_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_device_descriptor_napi.cpp @@ -14,13 +14,15 @@ */ #include "audio_device_descriptor_napi.h" -#include "audio_svc_manager.h" +#include "audio_system_manager.h" #include "hilog/log.h" -using namespace OHOS; +using namespace std; using OHOS::HiviewDFX::HiLog; using OHOS::HiviewDFX::HiLogLabel; +namespace OHOS { +namespace AudioStandard { napi_ref AudioDeviceDescriptorNapi::sConstructor_ = nullptr; sptr AudioDeviceDescriptorNapi::sAudioDescriptor_ = nullptr; @@ -42,9 +44,9 @@ AudioDeviceDescriptorNapi::~AudioDeviceDescriptorNapi() void AudioDeviceDescriptorNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint) { - HiLog::Debug(LABEL, "Destructor() is called!"); if (nativeObject != nullptr) { - reinterpret_cast(nativeObject)->~AudioDeviceDescriptorNapi(); + auto obj = static_cast(nativeObject); + delete obj; } } @@ -52,33 +54,28 @@ static AudioDeviceDescriptorNapi::DeviceType GetJSDeviceType(AudioDeviceDescript { AudioDeviceDescriptorNapi::DeviceType result; - HiLog::Debug(LABEL, "GetJSDeviceType() is called!, %{public}d", deviceType); switch (deviceType) { case AudioDeviceDescriptor::SPEAKER: result = AudioDeviceDescriptorNapi::SPEAKER; break; - case AudioDeviceDescriptor::WIRED_HEADSET: result = AudioDeviceDescriptorNapi::WIRED_HEADSET; break; - case AudioDeviceDescriptor::BLUETOOTH_SCO: result = AudioDeviceDescriptorNapi::BLUETOOTH_SCO; break; - case AudioDeviceDescriptor::BLUETOOTH_A2DP: result = AudioDeviceDescriptorNapi::BLUETOOTH_A2DP; break; - case AudioDeviceDescriptor::MIC: result = AudioDeviceDescriptorNapi::MIC; break; - default: result = AudioDeviceDescriptorNapi::INVALID; HiLog::Error(LABEL, "Unknown device type!"); break; } + return result; } @@ -86,21 +83,19 @@ static AudioDeviceDescriptorNapi::DeviceRole GetJSDeviceRole(AudioDeviceDescript { AudioDeviceDescriptorNapi::DeviceRole result; - HiLog::Debug(LABEL, "GetJSDeviceRole() is called!, %{public}d", deviceRole); switch (deviceRole) { case AudioDeviceDescriptor::INPUT_DEVICE: result = AudioDeviceDescriptorNapi::INPUT_DEVICE; break; - case AudioDeviceDescriptor::OUTPUT_DEVICE: result = AudioDeviceDescriptorNapi::OUTPUT_DEVICE; break; - default: result = AudioDeviceDescriptorNapi::INPUT_DEVICE; HiLog::Error(LABEL, "Unknown device role!"); break; } + return result; } @@ -114,7 +109,6 @@ napi_value AudioDeviceDescriptorNapi::Init(napi_env env, napi_value exports) }; const int32_t refCount = 1; - HiLog::Debug(LABEL, "AudioDeviceDescriptorNapi::Init is called!"); status = napi_define_class(env, AUDIO_DEVICE_DESCRIPTOR_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr, sizeof(audio_dev_desc_properties) / sizeof(audio_dev_desc_properties[0]), audio_dev_desc_properties, &constructor); @@ -124,12 +118,12 @@ napi_value AudioDeviceDescriptorNapi::Init(napi_env env, napi_value exports) status = napi_set_named_property(env, exports, AUDIO_DEVICE_DESCRIPTOR_NAPI_CLASS_NAME.c_str(), constructor); if (status == napi_ok) { - HiLog::Info(LABEL, "All props and functions are configured.."); return exports; } } } HiLog::Error(LABEL, "Failure in AudioDeviceDescriptorNapi::Init()"); + return exports; } @@ -139,72 +133,71 @@ napi_value AudioDeviceDescriptorNapi::Construct(napi_env env, napi_callback_info napi_value jsThis = nullptr; size_t argCount = 0; - HiLog::Debug(LABEL, "AudioDeviceDescriptorNapi::Construct() is called!"); status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr); if (status == napi_ok) { - AudioDeviceDescriptorNapi* obj = new AudioDeviceDescriptorNapi(); + unique_ptr obj = make_unique(); if (obj != nullptr) { obj->env_ = env; obj->audioDescriptor_ = sAudioDescriptor_; - status = napi_wrap(env, jsThis, reinterpret_cast(obj), + status = napi_wrap(env, jsThis, static_cast(obj.get()), AudioDeviceDescriptorNapi::Destructor, nullptr, &(obj->wrapper_)); if (status == napi_ok) { - HiLog::Debug(LABEL, "wrapping is succesful in AudioDeviceDescriptorNapi::Construct()"); + obj.release(); return jsThis; } } } HiLog::Error(LABEL, "Failed in AudioDeviceDescriptorNapi::Construct()!"); napi_get_undefined(env, &jsThis); + return jsThis; } napi_value AudioDeviceDescriptorNapi::CreateAudioDeviceDescriptorWrapper(napi_env env, - sptr audioDeviceDescriptor) + sptr deviceDescriptor) { napi_status status; napi_value result = nullptr; napi_value constructor; - HiLog::Debug(LABEL, "CreateAudioDeviceDescriptorWrapper() is called!"); - status = napi_get_reference_value(env, sConstructor_, &constructor); - if (status == napi_ok) { - sAudioDescriptor_ = audioDeviceDescriptor; - status = napi_new_instance(env, constructor, 0, nullptr, &result); - sAudioDescriptor_ = nullptr; + if (deviceDescriptor != nullptr) { + status = napi_get_reference_value(env, sConstructor_, &constructor); if (status == napi_ok) { - return result; + sAudioDescriptor_ = deviceDescriptor; + status = napi_new_instance(env, constructor, 0, nullptr, &result); + sAudioDescriptor_ = nullptr; + if (status == napi_ok) { + return result; + } } + HiLog::Error(LABEL, "Failed in CreateAudioDeviceDescriptorWrapper, %{public}d", status); + } else { + HiLog::Error(LABEL, "sptr is null"); } - HiLog::Error(LABEL, "Failed in AudioDeviceDescriptorNapi::CreateAudioDeviceDescriptorWrapper!, %{public}d", status); napi_get_undefined(env, &result); + return result; } napi_value AudioDeviceDescriptorNapi::GetDeviceRole(napi_env env, napi_callback_info info) { napi_status status; - AudioDeviceDescriptorNapi* audioDeviceDescriptor = nullptr; + AudioDeviceDescriptorNapi* deviceDescriptor = nullptr; size_t argc = 0; napi_value thisVar = nullptr; AudioDeviceDescriptor::DeviceRole deviceRole; napi_value jsResult = nullptr; - HiLog::Debug(LABEL, "GetDeviceRole() is called!"); napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); NAPI_ASSERT(env, argc == 0, "Invalid number of arguments"); - status = napi_unwrap(env, thisVar, (void **)&audioDeviceDescriptor); + status = napi_unwrap(env, thisVar, (void **)&deviceDescriptor); if (status == napi_ok) { - HiLog::Debug(LABEL, "Unwrapping is succesful in GetDeviceRole()!"); - deviceRole = audioDeviceDescriptor->audioDescriptor_->deviceRole_; - HiLog::Debug(LABEL, "deviceRole: %{public}d", deviceRole); + deviceRole = deviceDescriptor->audioDescriptor_->deviceRole_; status = napi_create_int32(env, GetJSDeviceRole(deviceRole), &jsResult); if (status == napi_ok) { - HiLog::Debug(LABEL, "returning device role!"); return jsResult; } } - HiLog::Debug(LABEL, "returning undefine from GetDeviceRole()!"); napi_get_undefined(env, &jsResult); return jsResult; } @@ -216,23 +209,20 @@ napi_value AudioDeviceDescriptorNapi::GetDeviceType(napi_env env, napi_callback_ napi_value thisVar = nullptr; AudioDeviceDescriptor::DeviceType deviceType; napi_value jsResult = nullptr; - AudioDeviceDescriptorNapi* audioDeviceDescriptor = nullptr; + AudioDeviceDescriptorNapi* deviceDescriptor = nullptr; - HiLog::Debug(LABEL, "GetDeviceType() is called!"); napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr); NAPI_ASSERT(env, argc == 0, "Invalid number of arguments"); - status = napi_unwrap(env, thisVar, (void **)&audioDeviceDescriptor); + status = napi_unwrap(env, thisVar, (void **)&deviceDescriptor); if (status == napi_ok) { - HiLog::Debug(LABEL, "Unwrapping is succesful in GetDeviceType()!"); - deviceType = audioDeviceDescriptor->audioDescriptor_->deviceType_; - HiLog::Debug(LABEL, "deviceType: %{public}d", deviceType); + deviceType = deviceDescriptor->audioDescriptor_->deviceType_; status = napi_create_int32(env, GetJSDeviceType(deviceType), &jsResult); if (status == napi_ok) { - HiLog::Debug(LABEL, "returning device type!"); return jsResult; } } - HiLog::Debug(LABEL, "returning undefined from GetDeviceType()!"); napi_get_undefined(env, &jsResult); return jsResult; } +} // namespace AudioStandard +} // namespace OHOS diff --git a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp old mode 100755 new mode 100644 index 241b359cec..0594107853 --- a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp @@ -17,15 +17,18 @@ #include "audio_device_descriptor_napi.h" #include "hilog/log.h" -using namespace OHOS; +using namespace std; using OHOS::HiviewDFX::HiLog; using OHOS::HiviewDFX::HiLogLabel; +namespace OHOS { +namespace AudioStandard { napi_ref AudioManagerNapi::sConstructor_ = nullptr; napi_ref AudioManagerNapi::audioVolumeTypeRef_ = nullptr; napi_ref AudioManagerNapi::deviceFlagRef_ = nullptr; napi_ref AudioManagerNapi::deviceRoleRef_ = nullptr; napi_ref AudioManagerNapi::deviceTypeRef_ = nullptr; +napi_ref AudioManagerNapi::audioRingModeRef_ = nullptr; #define GET_PARAMS(env, info, num) \ size_t argc = num; \ @@ -40,11 +43,20 @@ struct AudioManagerAsyncContext { napi_deferred deferred; napi_ref callbackRef = nullptr; int32_t volType; - int32_t volLevel; + int32_t deviceType; + int32_t ringMode; int32_t deviceFlag; - int status; + int32_t intValue; + int32_t status; + bool isMute; + bool isActive; + bool isTrue; + double volLevel; + double doubleValue; + string key; + string valueStr; AudioManagerNapi* objectInfo; - std::vector> deviceDescriptors; + vector> deviceDescriptors; }; namespace { @@ -70,65 +82,94 @@ AudioManagerNapi::~AudioManagerNapi() void AudioManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint) { if (nativeObject != nullptr) { - reinterpret_cast(nativeObject)->~AudioManagerNapi(); + auto obj = static_cast(nativeObject); + delete obj; } } -static AudioSvcManager::AudioVolumeType GetNativeAudioVolumeType(int32_t volumeType) +static AudioSystemManager::AudioVolumeType GetNativeAudioVolumeType(int32_t volumeType) { - AudioSvcManager::AudioVolumeType result; + AudioSystemManager::AudioVolumeType result = AudioSystemManager::STREAM_MUSIC; switch (volumeType) { case AudioManagerNapi::MEDIA: - result = AudioSvcManager::STREAM_MUSIC; + result = AudioSystemManager::STREAM_MUSIC; break; - case AudioManagerNapi::RINGTONE: - result = AudioSvcManager::STREAM_RING; + result = AudioSystemManager::STREAM_RING; + break; + default: + result = AudioSystemManager::STREAM_MUSIC; + HiLog::Error(LABEL, "Unknown volume type, Set it to default MEDIA!"); break; + } + + return result; +} + +static AudioDeviceDescriptor::DeviceType GetNativeDeviceType(int32_t deviceType) +{ + AudioDeviceDescriptor::DeviceType result = AudioDeviceDescriptor::DEVICE_TYPE_NONE; + switch (deviceType) { + case AudioDeviceDescriptorNapi::SPEAKER: + result = AudioDeviceDescriptor::SPEAKER; + break; + case AudioDeviceDescriptorNapi::WIRED_HEADSET: + result = AudioDeviceDescriptor::WIRED_HEADSET; + break; + case AudioDeviceDescriptorNapi::BLUETOOTH_SCO: + result = AudioDeviceDescriptor::BLUETOOTH_SCO; + break; + case AudioDeviceDescriptorNapi::BLUETOOTH_A2DP: + result = AudioDeviceDescriptor::BLUETOOTH_A2DP; + break; + case AudioDeviceDescriptorNapi::MIC: + result = AudioDeviceDescriptor::MIC; + break; + case AudioDeviceDescriptorNapi::INVALID: default: - result = AudioSvcManager::STREAM_MUSIC; - HiLog::Error(LABEL, "Unknown volume type!, %{public}d", volumeType); + result = AudioDeviceDescriptor::DEVICE_TYPE_NONE; + HiLog::Error(LABEL, "Unknown device type!"); break; } + return result; } static AudioDeviceDescriptor::DeviceFlag GetNativeDeviceFlag(int32_t deviceFlag) { - AudioDeviceDescriptor::DeviceFlag result; + AudioDeviceDescriptor::DeviceFlag result = AudioDeviceDescriptor::ALL_DEVICES_FLAG; switch (deviceFlag) { case AudioManagerNapi::OUTPUT_DEVICES_FLAG: result = AudioDeviceDescriptor::OUTPUT_DEVICES_FLAG; break; - case AudioManagerNapi::INPUT_DEVICES_FLAG: result = AudioDeviceDescriptor::INPUT_DEVICES_FLAG; break; - case AudioManagerNapi::ALL_DEVICES_FLAG: result = AudioDeviceDescriptor::ALL_DEVICES_FLAG; break; - default: result = AudioDeviceDescriptor::ALL_DEVICES_FLAG; HiLog::Error(LABEL, "Unknown device flag!, %{public}d", deviceFlag); break; } + return result; } -napi_status AudioManagerNapi::AddNamedProperty(napi_env env, napi_value object, const char *name, int32_t enumValue) +napi_status AudioManagerNapi::AddNamedProperty(napi_env env, napi_value object, const string name, int32_t enumValue) { napi_status status; napi_value enumNapiValue; status = napi_create_int32(env, enumValue, &enumNapiValue); if (status == napi_ok) { - status = napi_set_named_property(env, object, name, enumNapiValue); + status = napi_set_named_property(env, object, name.c_str(), enumNapiValue); } + return status; } @@ -137,23 +178,39 @@ napi_value AudioManagerNapi::CreateAudioVolumeTypeObject(napi_env env) napi_value result = nullptr; napi_status status; int32_t refCount = 1; + string propName; - HiLog::Debug(LABEL, "CreateAudioVolumeTypeObject is called!"); status = napi_create_object(env, &result); if (status == napi_ok) { - status = AddNamedProperty(env, result, "MEDIA", AudioManagerNapi::MEDIA); + for (int i = AudioManagerNapi::MEDIA; i <= AudioManagerNapi::RINGTONE; i++) { + switch (i) { + case AudioManagerNapi::MEDIA: + propName = "MEDIA"; + break; + case AudioManagerNapi::RINGTONE: + propName = "RINGTONE"; + break; + default: + HiLog::Error(LABEL, "Invalid prop!"); + continue; + } + status = AddNamedProperty(env, result, propName, i); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to add named prop!"); + break; + } + propName.clear(); + } if (status == napi_ok) { - status = AddNamedProperty(env, result, "RINGTONE", AudioManagerNapi::RINGTONE); + status = napi_create_reference(env, result, refCount, &audioVolumeTypeRef_); if (status == napi_ok) { - status = napi_create_reference(env, result, refCount, &audioVolumeTypeRef_); - if (status == napi_ok) { - return result; - } + return result; } } } HiLog::Error(LABEL, "CreateAudioVolumeTypeObject is Failed!"); napi_get_undefined(env, &result); + return result; } @@ -162,26 +219,42 @@ napi_value AudioManagerNapi::CreateDeviceFlagObject(napi_env env) napi_value result = nullptr; napi_status status; int32_t refCount = 1; + string propName; - HiLog::Debug(LABEL, "CreateDeviceFlagObject is called!"); status = napi_create_object(env, &result); if (status == napi_ok) { - status = AddNamedProperty(env, result, "OUTPUT_DEVICES_FLAG", AudioManagerNapi::OUTPUT_DEVICES_FLAG); + for (int i = AudioManagerNapi::OUTPUT_DEVICES_FLAG; i <= AudioManagerNapi::ALL_DEVICES_FLAG; i++) { + switch (i) { + case AudioManagerNapi::OUTPUT_DEVICES_FLAG: + propName = "OUTPUT_DEVICES_FLAG"; + break; + case AudioManagerNapi::INPUT_DEVICES_FLAG: + propName = "INPUT_DEVICES_FLAG"; + break; + case AudioManagerNapi::ALL_DEVICES_FLAG: + propName = "ALL_DEVICES_FLAG"; + break; + default: + HiLog::Error(LABEL, "Invalid prop!"); + continue; + } + status = AddNamedProperty(env, result, propName, i); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to add named prop!"); + break; + } + propName.clear(); + } if (status == napi_ok) { - status = AddNamedProperty(env, result, "INPUT_DEVICES_FLAG", AudioManagerNapi::INPUT_DEVICES_FLAG); + status = napi_create_reference(env, result, refCount, &deviceFlagRef_); if (status == napi_ok) { - status = AddNamedProperty(env, result, "ALL_DEVICES_FLAG", AudioManagerNapi::ALL_DEVICES_FLAG); - if (status == napi_ok) { - status = napi_create_reference(env, result, refCount, &deviceFlagRef_); - if (status == napi_ok) { - return result; - } - } + return result; } } } HiLog::Error(LABEL, "CreateDeviceFlagObject is Failed!"); napi_get_undefined(env, &result); + return result; } @@ -190,23 +263,39 @@ napi_value AudioManagerNapi::CreateDeviceRoleObject(napi_env env) napi_value result = nullptr; napi_status status; int32_t refCount = 1; + string propName; - HiLog::Debug(LABEL, "CreateDeviceRoleObject is called!"); status = napi_create_object(env, &result); if (status == napi_ok) { - status = AddNamedProperty(env, result, "INPUT_DEVICE", AudioDeviceDescriptorNapi::INPUT_DEVICE); + for (int i = AudioDeviceDescriptorNapi::INPUT_DEVICE; i <= AudioDeviceDescriptorNapi::OUTPUT_DEVICE; i++) { + switch (i) { + case AudioDeviceDescriptorNapi::INPUT_DEVICE: + propName = "INPUT_DEVICE"; + break; + case AudioDeviceDescriptorNapi::OUTPUT_DEVICE: + propName = "OUTPUT_DEVICE"; + break; + default: + HiLog::Error(LABEL, "Invalid prop!"); + continue; + } + status = AddNamedProperty(env, result, propName, i); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to add named prop!"); + break; + } + propName.clear(); + } if (status == napi_ok) { - status = AddNamedProperty(env, result, "OUTPUT_DEVICE", AudioDeviceDescriptorNapi::OUTPUT_DEVICE); + status = napi_create_reference(env, result, refCount, &deviceRoleRef_); if (status == napi_ok) { - status = napi_create_reference(env, result, refCount, &deviceRoleRef_); - if (status == napi_ok) { - return result; - } + return result; } } } HiLog::Error(LABEL, "CreateDeviceRoleObject is Failed!"); napi_get_undefined(env, &result); + return result; } @@ -215,9 +304,8 @@ napi_value AudioManagerNapi::CreateDeviceTypeObject(napi_env env) napi_value result = nullptr; napi_status status; int32_t refCount = 1; - const char *propName = nullptr; + string propName; - HiLog::Debug(LABEL, "CreateDeviceTypeObject is called!"); status = napi_create_object(env, &result); if (status == napi_ok) { for (int i = AudioDeviceDescriptorNapi::INVALID; i <= AudioDeviceDescriptorNapi::MIC; i++) { @@ -225,27 +313,21 @@ napi_value AudioManagerNapi::CreateDeviceTypeObject(napi_env env) case AudioDeviceDescriptorNapi::INVALID: propName = "INVALID"; break; - case AudioDeviceDescriptorNapi::SPEAKER: propName = "SPEAKER"; break; - case AudioDeviceDescriptorNapi::WIRED_HEADSET: propName = "WIRED_HEADSET"; break; - case AudioDeviceDescriptorNapi::BLUETOOTH_SCO: propName = "BLUETOOTH_SCO"; break; - case AudioDeviceDescriptorNapi::BLUETOOTH_A2DP: propName = "BLUETOOTH_A2DP"; break; - case AudioDeviceDescriptorNapi::MIC: propName = "MIC"; break; - default: HiLog::Error(LABEL, "Invalid prop!"); continue; @@ -255,7 +337,7 @@ napi_value AudioManagerNapi::CreateDeviceTypeObject(napi_env env) HiLog::Error(LABEL, "Failed to add named prop!"); break; } - propName = nullptr; + propName.clear(); } if (status == napi_ok) { status = napi_create_reference(env, result, refCount, &deviceTypeRef_); @@ -266,6 +348,51 @@ napi_value AudioManagerNapi::CreateDeviceTypeObject(napi_env env) } HiLog::Error(LABEL, "CreateDeviceTypeObject is Failed!"); napi_get_undefined(env, &result); + + return result; +} + +napi_value AudioManagerNapi::CreateAudioRingModeObject(napi_env env) +{ + napi_value result = nullptr; + napi_status status; + int32_t refCount = 1; + string propName; + + status = napi_create_object(env, &result); + if (status == napi_ok) { + for (int i = RINGER_MODE_NORMAL; i <= RINGER_MODE_VIBRATE; i++) { + switch (i) { + case RINGER_MODE_NORMAL: + propName = "RINGER_MODE_NORMAL"; + break; + case RINGER_MODE_SILENT: + propName = "RINGER_MODE_SILENT"; + break; + case RINGER_MODE_VIBRATE: + propName = "RINGER_MODE_VIBRATE"; + break; + default: + HiLog::Error(LABEL, "Invalid prop!"); + continue; + } + status = AddNamedProperty(env, result, propName, i); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to add named prop!"); + break; + } + propName.clear(); + } + if (status == napi_ok) { + status = napi_create_reference(env, result, refCount, &audioRingModeRef_); + if (status == napi_ok) { + return result; + } + } + } + HiLog::Error(LABEL, "CreateAudioRingModeObject is Failed!"); + napi_get_undefined(env, &result); + return result; } @@ -276,13 +403,23 @@ napi_value AudioManagerNapi::Init(napi_env env, napi_value exports) napi_value result = nullptr; const int32_t refCount = 1; - HiLog::Debug(LABEL, "AudioManagerNapi::Init() is called!"); napi_property_descriptor audio_svc_mngr_properties[] = { DECLARE_NAPI_FUNCTION("setVolume", SetVolume), DECLARE_NAPI_FUNCTION("getVolume", GetVolume), DECLARE_NAPI_FUNCTION("getMaxVolume", GetMaxVolume), DECLARE_NAPI_FUNCTION("getMinVolume", GetMinVolume), - DECLARE_NAPI_FUNCTION("getDevices", GetDevices) + DECLARE_NAPI_FUNCTION("getDevices", GetDevices), + DECLARE_NAPI_FUNCTION("setStreamMute", SetStreamMute), + DECLARE_NAPI_FUNCTION("isStreamMute", IsStreamMute), + DECLARE_NAPI_FUNCTION("isStreamActive", IsStreamActive), + DECLARE_NAPI_FUNCTION("setRingerMode", SetRingerMode), + DECLARE_NAPI_FUNCTION("getRingerMode", GetRingerMode), + DECLARE_NAPI_FUNCTION("setDeviceActive", SetDeviceActive), + DECLARE_NAPI_FUNCTION("isDeviceActive", IsDeviceActive), + DECLARE_NAPI_FUNCTION("setAudioParameter", SetAudioParameter), + DECLARE_NAPI_FUNCTION("getAudioParameter", GetAudioParameter), + DECLARE_NAPI_FUNCTION("setMicrophoneMute", SetMicrophoneMute), + DECLARE_NAPI_FUNCTION("isMicrophoneMute", IsMicrophoneMute) }; napi_property_descriptor static_prop[] = { @@ -290,7 +427,8 @@ napi_value AudioManagerNapi::Init(napi_env env, napi_value exports) DECLARE_NAPI_PROPERTY("AudioVolumeType", CreateAudioVolumeTypeObject(env)), DECLARE_NAPI_PROPERTY("DeviceFlag", CreateDeviceFlagObject(env)), DECLARE_NAPI_PROPERTY("DeviceRole", CreateDeviceRoleObject(env)), - DECLARE_NAPI_PROPERTY("DeviceType", CreateDeviceTypeObject(env)) + DECLARE_NAPI_PROPERTY("DeviceType", CreateDeviceTypeObject(env)), + DECLARE_NAPI_PROPERTY("AudioRingMode", CreateAudioRingModeObject(env)) }; status = napi_define_class(env, AUDIO_MNGR_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr, @@ -304,7 +442,6 @@ napi_value AudioManagerNapi::Init(napi_env env, napi_value exports) status = napi_define_properties(env, exports, sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop); if (status == napi_ok) { - HiLog::Info(LABEL, "All props and functions are configured.."); return exports; } } @@ -312,6 +449,7 @@ napi_value AudioManagerNapi::Init(napi_env env, napi_value exports) } HiLog::Error(LABEL, "Failure in AudioManagerNapi::Init()"); napi_get_undefined(env, &result); + return result; } @@ -323,22 +461,23 @@ napi_value AudioManagerNapi::Construct(napi_env env, napi_callback_info info) napi_value result = nullptr; size_t argCount = 0; - HiLog::Debug(LABEL, "AudioManagerNapi::Construct() is called!"); status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr); if (status == napi_ok) { - AudioManagerNapi* obj = new AudioManagerNapi(); + unique_ptr obj = make_unique(); if (obj != nullptr) { obj->env_ = env; - obj->audioMngr_ = AudioSvcManager::GetInstance(); - status = napi_wrap(env, jsThis, reinterpret_cast(obj), + obj->audioMngr_ = AudioSystemManager::GetInstance(); + status = napi_wrap(env, jsThis, static_cast(obj.get()), AudioManagerNapi::Destructor, nullptr, &(obj->wrapper_)); if (status == napi_ok) { + obj.release(); return jsThis; } } } HiLog::Error(LABEL, "Failed in AudioManagerNapi::Construct()!"); napi_get_undefined(env, &result); + return result; } @@ -348,7 +487,6 @@ napi_value AudioManagerNapi::CreateAudioManagerWrapper(napi_env env) napi_value result = nullptr; napi_value constructor; - HiLog::Debug(LABEL, "AudioManagerNapi::CreateAudioManagerWrapper() is called!"); status = napi_get_reference_value(env, sConstructor_, &constructor); if (status == napi_ok) { status = napi_new_instance(env, constructor, 0, nullptr, &result); @@ -358,6 +496,7 @@ napi_value AudioManagerNapi::CreateAudioManagerWrapper(napi_env env) } HiLog::Error(LABEL, "Failed in AudioManagerNapi::CreateaudioMngrWrapper!"); napi_get_undefined(env, &result); + return result; } @@ -366,25 +505,60 @@ napi_value AudioManagerNapi::GetAudioManager(napi_env env, napi_callback_info in napi_status status; size_t argCount = 0; - HiLog::Debug(LABEL, "AudioManagerNapi::GetAudioManager() is called!"); status = napi_get_cb_info(env, info, &argCount, nullptr, nullptr, nullptr); if (status != napi_ok || argCount != 0) { HiLog::Error(LABEL, "Invalid arguments!"); return nullptr; } + return AudioManagerNapi::CreateAudioManagerWrapper(env); } -static void SetVolumeAsyncCallbackComplete(napi_env env, napi_status status, void* data) +// Function to read string argument from napi_value +static string GetStringArgument(napi_env env, napi_value value) +{ + napi_status status; + string strValue = ""; + size_t bufLength = 0; + char *buffer = nullptr; + + status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength); + if (status == napi_ok && bufLength > 0) { + buffer = (char *) malloc((bufLength + 1) * sizeof(char)); + if (buffer != nullptr) { + status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength); + if (status == napi_ok) { + strValue = buffer; + } + free(buffer); + buffer = nullptr; + } + } + + return strValue; +} + +static void CommonCallbackRoutine(napi_env env, AudioManagerAsyncContext* &asyncContext, const napi_value &valueParam) { - AudioManagerAsyncContext* asyncContext = (AudioManagerAsyncContext*) data; napi_value result[ARGS_TWO] = {0}; napi_value retVal; - napi_get_undefined(env, &result[PARAM0]); - napi_get_undefined(env, &result[PARAM1]); + + if (!asyncContext->status) { + napi_get_undefined(env, &result[PARAM0]); + result[PARAM1] = valueParam; + } else { + napi_value message = nullptr; + napi_create_string_utf8(env, "Error, Operation not supported or Failed", NAPI_AUTO_LENGTH, &message); + napi_create_error(env, nullptr, message, &result[PARAM0]); + napi_get_undefined(env, &result[PARAM1]); + } if (asyncContext->deferred) { - napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]); + if (!asyncContext->status) { + napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]); + } else { + napi_reject_deferred(env, asyncContext->deferred, result[PARAM0]); + } } else { napi_value callback = nullptr; napi_get_reference_value(env, asyncContext->callbackRef, &callback); @@ -392,35 +566,108 @@ static void SetVolumeAsyncCallbackComplete(napi_env env, napi_status status, voi napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); + delete asyncContext; } -napi_value AudioManagerNapi::SetVolume(napi_env env, napi_callback_info info) +static void SetFunctionAsyncCallbackComplete(napi_env env, napi_status status, void* data) +{ + auto asyncContext = static_cast(data); + napi_value valueParam = nullptr; + + if (asyncContext != nullptr) { + if (!asyncContext->status) { + napi_get_undefined(env, &valueParam); + } + CommonCallbackRoutine(env, asyncContext, valueParam); + } else { + HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); + } +} + +static void IsTrueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +{ + auto asyncContext = static_cast(data); + napi_value valueParam = nullptr; + + if (asyncContext != nullptr) { + if (!asyncContext->status) { + napi_get_boolean(env, asyncContext->isTrue, &valueParam); + } + CommonCallbackRoutine(env, asyncContext, valueParam); + } else { + HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); + } +} + +static void GetDoubleValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +{ + auto asyncContext = static_cast(data); + napi_value valueParam = nullptr; + + if (asyncContext != nullptr) { + if (!asyncContext->status) { + napi_create_double(env, asyncContext->doubleValue, &valueParam); + } + CommonCallbackRoutine(env, asyncContext, valueParam); + } else { + HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); + } +} + +static void GetStringValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +{ + auto asyncContext = static_cast(data); + napi_value valueParam = nullptr; + + if (asyncContext != nullptr) { + if (!asyncContext->status) { + napi_create_string_utf8(env, asyncContext->valueStr.c_str(), NAPI_AUTO_LENGTH, &valueParam); + } + CommonCallbackRoutine(env, asyncContext, valueParam); + } else { + HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); + } +} + +static void GetIntValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +{ + auto asyncContext = static_cast(data); + napi_value valueParam = nullptr; + + if (asyncContext != nullptr) { + if (!asyncContext->status) { + napi_create_int32(env, asyncContext->intValue, &valueParam); + } + CommonCallbackRoutine(env, asyncContext, valueParam); + } else { + HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); + } +} + +napi_value AudioManagerNapi::SetMicrophoneMute(napi_env env, napi_callback_info info) { napi_status status; const int32_t refCount = 1; napi_value result = nullptr; - GET_PARAMS(env, info, ARGS_THREE); - NAPI_ASSERT(env, argc >= ARGS_TWO, "requires 2 parameters minimum"); + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); - HiLog::Debug(LABEL, "AudioManagerNapi::SetVolume() is called!"); - AudioManagerAsyncContext* asyncContext = new AudioManagerAsyncContext(); status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); if (status == napi_ok && asyncContext->objectInfo != nullptr) { for (size_t i = PARAM0; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); - if (i == PARAM0 && valueType == napi_number) { - napi_get_value_int32(env, argv[i], &asyncContext->volType); - } else if (i == PARAM1 && valueType == napi_number) { - napi_get_value_int32(env, argv[i], &asyncContext->volLevel); - } else if (i == PARAM2 && valueType == napi_function) { + if (i == PARAM0 && valueType == napi_boolean) { + napi_get_value_bool(env, argv[i], &asyncContext->isMute); + } else if (i == PARAM1 && valueType == napi_function) { napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; } else { - delete asyncContext; NAPI_ASSERT(env, false, "type mismatch"); } } @@ -432,74 +679,50 @@ napi_value AudioManagerNapi::SetVolume(napi_env env, napi_callback_info info) } napi_value resource = nullptr; - napi_create_string_utf8(env, "SetVolume", NAPI_AUTO_LENGTH, &resource); + napi_create_string_utf8(env, "SetMicrophoneMute", NAPI_AUTO_LENGTH, &resource); status = napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { - AudioManagerAsyncContext* context = (AudioManagerAsyncContext*) data; - context->objectInfo->audioMngr_->SetVolume(GetNativeAudioVolumeType(context->volType), - context->volLevel); - context->status = 0; + auto context = static_cast(data); + context->status = context->objectInfo->audioMngr_->SetMicrophoneMute(context->isMute); }, - SetVolumeAsyncCallbackComplete, (void*)asyncContext, &asyncContext->work); + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { - delete asyncContext; result = nullptr; } else { - napi_queue_async_work(env, asyncContext->work); + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } } - } else { - delete asyncContext; } - return result; -} - -static void GetVolumeAsyncCallbackComplete(napi_env env, napi_status status, void* data) -{ - AudioManagerAsyncContext* asyncContext = (AudioManagerAsyncContext*) data; - napi_value result[ARGS_TWO] = {0}; - napi_value retVal; - - napi_get_undefined(env, &result[PARAM0]); - napi_create_int32(env, asyncContext->volLevel, &result[PARAM1]); - if (asyncContext->deferred) { - napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]); - } else { - napi_value callback = nullptr; - napi_get_reference_value(env, asyncContext->callbackRef, &callback); - napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal); - napi_delete_reference(env, asyncContext->callbackRef); - } - napi_delete_async_work(env, asyncContext->work); - delete asyncContext; + return result; } -napi_value AudioManagerNapi::GetVolume(napi_env env, napi_callback_info info) +napi_value AudioManagerNapi::IsMicrophoneMute(napi_env env, napi_callback_info info) { napi_status status; const int32_t refCount = 1; napi_value result = nullptr; - GET_PARAMS(env, info, ARGS_TWO); - NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameters minimum"); + GET_PARAMS(env, info, ARGS_ONE); + + unique_ptr asyncContext = make_unique(); - HiLog::Debug(LABEL, "AudioManagerNapi::GetVolume() is called!"); - AudioManagerAsyncContext* asyncContext = new AudioManagerAsyncContext(); status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); if (status == napi_ok && asyncContext->objectInfo != nullptr) { for (size_t i = PARAM0; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); - if (i == PARAM0 && valueType == napi_number) { - napi_get_value_int32(env, argv[i], &asyncContext->volType); - } else if (i == PARAM1 && valueType == napi_function) { + if (i == PARAM0 && valueType == napi_function) { napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; } else { - delete asyncContext; NAPI_ASSERT(env, false, "type mismatch"); } } @@ -511,61 +734,42 @@ napi_value AudioManagerNapi::GetVolume(napi_env env, napi_callback_info info) } napi_value resource = nullptr; - napi_create_string_utf8(env, "GetVolume", NAPI_AUTO_LENGTH, &resource); + napi_create_string_utf8(env, "IsMicrophoneMute", NAPI_AUTO_LENGTH, &resource); status = napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { - AudioManagerAsyncContext* context = (AudioManagerAsyncContext*) data; - context->volLevel = - context->objectInfo->audioMngr_->GetVolume(GetNativeAudioVolumeType(context->volType)); - context->status = 0; + auto context = static_cast(data); + context->isMute = context->objectInfo->audioMngr_->IsMicrophoneMute(); + context->isTrue = context->isMute; }, - GetVolumeAsyncCallbackComplete, (void*)asyncContext, &asyncContext->work); + IsTrueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { - delete asyncContext; result = nullptr; } else { - napi_queue_async_work(env, asyncContext->work); + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } } - } else { - delete asyncContext; } - return result; -} -static void GetMaxVolumeAsyncCallbackComplete(napi_env env, napi_status status, void* data) -{ - AudioManagerAsyncContext* asyncContext = (AudioManagerAsyncContext*) data; - napi_value result[ARGS_TWO] = {0}; - napi_value retVal; - - napi_get_undefined(env, &result[PARAM0]); - napi_create_int32(env, asyncContext->volLevel, &result[PARAM1]); - - if (asyncContext->deferred) { - napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]); - } else { - napi_value callback = nullptr; - napi_get_reference_value(env, asyncContext->callbackRef, &callback); - napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal); - napi_delete_reference(env, asyncContext->callbackRef); - } - napi_delete_async_work(env, asyncContext->work); - delete asyncContext; + return result; } -napi_value AudioManagerNapi::GetMaxVolume(napi_env env, napi_callback_info info) +napi_value AudioManagerNapi::SetRingerMode(napi_env env, napi_callback_info info) { napi_status status; const int32_t refCount = 1; napi_value result = nullptr; GET_PARAMS(env, info, ARGS_TWO); - NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameters minimum"); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); - HiLog::Debug(LABEL, "AudioManagerNapi::GetMaxVolume() is called!"); - AudioManagerAsyncContext* asyncContext = new AudioManagerAsyncContext(); status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); if (status == napi_ok && asyncContext->objectInfo != nullptr) { for (size_t i = PARAM0; i < argc; i++) { @@ -573,12 +777,11 @@ napi_value AudioManagerNapi::GetMaxVolume(napi_env env, napi_callback_info info) napi_typeof(env, argv[i], &valueType); if (i == PARAM0 && valueType == napi_number) { - napi_get_value_int32(env, argv[i], &asyncContext->volType); + napi_get_value_int32(env, argv[i], &asyncContext->ringMode); } else if (i == PARAM1 && valueType == napi_function) { napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; } else { - delete asyncContext; NAPI_ASSERT(env, false, "type mismatch"); } } @@ -590,48 +793,692 @@ napi_value AudioManagerNapi::GetMaxVolume(napi_env env, napi_callback_info info) } napi_value resource = nullptr; - napi_create_string_utf8(env, "GetMaxVolume", NAPI_AUTO_LENGTH, &resource); + napi_create_string_utf8(env, "SetRingerMode", NAPI_AUTO_LENGTH, &resource); status = napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { - AudioManagerAsyncContext* context = (AudioManagerAsyncContext*) data; - context->volLevel = - context->objectInfo->audioMngr_->GetMaxVolume(GetNativeAudioVolumeType(context->volType)); - context->status = 0; + auto context = static_cast(data); + context->status = context->objectInfo->audioMngr_->SetRingerMode(static_cast(context->ringMode)); }, - GetMaxVolumeAsyncCallbackComplete, (void*)asyncContext, &asyncContext->work); + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { - delete asyncContext; result = nullptr; } else { - napi_queue_async_work(env, asyncContext->work); + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } } - } else { - delete asyncContext; } + return result; } -static void GetMinVolumeAsyncCallbackComplete(napi_env env, napi_status status, void* data) +napi_value AudioManagerNapi::GetRingerMode(napi_env env, napi_callback_info info) { - AudioManagerAsyncContext* asyncContext = (AudioManagerAsyncContext*) data; - napi_value result[ARGS_TWO] = {0}; - napi_value retVal; + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; - napi_get_undefined(env, &result[PARAM0]); - napi_create_int32(env, asyncContext->volLevel, &result[PARAM1]); + GET_PARAMS(env, info, ARGS_ONE); - if (asyncContext->deferred) { - napi_resolve_deferred(env, asyncContext->deferred, result[PARAM1]); - } else { - napi_value callback = nullptr; - napi_get_reference_value(env, asyncContext->callbackRef, &callback); - napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal); - napi_delete_reference(env, asyncContext->callbackRef); + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "GetRingerMode", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->ringMode = context->objectInfo->audioMngr_->GetRingerMode(); + context->intValue = context->ringMode; + context->status = 0; + }, + GetIntValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::SetStreamMute(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_THREE); + NAPI_ASSERT(env, argc >= ARGS_TWO, "requires 2 parameters minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_boolean) { + napi_get_value_bool(env, argv[i], &asyncContext->isMute); + } else if (i == PARAM2 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "SetStreamMute", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->status = context->objectInfo->audioMngr_->SetMute(GetNativeAudioVolumeType(context->volType), + context->isMute); + }, + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::IsStreamMute(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "IsStreamMute", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->isMute = + context->objectInfo->audioMngr_->IsStreamMute(GetNativeAudioVolumeType(context->volType)); + context->isTrue = context->isMute; + context->status = 0; + }, + IsTrueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::IsStreamActive(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "IsStreamActive", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->isActive = + context->objectInfo->audioMngr_->IsStreamActive(GetNativeAudioVolumeType(context->volType)); + context->isTrue = context->isActive; + context->status = 0; + }, + IsTrueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::SetDeviceActive(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_THREE); + NAPI_ASSERT(env, argc >= ARGS_TWO, "requires 2 parameters minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->deviceType); + } else if (i == PARAM1 && valueType == napi_boolean) { + napi_get_value_bool(env, argv[i], &asyncContext->isActive); + } else if (i == PARAM2 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "SetDeviceActive", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->status = context->objectInfo->audioMngr_->SetDeviceActive( + GetNativeDeviceType(context->deviceType), context->isActive); + }, + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::IsDeviceActive(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->deviceType); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "IsDeviceActive", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->isActive = + context->objectInfo->audioMngr_->IsDeviceActive(GetNativeDeviceType(context->deviceType)); + context->isTrue = context->isActive; + context->status = 0; + }, + IsTrueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::SetAudioParameter(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_THREE); + NAPI_ASSERT(env, argc >= ARGS_TWO, "requires 2 parameters minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_string) { + asyncContext->key = GetStringArgument(env, argv[i]); + } else if (i == PARAM1 && valueType == napi_string) { + asyncContext->valueStr = GetStringArgument(env, argv[i]); + } else if (i == PARAM2 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "SetAudioParameter", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->objectInfo->audioMngr_->SetAudioParameter(context->key, context->valueStr); + context->status = 0; + }, + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } } - napi_delete_async_work(env, asyncContext->work); - delete asyncContext; + + return result; +} + +napi_value AudioManagerNapi::GetAudioParameter(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_string) { + asyncContext->key = GetStringArgument(env, argv[i]); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "GetAudioParameter", NAPI_AUTO_LENGTH, &resource); + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->valueStr = context->objectInfo->audioMngr_->GetAudioParameter(context->key); + context->status = 0; + }, + GetStringValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::SetVolume(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_THREE); + NAPI_ASSERT(env, argc >= ARGS_TWO, "requires 2 parameters minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_number) { + napi_get_value_double(env, argv[i], &asyncContext->volLevel); + } else if (i == PARAM2 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "SetVolume", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->status = context->objectInfo->audioMngr_->SetVolume(GetNativeAudioVolumeType(context->volType), + static_cast(context->volLevel)); + }, + SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::GetVolume(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "GetVolume", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->volLevel = static_cast(context->objectInfo->audioMngr_->GetVolume( + GetNativeAudioVolumeType(context->volType))); + context->doubleValue = context->volLevel; + context->status = 0; + }, + GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; +} + +napi_value AudioManagerNapi::GetMaxVolume(napi_env env, napi_callback_info info) +{ + napi_status status; + const int32_t refCount = 1; + napi_value result = nullptr; + + GET_PARAMS(env, info, ARGS_TWO); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); + + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); + if (status == napi_ok && asyncContext->objectInfo != nullptr) { + for (size_t i = PARAM0; i < argc; i++) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[i], &valueType); + + if (i == PARAM0 && valueType == napi_number) { + napi_get_value_int32(env, argv[i], &asyncContext->volType); + } else if (i == PARAM1 && valueType == napi_function) { + napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); + break; + } else { + NAPI_ASSERT(env, false, "type mismatch"); + } + } + + if (asyncContext->callbackRef == nullptr) { + napi_create_promise(env, &asyncContext->deferred, &result); + } else { + napi_get_undefined(env, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, "GetMaxVolume", NAPI_AUTO_LENGTH, &resource); + + status = napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void* data) { + auto context = static_cast(data); + context->volLevel = static_cast(context->objectInfo->audioMngr_->GetMaxVolume( + GetNativeAudioVolumeType(context->volType))); + context->doubleValue = context->volLevel; + context->status = 0; + }, + GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + if (status != napi_ok) { + result = nullptr; + } else { + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } + } + } + + return result; } napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) @@ -641,10 +1488,10 @@ napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) napi_value result = nullptr; GET_PARAMS(env, info, ARGS_TWO); - NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameters minimum"); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); - HiLog::Debug(LABEL, "AudioManagerNapi::GetMinVolume() is called!"); - AudioManagerAsyncContext* asyncContext = new AudioManagerAsyncContext(); status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); if (status == napi_ok && asyncContext->objectInfo != nullptr) { for (size_t i = PARAM0; i < argc; i++) { @@ -657,7 +1504,6 @@ napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; } else { - delete asyncContext; NAPI_ASSERT(env, false, "type mismatch"); } } @@ -674,39 +1520,40 @@ napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { - AudioManagerAsyncContext* context = (AudioManagerAsyncContext*) data; - context->volLevel = - context->objectInfo->audioMngr_->GetMinVolume(GetNativeAudioVolumeType(context->volType)); + auto context = static_cast(data); + context->volLevel = static_cast(context->objectInfo->audioMngr_->GetMinVolume( + GetNativeAudioVolumeType(context->volType))); + context->doubleValue = context->volLevel; context->status = 0; }, - GetMinVolumeAsyncCallbackComplete, (void*)asyncContext, &asyncContext->work); + GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { - delete asyncContext; result = nullptr; } else { - napi_queue_async_work(env, asyncContext->work); + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } } - } else { - delete asyncContext; } + return result; } static void GetDevicesAsyncCallbackComplete(napi_env env, napi_status status, void* data) { - AudioManagerAsyncContext* asyncContext = (AudioManagerAsyncContext*) data; + auto asyncContext = static_cast(data); napi_value result[ARGS_TWO] = {0}; napi_value ddWrapper = nullptr; napi_value retVal; int32_t size = asyncContext->deviceDescriptors.size(); - HiLog::Debug(LABEL, "Size of Device Descriptors array, %{public}d!, deviceflag: %{public}d", - size, asyncContext->deviceFlag); + napi_create_array_with_length(env, size, &result[PARAM1]); for (int i = 0; i < size; i += 1) { AudioDeviceDescriptor *curDeviceDescriptor = asyncContext->deviceDescriptors[i]; - HiLog::Debug(LABEL, "Device role, %{public}d, Device type: %{public}d", - curDeviceDescriptor->deviceRole_, curDeviceDescriptor->deviceType_); ddWrapper = AudioDeviceDescriptorNapi::CreateAudioDeviceDescriptorWrapper(env, curDeviceDescriptor); napi_set_element(env, result[PARAM1], i, ddWrapper); } @@ -722,6 +1569,7 @@ static void GetDevicesAsyncCallbackComplete(napi_env env, napi_status status, vo napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); + delete asyncContext; } @@ -732,10 +1580,10 @@ napi_value AudioManagerNapi::GetDevices(napi_env env, napi_callback_info info) napi_value result = nullptr; GET_PARAMS(env, info, ARGS_TWO); - NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameters minimum"); + NAPI_ASSERT(env, argc >= ARGS_ONE, "requires 1 parameter minimum"); + + unique_ptr asyncContext = make_unique(); - HiLog::Debug(LABEL, "AudioManagerNapi::GetDevices() is called!"); - AudioManagerAsyncContext* asyncContext = new AudioManagerAsyncContext(); status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->objectInfo)); if (status == napi_ok && asyncContext->objectInfo != nullptr) { for (size_t i = PARAM0; i < argc; i++) { @@ -748,7 +1596,6 @@ napi_value AudioManagerNapi::GetDevices(napi_env env, napi_callback_info info) napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; } else { - delete asyncContext; NAPI_ASSERT(env, false, "type mismatch"); } } @@ -765,21 +1612,24 @@ napi_value AudioManagerNapi::GetDevices(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { - AudioManagerAsyncContext* context = (AudioManagerAsyncContext*) data; + auto context = static_cast(data); context->deviceDescriptors = context->objectInfo->audioMngr_->GetDevices(GetNativeDeviceFlag(context->deviceFlag)); context->status = 0; }, - GetDevicesAsyncCallbackComplete, (void*)asyncContext, &asyncContext->work); + GetDevicesAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { - delete asyncContext; result = nullptr; } else { - napi_queue_async_work(env, asyncContext->work); + status = napi_queue_async_work(env, asyncContext->work); + if (status == napi_ok) { + asyncContext.release(); + } else { + result = nullptr; + } } - } else { - delete asyncContext; } + return result; } @@ -802,6 +1652,7 @@ static napi_module g_module = { extern "C" __attribute__((constructor)) void RegisterModule(void) { - HiLog::Debug(LABEL, "RegisterModule() is called!"); napi_module_register(&g_module); } +} // namespace AudioStandard +} // namespace OHOS diff --git a/interfaces/innerkits/native/audiocommon/include/audio_info.h b/interfaces/innerkits/native/audiocommon/include/audio_info.h new file mode 100644 index 0000000000..392a15e782 --- /dev/null +++ b/interfaces/innerkits/native/audiocommon/include/audio_info.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_INFO_H +#define AUDIO_INFO_H + +#include + +namespace OHOS { +namespace AudioStandard { +// Audio Device Types +enum DeviceType { + /** + * Indicates device type none. + */ + DEVICE_TYPE_NONE = -1, + /** + * Indicates a speaker built in a device. + */ + SPEAKER = 0, + /** + * Indicates a headset, which is the combination of a pair of headphones and a microphone. + */ + WIRED_HEADSET = 1, + /** + * Indicates a Bluetooth device used for telephony. + */ + BLUETOOTH_SCO = 2, + /** + * Indicates a Bluetooth device supporting the Advanced Audio Distribution Profile (A2DP). + */ + BLUETOOTH_A2DP = 3, + /** + * Indicates a microphone built in a device. + */ + MIC = 4 +}; + +// Audio Role +enum DeviceRole { + /** + * Device role none. + */ + DEVICE_ROLE_NONE = -1, + /** + * Input device role. + */ + INPUT_DEVICE = 0, + /** + * Output device role. + */ + OUTPUT_DEVICE = 1 +}; + +enum AudioStreamType { + /** + * Indicates audio streams default. + */ + STREAM_DEFAULT = -1, + /** + * Indicates audio streams media. + */ + STREAM_MEDIA = 0, + /** + * Indicates audio streams of voices in calls. + */ + STREAM_VOICE_CALL = 1, + /** + * Indicates audio streams for system sounds. + */ + STREAM_SYSTEM = 2, + /** + * Indicates audio streams for ringtones. + */ + STREAM_RING = 3, + /** + * Indicates audio streams for music playback. + */ + STREAM_MUSIC = 4, + /** + * Indicates audio streams for alarms. + */ + STREAM_ALARM = 5, + /** + * Indicates audio streams for notifications. + */ + STREAM_NOTIFICATION = 6, + /** + * Indicates audio streams for voice calls routed through a connected Bluetooth device. + */ + STREAM_BLUETOOTH_SCO = 7, + /** + * Indicates audio streams for enforced audible. + */ + STREAM_ENFORCED_AUDIBLE = 8, + /** + * Indicates audio streams for dual-tone multi-frequency (DTMF) tones. + */ + STREAM_DTMF = 9, + /** + * Indicates audio streams exclusively transmitted through the speaker (text-to-speech) of a device. + */ + STREAM_TTS = 10, + /** + * Indicates audio streams used for prompts in terms of accessibility. + */ + STREAM_ACCESSIBILITY = 11 +}; + +enum AudioEncodingType { + ENCODING_PCM = 0, + ENCODING_AAC, // Currently not supported + ENCODING_INVALID +}; + +// Ringer Mode +enum AudioRingerMode { + RINGER_MODE_NORMAL = 0, + RINGER_MODE_SILENT = 1, + RINGER_MODE_VIBRATE = 2 +}; + +// format +enum AudioSampleFormat { + SAMPLE_U8 = 8, + SAMPLE_S16LE = 16, + SAMPLE_S24LE = 24, + SAMPLE_S32LE = 32, + INVALID_WIDTH = -1 +}; + +// channel +enum AudioChannel { + MONO = 1, + STEREO +}; + +// sampling rate +enum AudioSamplingRate { + SAMPLE_RATE_8000 = 8000, + SAMPLE_RATE_11025 = 11025, + SAMPLE_RATE_16000 = 16000, + SAMPLE_RATE_22050 = 22050, + SAMPLE_RATE_32000 = 32000, + SAMPLE_RATE_44100 = 44100, + SAMPLE_RATE_48000 = 48000 +}; + +typedef enum { + /** Invalid audio source */ + AUDIO_SOURCE_INVALID = -1, + /** Default audio source */ + AUDIO_SOURCE_DEFAULT = 0, + /** Microphone */ + AUDIO_MIC = 1, + /** Uplink voice */ + AUDIO_VOICE_UPLINK = 2, + /** Downlink voice */ + AUDIO_VOICE_DOWNLINK = 3, + /** Voice call */ + AUDIO_VOICE_CALL = 4, + /** Camcorder */ + AUDIO_CAMCORDER = 5, + /** Voice recognition */ + AUDIO_VOICE_RECOGNITION = 6, + /** Voice communication */ + AUDIO_VOICE_COMMUNICATION = 7, + /** Remote submix */ + AUDIO_REMOTE_SUBMIX = 8, + /** Unprocessed audio */ + AUDIO_UNPROCESSED = 9, + /** Voice performance */ + AUDIO_VOICE_PERFORMANCE = 10, + /** Echo reference */ + AUDIO_ECHO_REFERENCE = 1997, + /** Radio tuner */ + AUDIO_RADIO_TUNER = 1998, + /** Hotword */ + AUDIO_HOTWORD = 1999, + /** Extended remote submix */ + AUDIO_REMOTE_SUBMIX_EXTEND = 10007, +} AudioSourceType; + +struct AudioStreamParams { + uint32_t samplingRate; + uint8_t encoding; + uint8_t format; + uint8_t channels; +}; + +/** + * @brief Represents Timestamp information, including the frame position information and high-resolution time source. + */ +class Timestamp { +public: + Timestamp() : framePosition(0) + { + time.tv_sec = 0; + time.tv_nsec = 0; + } + virtual ~Timestamp() = default; + uint32_t framePosition; + struct timespec time; + + /** + * @brief Enumerates the time base of this Timestamp. Different timing methods are supported. + * + */ + enum Timestampbase { + /** Monotonically increasing time, excluding the system sleep time */ + MONOTONIC = 0 + }; +}; +typedef void* AudioIOHandle; + +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_INFO_H diff --git a/interfaces/innerkits/native/audiomanager/BUILD.gn b/interfaces/innerkits/native/audiomanager/BUILD.gn old mode 100755 new mode 100644 index 3389083eec..36e5a75a26 --- a/interfaces/innerkits/native/audiomanager/BUILD.gn +++ b/interfaces/innerkits/native/audiomanager/BUILD.gn @@ -9,41 +9,111 @@ # 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. import("//build/ohos.gni") +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" + +group("audio_client_test_packages") { + deps = [ + ":playback_test", + ":record_test", + ] +} + config("audio_client_public_config") { include_dirs = [ "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiopolicy/include", "//foundation/multimedia/audio_standard/services/include", "//foundation/multimedia/audio_standard/services/include/client", + "//foundation/multimedia/audio_standard/services/include/audiopolicy/client", "//utils/system/safwk/native/include", "//utils/native/base/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiosession/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", + "$pulseaudio_dir/src", + "$pulseaudio_dir/confgure/src", + "$pulseaudio_build_path/include", + "//third_party/bounds_checking_function/include", + ] + + cflags = [ + "-Wall", + "-Werror", ] if (target_cpu == "arm") { - cflags = [ "-DBINDER_IPC_32BIT" ] + cflags += [ "-DBINDER_IPC_32BIT" ] } + } + ohos_shared_library("audio_client") { install_enable = true sources = [ "//foundation/multimedia/audio_standard/services/src/audio_device_descriptor.cpp", "//foundation/multimedia/audio_standard/services/src/client/audio_manager_proxy.cpp", - "//foundation/multimedia/audio_standard/services/src/client/audio_svc_manager.cpp", + "//foundation/multimedia/audio_standard/services/src/client/audio_service_client.cpp", + "//foundation/multimedia/audio_standard/services/src/client/audio_session.cpp", + "//foundation/multimedia/audio_standard/services/src/client/audio_stream.cpp", + "//foundation/multimedia/audio_standard/services/src/client/audio_system_manager.cpp", ] - public_configs = [ ":audio_client_public_config" ] + public_configs = [ + ":audio_client_public_config", + ] - deps = [ "//utils/native/base:utils" ] + deps = [ + "//utils/native/base:utils", + "//foundation/multimedia/audio_standard/pulseaudio/src/pulse:pulse", + "//third_party/bounds_checking_function:libsec_static", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiopolicy:audio_policy_client", + ] external_deps = [ - "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", "samgr_L2:samgr_proxy", + "hiviewdfx_hilog_native:libhilog", ] subsystem_name = "multimedia" part_name = "multimedia_audio_standard" } + +ohos_executable("playback_test") { + install_enable = false + + sources = [ "//foundation/multimedia/audio_standard/services/test/playback_test.cpp" ] + + configs = [ + ":audio_client_public_config", + ] + + deps = [ + ":audio_client", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +ohos_executable("record_test") { + install_enable = false + + sources = [ "//foundation/multimedia/audio_standard/services/test/record_test.cpp" ] + + configs = [ ":audio_client_public_config" ] + + deps = [ ":audio_client" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog"] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} diff --git a/interfaces/innerkits/native/audiomanager/include/audio_svc_manager.h b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h old mode 100755 new mode 100644 similarity index 60% rename from interfaces/innerkits/native/audiomanager/include/audio_svc_manager.h rename to interfaces/innerkits/native/audiomanager/include/audio_system_manager.h index 062c3628af..d6c14364f1 --- a/interfaces/innerkits/native/audiomanager/include/audio_svc_manager.h +++ b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h @@ -13,20 +13,23 @@ * limitations under the License. */ -#ifndef ST_AUDIO_SVC_MANAGER_H -#define ST_AUDIO_SVC_MANAGER_H +#ifndef ST_AUDIO_SYSTEM_MANAGER_H +#define ST_AUDIO_SYSTEM_MANAGER_H #include #include "audio_device_descriptor.h" +#include "audio_stream.h" +#include "audio_policy_manager.h" namespace OHOS { +namespace AudioStandard { /** - * @brief The AudioSvcManager class is an abstract definition of audio manager. + * @brief The AudioSystemManager class is an abstract definition of audio manager. * Provides a series of client/interfaces for audio management */ -class AudioSvcManager { +class AudioSystemManager { public: enum AudioVolumeType { /** @@ -70,16 +73,28 @@ enum AudioVolumeType { */ STREAM_ACCESSIBILITY = 10 }; - static AudioSvcManager* GetInstance(); - void SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume); - int GetVolume(AudioSvcManager::AudioVolumeType volumeType); - int GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType); - int GetMinVolume(AudioSvcManager::AudioVolumeType volumeType); + static AudioSystemManager* GetInstance(); + int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume); + float GetVolume(AudioSystemManager::AudioVolumeType volumeType); + float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType); + float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType); + int32_t SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute); + bool IsStreamMute(AudioSystemManager::AudioVolumeType volumeType); + int32_t SetMicrophoneMute(bool IsMute); + bool IsMicrophoneMute(void); std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag); + const std::string GetAudioParameter(const std::string key); + void SetAudioParameter(const std::string key, const std::string value); + int32_t SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag); + bool IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType); + bool IsStreamActive(AudioSystemManager::AudioVolumeType volumeType); + bool SetRingerMode(AudioRingerMode ringMode); + AudioRingerMode GetRingerMode(); private: - AudioSvcManager(); - virtual ~AudioSvcManager(); + AudioSystemManager(); + virtual ~AudioSystemManager(); void init(); }; +} // namespace AudioStandard } // namespace OHOS -#endif // ST_AUDIO_SVC_MANAGER_H +#endif // ST_AUDIO_SYSTEM_MANAGER_H diff --git a/interfaces/innerkits/native/audiopolicy/BUILD.gn b/interfaces/innerkits/native/audiopolicy/BUILD.gn new file mode 100644 index 0000000000..4e4ba1a4c7 --- /dev/null +++ b/interfaces/innerkits/native/audiopolicy/BUILD.gn @@ -0,0 +1,95 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +config("audio_policy_public_config") { + include_dirs = [ + "//foundation/multimedia/audio_standard/services/include", + "//foundation/multimedia/audio_standard/services/include/client", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiopolicy/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/common", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/interface", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/manager", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/config", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service", + "//foundation/multimedia/audio_standard/services/include/audio_policy/common", + "//foundation/multimedia/audio_standard/services/include/audio_policy/server", + "//foundation/multimedia/audio_standard/services/include/audio_policy/client", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//foundation/multimedia/image/mock/native/include/foundation/multimedia/image/mock/native/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//utils/system/safwk/native/include", + "//utils/native/base/include", + "//third_party/bounds_checking_function/include", + ] + + cflags = [ + "-Wall", + "-Werror", + ] + + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } +} + +ohos_shared_library("audio_policy_client") { + install_enable = true + sources = [ + "//foundation/multimedia/audio_standard/services/src/audio_policy/client/audio_policy_proxy.cpp", + "//foundation/multimedia/audio_standard/services/src/audio_policy/client/audio_policy_manager.cpp", + ] + + public_configs = [ + ":audio_policy_public_config", + ] + + deps = [ + "//utils/native/base:utils", + ] + + external_deps = [ + "ipc:ipc_core", + "samgr_L2:samgr_proxy", + "safwk:system_ability_fwk", + "hiviewdfx_hilog_native:libhilog", + ] + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_executable("audio_policy_test") { + install_enable = false + + sources = [ "//foundation/multimedia/audio_standard/services/test/audio_policy_test.cpp" ] + + configs = [ + ":audio_policy_public_config", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} diff --git a/interfaces/innerkits/native/audiopolicy/include/audio_policy_manager.h b/interfaces/innerkits/native/audiopolicy/include/audio_policy_manager.h new file mode 100644 index 0000000000..cf677eefea --- /dev/null +++ b/interfaces/innerkits/native/audiopolicy/include/audio_policy_manager.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_MANAGER_H +#define ST_AUDIO_POLICY_MANAGER_H + +#include +#include "audio_info.h" + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyManager { +public: + static AudioPolicyManager& GetInstance() + { + static AudioPolicyManager policyManager; + return policyManager; + } + + int32_t SetStreamVolume(AudioStreamType streamType, float volume); + + float GetStreamVolume(AudioStreamType streamType); + + int32_t SetStreamMute(AudioStreamType streamType, bool mute); + + bool GetStreamMute(AudioStreamType streamType); + + bool IsStreamActive(AudioStreamType streamType); + + int32_t SetDeviceActive(DeviceType deviceType, bool active); + + bool IsDeviceActive(DeviceType deviceType); + + int32_t SetRingerMode(AudioRingerMode ringMode); + + AudioRingerMode GetRingerMode(); +private: + AudioPolicyManager() + { + Init(); + } + ~AudioPolicyManager() {} + + void Init(); +}; +} // namespce AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_POLICY_MANAGER_H diff --git a/interfaces/innerkits/native/audiorecorder/BUILD.gn b/interfaces/innerkits/native/audiorecorder/BUILD.gn new file mode 100644 index 0000000000..5cefb05e3a --- /dev/null +++ b/interfaces/innerkits/native/audiorecorder/BUILD.gn @@ -0,0 +1,91 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" + +group("audio_recorder_test_packages") { + deps = [ + ":audio_recorder_test", + ] +} + +config("audio_recorder_config") { + include_dirs = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiosession/include", + "//foundation/multimedia/audio_standard/services/include", + "//foundation/multimedia/audio_standard/services/include/client", + "$pulseaudio_dir/src", + "$pulseaudio_dir/confgure/src", + ] + + cflags = [ + "-Wall", + "-Werror", + ] + +} + +ohos_shared_library("audio_recorder") { + install_enable = true + + configs = [ + ":audio_recorder_config", + ] + + sources = [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", + ] + + public_configs = [ ":audio_external_library_config" ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +config("audio_external_library_config") { + include_dirs = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include" ] +} + +ohos_executable("audio_recorder_test") { + + install_enable = true + + sources = [ + "//foundation/multimedia/audio_standard/services/test/audio_recorder_test.cpp", + ] + + configs = [ + ":audio_recorder_config", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder:audio_recorder", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} diff --git a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h new file mode 100644 index 0000000000..407303bcb4 --- /dev/null +++ b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_RECORDER_H +#define AUDIO_RECORDER_H + +#include + +#include "audio_info.h" + +namespace OHOS { +namespace AudioStandard { +/** + * @brief Defines information about audio record parameters + */ +struct AudioRecorderParams { + /** Audio source type */ + AudioSourceType inputSource = AUDIO_MIC; + /** Audio codec format */ + AudioEncodingType audioEncoding = ENCODING_PCM; + /** Sampling rate */ + AudioSamplingRate samplingRate = SAMPLE_RATE_44100; + /** Number of audio channels */ + AudioChannel audioChannel = MONO; + /** Audio stream type */ + AudioStreamType streamType = STREAM_MEDIA; + /** audioSampleFormat */ + AudioSampleFormat audioSampleFormat = SAMPLE_S16LE; +}; + +/** + * @brief Enumerates the recording states of the current device. + */ +enum RecorderState { + /** Create new recorder instance */ + RECORDER_NEW, + /** Recorder Prepared state */ + RECORDER_PREPARED, + /** Recorder Running state */ + RECORDER_RUNNING, + /** Recorder Stopped state */ + RECORDER_STOPPED, + /** Recorder Released state */ + RECORDER_RELEASED, + /** Recorder INVALID state */ + RECORDER_INVALID +}; + +/** + * @brief Provides functions for applications to implement audio recording. + */ +class AudioRecorder { +public: + /** + * @brief creater recorder instance. + */ + static std::unique_ptr Create(AudioStreamType audioStreamType); + + /** + * @brief Obtains the number of frames required in the current condition, in bytes per sample. + * + * @param frameCount Indicates the pointer in which framecount will be written + * @return Returns {@link SUCCESS} if frameCount is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetFrameCount(uint32_t &frameCount) = 0; + + /** + * @brief Sets audio record parameters. + * + * @param params Indicates information about audio record parameters to set. For details, see + * {@link AudioRecorderParams}. + * @return Returns {@link SUCCESS} if the setting is successful; returns an error code defined + * in {@link audio_errors.h} otherwise. + */ + virtual int32_t SetParams(const AudioRecorderParams params) = 0; + + /** + * @brief Obtains audio recorder parameters. + * + * This function can be called after {@link SetParams} is successful. + * + * @param params Indicates information about audio recorder parameters. For details, see {@link AudioRecorderParams}. + * @return Returns {@link SUCCESS} if the parameter information is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetParams(AudioRecorderParams ¶ms) = 0; + + /** + * @brief Starts audio recording. + * + * @return Returns true if the recording is successfully started; returns false otherwise. + */ + virtual bool Start() = 0; + + /** + * @brief record audio data. + * + * @param buffer Indicates the pointer to the buffer into which the audio data is to be written. + * @param userSize Indicates the size of the buffer into which the audio data is to be written, in bytes. + * userSize >= frameCount * channelCount * BytesPerSample must evaluate to true. You can call + * {@link GetFrameCount} to obtain the frameCount value. + * @param isBlockingRead Specifies whether data reading will be blocked. + * @return Returns the size of the audio data read from the device. The value ranges from 0 to + * userSize. If the reading fails, one of the following error codes is returned. + * ERR_INVALID_PARAM: The input parameter is incorrect. + * ERR_ILLEGAL_STATE: The AudioRecorder instance is not initialized. + * ERR_INVALID_READ: The read size < 0. + */ + virtual int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) = 0; + + /** + * @brief Obtains the audio record state. + * + * @return Returns the audio record state defined in {@link RecorderState}. + */ + virtual RecorderState GetStatus() = 0; + + /** + * @brief Obtains the Timestamp. + * + * @param timestamp Indicates a {@link Timestamp} instance reference provided by the caller. + * @param base Indicates the time base, which can be {@link Timestamp.Timestampbase#BOOTTIME} or + * {@link Timestamp.Timestampbase#MONOTONIC}. + * @return Returns true if the timestamp is successfully obtained; returns false otherwise. + */ + virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) = 0; + + /** + * @brief Stops audio recording. + * + * @return Returns true if the recording is successfully stopped; returns false otherwise. + */ + virtual bool Stop() = 0; + /** + * @brief flush record stream. + * + * @return Returns true if the object is successfully flushed; returns false otherwise. + */ + virtual bool Flush() = 0; + + /** + * @brief Releases a local AudioRecorder object. + * + * @return Returns true if the object is successfully released; returns false otherwise. + */ + virtual bool Release() = 0; + + /** + * @brief Obtains the recorder buffer size. + * + * @param bufferSize Indicates a buffersize pointer value that wil be written. + * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetBufferSize(size_t &bufferSize) = 0; + + /** + * @brief Obtains the recorder supported formats. + * + * @return vector with recorder supported formats. + */ + virtual std::vector GetSupportedFormats() = 0; + + /** + * @brief Obtains the recorder supported channels. + * + * @return vector with recorder supported channels. + */ + virtual std::vector GetSupportedChannels() = 0; + + /** + * @brief Obtains the recorder supported encoding types. + * + * @return vector with recorder supported encoding types. + */ + virtual std::vector GetSupportedEncodingTypes() = 0; + + /** + * @brief Obtains the recorder supported SupportedSamplingRates. + * + * @return vector with recorder supported SupportedSamplingRates. + */ + virtual std::vector GetSupportedSamplingRates() = 0; + + virtual ~AudioRecorder(); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_RECORDER_H diff --git a/interfaces/innerkits/native/audiorenderer/BUILD.gn b/interfaces/innerkits/native/audiorenderer/BUILD.gn new file mode 100644 index 0000000000..f09ef6b71e --- /dev/null +++ b/interfaces/innerkits/native/audiorenderer/BUILD.gn @@ -0,0 +1,71 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" + +config("audio_renderer_config") { + include_dirs = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiosession/include", + "//foundation/multimedia/audio_standard/services/include", + "//foundation/multimedia/audio_standard/services/include/client", + "$pulseaudio_dir/src", + "$pulseaudio_dir/confgure/src", + ] + + cflags = [ + "-Wall", + "-Werror", + ] + +} + +ohos_shared_library("audio_renderer") { + install_enable = true + + configs = [ ":audio_renderer_config" ] + + sources = [ "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp" ] + + deps = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client" ] + + public_configs = [ ":audio_external_library_config" ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +ohos_executable("audio_renderer_test") { + + install_enable = true + + sources = [ "//foundation/multimedia/audio_standard/services/test/audio_renderer_test.cpp" ] + + configs = [ ":audio_renderer_config" ] + + deps = [ ":audio_renderer" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +config("audio_external_library_config") { + include_dirs = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer/include" ] +} diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h new file mode 100644 index 0000000000..98a861155f --- /dev/null +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_RENDERER_H +#define AUDIO_RENDERER_H + +#include + +#include "audio_info.h" + +namespace OHOS { +namespace AudioStandard { +/** + * @brief Defines information about audio renderer parameters. + */ + +struct AudioRendererParams { + /** Sample Format */ + AudioSampleFormat sampleFormat = SAMPLE_S16LE; + /** Sampling rate */ + AudioSamplingRate sampleRate = SAMPLE_RATE_8000; + /** Number of channels */ + AudioChannel channelCount = MONO; + /** Encoding Type */ + AudioEncodingType encodingType = ENCODING_PCM; +}; + +/** + * @brief Enumerates the rendering states of the current device. + */ +enum RendererState { + /** Create New Renderer instance */ + RENDERER_NEW, + /** Reneder Prepared state */ + RENDERER_PREPARED, + /** Rendere Running state */ + RENDERER_RUNNING, + /** Renderer Stopped state */ + RENDERER_STOPPED, + /** Renderer Released state */ + RENDERER_RELEASED, + /** INVALID state */ + RENDERER_INVALID +}; + +/** + * @brief Provides functions for applications to implement audio rendering. + */ +class AudioRenderer { +public: + /** + * @brief creater renderer instance. + * + * @param audioStreamType The audio streamtype to be created. + * refer AudioStreamType in audio_info.h. + * @return Returns unique pointer to the AudioRenderer object + */ + static std::unique_ptr Create(AudioStreamType audioStreamType); + /** + * @brief Obtains the number of frames required in the current condition, in bytes per sample. + * + * @param frameCount Indicates the reference variable in which framecount will be written + * @return Returns {@link SUCCESS} if frameCount is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetFrameCount(uint32_t &frameCount) = 0; + + /** + * @brief Sets audio renderer parameters. + * + * @param params Indicates information about audio renderer parameters to set. For details, see + * {@link AudioRendererParams}. + * @return Returns {@link SUCCESS} if the setting is successful; returns an error code defined + * in {@link audio_errors.h} otherwise. + */ + virtual int32_t SetParams(const AudioRendererParams params) = 0; + + /** + * @brief Obtains audio renderer parameters. + * + * This function can be called after {@link SetParams} is successful. + * + * @param params Indicates information about audio renderer parameters. For details, see {@link AudioRendererParams}. + * @return Returns {@link SUCCESS} if the parameter information is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetParams(AudioRendererParams ¶ms) = 0; + + /** + * @brief Starts audio rendering. + * + * @return Returns true if the rendering is successfully started; returns false otherwise. + */ + virtual bool Start() = 0; + + /** + * @brief Writes audio data. + * + * @param buffer Indicates the pointer to the buffer which contains the audio data to be written. + * @param bufferSize Indicates the size of the buffer which contains audio data to be written, in bytes. + * @return Returns the size of the audio data written to the device. The value ranges from 0 to + * bufferSize. If the write fails, one of the following error codes is returned. + * ERR_INVALID_PARAM: The input parameter is incorrect. + * ERR_ILLEGAL_STATE: The AudioRenderer instance is not initialized. + * ERR_INVALID_WRITE: The written audio data size is < 0. + * ERR_WRITE_FAILED: The audio data write failed . + */ + virtual int32_t Write(uint8_t *buffer, size_t bufferSize) = 0; + + /** + * @brief Obtains the audio renderer state. + * + * @return Returns the audio renderer state defined in {@link RendererState}. + */ + virtual RendererState GetStatus() = 0; + + /** + * @brief Obtains the timestamp. + * + * @param timestamp Indicates a {@link Timestamp} instance reference provided by the caller. + * @param base Indicates the time base, which can be {@link Timestamp.Timestampbase#BOOTTIME} or + * {@link Timestamp.Timestampbase#MONOTONIC}. + * @return Returns true if the timestamp is successfully obtained; returns false otherwise. + */ + virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) = 0; + + /** + * @brief drain renderer buffer. + * + * @return Returns true if the buffer is successfully drained; returns false otherwise. + */ + virtual bool Drain() = 0; + + /** + * @brief Stops audio rendering. + * + * @return Returns true if the rendering is successfully stopped; returns false otherwise. + */ + virtual bool Stop() = 0; + + /** + * @brief Releases a local AudioRenderer object. + * + * @return Returns true if the object is successfully released; returns false otherwise. + */ + virtual bool Release() = 0; + + /** + * @brief Obtains the renderer buffer size. + * + * @param bufferSize Indicates the reference variable into which buffer size value wil be written. + * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetBufferSize(size_t &bufferSize) = 0; + + /** + * @brief Obtains the foramts supported by renderer. + * + * @return Returns vector with supported formats. + */ + virtual std::vector GetSupportedFormats() = 0; + + /** + * @brief Obtains the SupportedSamplingRates supported by renderer. + * + * @return Returns vector with supported SupportedSamplingRates. + */ + virtual std::vector GetSupportedSamplingRates() = 0; + + /** + * @brief Obtains the channels supported by renderer. + * + * @return Returns vector with supported channels. + */ + virtual std::vector GetSupportedChannels() = 0; + + /** + * @brief Obtains the encoding types supported by renderer. + * + * @return Returns vector with supported encoding types. + */ + virtual std::vector GetSupportedEncodingTypes() = 0; + + virtual ~AudioRenderer(); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_RENDERER_H diff --git a/interfaces/innerkits/native/audiosession/include/audio_session.h b/interfaces/innerkits/native/audiosession/include/audio_session.h new file mode 100644 index 0000000000..08b32e9b00 --- /dev/null +++ b/interfaces/innerkits/native/audiosession/include/audio_session.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_SESSION_H +#define AUDIO_SESSION_H + +#include "audio_service_client.h" + +namespace OHOS { +namespace AudioStandard { +enum SessionType { + SESSION_CONTROL, + SESSION_PLAYBACK, + SESSION_RECORD +}; + +struct AudioDevDescriptor { +}; + +class AudioSession : public AudioServiceClient { +public: + uint32_t GetSessionID(); + + AudioDevDescriptor* GetActiveAudioSinkDevice(uint32_t sessionID); + AudioDevDescriptor* GetActiveAudioSourceDevice(uint32_t sessionID); + + bool SetActiveAudioSinkDevice(uint32_t sessionID, const AudioDevDescriptor& audioDesc); + bool SetActiveAudioSourceDevice(uint32_t sessionID, const AudioDevDescriptor& audioDesc); + float GetAudioStreamVolume(uint32_t sessionID); + float GetAudioDeviceVolume(uint32_t sessionID); + bool SetAudioStreamVolume(uint32_t sessionID, float volume); + bool SetAudioDeviceVolume(uint32_t sessionID, float volume); + +private: + AudioSession* CreateSession(SessionType eSession); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_SESSION_H diff --git a/interfaces/innerkits/native/audiostream/include/audio_stream.h b/interfaces/innerkits/native/audiostream/include/audio_stream.h new file mode 100644 index 0000000000..3e185f7460 --- /dev/null +++ b/interfaces/innerkits/native/audiostream/include/audio_stream.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_session.h" + +#ifndef AUDIO_STREAM_H +#define AUDIO_STREAM_H + +namespace OHOS { +namespace AudioStandard { +enum AudioMode { + AUDIO_MODE_PLAYBACK, + AUDIO_MODE_RECORD +}; + +/** + * @brief Enumerates the stream states of the current device. + * + * @since 1.0 + * @version 1.0 + */ +enum State { + /** New */ + NEW, + /** Prepared */ + PREPARED, + /** Running */ + RUNNING, + /** Stopped */ + STOPPED, + /** Released */ + RELEASED, + /** INVALID */ + INVALID +}; + +class AudioStream : public AudioSession { +public: + AudioStream(AudioStreamType eStreamType, AudioMode eMode); + virtual ~AudioStream(); + + int32_t SetAudioStreamInfo(const AudioStreamParams info); + int32_t GetAudioStreamInfo(AudioStreamParams &info); + + uint32_t GetAudioSessionID(); + State GetState(); + bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base); + int32_t GetBufferSize(size_t &bufferSize); + int32_t GetFrameCount(uint32_t &frameCount); + + std::vector GetSupportedFormats(); + std::vector GetSupportedChannels(); + std::vector GetSupportedEncodingTypes(); + std::vector GetSupportedSamplingRates(); + + // Common APIs + bool StartAudioStream(); + bool StopAudioStream(); + bool ReleaseAudioStream(); + bool FlushAudioStream(); + + // Playback related APIs + bool DrainAudioStream(); + size_t Write(uint8_t *buffer, size_t buffer_size); + + // Recorder related APIs + int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead); +private: + AudioStreamType eStreamType_; + AudioMode eMode_; + State state_; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_STREAM_H diff --git a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts old mode 100755 new mode 100644 index 2deecd5ab0..38c2edc5ee --- a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts +++ b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts @@ -12,199 +12,1279 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import {ErrorCallback, AsyncCallback} from './basic'; +import {ErrorCallback, AsyncCallback, Callback} from './basic'; +import {VideoPlayer, AudioPlayer} from '@ohos.Multimedia.media' /** * @name audio * @since 6 * @sysCap SystemCapability.Multimedia.Audio - * @import import audio from '@ohos.multimedia.audio'; + * @import import audio from '@ohos.Multimedia.audio'; * @permission */ declare namespace audio { + /** + * Obtains an AudioManager instance. + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + function getAudioManager(): AudioManager; + /** + * Obtains an SoundPlayer instance. + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + function createSoundPlayer(): SoundPlayer; + /** + * Obtains an ToneDescriptor instance. + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + function createToneDescriptor(tone: ToneType): ToneDescriptor; + /** + * Obtains an SoundEffectBuilder instance. + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + function getSoundEffectBuilder(): SoundEffectBuilder; + + /** + * Enumerates audio stream types. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum AudioVolumeType { + /** + * Audio streams for media purpose + */ + MEDIA = 1, + /** + * Audio streams for ring tones + */ + RINGTONE = 2, + } + + /** + * Enumerates audio device flags. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum DeviceFlag { + /** + * Output devices + */ + OUTPUT_DEVICES_FLAG = 1, + /** + * Input devices + */ + INPUT_DEVICES_FLAG = 2, + /** + * All devices + */ + ALL_DEVICES_FLAG = 3, + } + /** + * Enumerates device roles. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum DeviceRole { + /** + * Input role + */ + INPUT_DEVICE = 1, + /** + * Output role + */ + OUTPUT_DEVICE = 2, + } + /** + * Enumerates device types. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum DeviceType { + /** + * Invalid device + */ + INVALID = 0, + /** + * Speaker + */ + SPEAKER = 1, + /** + * Wired headset + */ + WIRED_HEADSET = 2, + /** + * Bluetooth device using the synchronous connection oriented link (SCO) + */ + BLUETOOTH_SCO = 3, + /** + * Bluetooth device using advanced audio distribution profile (A2DP) + */ + BLUETOOTH_A2DP = 4, + /** + * Microphone + */ + MIC = 5, + } + /** + * 音频铃声枚举. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum AudioRingMode { + /** + * 正常铃声模式 + */ + RINGER_MODE_NORMAL = 0, + /** + * 静音铃声模式 + */ + RINGER_MODE_SILENT = 1, + /** + * 振动铃声模式 + */ + RINGER_MODE_VIBRATE = 2, + } + /** + * 呼叫状态枚举. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum CallState { + /** + * 空闲状态 + */ + IDLE = 0, + /** + * 打电话状态 + */ + IN_CALL = 1, + /** + * 处于voip状态 + */ + IN_VOIP = 2, + /** + * 铃声状态 + */ + RINGTONE = 3, + } + /** + * 音频编码方式枚举. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum AudioEncodingFormat { + /** + * 默认 + */ + ENCODING_DEFAULT = 0, + /** + * 无效 + */ + ENCODING_INVALID = 1, + /** + * mp3 + */ + ENCODING_MP3 = 2, + /** + * pcm16bit + */ + ENCODING_PCM_16BIT = 3, + /** + * pcm8bit + */ + ENCODING_PCM_8BIT = 4, + /** + * pcmfloat + */ + ENCODING_PCM_FLOAT = 5, + } + /** + * 音频内容枚举. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum ContentType { + /** + * 电影 + */ + CONTENT_TYPE_MOVIE = 0, + /** + * 音乐 + */ + CONTENT_TYPE_MUSIC = 1, + /** + * 可视化 + */ + CONTENT_TYPE_SONIFICATION = 2, + /** + * 演讲 + */ + CONTENT_TYPE_SPEECH = 3, + /** + * 未知 + */ + CONTENT_TYPE_UNKNOWN = 4, + } + + enum InterruptType { + /** + * 静音 + */ + INTERRUPT_HINT_DUCK = 0, + /** + * 空 + */ + INTERRUPT_HINT_NONE = 1, + /** + * 暂停 + */ + INTERRUPT_HINT_PAUSE = 2, + /** + * 重新开始 + */ + INTERRUPT_HINT_RESUME = 3, + /** + * 停止 + */ + INTERRUPT_HINT_STOP = 4, + /** + * 不静音 + */ + INTERRUPT_HINT_UNDUCK = 5, + /** + * 开始 + */ + INTERRUPT_TYPE_BEGIN = 6, /** - * get the audiomanager of the audio + * 结束 + */ + INTERRUPT_TYPE_END = 7, + } + /** + * Manages audio volume and audio device information. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface AudioManager { + /** + * Sets volume for a stream. This method uses an asynchronous callback to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - function getAudioManager(): AudioManager; - + setVolume(audioType: AudioVolumeType, volume: number,callback: AsyncCallback): void; /** - * the type of audio stream + * Sets volume for a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - enum AudioVolumeType { - /** - * the media stream - */ - MEDIA = 1, - /** - * the ringtone stream - */ - RINGTONE = 2, - } - + setVolume(audioType: AudioVolumeType, volume: number): Promise; /** - * the flag type of device - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum DeviceFlag { - /** - * the device flag of output - */ - OUTPUT_DEVICES_FLAG = 1, - /** - * the device flag of input - */ - INPUT_DEVICES_FLAG = 2, - /** - * the device flag of all devices - */ - ALL_DEVICES_FLAG = 3, - } - /** - * the role of device - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum DeviceRole { - /** - * the role of input devices - */ - INPUT_DEVICE = 1, - /** - * the role of output devices - */ - OUTPUT_DEVICE = 2, - } - /** - * the type of device - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum DeviceType { - /** - * invalid - */ - INVALID = 0, - /** - * speaker - */ - SPEAKER = 1, - /** - * wired headset - */ - WIRED_HEADSET = 2, - /** - * bluetooth sco - */ - BLUETOOTH_SCO = 3, - /** - * bluetooth a2dp - */ - BLUETOOTH_A2DP = 4, - /** - * mic - */ - MIC = 5, - } - /** - * the audiomanager of the audio - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface AudioManager { - /** - * set the volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - setVolume(audioType: AudioVolumeType,volume: number,callback: AsyncCallback): void; - /** - * set the volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - setVolume(audioType: AudioVolumeType,volume: number): Promise; - /** - * get the volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getVolume(audioType: AudioVolumeType, callback: AsyncCallback): void; - /** - * get the volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getVolume(audioType: AudioVolumeType): Promise; - /** - * get the min volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getMinVolume(audioType: AudioVolumeType, callback: AsyncCallback): void - /** - * get the min volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getMinVolume(audioType: AudioVolumeType): Promise; - /** - * get the max volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getMaxVolume(audioType: AudioVolumeType, callback: AsyncCallback): void - /** - * get the max volume of the audiovolumetype - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getMaxVolume(audioType: AudioVolumeType): Promise; - /** - * get the device list of the audio devices by the audio flag - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getDevices(deviceFlag: DeviceFlag, callback: AsyncCallback): void; - /** - * get the device list of the audio devices by the audio flag - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - getDevices(deviceFlag: DeviceFlag): Promise; - } - + * Obtains volume of a stream. This method uses an asynchronous callback to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getVolume(audioType: AudioVolumeType, callback: AsyncCallback): void; /** - * the Descriptor of the device + * Obtains the volume of a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - interface AudioDeviceDescriptor { - /** - * the role of device - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - readonly deviceRole: DeviceRole; - /** - * the type of device - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - readonly deviceType: DeviceType; - } - + getVolume(audioType: AudioVolumeType): Promise; + /** + * Obtains the minimum volume allowed for a stream. This method uses an asynchronous callback to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getMinVolume(audioType: AudioVolumeType, callback: AsyncCallback): void + /** + * Obtains the minimum volume allowed for a stream. This method uses a promise to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getMinVolume(audioType: AudioVolumeType): Promise; + /** + * Obtains the maximum volume allowed for a stream. This method uses an asynchronous callback to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getMaxVolume(audioType: AudioVolumeType, callback: AsyncCallback): void + /** + * Obtains the maximum volume allowed for a stream. This method uses a promise to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getMaxVolume(audioType: AudioVolumeType): Promise; + /** + * Obtains the audio devices of a specified flag. This method uses an asynchronous callback to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getDevices(deviceFlag: DeviceFlag, callback: AsyncCallback): void + /** + * Obtains the audio devices with a specified flag. This method uses a promise to return the execution result. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + getDevices(deviceFlag: DeviceFlag): Promise; + /** + * 回调方式获取铃声模式。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getRingerMode(callback: AsyncCallback): void; + /** + * promise方式获取铃声模式。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getRingerMode(): Promise; + /** + * 设置铃声模式,回调方式返回是否成功。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setRingerMode(mode: AudioRingMode, callback: AsyncCallback): void; + /** + * 设置铃声模式,promise方式返回是否成功。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setRingerMode(mode: AudioRingMode): Promise; + /** + * 获取主输出帧数,回调方式返回帧数。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getMasterOutputFrameCount(callback: AsyncCallback): void; + /** + * 获取主输出帧数,promise方式返回帧数。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getMasterOutputFrameCount(): Promise; + /** + * 获取主输出采样率,回调方式返回采样率。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getMasterOutputSampleRate(callback: AsyncCallback): void; + /** + * 获取主输出采样率,promise方式返回采样率。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getMasterOutputSampleRate(): Promise; + /** + * 判断流是否静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isStreamMute(volumeType: AudioVolumeType, callback: AsyncCallback): void; + /** + * 判断流是否静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isStreamMute(volumeType: AudioVolumeType): Promise; + /** + * 判断流是否激活,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isStreamActive(volumeType: AudioVolumeType, callback: AsyncCallback): void; + /** + * 判断流是否激活,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isStreamActive(volumeType: AudioVolumeType): Promise; + /** + * 判断麦克风是否静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isMicrophoneMute(callback: AsyncCallback): void; + /** + * 判断麦克风是否静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isMicrophoneMute(): Promise; + /** + * 判断主设备是否静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isMasterMute(callback: AsyncCallback): void; //不倾向与实现 + /** + * 判断主设备是否静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isMasterMute(): Promise; //不倾向与实现 + /** + * 设置流静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setStreamMute(volumeType: AudioVolumeType, mute: boolean, callback: AsyncCallback) : void; + /** + * 设置流静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setStreamMute(volumeType: AudioVolumeType, mute: boolean): Promise; + /** + * 设置主设备静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setMasterMute(mute: boolean, callback: AsyncCallback): void; //不倾向与实现 + /** + * 设置主设备静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setMasterMute(mute: boolean): Promise; //不倾向与实现 + /** + * 设置麦克风是否静音,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setMicrophoneMute(isMute: boolean, callback: AsyncCallback): void; + /** + * 设置麦克风是否静音,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setMicrophoneMute(isMute: boolean): Promise; + /** + * 设备是否激活,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isDeviceActive(deviceType: DeviceType, callback: AsyncCallback): void; + /** + * 设备是否激活,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + isDeviceActive(deviceType: DeviceType): Promise; + /** + * 设置设备激活,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setDeviceActive(deviceType: DeviceType, active: boolean, callback: AsyncCallback): void; + /** + * 设置设备激活,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setDeviceActive(deviceType: DeviceType, active: boolean): Promise; + /** + * 连接蓝牙设备,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + connectBluetoothSco(callback: AsyncCallback): void; + /** + * 连接蓝牙设备,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + connectBluetoothSco(): Promise; + /** + * 断开蓝牙设备,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + disconnectBluetoothSco(callback: AsyncCallback): void; + /** + * 断开蓝牙设备,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + disconnectBluetoothSco(): Promise; + /** + * 获取音频参数,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getAudioParameter(key: string, callback: AsyncCallback): void; + /** + * 获取音频参数,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getAudioParameter(key: string): Promise; + /** + * 设置音频参数,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setAudioParameter(key: string, value: string, callback: AsyncCallback): void; + /** + * 设置音频参数,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setAudioParameter(key: string, value: string): Promise; + /** + * 获取打电话状态,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + getCallState(callback: AsyncCallback): void; /** - * the Descriptor list of the devices + * 获取打电话状态,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio * @devices + */ + getCallState(): Promise; + /** + * 设置打电话状态,回调方式返回。 * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setCallState(callState: CallState, callback: AsyncCallback): void; + /** + * 设置打电话状态,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setCallState(callState: CallState): Promise; + /** + * 激活音频中断。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + activateAudioInterrupt(interrupt: AudioInterrupt): void; + /** + * 不激活音频中断。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + deactivateAudioInterrupt(interrupt: AudioInterrupt): void; + /** + * 监听音频中断。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'interrupt', callback: Callback): void; + /** + * 监听错误消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'error', callback: ErrorCallback): void; + /** + * 监听设备变化。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'deviceChange', callback: Callback): void; + } + + /** + * Describes an audio device. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface AudioDeviceDescriptor { + /** + * id + * @devices + */ + id: number; + /** + * 名字 + * @devices + */ + name: string; + /** + * 地址 + * @devices + */ + address: string; + /** + * 采样率 + * @devices + */ + sampleRate: Array; + /** + * 通道数 + * @devices + */ + channelCounts: Array>; + /** + * 通道的mask序列 + * @devices + */ + channelIndexMasks: Array; + /** + * 通道的mask + * @devices + */ + channelMasks: Array; + /** + * 哈希值 + * @devices + */ + hashCode: number; + /** + * 编码方式 + * @devices + */ + encodeFormat: Array; + /** + * Audio device role + * @devices + */ + readonly deviceRole: DeviceRole; + /** + * Audio device type + * @devices + */ + readonly deviceType: DeviceType; + } + /** + * 音频通道的类型 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum ChannelMask { + /** + * mono + */ + CHANNEL_IN_MONO = 0, + /** + * stereo + */ + CHANNEL_IN_STEREO = 1, + /** + * 无效 + */ + CHANNEL_INVALID = 2, + } + /** + * 音频中断。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface AudioInterrupt { + /** + * 音频流类型 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + streamType: AudioVolumeType; + /** + * 音频内容 + * @devices + */ + contentType: ContentType; + /** + * 暂停时是否静音 + * @devices + */ + pauseWhenDucked: boolean; + /** + * 中断类型 + * @devices + */ + streamFlag: InterruptType; + /** + * 音频通道的mask + * @devices + */ + chanelMask: ChannelMask; + /** + * 音频编码方式 + * @devices + */ + encodingFormat: AudioEncodingFormat; + } + + /** + * A queue of AudioDeviceDescriptor, which is read-only. + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + type AudioDeviceDescriptors = Array>; + /** + * 短音类型。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum SoundType { + /** + * 点击 + */ + KEY_CLICK = 0, + /** + * 删除 + */ + KEYPRESS_DELETE = 1, + /** + * 无效 + */ + KEYPRESS_INVALID = 2, + /** + * 返回 + */ + KEYPRESS_RETURN = 3, + /** + * 空格键 + */ + KEYPRESS_SPACEBAR = 4, + /** + * 标准 + */ + KEYPRESS_STANDARD = 5, + /** + * 下 + */ + NAVIGATION_DOWN = 6, + /** + * 左 + */ + NAVIGATION_LEFT = 7, + /** + * 右 + */ + NAVIGATION_RIGHT = 8, + /** + * 上 + */ + NAVIGATION_UP = 9, + } + /** + * 短音播放器。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface SoundPlayer { + /** + * 读取短音,返回id,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSound(path: string, callback: AsyncCallback): void; + /** + * 读取短音,返回id,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSound(path: string): Promise; + /** + * 通过tone读取短音,返回id,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSoundByTone(tone: ToneType, durationMs: number, callback: AsyncCallback): void; + /** + * 通过tone读取短音,返回id,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSoundByTone(tone: ToneType, durationMs: number): Promise; + /** + * 通过流类型读取短音,返回id,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSoundByStream(audioStream: AudioVolumeType, volume: number, callback: AsyncCallback); + /** + * 通过流类型读取短音,返回id,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + loadSoundByStream(audioStream: AudioVolumeType, volume: number): Promise; + /** + * 删除短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + unloadSound(soundId: number); + /** + * 播放短音,回调方式返回id。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + play(soundId: number, options: SoundOptions, callback: AsyncCallback): void; + /** + * 播放短音,回调方式返回id。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + play(soundId: number, callback: AsyncCallback): void; + /** + * 播放短音,promise方式返回id。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + play(soundId: number, options?: SoundOptions): Promise; + /** + * 暂停短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + pause(taskId: number): void; + /** + * 暂停所有短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + pauseAll(): void; + /** + * 重新开始短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + resume(taskId: number): void; + /** + * 重新开始所有短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + resumeAll(): void; + /** + * 停止短音。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + stop(taskId: number): void; + /** + * 设置参数。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + setOptions(taskId: number, options: SoundOptions): void; + /** + * 释放。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + release(): void; + /** + * 监听暂停消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'pause', callback: Callback): void; + /** + * 监听暂停所有消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'pauseAll', callback: Callback): void; + /** + * 监听重新开始消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'resume', callback: Callback): void; + /** + * 监听重新开始所有的消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'resumeAll', callback: Callback): void; + /** + * 监听暂停的消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'stop', callback: Callback): void; + /** + * 监听参数变化的消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'optionsChange', callback: Callback): void; + /** + * 监听完成的消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'complete', callback: Callback): void; + /** + * 监听错误消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'error', callback: ErrorCallback): void; + /** + * 监听释放的消息。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'release', callback: Callback): void; + } + /** + * 短音参数。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface SoundOptions { + /** + * 循环次数 + * @devices + */ + loopNumber: number; + /** + * 速率 + * @devices + */ + speed: number; + /** + * 音量 + * @devices + */ + volumes: SoundVolumes; + /** + * 优先级 + * @devices + */ + priority: number; + } + /** + * 短音音量 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface SoundVolumes { + /** + * 左声道 + * @devices + */ + left: number; + /** + * 右声道 + * @devices + */ + right: number; + } + /** + * tone类型 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum ToneType { + /** + * DTMF_0 + */ + DTMF_0 = 0, + /** + * DTMF_1 + */ + DTMF_1 = 1, + /** + * DTMF_2 + */ + DTMF_2 = 2, + /** + * DTMF_3 + */ + DTMF_3 = 3, + /** + * DTMF_4 + */ + DTMF_4 = 4, + /** + * DTMF_5 + */ + DTMF_5 = 5, + /** + * DTMF_6 + */ + DTMF_6 = 6, + /** + * DTMF_7 + */ + DTMF_7 = 7, + /** + * DTMF_8 + */ + DTMF_8 = 8, + /** + * DTMF_9 + */ + DTMF_9 = 9, + /** + * DTMF_A + */ + DTMF_A = 10, + /** + * DTMF_B + */ + DTMF_B = 11, + /** + * DTMF_C + */ + DTMF_C = 12, + /** + * DTMF_D + */ + DTMF_D = 13, + /** + * DTMF_P + */ + DTMF_P = 14, + /** + * DTMF_S + */ + DTMF_S = 15, + /** + * PROP_PROMPT + */ + PROP_PROMPT = 16, + /** + * SUP_CALL_WAITING + */ + SUP_CALL_WAITING = 17, + } + /** + * tone描述 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface ToneDescriptor { + /** + * tone类型 + * @devices + */ + toneType: ToneType; + /** + * 高频 + * @devices + */ + highFrequency: number; + /** + * 低频 + * @devices + */ + lowFrequency: number; + } + /** + * 声音特效模式。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum SoundEffectMode { + /** + * 辅助 + */ + SOUND_EFFECT_MODE_AUXILIARY = 0, + /** + * 插入 + */ + SOUND_EFFECT_MODE_INSERT = 1, + /** + * 待加工 + */ + SOUND_EFFECT_MODE_PRE_PROCESSING = 2, + } + /** + * 声音特效类型。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum SoundEffectType { + /** + * AE + */ + SOUND_EFFECT_TYPE_AE = 0, + /** + * EC + */ + SOUND_EFFECT_TYPE_EC = 1, + /** + * GC + */ + SOUND_EFFECT_TYPE_GC = 2, + /** + * 无效 + */ + SOUND_EFFECT_TYPE_INVALID = 3, + /** + * NS + */ + SOUND_EFFECT_TYPE_NS = 4, + } + /** + * 声音特效衍生类型。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + enum SoundEffectDerivative { + /** + * GAIN_CONTRAL_EFFECT + */ + GAIN_CONTRAL_EFFECT = 0, + /** + * ECHO_CANCELER_EFFECT + */ + ECHO_CANCELER_EFFECT = 1, + /** + * NOISE_SUPPRESSOR_EFFECT + */ + NOISE_SUPPRESSOR_EFFECT = 2, + } + /** + * 声音特效创建器。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface SoundEffectBuilder { + /** + * 获取可创建的声音特效,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + acquireEffects(callback: AsyncCallback>): void; + /** + * 获取可创建的声音特效,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + acquireEffects(): Promise>; + /** + * 创建声音特效,回调方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + create(options: EffectOptions, callback: AsyncCallback): void; + /** + * 创建声音特效,promise方式返回。 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + create(options: EffectOptions): Promise; + } + /** + * 声音特效。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface SoundEffect { + /** + * 特效音模式 + * @devices + */ + mode: SoundEffectMode; + /** + * 名字 + * @devices + */ + name: string; + /** + * 类型 + * @devices + */ + type: SoundEffectType; + /** + * 衍生类型 + * @devices + */ + deriveType: SoundEffectDerivative; + /** + * uid + * @devices + */ + uid: string; + /** + * 激活 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + active(): void; + /** + * 停止 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + deactive(): void; + /** + * 释放 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + release(): void; + /** + * 监听激活的消息 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'active', callback: Callback): void; + /** + * 监听停止的消息 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'deactive', callback: Callback): void; + /** + * 监听释放的消息 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'release', callback: Callback): void; + /** + * 监听错误消息 + * @sysCap SystemCapability.Multimedia.Audio + * @devices + */ + on(type: 'error', callback: ErrorCallback): void; + } + /** + * 声音特效信息。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface EffectInfo { + /** + * 衍生类型 + * @devices + */ + deriveType: SoundEffectDerivative; + /** + * 是否可获取 + * @devices + */ + isAvailable: boolean; + } + /** + * 声音特效选项。 + * @devices + * @sysCap SystemCapability.Multimedia.Audio + */ + interface EffectOptions { + /** + * 衍生类型 + * @devices + */ + deriveType: SoundEffectDerivative + /** + * 音频播放器 + * @devices + */ + audioPlayer?: AudioPlayer; + /** + * 视频播放器 + * @devices + */ + videoPlayer?: VideoPlayer; + /** + * 包名 + * @devices */ - type AudioDeviceDescriptors = Array>; + pkgName: string; + } } export default audio; \ No newline at end of file diff --git a/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h b/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h old mode 100755 new mode 100644 index 54e25d7b78..af973338e9 --- a/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h +++ b/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h @@ -22,10 +22,15 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" +namespace OHOS { +namespace AudioStandard { static const std::string AUDIO_DEVICE_DESCRIPTOR_NAPI_CLASS_NAME = "AudioDeviceDescriptor"; class AudioDeviceDescriptorNapi { public: + AudioDeviceDescriptorNapi(); + ~AudioDeviceDescriptorNapi(); + enum DeviceType { INVALID = 0, SPEAKER = 1, @@ -42,22 +47,21 @@ public: static napi_value Init(napi_env env, napi_value exports); static napi_value CreateAudioDeviceDescriptorWrapper(napi_env env, - OHOS::sptr audioDeviceDescriptor); + sptr deviceDescriptor); private: - explicit AudioDeviceDescriptorNapi(); - ~AudioDeviceDescriptorNapi(); - static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); static napi_value Construct(napi_env env, napi_callback_info info); static napi_value GetDeviceRole(napi_env env, napi_callback_info info); static napi_value GetDeviceType(napi_env env, napi_callback_info info); static napi_ref sConstructor_; - static OHOS::sptr sAudioDescriptor_; + static sptr sAudioDescriptor_; - OHOS::sptr audioDescriptor_; + sptr audioDescriptor_; napi_env env_; napi_ref wrapper_; }; +} // namespace AudioStandard +} // namespace OHOS #endif /* AUDIO_DEVICE_DESCRIPTOR_NAPI_H_ */ diff --git a/interfaces/kits/js/audio_manager/include/audio_manager_napi.h b/interfaces/kits/js/audio_manager/include/audio_manager_napi.h old mode 100755 new mode 100644 index 39bf7f028f..9976ea3f98 --- a/interfaces/kits/js/audio_manager/include/audio_manager_napi.h +++ b/interfaces/kits/js/audio_manager/include/audio_manager_napi.h @@ -18,14 +18,19 @@ #include #include -#include "audio_svc_manager.h" +#include "audio_system_manager.h" #include "napi/native_api.h" #include "napi/native_node_api.h" +namespace OHOS { +namespace AudioStandard { static const std::string AUDIO_MNGR_NAPI_CLASS_NAME = "AudioManager"; class AudioManagerNapi { public: + AudioManagerNapi(); + ~AudioManagerNapi(); + enum AudioVolumeType { MEDIA = 1, RINGTONE = 2 @@ -40,9 +45,6 @@ public: static napi_value Init(napi_env env, napi_value exports); private: - explicit AudioManagerNapi(); - ~AudioManagerNapi(); - static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); static napi_value Construct(napi_env env, napi_callback_info info); static napi_value CreateAudioManagerWrapper(napi_env env); @@ -52,21 +54,36 @@ private: static napi_value GetMaxVolume(napi_env env, napi_callback_info info); static napi_value GetMinVolume(napi_env env, napi_callback_info info); static napi_value GetDevices(napi_env env, napi_callback_info info); + static napi_value SetStreamMute(napi_env env, napi_callback_info info); + static napi_value IsStreamMute(napi_env env, napi_callback_info info); + static napi_value IsStreamActive(napi_env env, napi_callback_info info); + static napi_value SetRingerMode(napi_env env, napi_callback_info info); + static napi_value GetRingerMode(napi_env env, napi_callback_info info); + static napi_value SetDeviceActive(napi_env env, napi_callback_info info); + static napi_value IsDeviceActive(napi_env env, napi_callback_info info); + static napi_value SetAudioParameter(napi_env env, napi_callback_info info); + static napi_value GetAudioParameter(napi_env env, napi_callback_info info); + static napi_value SetMicrophoneMute(napi_env env, napi_callback_info info); + static napi_value IsMicrophoneMute(napi_env env, napi_callback_info info); - static napi_status AddNamedProperty(napi_env env, napi_value object, const char *name, int32_t enumValue); + static napi_status AddNamedProperty(napi_env env, napi_value object, const std::string name, int32_t enumValue); static napi_value CreateAudioVolumeTypeObject(napi_env env); static napi_value CreateDeviceFlagObject(napi_env env); static napi_value CreateDeviceRoleObject(napi_env env); static napi_value CreateDeviceTypeObject(napi_env env); + static napi_value CreateAudioRingModeObject(napi_env env); static napi_ref sConstructor_; static napi_ref audioVolumeTypeRef_; static napi_ref deviceFlagRef_; static napi_ref deviceRoleRef_; static napi_ref deviceTypeRef_; + static napi_ref audioRingModeRef_; - OHOS::AudioSvcManager *audioMngr_; + AudioSystemManager *audioMngr_; napi_env env_; napi_ref wrapper_; }; +} // namespace AudioStandard +} // namespace OHOS #endif /* AUDIO_MNGR_NAPI_H_ */ diff --git a/libsnd/BUILD.gn b/libsnd/BUILD.gn new file mode 100644 index 0000000000..300fd6e360 --- /dev/null +++ b/libsnd/BUILD.gn @@ -0,0 +1,132 @@ +import("//build/ohos.gni") + +libsndfile_dir = "//third_party/libsnd" +libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" + +config("sndfile_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$libsndfile_dir/src", + "$libsndfile_dir/include", + "$libsndfile_build_path/include", + "$libsndfile_dir/src/GSM610", + "$libsndfile_dir/src/G72x", + "$libsndfile_dir/src/ALAC", + ] + + cflags = [ + "-Wall", + "-Werror", + ] +} + +ohos_source_set("sndfile_sources") { + sources = [ + "$libsndfile_dir/src/common.c", + "$libsndfile_dir/src/file_io.c", + "$libsndfile_dir/src/command.c", + "$libsndfile_dir/src/pcm.c", + "$libsndfile_dir/src/ulaw.c", + "$libsndfile_dir/src/alaw.c", + "$libsndfile_dir/src/float32.c", + "$libsndfile_dir/src/double64.c", + "$libsndfile_dir/src/ima_adpcm.c", + "$libsndfile_dir/src/ms_adpcm.c", + "$libsndfile_dir/src/gsm610.c", + "$libsndfile_dir/src/dwvw.c", + "$libsndfile_dir/src/vox_adpcm.c", + "$libsndfile_dir/src/interleave.c", + "$libsndfile_dir/src/strings.c", + "$libsndfile_dir/src/dither.c", + "$libsndfile_dir/src/cart.c", + "$libsndfile_dir/src/broadcast.c", + "$libsndfile_dir/src/audio_detect.c", + "$libsndfile_dir/src/ima_oki_adpcm.c", + "$libsndfile_dir/src/alac.c", + "$libsndfile_dir/src/chunk.c", + "$libsndfile_dir/src/ogg.c", + "$libsndfile_dir/src/chanmap.c", + "$libsndfile_dir/src/id3.c", + "$libsndfile_dir/src/sndfile.c", + "$libsndfile_dir/src/aiff.c", + "$libsndfile_dir/src/au.c", + "$libsndfile_dir/src/avr.c", + "$libsndfile_dir/src/caf.c", + "$libsndfile_dir/src/dwd.c", + "$libsndfile_dir/src/flac.c", + "$libsndfile_dir/src/g72x.c", + "$libsndfile_dir/src/htk.c", + "$libsndfile_dir/src/ircam.c", + "$libsndfile_dir/src/macos.c", + "$libsndfile_dir/src/mat4.c", + "$libsndfile_dir/src/mat5.c", + "$libsndfile_dir/src/nist.c", + "$libsndfile_dir/src/paf.c", + "$libsndfile_dir/src/pvf.c", + "$libsndfile_dir/src/raw.c", + "$libsndfile_dir/src/rx2.c", + "$libsndfile_dir/src/sd2.c", + "$libsndfile_dir/src/sds.c", + "$libsndfile_dir/src/svx.c", + "$libsndfile_dir/src/txw.c", + "$libsndfile_dir/src/voc.c", + "$libsndfile_dir/src/wve.c", + "$libsndfile_dir/src/w64.c", + "$libsndfile_dir/src/wavlike.c", + "$libsndfile_dir/src/wav.c", + "$libsndfile_dir/src/xi.c", + "$libsndfile_dir/src/mpc2k.c", + "$libsndfile_dir/src/rf64.c", + "$libsndfile_dir/src/ogg_vorbis.c", + "$libsndfile_dir/src/ogg_speex.c", + "$libsndfile_dir/src/ogg_pcm.c", + "$libsndfile_dir/src/ogg_opus.c", + "$libsndfile_dir/src/ogg_vcomment.c", + "$libsndfile_dir/src/nms_adpcm.c", + #"$libsndfile_dir/src/mpeg.c", + #"$libsndfile_dir/src/mpeg_decode.c", + #"$libsndfile_dir/src/mpeg_l3_encode.c", + "$libsndfile_dir/src/GSM610/add.c", + "$libsndfile_dir/src/GSM610/code.c", + "$libsndfile_dir/src/GSM610/decode.c", + "$libsndfile_dir/src/GSM610/gsm_create.c", + "$libsndfile_dir/src/GSM610/gsm_decode.c", + "$libsndfile_dir/src/GSM610/gsm_destroy.c", + "$libsndfile_dir/src/GSM610/gsm_encode.c", + "$libsndfile_dir/src/GSM610/gsm_option.c", + "$libsndfile_dir/src/GSM610/long_term.c", + "$libsndfile_dir/src/GSM610/lpc.c", + "$libsndfile_dir/src/GSM610/preprocess.c", + "$libsndfile_dir/src/GSM610/rpe.c", + "$libsndfile_dir/src/GSM610/short_term.c", + "$libsndfile_dir/src/GSM610/table.c", + "$libsndfile_dir/src/G72x/g721.c", + "$libsndfile_dir/src/G72x/g723_16.c", + "$libsndfile_dir/src/G72x/g723_24.c", + "$libsndfile_dir/src/G72x/g723_40.c", + "$libsndfile_dir/src/G72x/g72x.c", + "$libsndfile_dir/src/ALAC/ALACBitUtilities.c", + "$libsndfile_dir/src/ALAC/ag_dec.c", + "$libsndfile_dir/src/ALAC/ag_enc.c", + "$libsndfile_dir/src/ALAC/dp_dec.c", + "$libsndfile_dir/src/ALAC/dp_enc.c", + "$libsndfile_dir/src/ALAC/matrix_dec.c", + "$libsndfile_dir/src/ALAC/matrix_enc.c", + "$libsndfile_dir/src/ALAC/alac_decoder.c", + "$libsndfile_dir/src/ALAC/alac_encoder.c", + ] + + configs = [ + ":sndfile_config", + ] +} + +ohos_shared_library("sndfile") { + deps = [ + ":sndfile_sources", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/libsnd/include/config.h b/libsnd/include/config.h new file mode 100644 index 0000000000..a3856c9658 --- /dev/null +++ b/libsnd/include/config.h @@ -0,0 +1,320 @@ +/* Set to 1 if the compile is GNU GCC. */ +#define COMPILER_IS_GCC 1 + +/* Target processor clips on negative float to int conversion. */ +#define CPU_CLIPS_NEGATIVE 0 + +/* Target processor clips on positive float to int conversion. */ +#define CPU_CLIPS_POSITIVE 0 + +/* Target processor is big endian. */ +#define CPU_IS_BIG_ENDIAN 0 + +/* Target processor is little endian. */ +#define CPU_IS_LITTLE_ENDIAN 1 + +/* Set to 1 to enable experimental code. */ +#define ENABLE_EXPERIMENTAL_CODE 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_ALSA_ASOUNDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_BYTESWAP_H 1 + +/* Define to 1 if you have the `calloc' function. */ +#define HAVE_CALLOC 0 + +/* Define to 1 if you have the `ceil' function. */ +#define HAVE_CEIL 0 + +/* Set to 1 if S_IRGRP is defined. */ +#define HAVE_DECL_S_IRGRP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Will be set to 1 if flac, ogg and vorbis are available. */ +#define HAVE_EXTERNAL_XIPH_LIBS 0 + +/* Will be set to 1 if lame and mpg123 are available. */ +#define HAVE_MPEG 0 + +/* Define to 1 if you have the `floor' function. */ +#define HAVE_FLOOR 0 + +/* Define to 1 if you have the `fmod' function. */ +#define HAVE_FMOD 0 + +/* Define to 1 if you have the `free' function. */ +#define HAVE_FREE 0 + +/* Define to 1 if you have the `fstat' function. */ +#define HAVE_FSTAT 1 + +/* Define to 1 if you have the `fstat64' function. */ +#define HAVE_FSTAT64 1 + +/* Define to 1 if you have the `fsync' function. */ +#define HAVE_FSYNC 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 0 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the `gmtime' function. */ +#define HAVE_GMTIME + +/* Define if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you have the `localtime' function. */ +#define HAVE_LOCALTIME + +/* Define if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R + +/* Define if you have C99's lrint function. */ +#define HAVE_LRINT 1 + +/* Define if you have C99's lrintf function. */ +#define HAVE_LRINTF 1 + +/* Define to 1 if you have the `lround' function. */ +#define HAVE_LROUND 0 + +/* Define to 1 if you have the `lseek' function. */ +#define HAVE_LSEEK 1 + +/* Define to 1 if you have the `lseek64' function. */ +#define HAVE_LSEEK64 0 + +/* Define to 1 if you have the `malloc' function. */ +#define HAVE_MALLOC 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 0 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 0 + +/* Define to 1 if you have the `open' function. */ +#define HAVE_OPEN 1 + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `read' function. */ +#define HAVE_READ 1 + +/* Define to 1 if you have the `realloc' function. */ +#define HAVE_REALLOC 0 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Set to 1 if is available. */ +#define HAVE_SNDIO_H 0 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 0 + +/* Set to 1 if you have libsqlite3. */ +#define HAVE_SQLITE3 1 + +/* Define to 1 if the system has the type `ssize_t'. */ +#define HAVE_SSIZE_T 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IMMINTRIN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 0 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if you have the `write' function. */ +#define HAVE_WRITE 1 + +/* The darwin version, no-zero is valid */ +#define OSX_DARWIN_VERSION 0 + +/* Set to 1 if compiling for OpenBSD */ +#define OS_IS_OPENBSD 0 + +/* Set to 1 if compiling for Win32 */ +#define OS_IS_WIN32 0 + +/* Set to 1 if SSE2 is enabled */ +/* #undef USE_SSE2 */ + +/* Name of package */ +#define PACKAGE "libsndfile" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libsndfile" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libsndfile 1.0.31" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libsndfile" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0.31" + +/* Set to maximum allowed value of sf_count_t type. */ +#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL + +/* The size of `double', as computed by sizeof. */ + + +/* The size of `float', as computed by sizeof. */ + + +/* The size of `int', as computed by sizeof. */ + + +/* The size of `int64_t', as computed by sizeof. */ +#define SIZEOF_INT64_T 8 + +/* The size of `loff_t', as computed by sizeof. */ + + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `off64_t', as computed by sizeof. */ + + +/* The size of `off_t', as computed by sizeof. */ +#define SIZEOF_OFF_T 8 + +/* Set to sizeof (long) if unknown. */ +#define SIZEOF_SF_COUNT_T 8 + +/* The size of `short', as computed by sizeof. */ + + +/* The size of `size_t', as computed by sizeof. */ + + +/* The size of `ssize_t', as computed by sizeof. */ +#define SIZEOF_SSIZE_T 8 + +/* The size of `void*', as computed by sizeof. */ + + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 4 + +/* Set to long if unknown. */ +#define TYPEOF_SF_COUNT_T int64_t + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Set to 1 to use the native windows API */ +#define USE_WINDOWS_API 0 + +/* Version number of package */ +#define VERSION "1.0.31" + +/* Set to 1 if windows DLL is being built. */ +#define WIN32_TARGET_DLL 0 + +/* Target processor is big endian. */ +#define WORDS_BIGENDIAN 0 + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Define to 1 if on MINIX. */ +#define _MINIX 0 + +/* Define as `__inline' or '__inline__' if that's what the C compiler calls it, or to nothing if it is not supported. */ +/* #undef inline */ diff --git a/libsnd/include/sndfile.h b/libsnd/include/sndfile.h new file mode 100755 index 0000000000..f0e65010e7 --- /dev/null +++ b/libsnd/include/sndfile.h @@ -0,0 +1,817 @@ +/* + * Copyright (C) 1999-2016 Erik de Castro Lopo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* + * sndfile.h -- system-wide definitions + * + * API documentation is in the doc/ directory of the source code tarball + * and at http://libsndfile.github.io/libsndfile/api.html. +*/ + +#ifndef SNDFILE_H +#define SNDFILE_H + +/* This is the version 1.0.X header file. */ +#define SNDFILE_1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* The following file types can be read and written. + * A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise + * ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and + * SF_FORMAT_SUBMASK can be used to separate the major and minor file + * types. +*/ + +enum { + /* Major formats. */ + SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */ + SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */ + SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */ + SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */ + SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */ + SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */ + SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */ + SF_FORMAT_VOC = 0x080000, /* VOC files. */ + SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */ + SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */ + SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */ + SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */ + SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */ + SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */ + SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */ + SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */ + SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */ + SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */ + SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */ + SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */ + SF_FORMAT_CAF = 0x180000, /* Core Audio File format */ + SF_FORMAT_WVE = 0x190000, /* Psion WVE format */ + SF_FORMAT_OGG = 0x200000, /* Xiph OGG container */ + SF_FORMAT_MPC2K = 0x210000, /* Akai MPC 2000 sampler */ + SF_FORMAT_RF64 = 0x220000, /* RF64 WAV file */ + SF_FORMAT_MPEG = 0x230000, /* MPEG-1/2 audio stream */ + /* Subtypes from here on. */ + SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */ + SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */ + SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */ + SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */ + SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */ + SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */ + SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */ + SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */ + SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */ + SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */ + SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */ + SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */ + SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */ + SF_FORMAT_NMS_ADPCM_16 = 0x0022, /* 16kbs NMS G721-variant encoding. */ + SF_FORMAT_NMS_ADPCM_24 = 0x0023, /* 24kbs NMS G721-variant encoding. */ + SF_FORMAT_NMS_ADPCM_32 = 0x0024, /* 32kbs NMS G721-variant encoding. */ + SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */ + SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */ + SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */ + SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */ + SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */ + SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */ + SF_FORMAT_VORBIS = 0x0060, /* Xiph Vorbis encoding. */ + SF_FORMAT_OPUS = 0x0064, /* Xiph/Skype Opus encoding. */ + SF_FORMAT_ALAC_16 = 0x0070, /* Apple Lossless Audio Codec (16 bit). */ + SF_FORMAT_ALAC_20 = 0x0071, /* Apple Lossless Audio Codec (20 bit). */ + SF_FORMAT_ALAC_24 = 0x0072, /* Apple Lossless Audio Codec (24 bit). */ + SF_FORMAT_ALAC_32 = 0x0073, /* Apple Lossless Audio Codec (32 bit). */ + SF_FORMAT_MPEG_LAYER_I = 0x0080, /* MPEG-1 Audio Layer I */ + SF_FORMAT_MPEG_LAYER_II = 0x0081, /* MPEG-1 Audio Layer II */ + SF_FORMAT_MPEG_LAYER_III = 0x0082, /* MPEG-2 Audio Layer III */ + /* Endian-ness options. */ + SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */ + SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */ + SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */ + SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */ + SF_FORMAT_SUBMASK = 0x0000FFFF, + SF_FORMAT_TYPEMASK = 0x0FFF0000, + SF_FORMAT_ENDMASK = 0x30000000 +}; + +/* + * The following are the valid command numbers for the sf_command() + * interface. The use of these commands is documented in the file + * command.html in the doc directory of the source code distribution. +*/ +enum { + SFC_GET_LIB_VERSION = 0x1000, + SFC_GET_LOG_INFO = 0x1001, + SFC_GET_CURRENT_SF_INFO = 0x1002, + SFC_GET_NORM_DOUBLE = 0x1010, + SFC_GET_NORM_FLOAT = 0x1011, + SFC_SET_NORM_DOUBLE = 0x1012, + SFC_SET_NORM_FLOAT = 0x1013, + SFC_SET_SCALE_FLOAT_INT_READ = 0x1014, + SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015, + SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020, + SFC_GET_SIMPLE_FORMAT = 0x1021, + SFC_GET_FORMAT_INFO = 0x1028, + SFC_GET_FORMAT_MAJOR_COUNT = 0x1030, + SFC_GET_FORMAT_MAJOR = 0x1031, + SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032, + SFC_GET_FORMAT_SUBTYPE = 0x1033, + SFC_CALC_SIGNAL_MAX = 0x1040, + SFC_CALC_NORM_SIGNAL_MAX = 0x1041, + SFC_CALC_MAX_ALL_CHANNELS = 0x1042, + SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043, + SFC_GET_SIGNAL_MAX = 0x1044, + SFC_GET_MAX_ALL_CHANNELS = 0x1045, + SFC_SET_ADD_PEAK_CHUNK = 0x1050, + SFC_UPDATE_HEADER_NOW = 0x1060, + SFC_SET_UPDATE_HEADER_AUTO = 0x1061, + SFC_FILE_TRUNCATE = 0x1080, + SFC_SET_RAW_START_OFFSET = 0x1090, + /* Commands reserved for dithering, which is not implemented. */ + SFC_SET_DITHER_ON_WRITE = 0x10A0, + SFC_SET_DITHER_ON_READ = 0x10A1, + SFC_GET_DITHER_INFO_COUNT = 0x10A2, + SFC_GET_DITHER_INFO = 0x10A3, + SFC_GET_EMBED_FILE_INFO = 0x10B0, + SFC_SET_CLIPPING = 0x10C0, + SFC_GET_CLIPPING = 0x10C1, + SFC_GET_CUE_COUNT = 0x10CD, + SFC_GET_CUE = 0x10CE, + SFC_SET_CUE = 0x10CF, + SFC_GET_INSTRUMENT = 0x10D0, + SFC_SET_INSTRUMENT = 0x10D1, + SFC_GET_LOOP_INFO = 0x10E0, + SFC_GET_BROADCAST_INFO = 0x10F0, + SFC_SET_BROADCAST_INFO = 0x10F1, + SFC_GET_CHANNEL_MAP_INFO = 0x1100, + SFC_SET_CHANNEL_MAP_INFO = 0x1101, + SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110, + /* Support for Wavex Ambisonics Format */ + SFC_WAVEX_SET_AMBISONIC = 0x1200, + SFC_WAVEX_GET_AMBISONIC = 0x1201, + /* + * RF64 files can be set so that on-close, writable files that have less + * than 4GB of data in them are converted to RIFF/WAV, as per EBU + * recommendations. + */ + SFC_RF64_AUTO_DOWNGRADE = 0x1210, + SFC_SET_VBR_ENCODING_QUALITY = 0x1300, + SFC_SET_COMPRESSION_LEVEL = 0x1301, + SFC_SET_OGG_PAGE_LATENCY_MS = 0x1302, + SFC_SET_OGG_PAGE_LATENCY = 0x1303, + SFC_GET_BITRATE_MODE = 0x1302, + SFC_SET_BITRATE_MODE = 0x1303, + /* Cart Chunk support */ + SFC_SET_CART_INFO = 0x1400, + SFC_GET_CART_INFO = 0x1401, + /* Opus files original samplerate metadata */ + SFC_SET_ORIGINAL_SAMPLERATE = 0x1500, + SFC_GET_ORIGINAL_SAMPLERATE = 0x1501, + /* Following commands for testing only. */ + SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001, + /* + * These SFC_SET_ADD_* values are deprecated and will disappear at some + * time in the future. They are guaranteed to be here up to and + * including version 1.0.8 to avoid breakage of existing software. + * They currently do nothing and will continue to do nothing. + */ + SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051, + SFC_SET_ADD_DITHER_ON_WRITE = 0x1070, + SFC_SET_ADD_DITHER_ON_READ = 0x1071 +}; + + /* + * String types that can be set and read from files. Not all file types + * support this and even the file types which support one, may not support + * all string types. + */ +enum { + SF_STR_TITLE = 0x01, + SF_STR_COPYRIGHT = 0x02, + SF_STR_SOFTWARE = 0x03, + SF_STR_ARTIST = 0x04, + SF_STR_COMMENT = 0x05, + SF_STR_DATE = 0x06, + SF_STR_ALBUM = 0x07, + SF_STR_LICENSE = 0x08, + SF_STR_TRACKNUMBER = 0x09, + SF_STR_GENRE = 0x10 +}; + +/* + * Use the following as the start and end index when doing metadata + * transcoding. +*/ + +#define SF_STR_FIRST SF_STR_TITLE +#define SF_STR_LAST SF_STR_GENRE + +enum { + /* True and false */ + SF_FALSE = 0, + SF_TRUE = 1, + /* Modes for opening files. */ + SFM_READ = 0x10, + SFM_WRITE = 0x20, + SFM_RDWR = 0x30, + + SF_AMBISONIC_NONE = 0x40, + SF_AMBISONIC_B_FORMAT = 0x41 +}; + +/* Public error values. These are guaranteed to remain unchanged for the duration + * of the library major version number. + * There are also a large number of private error numbers which are internal to + * the library which can change at any time. +*/ + +enum { + SF_ERR_NO_ERROR = 0, + SF_ERR_UNRECOGNISED_FORMAT = 1, + SF_ERR_SYSTEM = 2, + SF_ERR_MALFORMED_FILE = 3, + SF_ERR_UNSUPPORTED_ENCODING = 4 +}; + + +/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP). +*/ + +enum { + SF_CHANNEL_MAP_INVALID = 0, + SF_CHANNEL_MAP_MONO = 1, + SF_CHANNEL_MAP_LEFT, /* Apple calls this 'Left' */ + SF_CHANNEL_MAP_RIGHT, /* Apple calls this 'Right' */ + SF_CHANNEL_MAP_CENTER, /* Apple calls this 'Center' */ + SF_CHANNEL_MAP_FRONT_LEFT, + SF_CHANNEL_MAP_FRONT_RIGHT, + SF_CHANNEL_MAP_FRONT_CENTER, + SF_CHANNEL_MAP_REAR_CENTER, /* Apple calls this 'Center Surround', Msft calls this 'Back Center' */ + SF_CHANNEL_MAP_REAR_LEFT, /* Apple calls this 'Left Surround', Msft calls this 'Back Left' */ + SF_CHANNEL_MAP_REAR_RIGHT, /* Apple calls this 'Right Surround', Msft calls this 'Back Right' */ + SF_CHANNEL_MAP_LFE, /* Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' */ + SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, /* Apple calls this 'Left Center' */ + SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, /* Apple calls this 'Right Center */ + SF_CHANNEL_MAP_SIDE_LEFT, /* Apple calls this 'Left Surround Direct' */ + SF_CHANNEL_MAP_SIDE_RIGHT, /* Apple calls this 'Right Surround Direct' */ + SF_CHANNEL_MAP_TOP_CENTER, /* Apple calls this 'Top Center Surround' */ + SF_CHANNEL_MAP_TOP_FRONT_LEFT, /* Apple calls this 'Vertical Height Left' */ + SF_CHANNEL_MAP_TOP_FRONT_RIGHT, /* Apple calls this 'Vertical Height Right' */ + SF_CHANNEL_MAP_TOP_FRONT_CENTER, /* Apple calls this 'Vertical Height Center' */ + SF_CHANNEL_MAP_TOP_REAR_LEFT, /* Apple and MS call this 'Top Back Left' */ + SF_CHANNEL_MAP_TOP_REAR_RIGHT, /* Apple and MS call this 'Top Back Right' */ + SF_CHANNEL_MAP_TOP_REAR_CENTER, /* Apple and MS call this 'Top Back Center' */ + SF_CHANNEL_MAP_AMBISONIC_B_W, + SF_CHANNEL_MAP_AMBISONIC_B_X, + SF_CHANNEL_MAP_AMBISONIC_B_Y, + SF_CHANNEL_MAP_AMBISONIC_B_Z, + SF_CHANNEL_MAP_MAX +}; + +/* Bitrate mode values (for use with SFC_GET/SET_BITRATE_MODE) +*/ +enum { + SF_BITRATE_MODE_CONSTANT = 0, + SF_BITRATE_MODE_AVERAGE, + SF_BITRATE_MODE_VARIABLE +}; + + +/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */ + +typedef struct sf_private_tag SNDFILE; + +/* The following typedef is system specific and is defined when libsndfile is + * compiled. sf_count_t will be a 64 bit value when the underlying OS allows + * 64 bit file offsets. + * On windows, we need to allow the same header file to be compiler by both GCC + * and the Microsoft compiler. +*/ + +typedef int64_t sf_count_t; +#ifndef SF_COUNT_MAX +#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL +#endif + + +/* A pointer to a SF_INFO structure is passed to sf_open () and filled in. + * On write, the SF_INFO structure is filled in by the user and passed into + * sf_open (). +*/ + +struct SF_INFO { + sf_count_t frames; /* Used to be called samples. Changed to avoid confusion. */ + int samplerate; + int channels; + int format; + int sections; + int seekable; +}; + +typedef struct SF_INFO SF_INFO; + +/* The SF_FORMAT_INFO struct is used to retrieve information about the sound + * file formats libsndfile supports using the sf_command () interface. + * + * Using this interface will allow applications to support new file formats + * and encoding types when libsndfile is upgraded, without requiring + * re-compilation of the application. + * + * Please consult the libsndfile documentation (particularly the information + * on the sf_command () interface) for examples of its use. +*/ + +typedef struct { + int format; + const char *name; + const char *extension; +} SF_FORMAT_INFO; + +/* + * Enums and typedefs for adding dither on read and write. + * Reserved for future implementation. +*/ + +enum { + SFD_DEFAULT_LEVEL = 0, + SFD_CUSTOM_LEVEL = 0x40000000, + SFD_NO_DITHER = 500, + SFD_WHITE = 501, + SFD_TRIANGULAR_PDF = 502 +}; + +typedef struct { + int type; + double level; + const char *name; +} SF_DITHER_INFO; + + /* Struct used to retrieve information about a file embedded within a + * larger file. See SFC_GET_EMBED_FILE_INFO. + */ + +typedef struct { + sf_count_t offset; + sf_count_t length; +} SF_EMBED_FILE_INFO; + +/* + * Struct used to retrieve cue marker information from a file +*/ + +typedef struct { + int32_t indx; + uint32_t position; + int32_t fcc_chunk; + int32_t chunk_start; + int32_t block_start; + uint32_t sample_offset; + char name [256]; +} SF_CUE_POINT; + +#define SF_CUES_VAR(count) \ + struct \ + { \ + uint32_t cue_count; \ + SF_CUE_POINT cue_points [count]; \ + } + +typedef SF_CUES_VAR (100) SF_CUES; + +/* + * Structs used to retrieve music sample information from a file. +*/ + +enum { + /* + * The loop mode field in SF_INSTRUMENT will be one of the following. + */ + SF_LOOP_NONE = 800, + SF_LOOP_FORWARD, + SF_LOOP_BACKWARD, + SF_LOOP_ALTERNATING +}; + +typedef struct { + int gain; + char basenote, detune; + char velocity_lo, velocity_hi; + char key_lo, key_hi; + int loop_count; + + struct { + int mode; + uint32_t start; + uint32_t end; + uint32_t count; + } loops [16]; /* make variable in a sensible way */ +} SF_INSTRUMENT; + +/* Struct used to retrieve loop information from a file. */ +typedef struct { + short time_sig_num; /* any positive integer > 0 */ + short time_sig_den; /* any positive power of 2 > 0 */ + int loop_mode; /* see SF_LOOP enum */ + + int num_beats; /* this is NOT the amount of quarter notes !!! */ + /* a full bar of 4/4 is 4 beats */ + /* a full bar of 7/8 is 7 beats */ + + float bpm; /* suggestion, as it can be calculated using other fields: */ + /* file's length, file's sampleRate and our time_sig_den */ + /* -> bpms are always the amount of _quarter notes_ per minute */ + + int root_key; /* MIDI note, or -1 for None */ + int future [6]; +} SF_LOOP_INFO; + + +/* Struct used to retrieve broadcast (EBU) information from a file. + * Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE. +*/ +#define SF_BROADCAST_INFO_VAR(coding_hist_size) \ + struct \ + { \ + char description [256]; \ + char originator [32]; \ + char originator_reference [32]; \ + char origination_date [10]; \ + char origination_time [8]; \ + uint32_t time_reference_low; \ + uint32_t time_reference_high; \ + short version; \ + char umid [64]; \ + int16_t loudness_value; \ + int16_t loudness_range; \ + int16_t max_true_peak_level; \ + int16_t max_momentary_loudness; \ + int16_t max_shortterm_loudness; \ + char reserved [180]; \ + uint32_t coding_history_size; \ + char coding_history [coding_hist_size]; \ + } + +/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */ +typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO; + +struct SF_CART_TIMER { + char usage [4]; + int32_t value; +}; + +typedef struct SF_CART_TIMER SF_CART_TIMER; + +#define SF_CART_INFO_VAR(p_tag_text_size) \ + struct \ + { \ + char version [4]; \ + char title [64]; \ + char artist [64]; \ + char cut_id [64]; \ + char client_id [64]; \ + char category [64]; \ + char classification [64]; \ + char out_cue [64]; \ + char start_date [10]; \ + char start_time [8]; \ + char end_date [10]; \ + char end_time [8]; \ + char producer_app_id [64]; \ + char producer_app_version [64]; \ + char user_def [64]; \ + int32_t level_reference; \ + SF_CART_TIMER post_timers [8]; \ + char reserved [276]; \ + char url [1024]; \ + uint32_t tag_text_size; \ + char tag_text [p_tag_text_size]; \ + } + +typedef SF_CART_INFO_VAR (256) SF_CART_INFO; + +/* Virtual I/O functionality. */ + +typedef sf_count_t (*sf_vio_get_filelen) (void *user_data); +typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data); +typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data); +typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data); +typedef sf_count_t (*sf_vio_tell) (void *user_data); + +struct SF_VIRTUAL_IO { + sf_vio_get_filelen get_filelen; + sf_vio_seek seek; + sf_vio_read read; + sf_vio_write write; + sf_vio_tell tell; +}; + +typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO; + + +/* Open the specified file for read, write or both. On error, this will + * return a NULL pointer. To find the error number, pass a NULL SNDFILE + * to sf_strerror (). + * All calls to sf_open() should be matched with a call to sf_close(). +*/ + +SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo); + + +/* Use the existing file descriptor to create a SNDFILE object. If close_desc + * is TRUE, the file descriptor will be closed when sf_close() is called. If + * it is FALSE, the descriptor will not be closed. + * When passed a descriptor like this, the library will assume that the start + * of file header is at the current file offset. This allows sound files within + * larger container files to be read and/or written. + * On error, this will return a NULL pointer. To find the error number, pass a + * NULL SNDFILE to sf_strerror (). + * All calls to sf_open_fd() should be matched with a call to sf_close(). + +*/ + +SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc); + +SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data); + + +/* sf_error () returns a error number which can be translated to a text + * string using sf_error_number(). +*/ + +int sf_error (SNDFILE *sndfile); + + +/* sf_strerror () returns to the caller a pointer to the current error message for + * the given SNDFILE. +*/ + +const char* sf_strerror (SNDFILE *sndfile); + + +/* sf_error_number () allows the retrieval of the error string for each internal + * error number. + * +*/ + +const char* sf_error_number (int errnum); + + +/* The following two error functions are deprecated but they will remain in the + * library for the foreseeable future. The function sf_strerror() should be used + * in their place. +*/ + +int sf_perror (SNDFILE *sndfile); +int sf_error_str (SNDFILE *sndfile, char* str, size_t len); + + +/* Allow the caller to retrieve information from or change aspects of the + * library behaviour. +*/ + +int sf_command (SNDFILE *sndfile, int command, void *data, int datasize); + + +/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */ + +int sf_format_check (const SF_INFO *info); + + +/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses + * the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as + * stdio.h function fseek (). + * An offset of zero with whence set to SEEK_SET will position the + * read / write pointer to the first data sample. + * On success sf_seek returns the current position in (multi-channel) + * samples from the start of the file. + * Please see the libsndfile documentation for moving the read pointer + * separately from the write pointer on files open in mode SFM_RDWR. + * On error all of these functions return -1. +*/ + +enum { + SF_SEEK_SET = SEEK_SET, + SF_SEEK_CUR = SEEK_CUR, + SF_SEEK_END = SEEK_END +}; + +sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence); + +/* Functions for retrieving and setting string data within sound files. + * Not all file types support this features; AIFF and WAV do. For both + * functions, the str_type parameter must be one of the SF_STR_* values + * defined above. + * On error, sf_set_string() returns non-zero while sf_get_string() + * returns NULL. +*/ + +int sf_set_string (SNDFILE *sndfile, int str_type, const char* str); + +const char* sf_get_string (SNDFILE *sndfile, int str_type); + + +/* Return the library version string. */ + +const char * sf_version_string (void); + +/* Return the current byterate at this point in the file. The byte rate in this + * case is the number of bytes per second of audio data. For instance, for a + * stereo, 18 bit PCM encoded file with an 16kHz sample rate, the byte rate + * would be 2 (stereo) * 2 (two bytes per sample) * 16000 => 64000 bytes/sec. + * For some file formats the returned value will be accurate and exact, for some + * it will be a close approximation, for some it will be the average bitrate for + * the whole file and for some it will be a time varying value that was accurate + * when the file was most recently read or written. + * To get the bitrate, multiple this value by 8. + * Returns -1 for unknown. +*/ +int sf_current_byterate (SNDFILE *sndfile); + +/* Functions for reading/writing the waveform data of a sound file. +*/ + +sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes); +sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes); + +/* Functions for reading and writing the data chunk in terms of frames. + * The number of items actually read/written = frames * number of channels. + * sf_xxxx_raw read/writes the raw data bytes from/to the file + * sf_xxxx_short passes data in the native short format + * sf_xxxx_int passes data in the native int format + * sf_xxxx_float passes data in the native float format + * sf_xxxx_double passes data in the native double format + * All of these read/write function return number of frames read/written. +*/ + +sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames); +sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames); + +sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames); +sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames); + +sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames); +sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames); + +sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames); +sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames); + + +/* Functions for reading and writing the data chunk in terms of items. + * Otherwise similar to above. + * All of these read/write function return number of items read/written. +*/ + +sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items); +sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items); + +sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items); +sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items); + +sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items); +sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items); + +sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items); +sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items); + + +/* Close the SNDFILE and clean up all memory allocations associated with this + * file. + * Returns 0 on success, or an error number. +*/ + +int sf_close (SNDFILE *sndfile); + + +/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file + * to force the writing of data to disk. If the file is opened SFM_READ + * no action is taken. +*/ + +void sf_write_sync (SNDFILE *sndfile); + +/* The function sf_wchar_open() is Windows Only! + * Open a file passing in a Windows Unicode filename. Otherwise, this is + * the same as sf_open(). +*/ + +#ifdef _WIN32 +SNDFILE* sf_wchar_open (const wchar_t *wpath, int mode, SF_INFO *sfinfo); +#endif + +/* Getting and setting of chunks from within a sound file. + * + * These functions allow the getting and setting of chunks within a sound file + * (for those formats which allow it). + * + * These functions fail safely. Specifically, they will not allow you to overwrite + * existing chunks or add extra versions of format specific reserved chunks but + * should allow you to retrieve any and all chunks (may not be implemented for + * all chunks or all file formats). +*/ + +struct SF_CHUNK_INFO { + char id [64]; /* The chunk identifier. */ + unsigned id_size; /* The size of the chunk identifier. */ + unsigned datalen; /* The size of that data. */ + void *data; /* Pointer to the data. */ +}; + +typedef struct SF_CHUNK_INFO SF_CHUNK_INFO; + +/* Set the specified chunk info (must be done before any audio data is written + * to the file). This will fail for format specific reserved chunks. + * The chunk_info->data pointer must be valid until the file is closed. + * Returns SF_ERR_NO_ERROR on success or non-zero on failure. +*/ +int sf_set_chunk (SNDFILE * sndfile, const SF_CHUNK_INFO * chunk_info); + +/* + * An opaque structure to an iterator over the all chunks of a given id +*/ +typedef struct SF_CHUNK_ITERATOR SF_CHUNK_ITERATOR; + +/* Get an iterator for all chunks matching chunk_info. + * The iterator will point to the first chunk matching chunk_info. + * Chunks are matching, if (chunk_info->id) matches the first + * (chunk_info->id_size) bytes of a chunk found in the SNDFILE* handle. + * If chunk_info is NULL, an iterator to all chunks in the SNDFILE* handle + * is returned. + * The values of chunk_info->datalen and chunk_info->data are ignored. + * If no matching chunks are found in the sndfile, NULL is returned. + * The returned iterator will stay valid until one of the following occurs + * a) The sndfile is closed. + * b) A new chunk is added using sf_set_chunk(). + * c) Another chunk iterator function is called on the same SNDFILE* handle + * that causes the iterator to be modified. + * The memory for the iterator belongs to the SNDFILE* handle and is freed when + * sf_close() is called. +*/ +SF_CHUNK_ITERATOR * sf_get_chunk_iterator (SNDFILE * sndfile, const SF_CHUNK_INFO * chunk_info); + +/* Iterate through chunks by incrementing the iterator. + * Increments the iterator and returns a handle to the new one. + * After this call, iterator will no longer be valid, and you must use the + * newly returned handle from now on. + * The returned handle can be used to access the next chunk matching + * the criteria as defined in sf_get_chunk_iterator(). + * If iterator points to the last chunk, this will free all resources + * associated with iterator and return NULL. + * The returned iterator will stay valid until sf_get_chunk_iterator_next + * is called again, the sndfile is closed or a new chunk us added. +*/ +SF_CHUNK_ITERATOR * sf_next_chunk_iterator (SF_CHUNK_ITERATOR * iterator); + +/* Get the size of the specified chunk. + * If the specified chunk exists, the size will be returned in the + * datalen field of the SF_CHUNK_INFO struct. + * Additionally, the id of the chunk will be copied to the id + * field of the SF_CHUNK_INFO struct and it's id_size field will + * be updated accordingly. + * If the chunk doesn't exist chunk_info->datalen will be zero, and the + * id and id_size fields will be undefined. + * The function will return SF_ERR_NO_ERROR on success or non-zero on + * failure. +*/ +int sf_get_chunk_size (const SF_CHUNK_ITERATOR * it, SF_CHUNK_INFO * chunk_info); + +/* Get the specified chunk data. + * If the specified chunk exists, up to chunk_info->datalen bytes of + * the chunk data will be copied into the chunk_info->data buffer + * (allocated by the caller) and the chunk_info->datalen field + * updated to reflect the size of the data. The id and id_size + * field will be updated according to the retrieved chunk + * If the chunk doesn't exist chunk_info->datalen will be zero, and the + * id and id_size fields will be undefined. + * The function will return SF_ERR_NO_ERROR on success or non-zero on + * failure. +*/ +int sf_get_chunk_data (const SF_CHUNK_ITERATOR * it, SF_CHUNK_INFO * chunk_info); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* SNDFILE_H */ diff --git a/ohos.build b/ohos.build old mode 100755 new mode 100644 index 29ab46795d..77f4837708 --- a/ohos.build +++ b/ohos.build @@ -7,10 +7,19 @@ ], "module_list": [ "//foundation/multimedia/audio_standard/services:audio_service", - "//foundation/multimedia/audio_standard/services:audio_service.rc", + "//foundation/multimedia/audio_standard/services:pulseaudio.rc", "//foundation/multimedia/audio_standard/sa_profile:audio_service_sa_profile", "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio", - "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio_js" + "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio_js", + "//foundation/multimedia/audio_standard/pulseaudio:pulseaudio_packages", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client_test_packages", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder:audio_recorder_test_packages", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer:audio_renderer_test", + "//foundation/multimedia/audio_standard/services:audio_policy_service_packages", + "//foundation/multimedia/audio_standard/sa_profile:audio_policy_service_sa_profile", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiopolicy:audio_policy_test", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer:audio_capturer_source", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer:audio_renderer_sink" ], "inner_kits": [ { @@ -18,9 +27,15 @@ "name": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", "header": { "header_files": [ - "audio_svc_manager.h" + "audio_system_manager.h", + "audio_session.h", + "audio_stream.h" ], - "header_base": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include" + "header_base": [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiosession/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include" + ] } }, { @@ -33,6 +48,31 @@ "header_base": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocapturer/include" } }, + { + "type": "none", + "name": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder:audio_recorder", + "header": { + "header_files": [ + "audio_recorder.h", + "audio_info.h" + ], + "header_base": [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include" + ] + } + }, + { + "type": "none", + "name": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer:audio_renderer", + "header": { + "header_files": [ + "audio_renderer.h", + "audio_info.h" + ], + "header_base": "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer/include" + } + }, { "type": "none", "name": "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio", diff --git a/pulseaudio/BUILD.gn b/pulseaudio/BUILD.gn new file mode 100644 index 0000000000..035f45faf1 --- /dev/null +++ b/pulseaudio/BUILD.gn @@ -0,0 +1,49 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" + +group("pulseaudio_packages") { + deps = [ + # ":gen_config_header", + "$libsndfile_build_path:sndfile", + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src:pa_daemon_config", + "$pulseaudio_build_path/src:pa_default_config", + "$pulseaudio_build_path/src/pulse:pulse-simple", + "$pulseaudio_build_path/src/pulse:pulse-mainloop-glib", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + "$pulseaudio_build_path/src/pulsecore:protocol-native", + "$pulseaudio_build_path/src/pulsecore:cli", + "$pulseaudio_build_path/src/pulsecore:protocol-cli", + "$pulseaudio_build_path/src/daemon:pulseaudio", + "$pulseaudio_build_path/src/utils:pacmd", + "$pulseaudio_build_path/src/utils:pacat", + "$pulseaudio_build_path/src/utils:pactl", + "$pulseaudio_build_path/src/modules:modules", + "$pulseaudio_build_path/src/modules/hdi:module-hdi-sink", + "$pulseaudio_build_path/src/modules/hdi:module-hdi-source", + ] +} + +action("gen_config_header") { + script = "//foundation/multimedia/audio_standard/pulseaudio/ohos_paconfig.sh" + + args = [ rebase_path("//third_party/pulseaudio", root_build_dir), rebase_path( "${target_gen_dir}/", root_build_dir),] + + outputs = [ "${target_gen_dir}/config.h", ] +} diff --git a/pulseaudio/conf/daemon.conf b/pulseaudio/conf/daemon.conf new file mode 100644 index 0000000000..8bcaf7cda6 --- /dev/null +++ b/pulseaudio/conf/daemon.conf @@ -0,0 +1,91 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for +## more information. Default values are commented out. Use either ; or # for +## commenting. + +; daemonize = no +; fail = yes +; allow-module-loading = yes +; disallow-exit = yes +disallow-exit = yes +allow-exit = no +; use-pid-file = yes +; system-instance = no +; local-server-type = user +; enable-shm = yes +; enable-memfd = yes +; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB +; lock-memory = no +; cpu-limit = no + +; high-priority = yes +; nice-level = -11 + +; realtime-scheduling = yes +; realtime-priority = 5 + +exit-idle-time = -1 +; scache-idle-time = 20 + +; dl-search-path = (depends on architecture) + +; load-default-script-file = yes +; default-script-file = + +; log-target = auto +; log-level = notice +; log-meta = no +; log-time = no +; log-backtrace = 0 + +; resample-method = speex-float-1 +; avoid-resampling = false +; enable-remixing = yes +; remixing-use-all-sink-channels = yes +; enable-lfe-remixing = no +; lfe-crossover-freq = 0 + +flat-volumes = no + +; rlimit-fsize = -1 +; rlimit-data = -1 +; rlimit-stack = -1 +; rlimit-core = -1 +; rlimit-as = -1 +; rlimit-rss = -1 +; rlimit-nproc = -1 +; rlimit-nofile = 256 +; rlimit-memlock = -1 +; rlimit-locks = -1 +; rlimit-sigpending = -1 +; rlimit-msgqueue = -1 +; rlimit-nice = 31 +; rlimit-rtprio = 9 +; rlimit-rttime = 200000 + +; default-sample-format = s16le +; default-sample-rate = 44100 +; alternate-sample-rate = 48000 +; default-sample-channels = 2 +; default-channel-map = front-left,front-right + +; default-fragments = 4 +; default-fragment-size-msec = 25 + +; enable-deferred-volume = yes +deferred-volume-safety-margin-usec = 1 +; deferred-volume-extra-delay-usec = 0 diff --git a/pulseaudio/conf/default.pa b/pulseaudio/conf/default.pa new file mode 100644 index 0000000000..1f08228fb4 --- /dev/null +++ b/pulseaudio/conf/default.pa @@ -0,0 +1,34 @@ +#!/usr/bin/pulseaudio -nF +# +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +# This startup script is used only if PulseAudio is started per-user +# (i.e. not in system mode) + +.fail + +# Load mandatory modules +load-module libmodule-cli-protocol-unix.z.so +load-module libmodule-native-protocol-unix.z.so auth-cookie=/data/local/.pulse_dir/cookie + +### Load audio drivers statically +### (it's probably better to not load these drivers manually, but instead +### use module-udev-detect -- see below -- for doing this automatically) +load-module libmodule-suspend-on-idle.z.so timeout=1 + +### Make some devices default +#set-default-sink output +#set-default-source input diff --git a/pulseaudio/include/config.h b/pulseaudio/include/config.h new file mode 100644 index 0000000000..219aee0ced --- /dev/null +++ b/pulseaudio/include/config.h @@ -0,0 +1,285 @@ +/* + * Autogenerated by the Meson build system. + * Do not edit, your changes will be lost. + */ + +#pragma once + +#define DESKTOPFILEDIR "/usr/local/share/applications" + +#define DISABLE_ORC 1 + +#define ENABLE_LEGACY_DATABASE_ENTRY_FORMAT 1 + +#define GETGROUPS_T gid_t + +#define GETTEXT_PACKAGE "pulseaudio" + +#define HAVE_ACCEPT4 1 + +#define HAVE_ALSA 1 + +#define HAVE_ALSA_UCM 1 + +#define HAVE_ARPA_INET_H 1 + +#define HAVE_ATOMIC_BUILTINS 1 + +#define HAVE_ATOMIC_BUILTINS_MEMORY_MODEL 1 + +#define HAVE_BYTESWAP_H 1 + +#define HAVE_CLOCK_GETTIME 1 + +#define HAVE_COREAUDIO 0 + +#define HAVE_CTIME_R 1 + +#define HAVE_DECL_ENVIRON 1 + +#define HAVE_DECL_SOUND_PCM_READ_BITS 1 + +#define HAVE_DECL_SOUND_PCM_READ_CHANNELS 1 + +#define HAVE_DECL_SOUND_PCM_READ_RATE 1 + +#define HAVE_DLADDR 1 + +#define HAVE_DLFCN_H 1 + +#define HAVE_FAST_64BIT_OPERATIONS 1 + +#define HAVE_FCHMOD 1 + +#define HAVE_FCHOWN 1 + +#define HAVE_FORK 1 + +#define HAVE_FSTAT 1 + +#define HAVE_GETADDRINFO 1 + +#define HAVE_GETGRGID_R 1 + +#define HAVE_GETGRNAM_R 1 + +#define HAVE_GETPWNAM_R 1 + +#define HAVE_GETPWUID_R 1 + +#define HAVE_GETTIMEOFDAY 1 + +#define HAVE_GETUID 1 + +#define HAVE_GRP_H 1 + +#define HAVE_HAL_COMPAT 1 + +#define HAVE_ICONV 1 + +#define HAVE_IPV6 1 + +#define HAVE_LANGINFO_H 1 + +#define HAVE_LINUX_SOCKIOS_H 1 + +#define HAVE_LOCALE_H 1 + +#define HAVE_LRINTF 1 + +#define HAVE_LSTAT 1 + +#define HAVE_MEMFD_CREATE 1 + +#define HAVE_MKFIFO 1 + +#define HAVE_MLOCK 1 + +/* Compiler supports mmx. */ +#define HAVE_MMX 1 + +#define HAVE_NANOSLEEP 1 + +#define HAVE_NETDB_H 1 + +#define HAVE_NETINET_IN_H 1 + +#define HAVE_NETINET_IN_SYSTM_H 1 + +#define HAVE_NETINET_IP_H 1 + +#define HAVE_NETINET_TCP_H 1 + +#define HAVE_OPEN64 1 + +#define HAVE_OPENSSL 1 + +#define HAVE_OSS_OUTPUT 1 + +#define HAVE_OSS_WRAPPER 1 + +#define HAVE_PCREPOSIX_H 1 + +#define HAVE_PIPE 1 + +#define HAVE_PIPE2 1 + +#define HAVE_POLL_H 1 + +#define HAVE_POSIX_FADVISE 1 + +#define HAVE_POSIX_MADVISE 1 + +#define HAVE_POSIX_MEMALIGN 1 + +#define HAVE_PPOLL 1 + +#define HAVE_PTHREAD 1 + +#define HAVE_PTHREAD_GETNAME_NP 1 + +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +#define HAVE_PTHREAD_SETAFFINITY_NP 1 + +#define HAVE_PTHREAD_SETNAME_NP 1 + +#define HAVE_PWD_H 1 + +#define HAVE_READLINK 1 + +#define HAVE_REGEX_H 1 + +#define HAVE_RUNNING_FROM_BUILD_TREE 1 + +#define HAVE_SCHED_H 1 + +#define HAVE_SETEGID 1 + +#define HAVE_SETEUID 1 + +#define HAVE_SETPGID 1 + +#define HAVE_SETREGID 1 + +#define HAVE_SETRESGID 1 + +#define HAVE_SETRESUID 1 + +#define HAVE_SETREUID 1 + +#define HAVE_SETSID 1 + +#define HAVE_SIGACTION 1 + +#define HAVE_SIGXCPU 1 + +/* Compiler supports sse. */ +#define HAVE_SSE 1 + +#define HAVE_STDINT_H 1 + +#define HAVE_STD_BOOL 1 + +#define HAVE_STRERROR_R 1 + +#define HAVE_STRTOD_L 1 + +#define HAVE_STRTOF 1 + +#define HAVE_SYMLINK 1 + +#define HAVE_SYSCONF 1 + +#define HAVE_SYSLOG_H 1 + +#define HAVE_SYS_EVENTFD_H 1 + +#define HAVE_SYS_IOCTL_H 1 + +#define HAVE_SYS_MMAN_H 1 + +#define HAVE_SYS_PRCTL_H 1 + +#define HAVE_SYS_RESOURCE_H 1 + +#define HAVE_SYS_SELECT_H 1 + +#define HAVE_SYS_SOCKET_H 1 + +#define HAVE_SYS_SYSCALL_H 1 + +#define HAVE_SYS_UIO_H 1 + +#define HAVE_SYS_UN_H 1 + +#define HAVE_SYS_WAIT_H 1 + +#define HAVE_UNAME 1 + +#define HAVE_WAVEOUT 0 + +#define ICONV_CONST + +#define LIBICONV_PLUG 1 + +#define MESON_BUILD 1 + +#define PACKAGE "pulseaudio" + +#define PACKAGE_NAME "pulseaudio" + +#define PACKAGE_VERSION "14.0-271-g1a19" + +#define PA_ACCESS_GROUP "pulse-access" + +#define PA_ALSA_PATHS_DIR "/usr/local/share/pulseaudio/alsa-mixer/paths" + +#define PA_ALSA_PROFILE_SETS_DIR "/usr/local/share/pulseaudio/alsa-mixer/profile-sets" + +#define PA_API_VERSION 12 + +#define PA_BINARY "/system/bin" + +#define PA_BUILDDIR "/home/workspace/pa/pulseaudio/confgure" + +#define PA_CFLAGS "Not yet supported on meson" + +#define PA_DEFAULT_CONFIG_DIR "/system/etc/pulse" + +#define PA_DEFAULT_CONFIG_DIR_UNQUOTED /usr/local/etc/pulse + +#define PA_DLSEARCHPATH "/system/lib" + +#define PA_INCDIR /usr/local/include + +#define PA_LIBDIR /usr/local/lib/x86_64-linux-gnu + +#define PA_MACHINE_ID "/usr/local/etc/machine-id" + +#define PA_MACHINE_ID_FALLBACK "/var/local/lib/dbus/machine-id" + +#define PA_MAJOR 14 + +#define PA_MINOR 0 + +#define PA_PROTOCOL_VERSION 35 + +#define PA_SOEXT ".so" + +#define PA_SYSTEM_CONFIG_PATH "/var/local/lib/pulse" + +#define PA_SYSTEM_GROUP "pulse" + +#define PA_SYSTEM_RUNTIME_PATH "/var/local/run/pulse" + +#define PA_SYSTEM_STATE_PATH "/var/local/lib/pulse" + +#define PA_SYSTEM_USER "pulse" + +#define PULSEDSP_LOCATION /usr/local/lib/x86_64-linux-gnu/pulseaudio + +#define PULSE_LOCALEDIR "/usr/local/share/locale" + +#define top_srcdir /home/workspace/pa/pulseaudio + diff --git a/pulseaudio/include/ltdl.h b/pulseaudio/include/ltdl.h new file mode 100644 index 0000000000..9ce4b7d3ea --- /dev/null +++ b/pulseaudio/include/ltdl.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +/* This file stubs the functionality of + * libtool library used by pulseaudio. + */ + +#include + +typedef void* lt_dlhandle; + +const char *lt_dlerror(void); +const char* lt_dlgetsearchpath(); +int lt_dlclose(lt_dlhandle handle); +lt_dlhandle lt_dlopenext(const char *filename); +void* lt_dlsym(lt_dlhandle handle, const char *symbol); diff --git a/pulseaudio/include/pulse/version.h b/pulseaudio/include/pulse/version.h new file mode 100644 index 0000000000..b4fda9325c --- /dev/null +++ b/pulseaudio/include/pulse/version.h @@ -0,0 +1,70 @@ +#ifndef fooversionhfoo /*-*-C-*-*/ +#define fooversionhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see . +***/ + +/* WARNING: Make sure to edit the real source file version.h.in! */ + +#include + +/** \file + * Define header version */ + +PA_C_DECL_BEGIN + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pa_get_headers_version() ("14.0.0") + +/** Return the version of the library the current application is + * linked to. */ +const char* pa_get_library_version(void); + +/** The current API version. Version 6 relates to Polypaudio + * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have + * PA_API_VERSION undefined. Please note that this is only ever + * increased on incompatible API changes! */ +#define PA_API_VERSION 12 + +/** The current protocol version. Version 8 relates to Polypaudio + * 0.8/PulseAudio 0.9. */ +#define PA_PROTOCOL_VERSION 35 + +/** The major version of PA. \since 0.9.15 */ +#define PA_MAJOR 14 + +/** The minor version of PA. \since 0.9.15 */ +#define PA_MINOR 0 + +/** The micro version of PA (will always be 0 from v1.0 onwards). \since 0.9.15 */ +#define PA_MICRO 0 + +/** Evaluates to TRUE if the PulseAudio library version is equal or + * newer than the specified. \since 0.9.16 */ +#define PA_CHECK_VERSION(major,minor,micro) \ + ((PA_MAJOR > (major)) || \ + (PA_MAJOR == (major) && PA_MINOR > (minor)) || \ + (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro))) + +PA_C_DECL_END + +#endif diff --git a/pulseaudio/ohos_paconfig.sh b/pulseaudio/ohos_paconfig.sh new file mode 100644 index 0000000000..cca462f023 --- /dev/null +++ b/pulseaudio/ohos_paconfig.sh @@ -0,0 +1,75 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +#!/bin/bash + +PASRC_PATH=$1 +PASRC_OUT_PATH=$2 + +function clean_pa_src() { + echo "Clean local generated files" + rm -rf ABOUT-NLS Makefile Makefile.in PulseAudioConfig.cmake PulseAudioConfigVersion.cmake aclocal.m4 + rm -rf autom4te.cache/ build-aux/ config.h config.h.in config.h.in~ config.log config.status configure + rm -rf libpulse-mainloop-glib.pc libpulse-simple.pc libpulse.pc libtool stamp-h1 +} + +clean_pa_src + +sed -i 's/\.\/git-version-gen .tarball-version//g' configure.ac +sed -i 's/\[m4_esyscmd()\],//g' configure.ac +sed -i 's/src doxygen man po/src doxygen man #po/g' Makefile.am + +PA_CONFIG_OPTIONS=" + --without-caps + --disable-alsa + --disable-x11 + --disable-oss-output + --disable-coreaudio-output + --disable-alsa + --disable-esound + --disable-gsettings + --disable-dbus + --disable-udev + --disable-ipv6 + --disable-openssl + --disable-avahi + --disable-jack +" +# We check for this here, because if pkg-config is not found in the +# system, it's likely that the pkg.m4 macro file is also not present, +# which will make PKG_PROG_PKG_CONFIG be undefined and the generated +# configure file faulty. +if ! pkg-config --version &>/dev/null; then + echo "pkg-config is required to bootstrap this program" + +fi +# Other necessary programs +if ! autopoint --version &>/dev/null ; then + echo "autopoint is required to bootstrap this program" + +fi + +autoreconf --force --install --verbose + +if test "x$NOCONFIGURE" = "x"; then + CFLAGS="$CFLAGS -g -O0" $PASRC_PATH/configure --enable-force-preopen ${PA_CONFIG_OPTIONS} && \ + make clean +fi + +sed -i 's/#define ENABLE_NLS 1//g' config.h +sed -i 's/#define HAVE_SHM_OPEN 1//g' config.h +sed -i 's/#define HAVE_RUNNING_FROM_BUILD_TREE 1//g' config.h +sed -i 's/#define HAVE_CPUID_H 1//g' config.h +sed -i 's/#define HAVE_EXECINFO_H 1//g' config.h +sed -i 's/#define HAVE_MEMFD 1//g' config.h +echo "#define PACKAGE_NAME \"pulseaudio\"" >> config.h diff --git a/pulseaudio/src/BUILD.gn b/pulseaudio/src/BUILD.gn new file mode 100644 index 0000000000..13c67f5ec9 --- /dev/null +++ b/pulseaudio/src/BUILD.gn @@ -0,0 +1,140 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" + +config("pulsecommon_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir/src", + "$pulseaudio_dir/include", + "$pulseaudio_build_path", + "$pulseaudio_build_path/src", + "$libsndfile_build_path/include", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-implicit-function-declaration", + "-Wno-unused-function", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + ] +} + +ohos_source_set("pulsecommon_sources") { + sources = [ + "$pulseaudio_dir/src/pulse/client-conf.c", + "$pulseaudio_dir/src/pulse/error.c", + "$pulseaudio_dir/src/pulse/fork-detect.c", + "$pulseaudio_dir/src/pulse/format.c", + "$pulseaudio_dir/src/pulse/json.c", + "$pulseaudio_dir/src/pulse/mainloop-api.c", + "$pulseaudio_dir/src/pulse/xmalloc.c", + "$pulseaudio_dir/src/pulse/proplist.c", + "$pulseaudio_dir/src/pulse/utf8.c", + "$pulseaudio_dir/src/pulse/channelmap.c", + "$pulseaudio_dir/src/pulse/sample.c", + "$pulseaudio_dir/src/pulse/util.c", + "$pulseaudio_dir/src/pulse/timeval.c", + "$pulseaudio_dir/src/pulse/rtclock.c", + "$pulseaudio_dir/src/pulse/volume.c", + "$pulseaudio_dir/src/pulsecore/authkey.c", + "$pulseaudio_dir/src/pulsecore/conf-parser.c", + "$pulseaudio_dir/src/pulsecore/core-error.c", + "$pulseaudio_dir/src/pulsecore/core-format.c", + "$pulseaudio_dir/src/pulsecore/core-rtclock.c", + "$pulseaudio_dir/src/pulsecore/core-util.c", + "$pulseaudio_dir/src/pulsecore/dynarray.c", + "$pulseaudio_dir/src/pulsecore/fdsem.c", + "$pulseaudio_dir/src/pulsecore/flist.c", + "$pulseaudio_dir/src/pulsecore/g711.c", + "$pulseaudio_dir/src/pulsecore/hashmap.c", + "$pulseaudio_dir/src/pulsecore/i18n.c", + "$pulseaudio_dir/src/pulsecore/idxset.c", + "$pulseaudio_dir/src/pulsecore/arpa-inet.c", + "$pulseaudio_dir/src/pulsecore/iochannel.c", + "$pulseaudio_dir/src/pulsecore/ioline.c", + "$pulseaudio_dir/src/pulsecore/ipacl.c", + "$pulseaudio_dir/src/pulsecore/lock-autospawn.c", + "$pulseaudio_dir/src/pulsecore/log.c", + "$pulseaudio_dir/src/pulsecore/ratelimit.c", + "$pulseaudio_dir/src/pulsecore/mcalign.c", + "$pulseaudio_dir/src/pulsecore/memblock.c", + "$pulseaudio_dir/src/pulsecore/memblockq.c", + "$pulseaudio_dir/src/pulsecore/memchunk.c", + "$pulseaudio_dir/src/pulsecore/native-common.c", + "$pulseaudio_dir/src/pulsecore/once.c", + "$pulseaudio_dir/src/pulsecore/packet.c", + "$pulseaudio_dir/src/pulsecore/parseaddr.c", + "$pulseaudio_dir/src/pulsecore/pdispatch.c", + "$pulseaudio_dir/src/pulsecore/pid.c", + "$pulseaudio_dir/src/pulsecore/pipe.c", + "$pulseaudio_dir/src/pulsecore/memtrap.c", + "$pulseaudio_dir/src/pulsecore/aupdate.c", + "$pulseaudio_dir/src/pulsecore/proplist-util.c", + "$pulseaudio_dir/src/pulsecore/pstream-util.c", + "$pulseaudio_dir/src/pulsecore/pstream.c", + "$pulseaudio_dir/src/pulsecore/queue.c", + "$pulseaudio_dir/src/pulsecore/random.c", + "$pulseaudio_dir/src/pulsecore/srbchannel.c", + "$pulseaudio_dir/src/pulsecore/sample-util.c", + "$pulseaudio_dir/src/pulsecore/shm.c", + "$pulseaudio_dir/src/pulsecore/bitset.c", + "$pulseaudio_dir/src/pulsecore/socket-client.c", + "$pulseaudio_dir/src/pulsecore/socket-server.c", + "$pulseaudio_dir/src/pulsecore/socket-util.c", + "$pulseaudio_dir/src/pulsecore/strbuf.c", + "$pulseaudio_dir/src/pulsecore/strlist.c", + "$pulseaudio_dir/src/pulsecore/tagstruct.c", + "$pulseaudio_dir/src/pulsecore/time-smoother.c", + "$pulseaudio_dir/src/pulsecore/tokenizer.c", + "$pulseaudio_dir/src/pulsecore/usergroup.c", + "$pulseaudio_dir/src/pulsecore/sndfile-util.c", + "$pulseaudio_dir/src/pulsecore/mutex-posix.c", + "$pulseaudio_dir/src/pulsecore/semaphore-posix.c", + "$pulseaudio_dir/src/pulsecore/thread-posix.c", + ] + + configs = [ ":pulsecommon_config" ] +} + +ohos_shared_library("pulsecommon") { + deps = [ + ":pulsecommon_sources", + "$libsndfile_build_path:sndfile", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} +ohos_prebuilt_etc("pa_daemon_config") { + source = "//foundation/multimedia/audio_standard/pulseaudio/conf/daemon.conf" + + subsystem_name = "multimedia" + module_install_dir = "etc/pulse" + part_name = "multimedia_audio_standard" +} + +ohos_prebuilt_etc("pa_default_config") { + source = "//foundation/multimedia/audio_standard/pulseaudio/conf/default.pa" + subsystem_name = "multimedia" + module_install_dir = "etc/pulse" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/daemon/BUILD.gn b/pulseaudio/src/daemon/BUILD.gn new file mode 100644 index 0000000000..34e167d9d4 --- /dev/null +++ b/pulseaudio/src/daemon/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_src_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//third_party/pulseaudio" + +config("daemon_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir/include", + "$pulseaudio_src_dir/src/daemon", + "$pulseaudio_src_dir/src", + "$pulseaudio_build_path", + "$pulseaudio_build_path/src", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-unused-function", + "-DHAVE_CONFIG_H", + "-DHAVE_UNISTD_H", + ] +} + +ohos_source_set("pulseaudio_sources") { + sources = [ + "$pulseaudio_src_dir/src/daemon/caps.c", + "$pulseaudio_src_dir/src/daemon/cmdline.c", + "$pulseaudio_src_dir/src/daemon/cpulimit.c", + "$pulseaudio_dir/src/daemon/ohos_daemon-conf.c", + "$pulseaudio_dir/src/daemon/ohos_pa_main.c", + ] + + configs = [ ":daemon_config" ] +} + +ohos_shared_library("pulseaudio") { + ldflags = [ "-ffast-math" ] + deps = [ + ":pulseaudio_sources", + "$pulseaudio_dir/src/pulse:pulse", + "$pulseaudio_dir/src/pulsecore:pulsecore", + "$pulseaudio_dir/src:pulsecommon", + ] + + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} diff --git a/pulseaudio/src/daemon/ohos_daemon-conf.c b/pulseaudio/src/daemon/ohos_daemon-conf.c new file mode 100644 index 0000000000..4a6fe0b3d3 --- /dev/null +++ b/pulseaudio/src/daemon/ohos_daemon-conf.c @@ -0,0 +1,872 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "daemon-conf.h" + +#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER PA_PATH_SEP "default.pa" +#define DEFAULT_SYSTEM_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "system.pa" + +#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER PA_PATH_SEP "daemon.conf" + +#define ENV_SCRIPT_FILE "PULSE_SCRIPT" +#define ENV_CONFIG_FILE "PULSE_CONFIG" +#define ENV_DL_SEARCH_PATH "PULSE_DLPATH" + +static const pa_daemon_conf default_conf = { + .cmd = PA_CMD_DAEMON, + .daemonize = false, + .fail = true, + .high_priority = true, + .nice_level = -11, + .realtime_scheduling = true, + .realtime_priority = 5, /* Half of JACK's default rtprio */ + .disallow_module_loading = false, + .disallow_exit = false, + .flat_volumes = false, + .rescue_streams = true, + .exit_idle_time = -1, + .scache_idle_time = 20, + .script_commands = NULL, + .dl_search_path = NULL, + .load_default_script_file = true, + .default_script_file = NULL, + .log_target = NULL, + .log_level = PA_LOG_NOTICE, + .log_backtrace = 0, + .log_meta = false, + .log_time = false, + .resample_method = PA_RESAMPLER_AUTO, + .avoid_resampling = false, + .disable_remixing = false, + .remixing_use_all_sink_channels = true, + .remixing_produce_lfe = false, + .remixing_consume_lfe = false, + .lfe_crossover_freq = 0, + .config_file = NULL, + .use_pid_file = true, + .system_instance = false, +#ifdef HAVE_DBUS + .local_server_type = PA_SERVER_TYPE_UNSET, /* The actual default is _USER, but we have to detect when the user doesn't specify this option. */ +#endif + .no_cpu_limit = true, + .disable_shm = false, + .disable_memfd = false, + .lock_memory = false, + .deferred_volume = true, + .default_n_fragments = 4, + .default_fragment_size_msec = 25, + .deferred_volume_safety_margin_usec = 8000, + .deferred_volume_extra_delay_usec = 0, + .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }, + .alternate_sample_rate = 48000, + .default_channel_map = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, + .shm_size = 0 +#ifdef HAVE_SYS_RESOURCE_H + ,.rlimit_fsize = { .value = 0, .is_set = false }, + .rlimit_data = { .value = 0, .is_set = false }, + .rlimit_stack = { .value = 0, .is_set = false }, + .rlimit_core = { .value = 0, .is_set = false } +#ifdef RLIMIT_RSS + ,.rlimit_rss = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_NPROC + ,.rlimit_nproc = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_NOFILE + ,.rlimit_nofile = { .value = 256, .is_set = true } +#endif +#ifdef RLIMIT_MEMLOCK + ,.rlimit_memlock = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_AS + ,.rlimit_as = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_LOCKS + ,.rlimit_locks = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_SIGPENDING + ,.rlimit_sigpending = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_MSGQUEUE + ,.rlimit_msgqueue = { .value = 0, .is_set = false } +#endif +#ifdef RLIMIT_NICE + ,.rlimit_nice = { .value = 31, .is_set = true } /* nice level of -11 */ +#endif +#ifdef RLIMIT_RTPRIO + ,.rlimit_rtprio = { .value = 9, .is_set = true } /* One below JACK's default for the server */ +#endif +#ifdef RLIMIT_RTTIME + ,.rlimit_rttime = { .value = 200*PA_USEC_PER_MSEC, .is_set = true } /* rtkit's limit is 200 ms */ +#endif +#endif +}; + +pa_daemon_conf *pa_daemon_conf_new(void) { + pa_daemon_conf *c; + + c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); + +#ifdef OS_IS_WIN32 + c->dl_search_path = pa_sprintf_malloc("%s" PA_PATH_SEP "lib" PA_PATH_SEP "pulse-%d.%d" PA_PATH_SEP "modules", + pa_win32_get_toplevel(NULL), PA_MAJOR, PA_MINOR); +#else +#ifdef HAVE_RUNNING_FROM_BUILD_TREE + if (pa_run_from_build_tree()) { + pa_log_notice("Detected that we are run from the build tree, fixing search path."); +#ifdef MESON_BUILD + c->dl_search_path = pa_xstrdup(PA_BUILDDIR PA_PATH_SEP "src" PA_PATH_SEP "modules"); +#else + c->dl_search_path = pa_xstrdup(PA_BUILDDIR); +#endif // Endof #ifdef MESON_BUILD + } else +#endif // Endof #ifdef HAVE_RUNNING_FROM_BUILD_TREE + c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); +#endif // Endof #ifdef OS_IS_WIN32 + + return c; +} + +void pa_daemon_conf_free(pa_daemon_conf *c) { + pa_assert(c); + + pa_xfree(c->script_commands); + pa_xfree(c->dl_search_path); + pa_xfree(c->default_script_file); + + if (c->log_target) + pa_log_target_free(c->log_target); + + pa_xfree(c->config_file); + pa_xfree(c); +} + +int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { + pa_log_target *log_target = NULL; + + pa_assert(c); + pa_assert(string); + + if (!pa_streq(string, "auto")) { + log_target = pa_log_parse_target(string); + + if (!log_target) + return -1; + } + + c->log_target = log_target; + + return 0; +} + +int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { + uint32_t u; + pa_assert(c); + pa_assert(string); + + if (pa_atou(string, &u) >= 0) { + if (u >= PA_LOG_LEVEL_MAX) + return -1; + + c->log_level = (pa_log_level_t) u; + } else if (pa_startswith(string, "debug")) + c->log_level = PA_LOG_DEBUG; + else if (pa_startswith(string, "info")) + c->log_level = PA_LOG_INFO; + else if (pa_startswith(string, "notice")) + c->log_level = PA_LOG_NOTICE; + else if (pa_startswith(string, "warn")) + c->log_level = PA_LOG_WARN; + else if (pa_startswith(string, "err")) + c->log_level = PA_LOG_ERROR; + else + return -1; + + return 0; +} + +int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { + int m; + pa_assert(c); + pa_assert(string); + + if ((m = pa_parse_resample_method(string)) < 0) + return -1; + + c->resample_method = m; + return 0; +} + +int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string) { + pa_assert(c); + pa_assert(string); + + if (pa_streq(string, "user")) + c->local_server_type = PA_SERVER_TYPE_USER; + else if (pa_streq(string, "system")) { + c->local_server_type = PA_SERVER_TYPE_SYSTEM; + } else if (pa_streq(string, "none")) { + c->local_server_type = PA_SERVER_TYPE_NONE; + } else + return -1; + + return 0; +} + +static int parse_log_target(pa_config_parser_state *state) { + pa_daemon_conf *c; + + pa_assert(state); + + c = state->data; + + if (pa_daemon_conf_set_log_target(c, state->rvalue) < 0) { + pa_log(_("[%s:%u] Invalid log target '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + return 0; +} + +static int parse_log_level(pa_config_parser_state *state) { + pa_daemon_conf *c; + + pa_assert(state); + + c = state->data; + + if (pa_daemon_conf_set_log_level(c, state->rvalue) < 0) { + pa_log(_("[%s:%u] Invalid log level '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + return 0; +} + +static int parse_resample_method(pa_config_parser_state *state) { + pa_daemon_conf *c; + + pa_assert(state); + + c = state->data; + + if (pa_daemon_conf_set_resample_method(c, state->rvalue) < 0) { + pa_log(_("[%s:%u] Invalid resample method '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + return 0; +} + +#ifdef HAVE_SYS_RESOURCE_H +static int parse_rlimit(pa_config_parser_state *state) { + struct pa_rlimit *r; + + pa_assert(state); + + r = state->data; + + if (state->rvalue[strspn(state->rvalue, "\t ")] == 0) { + /* Empty string */ + r->is_set = 0; + r->value = 0; + } else { + int32_t k; + if (pa_atoi(state->rvalue, &k) < 0) { + pa_log(_("[%s:%u] Invalid rlimit '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + r->is_set = k >= 0; + r->value = k >= 0 ? (rlim_t) k : 0; + } + + return 0; +} +#endif + +static int parse_sample_format(pa_config_parser_state *state) { + pa_daemon_conf *c; + pa_sample_format_t f; + + pa_assert(state); + + c = state->data; + + if ((f = pa_parse_sample_format(state->rvalue)) < 0) { + pa_log(_("[%s:%u] Invalid sample format '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->default_sample_spec.format = f; + return 0; +} + +static int parse_sample_rate(pa_config_parser_state *state) { + pa_daemon_conf *c; + uint32_t r; + + pa_assert(state); + + c = state->data; + + if (pa_atou(state->rvalue, &r) < 0 || !pa_sample_rate_valid(r)) { + pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->default_sample_spec.rate = r; + return 0; +} + +static int parse_alternate_sample_rate(pa_config_parser_state *state) { + pa_daemon_conf *c; + uint32_t r; + + pa_assert(state); + + c = state->data; + + if (pa_atou(state->rvalue, &r) < 0 || !pa_sample_rate_valid(r)) { + pa_log(_("[%s:%u] Invalid sample rate '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->alternate_sample_rate = r; + return 0; +} + +struct channel_conf_info { + pa_daemon_conf *conf; + bool default_sample_spec_set; + bool default_channel_map_set; +}; + +static int parse_sample_channels(pa_config_parser_state *state) { + struct channel_conf_info *i; + int32_t n; + + pa_assert(state); + + i = state->data; + + if (pa_atoi(state->rvalue, &n) < 0 || !pa_channels_valid(n)) { + pa_log(_("[%s:%u] Invalid sample channels '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + i->conf->default_sample_spec.channels = (uint8_t) n; + i->default_sample_spec_set = true; + return 0; +} + +static int parse_channel_map(pa_config_parser_state *state) { + struct channel_conf_info *i; + + pa_assert(state); + + i = state->data; + + if (!pa_channel_map_parse(&i->conf->default_channel_map, state->rvalue)) { + pa_log(_("[%s:%u] Invalid channel map '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + i->default_channel_map_set = true; + return 0; +} + +static int parse_fragments(pa_config_parser_state *state) { + pa_daemon_conf *c; + int32_t n; + + pa_assert(state); + + c = state->data; + + if (pa_atoi(state->rvalue, &n) < 0 || n < 2) { + pa_log(_("[%s:%u] Invalid number of fragments '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->default_n_fragments = (unsigned) n; + return 0; +} + +static int parse_fragment_size_msec(pa_config_parser_state *state) { + pa_daemon_conf *c; + int32_t n; + + pa_assert(state); + + c = state->data; + + if (pa_atoi(state->rvalue, &n) < 0 || n < 1) { + pa_log(_("[%s:%u] Invalid fragment size '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->default_fragment_size_msec = (unsigned) n; + return 0; +} + +static int parse_nice_level(pa_config_parser_state *state) { + pa_daemon_conf *c; + int32_t level; + + pa_assert(state); + + c = state->data; + + if (pa_atoi(state->rvalue, &level) < 0 || level < -20 || level > 19) { + pa_log(_("[%s:%u] Invalid nice level '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + c->nice_level = (int) level; + return 0; +} + +static int parse_rtprio(pa_config_parser_state *state) { +#if !defined(OS_IS_WIN32) && defined(HAVE_SCHED_H) + pa_daemon_conf *c; + int32_t rtprio; +#endif + + pa_assert(state); + +#ifdef OS_IS_WIN32 + pa_log("[%s:%u] Realtime priority not available on win32.", state->filename, state->lineno); +#else +# ifdef HAVE_SCHED_H + c = state->data; + + if (pa_atoi(state->rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) { + pa_log("[%s:%u] Invalid realtime priority '%s'.", state->filename, state->lineno, state->rvalue); + return -1; + } + + c->realtime_priority = (int) rtprio; +# endif +#endif /* OS_IS_WIN32 */ + + return 0; +} + +static int parse_disable_lfe_remix(pa_config_parser_state *state) { + pa_daemon_conf *c; + int k; + + pa_assert(state); + c = state->data; + + if ((k = pa_parse_boolean(state->rvalue)) < 0) { + pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue); + return -1; + } + + c->remixing_produce_lfe = c->remixing_consume_lfe = !k; + + pa_log("[%s:%u] Deprecated option 'disable-lfe-remixing' found.", state->filename, state->lineno); + pa_log("[%s:%u] Please migrate to 'remixing-produce-lfe' and 'remixing-consume-lfe', set both to '%s'.", + state->filename, state->lineno, pa_yes_no(c->remixing_produce_lfe)); + + return 0; +} + +static int parse_enable_lfe_remix(pa_config_parser_state *state) { + pa_daemon_conf *c; + int k; + + pa_assert(state); + c = state->data; + + if ((k = pa_parse_boolean(state->rvalue)) < 0) { + pa_log("[%s:%u] Failed to parse boolean value: %s", state->filename, state->lineno, state->rvalue); + return -1; + } + + c->remixing_produce_lfe = c->remixing_consume_lfe = k; + + pa_log("[%s:%u] Deprecated option 'enable-lfe-remixing' found.", state->filename, state->lineno); + pa_log("[%s:%u] Please migrate to 'remixing-produce-lfe' and 'remixing-consume-lfe', set both to '%s'.", + state->filename, state->lineno, pa_yes_no(c->remixing_produce_lfe)); + + return 0; +} + +#ifdef HAVE_DBUS +static int parse_server_type(pa_config_parser_state *state) { + pa_daemon_conf *c; + + pa_assert(state); + + c = state->data; + + if (pa_daemon_conf_set_local_server_type(c, state->rvalue) < 0) { + pa_log(_("[%s:%u] Invalid server type '%s'."), state->filename, state->lineno, state->rvalue); + return -1; + } + + return 0; +} +#endif + +int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { + int r = -1; + FILE *f = NULL; + struct channel_conf_info ci; + pa_config_item table[] = { + { "daemonize", pa_config_parse_bool, &c->daemonize, NULL }, + { "fail", pa_config_parse_bool, &c->fail, NULL }, + { "high-priority", pa_config_parse_bool, &c->high_priority, NULL }, + { "realtime-scheduling", pa_config_parse_bool, &c->realtime_scheduling, NULL }, + { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading, NULL }, + { "allow-module-loading", pa_config_parse_not_bool, &c->disallow_module_loading, NULL }, + { "disallow-exit", pa_config_parse_bool, &c->disallow_exit, NULL }, + { "allow-exit", pa_config_parse_not_bool, &c->disallow_exit, NULL }, + { "use-pid-file", pa_config_parse_bool, &c->use_pid_file, NULL }, + { "system-instance", pa_config_parse_bool, &c->system_instance, NULL }, +#ifdef HAVE_DBUS + { "local-server-type", parse_server_type, c, NULL }, +#endif + { "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL }, + { "cpu-limit", pa_config_parse_not_bool, &c->no_cpu_limit, NULL }, + { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, + { "enable-memfd", pa_config_parse_not_bool, &c->disable_memfd, NULL }, + { "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL }, + { "rescue-streams", pa_config_parse_bool, &c->rescue_streams, NULL }, + { "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL }, + { "enable-deferred-volume", pa_config_parse_bool, &c->deferred_volume, NULL }, + { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time, NULL }, + { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time, NULL }, + { "realtime-priority", parse_rtprio, c, NULL }, + { "dl-search-path", pa_config_parse_string, &c->dl_search_path, NULL }, + { "default-script-file", pa_config_parse_string, &c->default_script_file, NULL }, + { "log-target", parse_log_target, c, NULL }, + { "log-level", parse_log_level, c, NULL }, + { "verbose", parse_log_level, c, NULL }, + { "resample-method", parse_resample_method, c, NULL }, + { "default-sample-format", parse_sample_format, c, NULL }, + { "default-sample-rate", parse_sample_rate, c, NULL }, + { "alternate-sample-rate", parse_alternate_sample_rate, c, NULL }, + { "default-sample-channels", parse_sample_channels, &ci, NULL }, + { "default-channel-map", parse_channel_map, &ci, NULL }, + { "default-fragments", parse_fragments, c, NULL }, + { "default-fragment-size-msec", parse_fragment_size_msec, c, NULL }, + { "deferred-volume-safety-margin-usec", + pa_config_parse_unsigned, &c->deferred_volume_safety_margin_usec, NULL }, + { "deferred-volume-extra-delay-usec", + pa_config_parse_int, &c->deferred_volume_extra_delay_usec, NULL }, + { "nice-level", parse_nice_level, c, NULL }, + { "avoid-resampling", pa_config_parse_bool, &c->avoid_resampling, NULL }, + { "disable-remixing", pa_config_parse_bool, &c->disable_remixing, NULL }, + { "enable-remixing", pa_config_parse_not_bool, &c->disable_remixing, NULL }, + { "remixing-use-all-sink-channels", + pa_config_parse_bool, &c->remixing_use_all_sink_channels, NULL }, + { "disable-lfe-remixing", parse_disable_lfe_remix, c, NULL }, + { "enable-lfe-remixing", parse_enable_lfe_remix, c, NULL }, + { "remixing-produce-lfe", pa_config_parse_bool, &c->remixing_produce_lfe, NULL }, + { "remixing-consume-lfe", pa_config_parse_bool, &c->remixing_consume_lfe, NULL }, + { "lfe-crossover-freq", pa_config_parse_unsigned, &c->lfe_crossover_freq, NULL }, + { "load-default-script-file", pa_config_parse_bool, &c->load_default_script_file, NULL }, + { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, + { "log-meta", pa_config_parse_bool, &c->log_meta, NULL }, + { "log-time", pa_config_parse_bool, &c->log_time, NULL }, + { "log-backtrace", pa_config_parse_unsigned, &c->log_backtrace, NULL }, +#ifdef HAVE_SYS_RESOURCE_H + { "rlimit-fsize", parse_rlimit, &c->rlimit_fsize, NULL }, + { "rlimit-data", parse_rlimit, &c->rlimit_data, NULL }, + { "rlimit-stack", parse_rlimit, &c->rlimit_stack, NULL }, + { "rlimit-core", parse_rlimit, &c->rlimit_core, NULL }, +#ifdef RLIMIT_RSS + { "rlimit-rss", parse_rlimit, &c->rlimit_rss, NULL }, +#endif +#ifdef RLIMIT_NOFILE + { "rlimit-nofile", parse_rlimit, &c->rlimit_nofile, NULL }, +#endif +#ifdef RLIMIT_AS + { "rlimit-as", parse_rlimit, &c->rlimit_as, NULL }, +#endif +#ifdef RLIMIT_NPROC + { "rlimit-nproc", parse_rlimit, &c->rlimit_nproc, NULL }, +#endif +#ifdef RLIMIT_MEMLOCK + { "rlimit-memlock", parse_rlimit, &c->rlimit_memlock, NULL }, +#endif +#ifdef RLIMIT_LOCKS + { "rlimit-locks", parse_rlimit, &c->rlimit_locks, NULL }, +#endif +#ifdef RLIMIT_SIGPENDING + { "rlimit-sigpending", parse_rlimit, &c->rlimit_sigpending, NULL }, +#endif +#ifdef RLIMIT_MSGQUEUE + { "rlimit-msgqueue", parse_rlimit, &c->rlimit_msgqueue, NULL }, +#endif +#ifdef RLIMIT_NICE + { "rlimit-nice", parse_rlimit, &c->rlimit_nice, NULL }, +#endif +#ifdef RLIMIT_RTPRIO + { "rlimit-rtprio", parse_rlimit, &c->rlimit_rtprio, NULL }, +#endif +#ifdef RLIMIT_RTTIME + { "rlimit-rttime", parse_rlimit, &c->rlimit_rttime, NULL }, +#endif +#endif + { NULL, NULL, NULL, NULL }, + }; + + pa_xfree(c->config_file); + c->config_file = NULL; + + f = filename ? + pa_fopen_cloexec(c->config_file = pa_xstrdup(filename), "r") : + pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); + + if (!f && errno != ENOENT) { + pa_log_warn(_("Failed to open configuration file: %s"), pa_cstrerror(errno)); + goto finish; + } + + ci.default_channel_map_set = ci.default_sample_spec_set = false; + ci.conf = c; + + r = f ? pa_config_parse(c->config_file, f, table, NULL, true, NULL) : 0; + + if (r >= 0) { + + /* Make sure that channel map and sample spec fit together */ + + if (ci.default_sample_spec_set && + ci.default_channel_map_set && + c->default_channel_map.channels != c->default_sample_spec.channels) { + pa_log_error(_("The specified default channel map has a different number of channels than the specified default number of channels.")); + r = -1; + goto finish; + } else if (ci.default_sample_spec_set) + pa_channel_map_init_extend(&c->default_channel_map, c->default_sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + else if (ci.default_channel_map_set) + c->default_sample_spec.channels = c->default_channel_map.channels; + } + +finish: + if (f) + fclose(f); + + return r; +} + +int pa_daemon_conf_env(pa_daemon_conf *c) { + char *e; + pa_assert(c); + + if ((e = getenv(ENV_DL_SEARCH_PATH))) { + pa_xfree(c->dl_search_path); + c->dl_search_path = pa_xstrdup(e); + } + if ((e = getenv(ENV_SCRIPT_FILE))) { + pa_xfree(c->default_script_file); + c->default_script_file = pa_xstrdup(e); + } + + return 0; +} + +const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c) { + pa_assert(c); + + if (!c->default_script_file) { + if (c->system_instance) + c->default_script_file = pa_find_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE); + else + c->default_script_file = pa_find_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE); + } + + return c->default_script_file; +} + +FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) { + FILE *f; + pa_assert(c); + + if (!c->default_script_file) { + if (c->system_instance) + f = pa_open_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE, &c->default_script_file); + else + f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file); + } else + f = pa_fopen_cloexec(c->default_script_file, "r"); + + return f; +} + +char *pa_daemon_conf_dump(pa_daemon_conf *c) { + static const char* const log_level_to_string[] = { + [PA_LOG_DEBUG] = "debug", + [PA_LOG_INFO] = "info", + [PA_LOG_NOTICE] = "notice", + [PA_LOG_WARN] = "warning", + [PA_LOG_ERROR] = "error" + }; + +#ifdef HAVE_DBUS + static const char* const server_type_to_string[] = { + [PA_SERVER_TYPE_UNSET] = "!!UNSET!!", + [PA_SERVER_TYPE_USER] = "user", + [PA_SERVER_TYPE_SYSTEM] = "system", + [PA_SERVER_TYPE_NONE] = "none" + }; +#endif + + pa_strbuf *s; + char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char *log_target = NULL; + + pa_assert(c); + + s = pa_strbuf_new(); + + if (c->config_file) + pa_strbuf_printf(s, _("### Read from configuration file: %s ###\n"), c->config_file); + + pa_assert(c->log_level < PA_LOG_LEVEL_MAX); + + if (c->log_target) + log_target = pa_log_target_to_string(c->log_target); + + pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize)); + pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail)); + pa_strbuf_printf(s, "high-priority = %s\n", pa_yes_no(c->high_priority)); + pa_strbuf_printf(s, "nice-level = %i\n", c->nice_level); + pa_strbuf_printf(s, "realtime-scheduling = %s\n", pa_yes_no(c->realtime_scheduling)); + pa_strbuf_printf(s, "realtime-priority = %i\n", c->realtime_priority); + pa_strbuf_printf(s, "allow-module-loading = %s\n", pa_yes_no(!c->disallow_module_loading)); + pa_strbuf_printf(s, "allow-exit = %s\n", pa_yes_no(!c->disallow_exit)); + pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file)); + pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance)); +#ifdef HAVE_DBUS + pa_strbuf_printf(s, "local-server-type = %s\n", server_type_to_string[c->local_server_type]); +#endif + pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit)); + pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm)); + pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes)); + pa_strbuf_printf(s, "rescue-streams = %s\n", pa_yes_no(c->rescue_streams)); + pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory)); + pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); + pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); + pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path)); + pa_strbuf_printf(s, "default-script-file = %s\n", pa_strempty(pa_daemon_conf_get_default_script_file(c))); + pa_strbuf_printf(s, "load-default-script-file = %s\n", pa_yes_no(c->load_default_script_file)); + pa_strbuf_printf(s, "log-target = %s\n", pa_strempty(log_target)); + pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); + pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); + pa_strbuf_printf(s, "avoid-resampling = %s\n", pa_yes_no(c->avoid_resampling)); + pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing)); + pa_strbuf_printf(s, "remixing-use-all-sink-channels = %s\n", pa_yes_no(c->remixing_use_all_sink_channels)); + pa_strbuf_printf(s, "remixing-produce-lfe = %s\n", pa_yes_no(c->remixing_produce_lfe)); + pa_strbuf_printf(s, "remixing-consume-lfe = %s\n", pa_yes_no(c->remixing_consume_lfe)); + pa_strbuf_printf(s, "lfe-crossover-freq = %u\n", c->lfe_crossover_freq); + pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); + pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); + pa_strbuf_printf(s, "alternate-sample-rate = %u\n", c->alternate_sample_rate); + pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); + pa_strbuf_printf(s, "default-channel-map = %s\n", pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map)); + pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments); + pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec); + pa_strbuf_printf(s, "enable-deferred-volume = %s\n", pa_yes_no(c->deferred_volume)); + pa_strbuf_printf(s, "deferred-volume-safety-margin-usec = %u\n", c->deferred_volume_safety_margin_usec); + pa_strbuf_printf(s, "deferred-volume-extra-delay-usec = %d\n", c->deferred_volume_extra_delay_usec); + pa_strbuf_printf(s, "shm-size-bytes = %lu\n", (unsigned long) c->shm_size); + pa_strbuf_printf(s, "log-meta = %s\n", pa_yes_no(c->log_meta)); + pa_strbuf_printf(s, "log-time = %s\n", pa_yes_no(c->log_time)); + pa_strbuf_printf(s, "log-backtrace = %u\n", c->log_backtrace); +#ifdef HAVE_SYS_RESOURCE_H + pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1); + pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1); + pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1); + pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); +#ifdef RLIMIT_RSS + pa_strbuf_printf(s, "rlimit-rss = %li\n", c->rlimit_rss.is_set ? (long int) c->rlimit_rss.value : -1); +#endif +#ifdef RLIMIT_AS + pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1); +#endif +#ifdef RLIMIT_NPROC + pa_strbuf_printf(s, "rlimit-nproc = %li\n", c->rlimit_nproc.is_set ? (long int) c->rlimit_nproc.value : -1); +#endif +#ifdef RLIMIT_NOFILE + pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1); +#endif +#ifdef RLIMIT_MEMLOCK + pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1); +#endif +#ifdef RLIMIT_LOCKS + pa_strbuf_printf(s, "rlimit-locks = %li\n", c->rlimit_locks.is_set ? (long int) c->rlimit_locks.value : -1); +#endif +#ifdef RLIMIT_SIGPENDING + pa_strbuf_printf(s, "rlimit-sigpending = %li\n", c->rlimit_sigpending.is_set ? (long int) c->rlimit_sigpending.value : -1); +#endif +#ifdef RLIMIT_MSGQUEUE + pa_strbuf_printf(s, "rlimit-msgqueue = %li\n", c->rlimit_msgqueue.is_set ? (long int) c->rlimit_msgqueue.value : -1); +#endif +#ifdef RLIMIT_NICE + pa_strbuf_printf(s, "rlimit-nice = %li\n", c->rlimit_nice.is_set ? (long int) c->rlimit_nice.value : -1); +#endif +#ifdef RLIMIT_RTPRIO + pa_strbuf_printf(s, "rlimit-rtprio = %li\n", c->rlimit_rtprio.is_set ? (long int) c->rlimit_rtprio.value : -1); +#endif +#ifdef RLIMIT_RTTIME + pa_strbuf_printf(s, "rlimit-rttime = %li\n", c->rlimit_rttime.is_set ? (long int) c->rlimit_rttime.value : -1); +#endif +#endif + + pa_xfree(log_target); + + return pa_strbuf_to_string_free(s); +} diff --git a/pulseaudio/src/daemon/ohos_pa_main.c b/pulseaudio/src/daemon/ohos_pa_main.c new file mode 100644 index 0000000000..2d56ad3236 --- /dev/null +++ b/pulseaudio/src/daemon/ohos_pa_main.c @@ -0,0 +1,1274 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif + +#ifdef HAVE_LIBWRAP +#include +#include +#endif + +#ifdef HAVE_DBUS +#include +#endif + +#ifdef HAVE_SYSTEMD_DAEMON +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_DBUS +#include +#endif +#include + +#include "cmdline.h" +#include "cpulimit.h" +#include "daemon-conf.h" +#include "dumpmodules.h" +#include "caps.h" +#include "ltdl-bind-now.h" +#include "server-lookup.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* End of #ifdef __cplusplus */ +#ifdef DISABLE_LIBTOOL_PRELOAD +/* FIXME: work around a libtool bug by making sure we have 2 elements. Bug has + * been reported: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=29576 */ +const lt_dlsymlist lt_preloaded_symbols[] = { + { "@PROGRAM@", NULL }, + { NULL, NULL } +}; +#endif + +#ifdef HAVE_LIBWRAP +/* Only one instance of these variables */ +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + +#ifdef HAVE_OSS_WRAPPER +/* padsp looks for this symbol in the running process and disables + * itself if it finds it and it is set to 7 (which is actually a bit + * mask). For details see padsp. */ +int __padsp_disabled__ = 7; +#endif + +static void signal_callback(pa_mainloop_api* m, pa_signal_event *e, int sig, void *userdata) { + pa_module *module = NULL; + + pa_log_info("Got signal %s.", pa_sig2str(sig)); + + switch (sig) { +#ifdef SIGUSR1 + case SIGUSR1: + pa_module_load(&module, userdata, "module-cli", NULL); + break; +#endif + +#ifdef SIGUSR2 + case SIGUSR2: + pa_module_load(&module, userdata, "module-cli-protocol-unix", NULL); + break; +#endif + +#ifdef SIGHUP + case SIGHUP: { + char *c = pa_full_status_string(userdata); + pa_log_notice("%s", c); + pa_xfree(c); + return; + } +#endif + + case SIGINT: + case SIGTERM: + default: + pa_log_info("Exiting."); + m->quit(m, 0); + break; + } +} + +#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H) + +static int change_user(void) { + struct passwd *pw; + struct group * gr; + int r; + + /* This function is called only in system-wide mode. It creates a + * runtime dir in /var/run/ with proper UID/GID and drops privs + * afterwards. */ + + if (!(pw = getpwnam(PA_SYSTEM_USER))) { + pa_log(_("Failed to find user '%s'."), PA_SYSTEM_USER); + return -1; + } + + if (!(gr = getgrnam(PA_SYSTEM_GROUP))) { + pa_log(_("Failed to find group '%s'."), PA_SYSTEM_GROUP); + return -1; + } + + pa_log_info("Found user '%s' (UID %lu) and group '%s' (GID %lu).", + PA_SYSTEM_USER, (unsigned long) pw->pw_uid, + PA_SYSTEM_GROUP, (unsigned long) gr->gr_gid); + + if (pw->pw_gid != gr->gr_gid) { + pa_log(_("GID of user '%s' and of group '%s' don't match."), PA_SYSTEM_USER, PA_SYSTEM_GROUP); + return -1; + } + + if (!pa_streq(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH)) + pa_log_warn(_("Home directory of user '%s' is not '%s', ignoring."), PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH); + + if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid, true) < 0) { + pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno)); + return -1; + } + + if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid, true) < 0) { + pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_STATE_PATH, pa_cstrerror(errno)); + return -1; + } + + /* We don't create the config dir here, because we don't need to write to it */ + + if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) { + pa_log(_("Failed to change group list: %s"), pa_cstrerror(errno)); + return -1; + } + +#if defined(HAVE_SETRESGID) + r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid); +#elif defined(HAVE_SETEGID) + if ((r = setgid(gr->gr_gid)) >= 0) + r = setegid(gr->gr_gid); +#elif defined(HAVE_SETREGID) + r = setregid(gr->gr_gid, gr->gr_gid); +#else +#error "No API to drop privileges" +#endif + + if (r < 0) { + pa_log(_("Failed to change GID: %s"), pa_cstrerror(errno)); + return -1; + } + +#if defined(HAVE_SETRESUID) + r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid); +#elif defined(HAVE_SETEUID) + if ((r = setuid(pw->pw_uid)) >= 0) + r = seteuid(pw->pw_uid); +#elif defined(HAVE_SETREUID) + r = setreuid(pw->pw_uid, pw->pw_uid); +#else +#error "No API to drop privileges" +#endif + + if (r < 0) { + pa_log(_("Failed to change UID: %s"), pa_cstrerror(errno)); + return -1; + } + + pa_drop_caps(); + + pa_set_env("USER", PA_SYSTEM_USER); + pa_set_env("USERNAME", PA_SYSTEM_USER); + pa_set_env("LOGNAME", PA_SYSTEM_USER); + pa_set_env("HOME", PA_SYSTEM_RUNTIME_PATH); + + /* Relevant for pa_runtime_path() */ + if (!getenv("PULSE_RUNTIME_PATH")) + pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); + + if (!getenv("PULSE_CONFIG_PATH")) + pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH); + + if (!getenv("PULSE_STATE_PATH")) + pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH); + + pa_log_info("Successfully changed user to \"" PA_SYSTEM_USER "\"."); + + return 0; +} + +#else /* HAVE_PWD_H && HAVE_GRP_H */ + +static int change_user(void) { + pa_log(_("System wide mode unsupported on this platform.")); + return -1; +} + +#endif /* HAVE_PWD_H && HAVE_GRP_H */ + +#ifdef HAVE_SYS_RESOURCE_H + +static int set_one_rlimit(const pa_rlimit *r, int resource, const char *name) { + struct rlimit rl; + pa_assert(r); + + if (!r->is_set) + return 0; + + rl.rlim_cur = rl.rlim_max = r->value; + + if (setrlimit(resource, &rl) < 0) { + pa_log_info("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno)); + return -1; + } + + return 0; +} + +static void set_all_rlimits(const pa_daemon_conf *conf) { + set_one_rlimit(&conf->rlimit_fsize, RLIMIT_FSIZE, "RLIMIT_FSIZE"); + set_one_rlimit(&conf->rlimit_data, RLIMIT_DATA, "RLIMIT_DATA"); + set_one_rlimit(&conf->rlimit_stack, RLIMIT_STACK, "RLIMIT_STACK"); + set_one_rlimit(&conf->rlimit_core, RLIMIT_CORE, "RLIMIT_CORE"); +#ifdef RLIMIT_RSS + set_one_rlimit(&conf->rlimit_rss, RLIMIT_RSS, "RLIMIT_RSS"); +#endif +#ifdef RLIMIT_NPROC + set_one_rlimit(&conf->rlimit_nproc, RLIMIT_NPROC, "RLIMIT_NPROC"); +#endif +#ifdef RLIMIT_NOFILE + set_one_rlimit(&conf->rlimit_nofile, RLIMIT_NOFILE, "RLIMIT_NOFILE"); +#endif +#ifdef RLIMIT_MEMLOCK + set_one_rlimit(&conf->rlimit_memlock, RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK"); +#endif +#ifdef RLIMIT_AS + set_one_rlimit(&conf->rlimit_as, RLIMIT_AS, "RLIMIT_AS"); +#endif +#ifdef RLIMIT_LOCKS + set_one_rlimit(&conf->rlimit_locks, RLIMIT_LOCKS, "RLIMIT_LOCKS"); +#endif +#ifdef RLIMIT_SIGPENDING + set_one_rlimit(&conf->rlimit_sigpending, RLIMIT_SIGPENDING, "RLIMIT_SIGPENDING"); +#endif +#ifdef RLIMIT_MSGQUEUE + set_one_rlimit(&conf->rlimit_msgqueue, RLIMIT_MSGQUEUE, "RLIMIT_MSGQUEUE"); +#endif +#ifdef RLIMIT_NICE + set_one_rlimit(&conf->rlimit_nice, RLIMIT_NICE, "RLIMIT_NICE"); +#endif +#ifdef RLIMIT_RTPRIO + set_one_rlimit(&conf->rlimit_rtprio, RLIMIT_RTPRIO, "RLIMIT_RTPRIO"); +#endif +#ifdef RLIMIT_RTTIME + set_one_rlimit(&conf->rlimit_rttime, RLIMIT_RTTIME, "RLIMIT_RTTIME"); +#endif +} +#endif + +static char *check_configured_address(void) { + char *default_server = NULL; + pa_client_conf *c = pa_client_conf_new(); + + pa_client_conf_load(c, true, true); + + if (c->default_server && *c->default_server) + default_server = pa_xstrdup(c->default_server); + + pa_client_conf_free(c); + + return default_server; +} + +#ifdef HAVE_DBUS +static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) { + DBusError error; + pa_dbus_connection *conn; + + dbus_error_init(&error); + + if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) { + pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message); + goto fail; + } + + if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + pa_log_debug("Got %s!", name); + return conn; + } + + if (dbus_error_is_set(&error)) + pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message); + else + pa_log_error("D-Bus name %s already taken.", name); + + /* PA cannot be started twice by the same user and hence we can + * ignore mostly the case that a name is already taken. */ + +fail: + if (conn) + pa_dbus_connection_unref(conn); + + dbus_error_free(&error); + return NULL; +} +#endif + +int ohos_pa_main(int argc, char *argv[]) { + pa_core *c = NULL; + pa_strbuf *buf = NULL; + pa_daemon_conf *conf = NULL; + pa_mainloop *mainloop = NULL; + char *s; + char *configured_address; + int r = 0, retval = 1, d = 0; + bool valid_pid_file = false; +#ifdef HAVE_NO_OHOS + bool ltdl_init = false; +#endif + int n_fds = 0, *passed_fds = NULL; + const char *e; +#ifdef HAVE_FORK + int daemon_pipe[2] = { -1, -1 }; + int daemon_pipe2[2] = { -1, -1 }; +#endif + int autospawn_fd = -1; + bool autospawn_locked = false; +#ifdef HAVE_DBUS + pa_dbusobj_server_lookup *server_lookup = NULL; /* /org/pulseaudio/server_lookup */ + pa_dbus_connection *lookup_service_bus = NULL; /* Always the user bus. */ + pa_dbus_connection *server_bus = NULL; /* The bus where we reserve org.pulseaudio.Server, either the user or the system bus. */ + bool start_server; +#endif + + pa_log_set_ident("pulseaudio"); + pa_log_set_level(PA_LOG_NOTICE); + pa_log_set_flags(PA_LOG_COLORS|PA_LOG_PRINT_FILE|PA_LOG_PRINT_LEVEL, PA_LOG_RESET); + +#if !defined(HAVE_BIND_NOW) && defined(__linux__) && defined(__OPTIMIZE__) + /* + Disable lazy relocations to make usage of external libraries + more deterministic for our RT threads. We abuse __OPTIMIZE__ as + a check whether we are a debug build or not. This all is + admittedly a bit snake-oilish. + */ + + if (!getenv("LD_BIND_NOW")) { + char *rp; + char *canonical_rp; + + /* We have to execute ourselves, because the libc caches the + * value of $LD_BIND_NOW on initialization. */ + + pa_set_env("LD_BIND_NOW", "1"); + + if ((canonical_rp = pa_realpath(PA_BINARY))) { + + if ((rp = pa_readlink("/proc/self/exe"))) { + + if (pa_streq(rp, canonical_rp)) + pa_assert_se(execv(rp, argv) == 0); + else + pa_log_warn("/proc/self/exe does not point to %s, cannot self execute. Are you playing games?", canonical_rp); + + pa_xfree(rp); + + } else + pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); + + pa_xfree(canonical_rp); + + } else + pa_log_warn("Couldn't canonicalize binary path, cannot self execute."); + } +#endif + +#ifdef HAVE_SYSTEMD_DAEMON + n_fds = sd_listen_fds(0); + if (n_fds > 0) { + int i = n_fds; + + passed_fds = pa_xnew(int, n_fds+2); + passed_fds[n_fds] = passed_fds[n_fds+1] = -1; + while (i--) + passed_fds[i] = SD_LISTEN_FDS_START + i; + } +#endif + + if (!passed_fds) { + n_fds = 0; + passed_fds = pa_xnew(int, 2); + passed_fds[0] = passed_fds[1] = -1; + } + + if ((e = getenv("PULSE_PASSED_FD"))) { + int passed_fd = atoi(e); + if (passed_fd > 2) + passed_fds[n_fds] = passed_fd; + } + + /* We might be autospawned, in which case have no idea in which + * context we have been started. Let's cleanup our execution + * context as good as possible */ + + pa_reset_personality(); + pa_drop_root(); +#ifdef HAVE_NO_OHOS + pa_close_allv(passed_fds); + pa_xfree(passed_fds); +#endif + pa_reset_sigs(-1); + pa_unblock_sigs(-1); + pa_reset_priority(); + + /* Load locale from the environment. */ + setlocale(LC_ALL, ""); + + /* Set LC_NUMERIC to C so that floating point strings are consistently + * formatted and parsed across locales. */ + setlocale(LC_NUMERIC, "C"); + + pa_init_i18n(); + + conf = pa_daemon_conf_new(); + + if (pa_daemon_conf_load(conf, NULL) < 0) + goto finish; + + if (pa_daemon_conf_env(conf) < 0) + goto finish; + + if (pa_cmdline_parse(conf, argc, argv, &d) < 0) { + pa_log(_("Failed to parse command line.")); + goto finish; + } + + if (conf->log_target) + pa_log_set_target(conf->log_target); + else { + pa_log_target target = { .type = PA_LOG_STDERR, .file = NULL }; + pa_log_set_target(&target); + } + + pa_log_set_level(conf->log_level); + if (conf->log_meta) + pa_log_set_flags(PA_LOG_PRINT_META, PA_LOG_SET); + if (conf->log_time) + pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET); + pa_log_set_show_backtrace(conf->log_backtrace); + +#ifdef HAVE_DBUS + /* conf->system_instance and conf->local_server_type control almost the + * same thing; make them agree about what is requested. */ + switch (conf->local_server_type) { + case PA_SERVER_TYPE_UNSET: + conf->local_server_type = conf->system_instance ? PA_SERVER_TYPE_SYSTEM : PA_SERVER_TYPE_USER; + break; + case PA_SERVER_TYPE_USER: + case PA_SERVER_TYPE_NONE: + conf->system_instance = false; + break; + case PA_SERVER_TYPE_SYSTEM: + conf->system_instance = true; + break; + default: + pa_assert_not_reached(); + } + + start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (getuid() == 0 && conf->local_server_type == PA_SERVER_TYPE_SYSTEM); + + if (!start_server && conf->local_server_type == PA_SERVER_TYPE_SYSTEM) { + pa_log_notice(_("System mode refused for non-root user. Only starting the D-Bus server lookup service.")); + conf->system_instance = false; + } +#endif + +#ifdef HAVE_NO_OHOS + LTDL_SET_PRELOADED_SYMBOLS(); + pa_ltdl_init(); + ltdl_init = true; + + if (conf->dl_search_path) + lt_dlsetsearchpath(conf->dl_search_path); +#endif + +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + + pa_random_seed(); + + switch (conf->cmd) { + case PA_CMD_DUMP_MODULES: +#ifdef HAVE_NO_OHOS + pa_dump_modules(conf, argc-d, argv+d); +#endif + retval = 0; + goto finish; + + case PA_CMD_DUMP_CONF: { + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + s = pa_daemon_conf_dump(conf); + fputs(s, stdout); + pa_xfree(s); + retval = 0; + goto finish; + } + + case PA_CMD_DUMP_RESAMPLE_METHODS: { + int i; + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + for (i = 0; i < PA_RESAMPLER_MAX; i++) + if (pa_resample_method_supported(i)) + printf("%s\n", pa_resample_method_to_string(i)); + + retval = 0; + goto finish; + } + + case PA_CMD_HELP : + pa_cmdline_help(argv[0]); + retval = 0; + goto finish; + + case PA_CMD_VERSION : + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); + retval = 0; + goto finish; + + case PA_CMD_CHECK: { + pid_t pid; + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) + pa_log_info("Daemon not running"); + else { + pa_log_info("Daemon running as PID %u", pid); + retval = 0; + } + + goto finish; + + } + case PA_CMD_KILL: + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0) + pa_log(_("Failed to kill daemon: %s"), pa_cstrerror(errno)); + else + retval = 0; + + goto finish; + + case PA_CMD_CLEANUP_SHM: + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + + if (pa_shm_cleanup() >= 0) + retval = 0; + + goto finish; + + default: + pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START); + } + + if (d < argc) { + pa_log("Too many arguments."); + goto finish; + } + +#ifdef HAVE_GETUID + if (getuid() == 0 && !conf->system_instance) + pa_log_warn(_("This program is not intended to be run as root (unless --system is specified).")); +#ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */ + else if (getuid() != 0 && conf->system_instance) { + pa_log(_("Root privileges required.")); + goto finish; + } +#endif +#endif /* HAVE_GETUID */ + + if (conf->cmd == PA_CMD_START && conf->system_instance) { + pa_log(_("--start not supported for system instances.")); + goto finish; + } + + if (conf->cmd == PA_CMD_START && (configured_address = check_configured_address())) { + /* There is an server address in our config, but where did it come from? + * By default a standard X11 login will load module-x11-publish which will + * inject PULSE_SERVER X11 property. If the PA daemon crashes, we will end + * up hitting this code path. So we have to check to see if our configured_address + * is the same as the value that would go into this property so that we can + * recover (i.e. autospawn) from a crash. + */ + char *ufn; + bool start_anyway = false; + + if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { + char *id; + + if ((id = pa_machine_id())) { + pa_strlist *server_list; + char formatted_ufn[256]; + + pa_snprintf(formatted_ufn, sizeof(formatted_ufn), "{%s}unix:%s", id, ufn); + pa_xfree(id); + + if ((server_list = pa_strlist_parse(configured_address))) { + char *u = NULL; + + /* We only need to check the first server */ + server_list = pa_strlist_pop(server_list, &u); + pa_strlist_free(server_list); + + start_anyway = (u && pa_streq(formatted_ufn, u)); + pa_xfree(u); + } + } + pa_xfree(ufn); + } + + if (!start_anyway) { + pa_log_notice(_("User-configured server at %s, refusing to start/autospawn."), configured_address); + pa_xfree(configured_address); + retval = 0; + goto finish; + } + + pa_log_notice(_("User-configured server at %s, which appears to be local. Probing deeper."), configured_address); + pa_xfree(configured_address); + } + + if (conf->system_instance && !conf->disallow_exit) + pa_log_warn(_("Running in system mode, but --disallow-exit not set.")); + + if (conf->system_instance && !conf->disallow_module_loading) + pa_log_warn(_("Running in system mode, but --disallow-module-loading not set.")); + + if (conf->system_instance && !conf->disable_shm) { + pa_log_notice(_("Running in system mode, forcibly disabling SHM mode.")); + conf->disable_shm = true; + } + + if (conf->system_instance && conf->exit_idle_time >= 0) { + pa_log_notice(_("Running in system mode, forcibly disabling exit idle time.")); + conf->exit_idle_time = -1; + } + + if (conf->cmd == PA_CMD_START) { + /* If we shall start PA only when it is not running yet, we + * first take the autospawn lock to make things + * synchronous. */ + + /* This locking and thread synchronisation code doesn't work reliably + * on kFreeBSD (Debian bug #705435), or in upstream FreeBSD ports + * (bug reference: ports/128947, patched in SVN r231972). */ +#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) + if ((autospawn_fd = pa_autospawn_lock_init()) < 0) { + pa_log("Failed to initialize autospawn lock"); + goto finish; + } + + if ((pa_autospawn_lock_acquire(true) < 0)) { + pa_log("Failed to acquire autospawn lock"); + goto finish; + } + + autospawn_locked = true; +#endif + } + + if (conf->daemonize) { +#ifdef HAVE_FORK + pid_t child; +#endif + + if (pa_stdio_acquire() < 0) { + pa_log(_("Failed to acquire stdio.")); + goto finish; + } + +#ifdef HAVE_FORK + if (pipe(daemon_pipe) < 0) { + pa_log(_("pipe() failed: %s"), pa_cstrerror(errno)); + goto finish; + } + + if ((child = fork()) < 0) { + pa_log(_("fork() failed: %s"), pa_cstrerror(errno)); + pa_close_pipe(daemon_pipe); + goto finish; + } + + if (child != 0) { + ssize_t n; + /* Father */ + + pa_assert_se(pa_close(daemon_pipe[1]) == 0); + daemon_pipe[1] = -1; + + if ((n = pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL)) != sizeof(retval)) { + + if (n < 0) + pa_log(_("read() failed: %s"), pa_cstrerror(errno)); + + retval = 1; + } + + if (retval) + pa_log(_("Daemon startup failed.")); + else + pa_log_info("Daemon startup successful."); + + goto finish; + } + + if (autospawn_fd >= 0) { + /* The lock file is unlocked from the parent, so we need + * to close it in the child */ + + pa_autospawn_lock_release(); + pa_autospawn_lock_done(true); + + autospawn_locked = false; + autospawn_fd = -1; + } + + pa_assert_se(pa_close(daemon_pipe[0]) == 0); + daemon_pipe[0] = -1; +#endif + + if (!conf->log_target) { +#ifdef HAVE_SYSTEMD_JOURNAL + pa_log_target target = { .type = PA_LOG_JOURNAL, .file = NULL }; +#else + pa_log_target target = { .type = PA_LOG_SYSLOG, .file = NULL }; +#endif + pa_log_set_target(&target); + } + +#ifdef HAVE_SETSID + if (setsid() < 0) { + pa_log(_("setsid() failed: %s"), pa_cstrerror(errno)); + goto finish; + } +#endif + +#ifdef HAVE_FORK + /* We now are a session and process group leader. Let's fork + * again and let the father die, so that we'll become a + * process that can never acquire a TTY again, in a session and + * process group without leader */ + + if (pipe(daemon_pipe2) < 0) { + pa_log(_("pipe() failed: %s"), pa_cstrerror(errno)); + goto finish; + } + + if ((child = fork()) < 0) { + pa_log(_("fork() failed: %s"), pa_cstrerror(errno)); + pa_close_pipe(daemon_pipe2); + goto finish; + } + + if (child != 0) { + ssize_t n; + /* Father */ + + pa_assert_se(pa_close(daemon_pipe2[1]) == 0); + daemon_pipe2[1] = -1; + + if ((n = pa_loop_read(daemon_pipe2[0], &retval, sizeof(retval), NULL)) != sizeof(retval)) { + + if (n < 0) + pa_log(_("read() failed: %s"), pa_cstrerror(errno)); + + retval = 1; + } + + /* We now have to take care of signalling the first fork with + * the return value we've received from this fork... */ + pa_assert(daemon_pipe[1] >= 0); + + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); + pa_close(daemon_pipe[1]); + daemon_pipe[1] = -1; + + goto finish; + } + + pa_assert_se(pa_close(daemon_pipe2[0]) == 0); + daemon_pipe2[0] = -1; + + /* We no longer need the (first) daemon_pipe as it's handled in our child above */ + pa_close_pipe(daemon_pipe); +#endif + +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif + + pa_nullify_stdfds(); + } + + pa_set_env_and_record("PULSE_INTERNAL", "1"); + pa_assert_se(chdir("/") == 0); + umask(0077); + +#ifdef HAVE_SYS_RESOURCE_H + set_all_rlimits(conf); +#endif + pa_rtclock_hrtimer_enable(); + + if (conf->high_priority) + pa_raise_priority(conf->nice_level); + + if (conf->system_instance) + if (change_user() < 0) + goto finish; + + pa_set_env_and_record("PULSE_SYSTEM", conf->system_instance ? "1" : "0"); + + pa_log_info("This is PulseAudio %s", PACKAGE_VERSION); + pa_log_debug("Compilation CFLAGS: %s", PA_CFLAGS); + +#ifdef HAVE_LIBSAMPLERATE + pa_log_warn("Compiled with DEPRECATED libsamplerate support!"); +#endif + + s = pa_uname_string(); + pa_log_debug("Running on host: %s", s); + pa_xfree(s); + + pa_log_debug("Found %u CPUs.", pa_ncpus()); + + pa_log_info("Page size is %zu bytes", pa_page_size()); + +#ifdef HAVE_VALGRIND_MEMCHECK_H + pa_log_debug("Compiled with Valgrind support: yes"); +#else + pa_log_debug("Compiled with Valgrind support: no"); +#endif + + pa_log_debug("Running in valgrind mode: %s", pa_yes_no(pa_in_valgrind())); + + pa_log_debug("Running in VM: %s", pa_yes_no(pa_running_in_vm())); + +#ifdef HAVE_RUNNING_FROM_BUILD_TREE + pa_log_debug("Running from build tree: %s", pa_yes_no(pa_run_from_build_tree())); +#else + pa_log_debug("Running from build tree: no"); +#endif + +#ifdef __OPTIMIZE__ + pa_log_debug("Optimized build: yes"); +#else + pa_log_debug("Optimized build: no"); +#endif + +#ifdef NDEBUG + pa_log_debug("NDEBUG defined, all asserts disabled."); +#elif defined(FASTPATH) + pa_log_debug("FASTPATH defined, only fast path asserts disabled."); +#else + pa_log_debug("All asserts enabled."); +#endif + + if (!(s = pa_machine_id())) { + pa_log(_("Failed to get machine ID")); + goto finish; + } + pa_log_info("Machine ID is %s.", s); + pa_xfree(s); + + if ((s = pa_session_id())) { + pa_log_info("Session ID is %s.", s); + pa_xfree(s); + } + + if (!(s = pa_get_runtime_dir())) + goto finish; + pa_log_info("Using runtime directory %s.", s); + pa_xfree(s); + + if (!(s = pa_get_state_dir())) + goto finish; + pa_log_info("Using state directory %s.", s); + pa_xfree(s); + + pa_log_info("Using modules directory %s.", conf->dl_search_path); + + pa_log_info("Running in system mode: %s", pa_yes_no(pa_in_system_mode())); + + if (pa_in_system_mode()) + pa_log_warn(_("OK, so you are running PA in system mode. Please make sure that you actually do want to do that.\n" + "Please read http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/ for an explanation why system mode is usually a bad idea.")); + + if (conf->use_pid_file) { + int z; + + if ((z = pa_pid_file_create("pulseaudio")) != 0) { + + if (conf->cmd == PA_CMD_START && z > 0) { + /* If we are already running and with are run in + * --start mode, then let's return this as success. */ + + retval = 0; + goto finish; + } + + pa_log(_("pa_pid_file_create() failed.")); + goto finish; + } + + valid_pid_file = true; + } + + pa_disable_sigpipe(); + + if (pa_rtclock_hrtimer()) + pa_log_info("System supports high resolution timers"); + else + pa_log_info("System appears to not support high resolution timers"); + + if (conf->lock_memory) { +#if defined(HAVE_SYS_MMAN_H) && !defined(__ANDROID__) + if (mlockall(MCL_FUTURE) < 0) + pa_log_warn("mlockall() failed: %s", pa_cstrerror(errno)); + else + pa_log_info("Successfully locked process into memory."); +#else + pa_log_warn("Memory locking requested but not supported on platform."); +#endif + } + + pa_memtrap_install(); + + pa_assert_se(mainloop = pa_mainloop_new()); + + if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, + !conf->disable_shm && !conf->disable_memfd && pa_memfd_is_locally_supported(), + conf->shm_size))) { + pa_log(_("pa_core_new() failed.")); + goto finish; + } + + c->default_sample_spec = conf->default_sample_spec; + c->alternate_sample_rate = conf->alternate_sample_rate; + c->default_channel_map = conf->default_channel_map; + c->default_n_fragments = conf->default_n_fragments; + c->default_fragment_size_msec = conf->default_fragment_size_msec; + c->deferred_volume_safety_margin_usec = conf->deferred_volume_safety_margin_usec; + c->deferred_volume_extra_delay_usec = conf->deferred_volume_extra_delay_usec; + c->lfe_crossover_freq = conf->lfe_crossover_freq; + c->exit_idle_time = conf->exit_idle_time; + c->scache_idle_time = conf->scache_idle_time; + c->resample_method = conf->resample_method; + c->realtime_priority = conf->realtime_priority; + c->realtime_scheduling = conf->realtime_scheduling; + c->avoid_resampling = conf->avoid_resampling; + c->disable_remixing = conf->disable_remixing; + c->remixing_use_all_sink_channels = conf->remixing_use_all_sink_channels; + c->remixing_produce_lfe = conf->remixing_produce_lfe; + c->remixing_consume_lfe = conf->remixing_consume_lfe; + c->deferred_volume = conf->deferred_volume; + c->running_as_daemon = conf->daemonize; + c->disallow_exit = conf->disallow_exit; + c->flat_volumes = conf->flat_volumes; + c->rescue_streams = conf->rescue_streams; +#ifdef HAVE_DBUS + c->server_type = conf->local_server_type; +#endif + + pa_core_check_idle(c); + + c->state = PA_CORE_RUNNING; +#ifdef HAVE_CPU_INFO + pa_cpu_init(&c->cpu_info); +#endif + pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); + pa_signal_new(SIGINT, signal_callback, c); + pa_signal_new(SIGTERM, signal_callback, c); +#ifdef SIGUSR1 + pa_signal_new(SIGUSR1, signal_callback, c); +#endif +#ifdef SIGUSR2 + pa_signal_new(SIGUSR2, signal_callback, c); +#endif +#ifdef SIGHUP + pa_signal_new(SIGHUP, signal_callback, c); +#endif + + if (!conf->no_cpu_limit) + pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0); + + buf = pa_strbuf_new(); + +#ifdef HAVE_DBUS + pa_assert_se(dbus_threads_init_default()); + + if (start_server) +#endif + { + const char *command_source = NULL; + + if (conf->load_default_script_file) { + FILE *f; + + if ((f = pa_daemon_conf_open_default_script_file(conf))) { + r = pa_cli_command_execute_file_stream(c, f, buf, &conf->fail); + fclose(f); + command_source = pa_daemon_conf_get_default_script_file(conf); + } + } + + if (r >= 0) { + r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail); + command_source = _("command line arguments"); + } + + pa_log_error("%s", s = pa_strbuf_to_string_free(buf)); + pa_xfree(s); + + if (r < 0 && conf->fail) { + pa_log(_("Failed to initialize daemon due to errors while executing startup commands. Source of commands: %s"), command_source); + goto finish; + } + + if (!c->modules || pa_idxset_size(c->modules) == 0) { + pa_log(_("Daemon startup without any loaded modules, refusing to work.")); + goto finish; + } +#ifdef HAVE_DBUS + } else { + /* When we just provide the D-Bus server lookup service, we don't want + * any modules to be loaded. We haven't loaded any so far, so one might + * think there's no way to contact the server, but receiving certain + * signals could still cause modules to load. */ + conf->disallow_module_loading = true; +#endif + } + + /* We completed the initial module loading, so let's disable it + * from now on, if requested */ + c->disallow_module_loading = conf->disallow_module_loading; + +#ifdef HAVE_DBUS + if (!conf->system_instance) { + if ((server_lookup = pa_dbusobj_server_lookup_new(c))) { + if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.PulseAudio1"))) + goto finish; + } + } + + if (start_server) + server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server"); +#endif + +#ifdef HAVE_FORK + if (daemon_pipe2[1] >= 0) { + int ok = 0; + pa_loop_write(daemon_pipe2[1], &ok, sizeof(ok), NULL); + pa_close(daemon_pipe2[1]); + daemon_pipe2[1] = -1; + } +#endif + + pa_log_info("Daemon startup complete."); + +#ifdef HAVE_SYSTEMD_DAEMON + sd_notify(0, "READY=1"); +#endif + + retval = 0; + if (pa_mainloop_run(mainloop, &retval) < 0) + goto finish; + + pa_log_info("Daemon shutdown initiated."); + +#ifdef HAVE_SYSTEMD_DAEMON + sd_notify(0, "STOPPING=1"); +#endif + +finish: +#ifdef HAVE_DBUS + if (server_bus) + pa_dbus_connection_unref(server_bus); + if (lookup_service_bus) + pa_dbus_connection_unref(lookup_service_bus); + if (server_lookup) + pa_dbusobj_server_lookup_free(server_lookup); +#endif + + if (autospawn_fd >= 0) { + if (autospawn_locked) + pa_autospawn_lock_release(); + + pa_autospawn_lock_done(false); + } + + if (c) { + /* Ensure all the modules/samples are unloaded when the core is still ref'ed, + * as unlink callback hooks in modules may need the core to be ref'ed */ + pa_module_unload_all(c); + pa_scache_free_all(c); + + pa_core_unref(c); + pa_log_info("Daemon terminated."); + } + + if (!conf->no_cpu_limit) + pa_cpu_limit_done(); + + pa_signal_done(); + +#ifdef HAVE_FORK + /* If we have daemon_pipe[1] still open, this means we've failed after + * the first fork, but before the second. Therefore just write to it. */ + if (daemon_pipe[1] >= 0) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); + else if (daemon_pipe2[1] >= 0) + pa_loop_write(daemon_pipe2[1], &retval, sizeof(retval), NULL); + + pa_close_pipe(daemon_pipe2); + pa_close_pipe(daemon_pipe); +#endif + + if (mainloop) + pa_mainloop_free(mainloop); + + if (conf) + pa_daemon_conf_free(conf); + + if (valid_pid_file) + pa_pid_file_remove(); + + /* This has no real purpose except making things valgrind-clean */ + pa_unset_env_recorded(); + +#ifdef OS_IS_WIN32 + WSACleanup(); +#endif + +#ifdef HAVE_NO_OHOS + if (ltdl_init) + pa_ltdl_done(); +#endif + +#ifdef HAVE_DBUS + dbus_shutdown(); +#endif + + return retval; +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ diff --git a/pulseaudio/src/modules/BUILD.gn b/pulseaudio/src/modules/BUILD.gn new file mode 100644 index 0000000000..e02fe30630 --- /dev/null +++ b/pulseaudio/src/modules/BUILD.gn @@ -0,0 +1,182 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" + +group("modules") { + deps = [ + ":module-native-protocol-fd", + ":module-native-protocol-tcp", + ":module-native-protocol-unix", + ":module-cli-protocol-unix", + ":module-pipe-sink", + ":module-pipe-source", + ":module-suspend-on-idle" + ] +} + +group("common_deps") { + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + ] +} + +config("common_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir/src/modules", + "$pulseaudio_dir/src", + "$pulseaudio_dir", + "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", + ] + + cflags = [ + "-Wall", + "-Werror", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + "-D__INCLUDED_FROM_PULSE_AUDIO", + ] +} + +ohos_shared_library("module-native-protocol-fd") { + sources = [ "$pulseaudio_dir/src/modules/module-native-protocol-fd.c" ] + cflags = [ "-DPA_MODULE_NAME=libmodule_native_protocol_fd_z_so" ] + ldflags = [ + "-Wl", + "--no-undefined", + ] + configs = [ ":common_config" ] + deps = [ + ":common_deps", + "$pulseaudio_build_path/src/pulsecore:protocol-native", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-native-protocol-tcp") { + sources = [ "$pulseaudio_dir/src/modules/module-protocol-stub.c" ] + cflags = [ + "-DPA_MODULE_NAME=libmodule_native_protocol_tcp_z_so", + "-DUSE_PROTOCOL_NATIVE", + "-DUSE_TCP_SOCKETS", + ] + ldflags = [ + "-Wl", + "--no-undefined", + ] + configs = [ ":common_config" ] + deps = [ + ":common_deps", + "$pulseaudio_build_path/src/pulsecore:protocol-native", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-native-protocol-unix") { + sources = [ "$pulseaudio_dir/src/modules/module-protocol-stub.c" ] + cflags = [ + "-DPA_MODULE_NAME=libmodule_native_protocol_unix_z_so", + "-DUSE_PROTOCOL_NATIVE", + "-DUSE_UNIX_SOCKETS", + ] + ldflags = [ + "-Wl", + "--no-undefined", + ] + configs = [ ":common_config" ] + deps = [ + ":common_deps", + "$pulseaudio_build_path/src/pulsecore:protocol-native", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-cli-protocol-unix") { + sources = [ "$pulseaudio_dir/src/modules/module-protocol-stub.c" ] + cflags = [ + "-DPA_MODULE_NAME=libmodule_cli_protocol_unix_z_so", + "-DUSE_PROTOCOL_CLI", + "-DUSE_UNIX_SOCKETS", + ] + ldflags = [ + "-Wl", + "--no-undefined", + ] + configs = [ ":common_config" ] + deps = [ + ":common_deps", + "$pulseaudio_build_path/src/pulsecore:protocol-cli", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-pipe-sink") { + sources = [ "$pulseaudio_dir/src/modules/module-pipe-sink.c" ] + cflags = [ "-DPA_MODULE_NAME=libmodule_pipe_sink_z_so" ] + ldflags = [ + "-Wl", + "--no-undefined", + ] + configs = [ ":common_config" ] + deps = [ ":common_deps" ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-pipe-source") { + sources = ["$pulseaudio_dir/src/modules/module-pipe-source.c",] + cflags = [ "-DPA_MODULE_NAME=libmodule_pipe_source_z_so" ] + + ldflags = [ + "-Wl", + "--no-undefined", + ] + + configs = [ ":common_config" ] + deps = [ ":common_deps" ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-suspend-on-idle") { + sources = ["$pulseaudio_dir/src/modules/module-suspend-on-idle.c",] + cflags = [ "-DPA_MODULE_NAME=libmodule_suspend_on_idle_z_so" ] + + ldflags = [ + "-Wl", + "--no-undefined", + ] + + configs = [ ":common_config" ] + deps = [ ":common_deps" ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/modules/hdi/BUILD.gn b/pulseaudio/src/modules/hdi/BUILD.gn new file mode 100644 index 0000000000..5de40efcd3 --- /dev/null +++ b/pulseaudio/src/modules/hdi/BUILD.gn @@ -0,0 +1,96 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" + +config("hdi_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir/src", + "$pulseaudio_dir", + "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", + "//drivers/peripheral/audio/interfaces/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer/include", + ] + + cflags = [ + "-Wall", + "-Werror", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + "-D__INCLUDED_FROM_PULSE_AUDIO", + ] +} + +ohos_shared_library("module-hdi-sink") { + sources = [ + "$pulseaudio_build_path/src/modules/hdi/hdi_sink.c", + "$pulseaudio_build_path/src/modules/hdi/module_hdi_sink.c" + ] + + configs = [ ":hdi_config" ] + + cflags = [ + "-DPA_MODULE_NAME=libmodule_hdi_sink_z_so", + ] + + ldflags = [ + "-Wl", + "--no-undefined", + ] + + deps = [ + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + "$pulseaudio_build_path/src:pulsecommon", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer:audio_renderer_sink", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("module-hdi-source") { + sources = [ + "hdi_source.c", + "module_hdi_source.c" + ] + + configs = [ ":hdi_config" ] + + cflags = [ + "-DPA_MODULE_NAME=libmodule_hdi_source_z_so", + ] + + deps = [ + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + "$pulseaudio_build_path/src:pulsecommon", + "//third_party/bounds_checking_function:libsec_static", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer:audio_capturer_source", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/modules/hdi/hdi_sink.c b/pulseaudio/src/modules/hdi/hdi_sink.c new file mode 100644 index 0000000000..8614dab183 --- /dev/null +++ b/pulseaudio/src/modules/hdi/hdi_sink.c @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SINK_NAME "hdi_output" +#define DEFAULT_AUDIO_DEVICE_NAME "Speaker" +#define DEFAULT_BUFFER_SIZE 8192 +#define MAX_SINK_VOLUME_LEVEL 1.0 + +struct Userdata { + size_t buffer_size; + size_t bytes_dropped; + pa_thread_mq thread_mq; + pa_memchunk memchunk; + pa_usec_t block_usec; + pa_usec_t timestamp; + pa_thread *thread; + pa_rtpoll *rtpoll; + pa_core *core; + pa_module *module; + pa_sink *sink; +}; + +static void UserdataFree(struct Userdata *u); + +static ssize_t RenderWrite(pa_memchunk *pchunk) +{ + size_t index, length; + ssize_t count = 0; + void *p = NULL; + int32_t ret; + + pa_assert(pchunk); + + index = pchunk->index; + length = pchunk->length; + p = pa_memblock_acquire(pchunk->memblock); + pa_assert(p); + + while (true) { + uint64_t writeLen = 0; + + ret = AudioRendererRenderFrame((char *) p + index, (uint64_t)length, &writeLen); + if (writeLen > length) { + pa_log_error("Error writeLen > actual bytes. Length: %u, Written: %llu bytes, %d ret", + length, writeLen, ret); + count = -1 - count; + break; + } + if (writeLen == 0) { + pa_log_error("Failed to render Length: %u, Written: %llu bytes, %d ret", + length, writeLen, ret); + count = -1 - count; + break; + } else { + pa_log_info("Success: outputting to audio renderer Length: %u, Written: %llu bytes, %d ret", + length, writeLen, ret); + count += writeLen; + index += writeLen; + length -= writeLen; + pa_log_info("Remaining bytes Length: %u", length); + if (length <= 0) { + break; + } + } + } + pa_memblock_release(pchunk->memblock); + + return count; +} + +static void ProcessRenderUseTiming(struct Userdata *u, pa_usec_t now) +{ + size_t dropped; + size_t consumed = 0; + + pa_assert(u); + + // Fill the buffer up the latency size + while (u->timestamp < now + u->block_usec) { + ssize_t written = 0; + pa_memchunk chunk; + + pa_sink_render(u->sink, u->sink->thread_info.max_request, &chunk); + + pa_assert(chunk.length > 0); + + if ((written = RenderWrite(&chunk)) < 0) + written = -1 - written; + + pa_memblock_unref(chunk.memblock); + + u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec); + + dropped = chunk.length - written; + + if (u->bytes_dropped != 0 && dropped != chunk.length) { + pa_log_debug("HDI-sink continuously dropped %zu bytes", u->bytes_dropped); + u->bytes_dropped = 0; + } + + if (u->bytes_dropped == 0 && dropped != 0) + pa_log_debug("HDI-sink just dropped %zu bytes", dropped); + + u->bytes_dropped += dropped; + + consumed += chunk.length; + + if (consumed >= u->sink->thread_info.max_request) + break; + } +} + +static void ThreadFuncUseTiming(void *userdata) +{ + struct Userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread (use timing) starting up"); + pa_thread_mq_install(&u->thread_mq); + + u->timestamp = pa_rtclock_now(); + + while (true) { + pa_usec_t now = 0; + int ret; + + if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) + now = pa_rtclock_now(); + + if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) + pa_sink_process_rewind(u->sink, 0); + + // Render some data and drop it immediately + if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { + if (u->timestamp <= now) + ProcessRenderUseTiming(u, now); + + pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp); + } else + pa_rtpoll_set_timer_disabled(u->rtpoll); + + // Hmm, nothing to do. Let's sleep + if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) + goto fail; + + if (ret == 0) { + goto finish; + } + } + +fail: + // If this was no regular exit from the loop we have to continue + // processing messages until we received PA_MESSAGE_SHUTDOWN + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, + u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread (use timing) shutting down"); +} + +static void SinkUpdateRequestedLatencyCb(pa_sink *s) +{ + struct Userdata *u = NULL; + size_t nbytes; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + u->block_usec = pa_sink_get_requested_latency_within_thread(s); + + if (u->block_usec == (pa_usec_t) - 1) + u->block_usec = s->thread_info.max_latency; + + nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec); + pa_sink_set_max_request_within_thread(s, nbytes); +} + +// Called from IO context +static int SinkProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset, + pa_memchunk *chunk) +{ + struct Userdata *u = PA_SINK(o)->userdata; + switch (code) { + case PA_SINK_MESSAGE_GET_LATENCY: { + size_t n = 0; + n = n + u->memchunk.length; + *((int64_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); + return 0; + } + default: + break; + } + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +// Called from the IO thread. +static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t newState, + pa_suspend_cause_t newSuspendCause) +{ + struct Userdata *u = NULL; + + pa_assert(s); + pa_assert_se(u = s->userdata); + + if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) { + if (PA_SINK_IS_OPENED(newState)) + u->timestamp = pa_rtclock_now(); + } else if (PA_SINK_IS_OPENED(s->thread_info.state)) { + if (newState == PA_SINK_SUSPENDED) { + // Continuously dropping data (clear counter on entering suspended state. + if (u->bytes_dropped != 0) { + pa_log_debug("HDI-sink continuously dropping data - clear statistics (%zu -> 0 bytes dropped)", + u->bytes_dropped); + u->bytes_dropped = 0; + } + } + } + + return 0; +} + +static int32_t PrepareDevice(const pa_sample_spec *ss) +{ + AudioSinkAttr sample_attrs; + int32_t ret; + + sample_attrs.format = AUDIO_FORMAT_PCM_16_BIT; + sample_attrs.sampleRate = ss->rate; + sample_attrs.channel = ss->channels; + sample_attrs.volume = MAX_SINK_VOLUME_LEVEL; + + ret = AudioRendererSinkInit(&sample_attrs); + if (ret != 0) { + pa_log_error("audiorenderer Init failed!"); + return -1; + } + + ret = AudioRendererSinkStart(); + if (ret != 0) { + pa_log_error("audiorenderer control start failed!"); + AudioRendererSinkDeInit(); + return -1; + } + + ret = AudioRendererSinkSetVolume(MAX_SINK_VOLUME_LEVEL, MAX_SINK_VOLUME_LEVEL); + if (ret != 0) { + pa_log_error("audiorenderer set volume failed!"); + AudioRendererSinkStop(); + AudioRendererSinkDeInit(); + return -1; + } + + return 0; +} + +static pa_sink* PaHdiSinkInit(pa_module *m, pa_modargs *ma, const char *driver) +{ + pa_sample_spec ss; + pa_sink_new_data data; + pa_channel_map map; + pa_sink *sink = NULL; + + ss = m->core->default_sample_spec; + map = m->core->default_channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log("Failed to parse sample specification and channel map"); + goto fail; + } + + if (PrepareDevice(&ss) < 0) + goto fail; + + pa_sink_new_data_init(&data); + data.driver = driver; + data.module = m; + + pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); + pa_sink_new_data_set_sample_spec(&data, &ss); + pa_sink_new_data_set_channel_map(&data, &map); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, DEFAULT_AUDIO_DEVICE_NAME); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI sink is %s", + DEFAULT_AUDIO_DEVICE_NAME); + + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { + pa_log("Invalid properties"); + pa_sink_new_data_done(&data); + goto fail; + } + + sink = pa_sink_new(m->core, &data, + PA_SINK_HARDWARE | PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY); + pa_sink_new_data_done(&data); + + return sink; + +fail: + return NULL; +} + +pa_sink *PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver) +{ + struct Userdata *u = NULL; + char *threadName = NULL; + + pa_assert(m); + pa_assert(ma); + + u = pa_xnew0(struct Userdata, 1); + u->core = m->core; + u->module = m; + + pa_memchunk_reset(&u->memchunk); + u->rtpoll = pa_rtpoll_new(); + + if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { + pa_log("pa_thread_mq_init() failed."); + goto fail; + } + + u->sink = PaHdiSinkInit(m, ma, driver); + if (!u->sink) { + pa_log("Failed to create sink object"); + goto fail; + } + + u->sink->parent.process_msg = SinkProcessMsg; + u->sink->set_state_in_io_thread = SinkSetStateInIoThreadCb; + u->sink->update_requested_latency = SinkUpdateRequestedLatencyCb; + u->sink->userdata = u; + + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + + u->bytes_dropped = 0; + u->buffer_size = DEFAULT_BUFFER_SIZE; + if (pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size) < 0) { + pa_log("Failed to parse buffer_size argument."); + goto fail; + } + + u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec); + pa_sink_set_latency_range(u->sink, 0, u->block_usec); + pa_sink_set_max_request(u->sink, u->buffer_size); + + threadName = pa_sprintf_malloc("hdi-sink-playback"); + if (!(u->thread = pa_thread_new(threadName, ThreadFuncUseTiming, u))) { + pa_log("Failed to create thread."); + goto fail; + } + pa_xfree(threadName); + threadName = NULL; + + pa_sink_put(u->sink); + + return u->sink; +fail: + pa_xfree(threadName); + + if (u) { + UserdataFree(u); + } + + return NULL; +} + +static void UserdataFree(struct Userdata *u) +{ + pa_assert(u); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + AudioRendererSinkStop(); + AudioRendererSinkDeInit(); + + pa_xfree(u); +} + +void PaHdiSinkFree(pa_sink *s) +{ + struct Userdata *u = NULL; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + UserdataFree(u); +} diff --git a/pulseaudio/src/modules/hdi/hdi_source.c b/pulseaudio/src/modules/hdi/hdi_source.c new file mode 100644 index 0000000000..03fbd803e6 --- /dev/null +++ b/pulseaudio/src/modules/hdi/hdi_source.c @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hdi_source.h" +#include "media_log.h" + +static void userdata_free(struct userdata *u) { + pa_assert(u); + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + AudioCapturerSourceStop(); + AudioCapturerSourceDeInit(); + pa_xfree(u); +} + +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t now; + now = pa_rtclock_now(); + *((int64_t*) data) = (int64_t)now - (int64_t)u->timestamp; + return 0; + } + default: { + pa_log("source_process_msg default case"); + return pa_source_process_msg(o, code, data, offset, chunk); + } + } +} + +/* Called from the IO thread. */ +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { + struct userdata *u; + pa_assert(s); + pa_assert_se(u = s->userdata); + if (s->thread_info.state == PA_SOURCE_SUSPENDED || s->thread_info.state == PA_SOURCE_INIT) { + if (PA_SOURCE_IS_OPENED(new_state)) + u->timestamp = pa_rtclock_now(); + } + + return 0; +} + +static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_output_new_data *data, + struct userdata *u) { + MEDIA_DEBUG_LOG("HDI Source: Detected source output"); + pa_assert(data); + pa_assert(u); + + if (!strcmp(u->source->name, data->source->name)) { + // Signal Ready when a Source Output is connected + if (!u->IsReady) + u->IsReady = true; + pa_source_suspend(u->source, false, PA_SUSPEND_IDLE); + } + return PA_HOOK_OK; +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + bool timer_elapsed = false; + + pa_assert(u); + + if (u->core->realtime_scheduling) + pa_thread_make_realtime(u->core->realtime_priority); + + pa_thread_mq_install(&u->thread_mq); + u->timestamp = pa_rtclock_now(); + MEDIA_DEBUG_LOG("HDI Source: u->timestamp : %{public}llu", u->timestamp); + + for (;;) { + int ret = 0; + int32_t retries = 0; + uint64_t requestBytes; + uint64_t replyBytes = 0; + void *p; + + MEDIA_DEBUG_LOG("HDI Source: replyBytes before read : %{public}llu", replyBytes); + if (PA_SOURCE_IS_OPENED(u->source->thread_info.state) && + (u->source->thread_info.state != PA_SOURCE_SUSPENDED && u->IsReady)) { + MEDIA_DEBUG_LOG("HDI Source: PA_SOURCE_IS_OPENED"); + pa_usec_t now; + pa_memchunk chunk; + + now = pa_rtclock_now(); + MEDIA_DEBUG_LOG("HDI Source: now : %{public}llu", now); + MEDIA_DEBUG_LOG("HDI Source: Is timer_elapsed : %{public}d", timer_elapsed); + + if (timer_elapsed && (chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec)) > 0) { + chunk.length = u->buffer_size; + MEDIA_DEBUG_LOG("HDI Source: chunk.length = u->buffer_size: %{public}zu", chunk.length); + chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); + pa_assert(chunk.memblock); + p = pa_memblock_acquire(chunk.memblock); + pa_assert(p); + + requestBytes = pa_memblock_get_length(chunk.memblock); + AudioCapturerSourceFrame((char *) p, (uint64_t)requestBytes, &replyBytes); + + pa_memblock_release(chunk.memblock); + MEDIA_DEBUG_LOG("HDI Source: request bytes: %{public}llu, replyBytes: %{public}llu", requestBytes, replyBytes); + if(replyBytes > requestBytes) { + MEDIA_ERR_LOG("HDI Source: Error replyBytes > requestBytes. Requested data Length: %{public}llu, Read: %{public}llu bytes, %{public}d ret", requestBytes, replyBytes, ret); + pa_memblock_unref(chunk.memblock); + break; + } + if (replyBytes == 0) { + MEDIA_INFO_LOG("HDI Source: reply bytes 0"); + if (retries < MAX_RETRIES) { + usleep(FIVE_MSEC); + ++retries; + MEDIA_DEBUG_LOG("HDI Source: Requested data Length: %{public}llu bytes, Read: %{public}llu bytes. Sleep: %{public}d usec microseconds. Retry Times %{public}d", requestBytes, replyBytes, FIVE_MSEC, retries); + continue; + } else { + MEDIA_ERR_LOG("HDI Source: Failed to read after %{public}d retries, Requested data Length: %{public}llu bytes, Read: %{public}llu bytes, %{public}d ret", retries, requestBytes, replyBytes, ret); + pa_memblock_unref(chunk.memblock); + break; + } + } + + retries = 0; + chunk.index = 0; + chunk.length = replyBytes; + pa_source_post(u->source, &chunk); + pa_memblock_unref(chunk.memblock); + u->timestamp += pa_bytes_to_usec(chunk.length, &u->source->sample_spec); + MEDIA_INFO_LOG("HDI Source: new u->timestamp : %{public}llu", u->timestamp); + } + + pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->block_usec); + } else { + pa_rtpoll_set_timer_disabled(u->rtpoll); + MEDIA_INFO_LOG("HDI Source: pa_rtpoll_set_timer_disabled done "); + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) { + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + MEDIA_INFO_LOG("HDI Source: pa_rtpoll_run ret:%{public}d failed", ret ); + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + return; + } + + timer_elapsed = pa_rtpoll_timer_elapsed(u->rtpoll); + + if (ret == 0) { + MEDIA_INFO_LOG("HDI Source: pa_rtpoll_run ret:%{public}d return", ret ); + return; + } + } +} + +pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { + struct userdata *u = NULL; + pa_sample_spec ss; + char *thread_name = NULL; + pa_channel_map map; + pa_source_new_data data; + int32_t ret; + + pa_assert(m); + pa_assert(ma); + + ss = m->core->default_sample_spec; + map = m->core->default_channel_map; + + /* Override with modargs if provided */ + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + MEDIA_INFO_LOG("Failed to parse sample specification and channel map"); + goto fail; + } + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->rtpoll = pa_rtpoll_new(); + + // Set IsReady to false at start. will be made true when a Source Output is connected + u->IsReady = false; + + if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { + MEDIA_INFO_LOG("pa_thread_mq_init() failed."); + goto fail; + } + + u->buffer_size = DEFAULT_BUFFER_SIZE; + + AudioSourceAttr attrs; + attrs.format = AUDIO_FORMAT_PCM_16_BIT; + attrs.channel = ss.channels; + attrs.sampleRate = ss.rate; + + MEDIA_INFO_LOG("AudioDeviceCreateCapture format: %{public}d, channel: %{public}d, sampleRate: %{public}d", + attrs.format, attrs.channel, attrs.sampleRate); + + ret = AudioCapturerSourceInit(&attrs); + if (ret != 0) { + MEDIA_INFO_LOG("Audio capture init failed!"); + goto fail; + } + + ret = AudioCapturerSourceStart(); + if (ret != 0) { + MEDIA_INFO_LOG("Audio capture start failed!"); + AudioCapturerSourceDeInit(); + goto fail; + } + + ret = AudioCapturerSourceSetVolume(VOLUME_VALUE, VOLUME_VALUE); + if (ret != 0) { + MEDIA_INFO_LOG("audio capture set volume failed!"); + AudioCapturerSourceStop(); + AudioCapturerSourceDeInit(); + goto fail; + } + + pa_source_new_data_init(&data); + data.driver = __FILE__; + data.module = m; + pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, DEFAULT_AUDIO_DEVICE_NAME); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI source %s", DEFAULT_AUDIO_DEVICE_NAME); + pa_source_new_data_set_sample_spec(&data, &ss); + pa_source_new_data_set_channel_map(&data, &map);; + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long)u->buffer_size); + + if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { + MEDIA_INFO_LOG("Invalid properties"); + pa_source_new_data_done(&data); + goto fail; + } + + u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); + pa_source_new_data_done(&data); + + if (!u->source) { + MEDIA_INFO_LOG("Failed to create source object"); + goto fail; + } + + u->source->parent.process_msg = source_process_msg; + u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb; + u->source->userdata = u; + + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + + if (pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size) < 0) { + MEDIA_INFO_LOG("Failed to parse buffer_size argument."); + goto fail; + } + + u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec); + pa_source_set_latency_range(u->source, 0, u->block_usec); + u->source->thread_info.max_rewind = pa_usec_to_bytes(u->block_usec, &u->source->sample_spec); + + pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL, + (pa_hook_cb_t) source_output_fixate_hook_cb, u); + + thread_name = pa_sprintf_malloc("hdi-source-record"); + if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) { + MEDIA_INFO_LOG("Failed to create thread."); + goto fail; + } + pa_xfree(thread_name); + thread_name = NULL; + pa_source_put(u->source); + return u->source; + +fail: + pa_xfree(thread_name); + + if (u) + userdata_free(u); + + return NULL; +} + +void pa_hdi_source_free(pa_source *s) { + struct userdata *u; + pa_source_assert_ref(s); + pa_assert_se(u = s->userdata); + userdata_free(u); +} diff --git a/pulseaudio/src/modules/hdi/hdi_source.h b/pulseaudio/src/modules/hdi/hdi_source.h new file mode 100644 index 0000000000..2bb66a0099 --- /dev/null +++ b/pulseaudio/src/modules/hdi/hdi_source.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 +#include + +#define DEFAULT_SOURCE_NAME "hdi_input" +#define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic" + +#define DEFAULT_BUFFER_SIZE (1024 * 16) +#define VOLUME_VALUE 100.0 +#define FIVE_MSEC 5000 +#define MAX_RETRIES 5 +#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2) +#define MIN_LATENCY_USEC (500) +#define AUDIO_POINT_NUM 1024 +#define AUDIO_FRAME_NUM_IN_BUF 30 + +struct userdata { + pa_core *core; + pa_module *module; + pa_source *source; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + size_t buffer_size; + pa_usec_t block_usec; + pa_usec_t timestamp; + // A flag to signal us to prevent silent record during bootup + bool IsReady; +}; + +pa_source* pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver); + +void pa_hdi_source_free(pa_source *s); diff --git a/pulseaudio/src/modules/hdi/module_hdi_sink.c b/pulseaudio/src/modules/hdi/module_hdi_sink.c new file mode 100644 index 0000000000..f47aa9ed2f --- /dev/null +++ b/pulseaudio/src/modules/hdi/module_hdi_sink.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +pa_sink* PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver); +void PaHdiSinkFree(pa_sink *s); + +PA_MODULE_AUTHOR("OpenHarmony"); +PA_MODULE_DESCRIPTION("OpenHarmony HDI Sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(false); +PA_MODULE_USAGE( + "sink_name= " + "sink_properties= " + "format= " + "rate= " + "channels= " + "channel_map= " + "buffer_size=" + ); + +static const char * const VALID_MODARGS[] = { + "sink_name", + "sink_properties", + "format", + "rate", + "channels", + "channel_map", + "buffer_size", + NULL +}; + +int pa__init(pa_module *m) +{ + pa_modargs *ma = NULL; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, VALID_MODARGS))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (!(m->userdata = PaHdiSinkNew(m, ma, __FILE__))) { + goto fail; + } + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) { + pa_modargs_free(ma); + } + + pa__done(m); + + return -1; +} + +int pa__get_n_used(pa_module *m) +{ + pa_sink *sink = NULL; + + pa_assert(m); + pa_assert_se(sink = m->userdata); + + return pa_sink_linked_by(sink); +} + +void pa__done(pa_module *m) +{ + pa_sink *sink = NULL; + + pa_assert(m); + + if ((sink = m->userdata)) { + PaHdiSinkFree(sink); + } +} diff --git a/pulseaudio/src/modules/hdi/module_hdi_source.c b/pulseaudio/src/modules/hdi/module_hdi_source.c new file mode 100644 index 0000000000..e739bf7ea6 --- /dev/null +++ b/pulseaudio/src/modules/hdi/module_hdi_source.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "hdi_source.h" + +PA_MODULE_AUTHOR("OpenHarmony"); +PA_MODULE_DESCRIPTION("OpenHarmony HDI Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(false); +PA_MODULE_USAGE( + "source_name= " + "source_properties= " + "format= " + "rate= " + "channels= " + "channel_map=" + "buffer_size=" + ); + +static const char * const VALID_MODARGS[] = { + "source_name", + "source_properties", + "format", + "rate", + "channels", + "channel_map", + "buffer_size", + NULL +}; + +int pa__init(pa_module*m) +{ + pa_modargs *ma = NULL; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, VALID_MODARGS))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (!(m->userdata = pa_hdi_source_new(m, ma, __FILE__))) + goto fail; + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + return -1; +} + +int pa__get_n_used(pa_module *m) +{ + pa_source *source = NULL; + + pa_assert(m); + pa_assert_se(source = m->userdata); + + return pa_source_linked_by(source); +} + +void pa__done(pa_module*m) +{ + pa_source *source = NULL; + + pa_assert(m); + + if ((source = m->userdata)) + pa_hdi_source_free(source); +} diff --git a/pulseaudio/src/pulse/BUILD.gn b/pulseaudio/src/pulse/BUILD.gn new file mode 100644 index 0000000000..fddf966aff --- /dev/null +++ b/pulseaudio/src/pulse/BUILD.gn @@ -0,0 +1,113 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" + +config("pulse_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir/src/pulse", + "$pulseaudio_dir/src", + "$pulseaudio_dir", + "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", + "//third_party/glib/glib", + "//third_party/glib", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-implicit-function-declaration", + "-Wno-sign-compare", + "-Wno-unused-function", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + ] +} + +ohos_source_set("pulse_sources") { + sources = [ + "$pulseaudio_dir/src/pulse/channelmap.c", + "$pulseaudio_dir/src/pulse/context.c", + "$pulseaudio_dir/src/pulse/direction.c", + "$pulseaudio_dir/src/pulse/error.c", + "$pulseaudio_dir/src/pulse/ext-device-manager.c", + "$pulseaudio_dir/src/pulse/ext-device-restore.c", + "$pulseaudio_dir/src/pulse/ext-stream-restore.c", + "$pulseaudio_dir/src/pulse/format.c", + "$pulseaudio_dir/src/pulse/internal.h", + "$pulseaudio_dir/src/pulse/introspect.c", + "$pulseaudio_dir/src/pulse/mainloop-api.c", + "$pulseaudio_dir/src/pulse/mainloop-signal.c", + "$pulseaudio_dir/src/pulse/mainloop.c", + "$pulseaudio_dir/src/pulse/operation.c", + "$pulseaudio_dir/src/pulse/proplist.c", + "$pulseaudio_dir/src/pulse/rtclock.c", + "$pulseaudio_dir/src/pulse/sample.c", + "$pulseaudio_dir/src/pulse/scache.c", + "$pulseaudio_dir/src/pulse/stream.c", + "$pulseaudio_dir/src/pulse/subscribe.c", + "$pulseaudio_dir/src/pulse/thread-mainloop.c", + "$pulseaudio_dir/src/pulse/timeval.c", + "$pulseaudio_dir/src/pulse/utf8.c", + "$pulseaudio_dir/src/pulse/util.c", + "$pulseaudio_dir/src/pulse/volume.c", + "$pulseaudio_dir/src/pulse/xmalloc.c", + ] + + configs = [ + ":pulse_config", + ] +} + +ohos_shared_library("pulse") { + deps = [ + ":pulse_sources", + "$pulseaudio_build_path/src:pulsecommon", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("pulse-simple") { + sources = [ "$pulseaudio_dir/src/pulse/simple.c" ] + + configs = [ ":pulse_config" ] + + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulse:pulse", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("pulse-mainloop-glib") { + sources = [ "$pulseaudio_build_path/src/pulse/ohos_glib-mainloop.c" ] + + configs = [ ":pulse_config" ] + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "//third_party/glib:glib", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/pulse/ohos_glib-mainloop.c b/pulseaudio/src/pulse/ohos_glib-mainloop.c new file mode 100644 index 0000000000..82c45713fd --- /dev/null +++ b/pulseaudio/src/pulse/ohos_glib-mainloop.c @@ -0,0 +1,661 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include "glib-mainloop.h" + +struct pa_io_event { + pa_glib_mainloop *mainloop; + int dead; + + GPollFD poll_fd; + int poll_fd_added; + + pa_io_event_cb_t callback; + void *userdata; + pa_io_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_io_event); +}; + +struct pa_time_event { + pa_glib_mainloop *mainloop; + int dead; + + int enabled; + struct timeval timeval; + + pa_time_event_cb_t callback; + void *userdata; + pa_time_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_time_event); +}; + +struct pa_defer_event { + pa_glib_mainloop *mainloop; + int dead; + + int enabled; + + pa_defer_event_cb_t callback; + void *userdata; + pa_defer_event_destroy_cb_t destroy_callback; + + PA_LLIST_FIELDS(pa_defer_event); +}; + +struct pa_glib_mainloop { + GSource source; + + pa_mainloop_api api; + GMainContext *context; + + PA_LLIST_HEAD(pa_io_event, io_events); + PA_LLIST_HEAD(pa_time_event, time_events); + PA_LLIST_HEAD(pa_defer_event, defer_events); + + int n_enabled_defer_events, n_enabled_time_events; + int io_events_please_scan, time_events_please_scan, defer_events_please_scan; + + pa_time_event *cached_next_time_event; +}; + +static void cleanup_io_events(pa_glib_mainloop *g, int force) { + pa_io_event *e; + + e = g->io_events; + while (e) { + pa_io_event *n = e->next; + + if (!force && g->io_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_io_event, g->io_events, e); + + if (e->dead) { + g_assert(g->io_events_please_scan > 0); + g->io_events_please_scan--; + } + + if (e->poll_fd_added) + g_source_remove_poll(&g->source, &e->poll_fd); + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + g_assert(g->io_events_please_scan == 0); +} + +static void cleanup_time_events(pa_glib_mainloop *g, int force) { + pa_time_event *e; + + e = g->time_events; + while (e) { + pa_time_event *n = e->next; + + if (!force && g->time_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_time_event, g->time_events, e); + + if (e->dead) { + g_assert(g->time_events_please_scan > 0); + g->time_events_please_scan--; + } + + if (!e->dead && e->enabled) { + g_assert(g->n_enabled_time_events > 0); + g->n_enabled_time_events--; + } + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + g_assert(g->time_events_please_scan == 0); +} + +static void cleanup_defer_events(pa_glib_mainloop *g, int force) { + pa_defer_event *e; + + e = g->defer_events; + while (e) { + pa_defer_event *n = e->next; + + if (!force && g->defer_events_please_scan <= 0) + break; + + if (force || e->dead) { + PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e); + + if (e->dead) { + g_assert(g->defer_events_please_scan > 0); + g->defer_events_please_scan--; + } + + if (!e->dead && e->enabled) { + g_assert(g->n_enabled_defer_events > 0); + g->n_enabled_defer_events--; + } + + if (e->destroy_callback) + e->destroy_callback(&g->api, e, e->userdata); + + pa_xfree(e); + } + + e = n; + } + + g_assert(g->defer_events_please_scan == 0); +} + +static gushort map_flags_to_glib(pa_io_event_flags_t flags) { + return (gushort) + ((flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | + (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | + (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) | + (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0)); +} + +static pa_io_event_flags_t map_flags_from_glib(gushort flags) { + return + (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | + (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | + (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | + (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); +} + +static pa_io_event* glib_io_new( + pa_mainloop_api*m, + int fd, + pa_io_event_flags_t f, + pa_io_event_cb_t cb, + void *userdata) { + + pa_io_event *e; + pa_glib_mainloop *g; + + g_assert(m); + g_assert(m->userdata); + g_assert(fd >= 0); + g_assert(cb); + + g = m->userdata; + + e = pa_xnew(pa_io_event, 1); + e->mainloop = g; + e->dead = 0; + + e->poll_fd.fd = fd; + e->poll_fd.events = map_flags_to_glib(f); + e->poll_fd.revents = 0; + + e->callback = cb; + e->userdata = userdata; + e->destroy_callback = NULL; + + PA_LLIST_PREPEND(pa_io_event, g->io_events, e); + + g_source_add_poll(&g->source, &e->poll_fd); + e->poll_fd_added = 1; + + return e; +} + +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { + g_assert(e); + g_assert(!e->dead); + + e->poll_fd.events = map_flags_to_glib(f); +} + +static void glib_io_free(pa_io_event*e) { + g_assert(e); + g_assert(!e->dead); + + e->dead = 1; + e->mainloop->io_events_please_scan++; + + if (e->poll_fd_added) { + g_source_remove_poll(&e->mainloop->source, &e->poll_fd); + e->poll_fd_added = 0; + } +} + +static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) { + g_assert(e); + g_assert(!e->dead); + + e->destroy_callback = cb; +} + +/* Time sources */ + +static pa_time_event* glib_time_new( + pa_mainloop_api*m, + const struct timeval *tv, + pa_time_event_cb_t cb, + void *userdata) { + + pa_glib_mainloop *g; + pa_time_event *e; + + g_assert(m); + g_assert(m->userdata); + g_assert(cb); + + g = m->userdata; + + e = pa_xnew(pa_time_event, 1); + e->mainloop = g; + e->dead = 0; + + if ((e->enabled = !!tv)) { + e->timeval = *tv; + g->n_enabled_time_events++; + + if (g->cached_next_time_event) { + g_assert(g->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0) + g->cached_next_time_event = e; + } + } + + e->callback = cb; + e->userdata = userdata; + e->destroy_callback = NULL; + + PA_LLIST_PREPEND(pa_time_event, g->time_events, e); + + return e; +} + +static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { + g_assert(e); + g_assert(!e->dead); + + if (e->enabled && !tv) { + g_assert(e->mainloop->n_enabled_time_events > 0); + e->mainloop->n_enabled_time_events--; + } else if (!e->enabled && tv) + e->mainloop->n_enabled_time_events++; + + if ((e->enabled = !!tv)) + e->timeval = *tv; + + if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; + + if (e->mainloop->cached_next_time_event && e->enabled) { + g_assert(e->mainloop->cached_next_time_event->enabled); + + if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) + e->mainloop->cached_next_time_event = e; + } +} + +static void glib_time_free(pa_time_event *e) { + g_assert(e); + g_assert(!e->dead); + + e->dead = 1; + e->mainloop->time_events_please_scan++; + + if (e->enabled) + e->mainloop->n_enabled_time_events--; + + if (e->mainloop->cached_next_time_event == e) + e->mainloop->cached_next_time_event = NULL; +} + +static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { + g_assert(e); + g_assert(!e->dead); + + e->destroy_callback = cb; +} + +/* Deferred sources */ + +static pa_defer_event* glib_defer_new( + pa_mainloop_api*m, + pa_defer_event_cb_t cb, + void *userdata) { + + pa_defer_event *e; + pa_glib_mainloop *g; + + g_assert(m); + g_assert(m->userdata); + g_assert(cb); + + g = m->userdata; + + e = pa_xnew(pa_defer_event, 1); + e->mainloop = g; + e->dead = 0; + + e->enabled = 1; + g->n_enabled_defer_events++; + + e->callback = cb; + e->userdata = userdata; + e->destroy_callback = NULL; + + PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e); + return e; +} + +static void glib_defer_enable(pa_defer_event *e, int b) { + g_assert(e); + g_assert(!e->dead); + + if (e->enabled && !b) { + g_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; + } else if (!e->enabled && b) + e->mainloop->n_enabled_defer_events++; + + e->enabled = b; +} + +static void glib_defer_free(pa_defer_event *e) { + g_assert(e); + g_assert(!e->dead); + + e->dead = 1; + e->mainloop->defer_events_please_scan++; + + if (e->enabled) { + g_assert(e->mainloop->n_enabled_defer_events > 0); + e->mainloop->n_enabled_defer_events--; + } +} + +static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { + g_assert(e); + g_assert(!e->dead); + + e->destroy_callback = cb; +} + +/* quit() */ + +static void glib_quit(pa_mainloop_api*a, int retval) { + + g_warning("quit() ignored"); + + /* NOOP */ +} + +static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { + pa_time_event *t, *n = NULL; + g_assert(g); + + if (g->cached_next_time_event) + return g->cached_next_time_event; + + for (t = g->time_events; t; t = t->next) { + + if (t->dead || !t->enabled) + continue; + + if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { + n = t; + + /* Shortcut for tv = { 0, 0 } */ + if (n->timeval.tv_sec <= 0) + break; + } + } + + g->cached_next_time_event = n; + return n; +} + +static void scan_dead(pa_glib_mainloop *g) { + g_assert(g); + + if (g->io_events_please_scan) + cleanup_io_events(g, 0); + + if (g->time_events_please_scan) + cleanup_time_events(g, 0); + + if (g->defer_events_please_scan) + cleanup_defer_events(g, 0); +} + +static gboolean prepare_func(GSource *source, gint *timeout) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + + g_assert(g); + g_assert(timeout); + + scan_dead(g); + + if (g->n_enabled_defer_events) { + *timeout = 0; + return TRUE; + } else if (g->n_enabled_time_events) { + pa_time_event *t; + gint64 now; + struct timeval tvnow; + pa_usec_t usec; + + t = find_next_time_event(g); + g_assert(t); + + now = g_get_real_time(); + tvnow.tv_sec = now / 1000000; + tvnow.tv_usec = now % 1000000; + + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { + *timeout = 0; + return TRUE; + } + usec = pa_timeval_diff(&t->timeval, &tvnow); + *timeout = (gint) (usec / 1000); + } else + *timeout = -1; + + return FALSE; +} +static gboolean check_func(GSource *source) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + pa_io_event *e; + + g_assert(g); + + if (g->n_enabled_defer_events) + return TRUE; + else if (g->n_enabled_time_events) { + pa_time_event *t; + gint64 now; + struct timeval tvnow; + + t = find_next_time_event(g); + g_assert(t); + now = g_get_real_time(); + tvnow.tv_sec = now / 1000000; + tvnow.tv_usec = now % 1000000; + + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) + return TRUE; + } + + for (e = g->io_events; e; e = e->next) + if (!e->dead && e->poll_fd.revents != 0) + return TRUE; + + return FALSE; +} + +static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) { + pa_glib_mainloop *g = (pa_glib_mainloop*) source; + pa_io_event *e; + + g_assert(g); + + if (g->n_enabled_defer_events) { + pa_defer_event *d; + + for (d = g->defer_events; d; d = d->next) { + if (d->dead || !d->enabled) + continue; + + break; + } + + g_assert(d); + + d->callback(&g->api, d, d->userdata); + return TRUE; + } + + if (g->n_enabled_time_events) { + gint64 now; + struct timeval tvnow; + pa_time_event *t; + + t = find_next_time_event(g); + g_assert(t); + now = g_get_real_time(); + tvnow.tv_sec = now / 1000000; + tvnow.tv_usec = now % 1000000; + + if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { + + /* Disable time event */ + glib_time_restart(t, NULL); + + t->callback(&g->api, t, &t->timeval, t->userdata); + return TRUE; + } + } + + for (e = g->io_events; e; e = e->next) + if (!e->dead && e->poll_fd.revents != 0) { + e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata); + e->poll_fd.revents = 0; + return TRUE; + } + + return FALSE; +} + +static const pa_mainloop_api vtable = { + .userdata = NULL, + + .io_new = glib_io_new, + .io_enable = glib_io_enable, + .io_free = glib_io_free, + .io_set_destroy = glib_io_set_destroy, + + .time_new = glib_time_new, + .time_restart = glib_time_restart, + .time_free = glib_time_free, + .time_set_destroy = glib_time_set_destroy, + + .defer_new = glib_defer_new, + .defer_enable = glib_defer_enable, + .defer_free = glib_defer_free, + .defer_set_destroy = glib_defer_set_destroy, + + .quit = glib_quit, +}; + +pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { + pa_glib_mainloop *g; + + static GSourceFuncs source_funcs = { + prepare_func, + check_func, + dispatch_func, + NULL, + NULL, + NULL + }; + + g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop)); + g_main_context_ref(g->context = c ? c : g_main_context_default()); + + g->api = vtable; + g->api.userdata = g; + + PA_LLIST_HEAD_INIT(pa_io_event, g->io_events); + PA_LLIST_HEAD_INIT(pa_time_event, g->time_events); + PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events); + + g->n_enabled_defer_events = g->n_enabled_time_events = 0; + g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0; + + g->cached_next_time_event = NULL; + + g_source_attach(&g->source, g->context); + g_source_set_can_recurse(&g->source, FALSE); + + return g; +} + +void pa_glib_mainloop_free(pa_glib_mainloop* g) { + g_assert(g); + + cleanup_io_events(g, 1); + cleanup_defer_events(g, 1); + cleanup_time_events(g, 1); + + g_main_context_unref(g->context); + g_source_destroy(&g->source); + g_source_unref(&g->source); +} + +pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { + g_assert(g); + + return &g->api; +} diff --git a/pulseaudio/src/pulsecore/BUILD.gn b/pulseaudio/src/pulsecore/BUILD.gn new file mode 100644 index 0000000000..2a29c259c3 --- /dev/null +++ b/pulseaudio/src/pulsecore/BUILD.gn @@ -0,0 +1,182 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" + +config("pulsecore_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir", + "$pulseaudio_dir/src", + "$pulseaudio_build_path/include", + "$pulseaudio_build_path/src", + "//third_party/glib/glib", + "//third_party/glib", + "$libsndfile_build_path/include", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-implicit-function-declaration", + "-Wno-unused-function", + "-Wno-uninitialized", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + "-D__INCLUDED_FROM_PULSE_AUDIO", + ] +} + +ohos_source_set("pulsecore_sources") { + sources = [ + "$pulseaudio_build_path/src/pulsecore/ltdl-stub.c", + "$pulseaudio_dir/src/pulsecore/asyncmsgq.c", + "$pulseaudio_dir/src/pulsecore/asyncq.c", + "$pulseaudio_dir/src/pulsecore/auth-cookie.c", + "$pulseaudio_dir/src/pulsecore/card.c", + "$pulseaudio_dir/src/pulsecore/cli-command.c", + "$pulseaudio_dir/src/pulsecore/cli-text.c", + "$pulseaudio_dir/src/pulsecore/client.c", + "$pulseaudio_dir/src/pulsecore/core-scache.c", + "$pulseaudio_dir/src/pulsecore/core-subscribe.c", + "$pulseaudio_dir/src/pulsecore/core.c", + #"$pulseaudio_dir/src/pulsecore/cpu.c", + "$pulseaudio_dir/src/pulsecore/cpu-arm.c", + #"$pulseaudio_dir/src/pulsecore/cpu-orc.c", + #"$pulseaudio_dir/src/pulsecore/cpu-x86.c", + "$pulseaudio_dir/src/pulsecore/device-port.c", + "$pulseaudio_dir/src/pulsecore/database.c", + "$pulseaudio_dir/src/pulsecore/database-simple.c", + "$pulseaudio_dir/src/pulsecore/ffmpeg/resample2.c", + "$pulseaudio_dir/src/pulsecore/filter/biquad.c", + "$pulseaudio_dir/src/pulsecore/filter/crossover.c", + "$pulseaudio_dir/src/pulsecore/filter/lfe-filter.c", + "$pulseaudio_dir/src/pulsecore/hook-list.c", + "$pulseaudio_dir/src/pulsecore/ltdl-helper.c", + "$pulseaudio_dir/src/pulsecore/message-handler.c", + "$pulseaudio_dir/src/pulsecore/mix.c", + "$pulseaudio_dir/src/pulsecore/modargs.c", + "$pulseaudio_dir/src/pulsecore/modinfo.c", + "$pulseaudio_dir/src/pulsecore/module.c", + "$pulseaudio_dir/src/pulsecore/msgobject.c", + "$pulseaudio_dir/src/pulsecore/namereg.c", + "$pulseaudio_dir/src/pulsecore/object.c", + "$pulseaudio_dir/src/pulsecore/play-memblockq.c", + "$pulseaudio_dir/src/pulsecore/play-memchunk.c", + "$pulseaudio_dir/src/pulsecore/remap.c", + "$pulseaudio_dir/src/pulsecore/resampler.c", + "$pulseaudio_dir/src/pulsecore/resampler/ffmpeg.c", + "$pulseaudio_dir/src/pulsecore/resampler/peaks.c", + "$pulseaudio_dir/src/pulsecore/resampler/trivial.c", + "$pulseaudio_dir/src/pulsecore/rtpoll.c", + "$pulseaudio_dir/src/pulsecore/sconv-s16be.c", + "$pulseaudio_dir/src/pulsecore/sconv-s16le.c", + "$pulseaudio_dir/src/pulsecore/sconv.c", + "$pulseaudio_dir/src/pulsecore/shared.c", + "$pulseaudio_dir/src/pulsecore/sink.c", + "$pulseaudio_dir/src/pulsecore/sink-input.c", + "$pulseaudio_dir/src/pulsecore/sioman.c", + "$pulseaudio_dir/src/pulsecore/sound-file-stream.c", + "$pulseaudio_dir/src/pulsecore/sound-file.c", + "$pulseaudio_dir/src/pulsecore/source.c", + "$pulseaudio_dir/src/pulsecore/source-output.c", + "$pulseaudio_dir/src/pulsecore/start-child.c", + "$pulseaudio_dir/src/pulsecore/stream-util.c", + "$pulseaudio_dir/src/pulsecore/svolume_arm.c", + "$pulseaudio_dir/src/pulsecore/svolume_c.c", + "$pulseaudio_dir/src/pulsecore/svolume_mmx.c", + "$pulseaudio_dir/src/pulsecore/svolume_sse.c", + "$pulseaudio_dir/src/pulsecore/thread-mq.c", + ] + + configs = [ ":pulsecore_config" ] +} + +ohos_shared_library("pulsecore") { + deps = [ + ":pulsecore_sources", + "$pulseaudio_build_path/src:pulsecommon", + "$libsndfile_build_path:sndfile", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +config("modules_internal_lib_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_build_path/include", + "$pulseaudio_dir/src", + "$pulseaudio_dir", + "$pulseaudio_build_path/src", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-unused-function", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + "-D__INCLUDED_FROM_PULSE_AUDIO", + ] +} + +ohos_shared_library("cli") { + sources = [ "$pulseaudio_dir/src/pulsecore/cli.c" ] + + configs = [ ":modules_internal_lib_config" ] + + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("protocol-cli") { + sources = [ "$pulseaudio_dir/src/pulsecore/protocol-cli.c" ] + + configs = [ ":modules_internal_lib_config" ] + + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + "$pulseaudio_build_path/src/pulsecore:cli", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_shared_library("protocol-native") { + sources = [ "$pulseaudio_dir/src/pulsecore/protocol-native.c" ] + + configs = [ ":modules_internal_lib_config" ] + + deps = [ + "$pulseaudio_build_path/src:pulsecommon", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/pulsecore/ltdl-stub.c b/pulseaudio/src/pulsecore/ltdl-stub.c new file mode 100644 index 0000000000..ce239ab9b8 --- /dev/null +++ b/pulseaudio/src/pulsecore/ltdl-stub.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "config.h" +#include +#include "ltdl.h" +#include + +#define SYSTEM_LIB_PATH "/system/lib/" + +lt_dlhandle lt_dlopenext(const char *filename) { + pa_assert(filename); + return (dlopen(filename, RTLD_NOW)); +} + +void* lt_dlsym(lt_dlhandle handle, const char *symbol) { + pa_assert(handle); + pa_assert(symbol); + + return (dlsym(handle, symbol)); +} + +int lt_dlclose(lt_dlhandle handle) { + pa_assert(handle); + return (dlclose(handle)); +} + +const char *lt_dlerror(void) { + return dlerror(); +} + +const char* lt_dlgetsearchpath() { + const char* path = SYSTEM_LIB_PATH; + return path; +} diff --git a/pulseaudio/src/utils/BUILD.gn b/pulseaudio/src/utils/BUILD.gn new file mode 100644 index 0000000000..7722a9e593 --- /dev/null +++ b/pulseaudio/src/utils/BUILD.gn @@ -0,0 +1,85 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/ohos.gni") + +pulseaudio_dir = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" + +config("pulseutils_config") { + visibility = [ ":*" ] + + include_dirs = [ + "$pulseaudio_dir", + "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", + "$pulseaudio_dir/src", + "$libsndfile_build_path/include", + ] + + cflags = [ + "-Wall", + "-Werror", + "-Wno-implicit-function-declaration", + "-DHAVE_CONFIG_H", + "-D_GNU_SOURCE", + ] +} + +ohos_executable("pacat") { + + sources = [ "$pulseaudio_dir/src/utils/pacat.c" ] + + configs = [ ":pulseutils_config" ] + + deps = [ + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src:pulsecommon", + "$libsndfile_build_path:sndfile", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_executable("pactl") { + sources = [ "$pulseaudio_dir/src/utils/pactl.c" ] + + configs = [ ":pulseutils_config" ] + + deps = [ + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src:pulsecommon", + "$libsndfile_build_path:sndfile", + ] + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_executable("pacmd") { + + install_enable = true + + sources = [ "$pulseaudio_dir/src/utils/pacmd.c" ] + + configs = [ ":pulseutils_config" ] + + deps = [ + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src:pulsecommon", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} diff --git a/sa_profile/3001.xml b/sa_profile/3001.xml old mode 100755 new mode 100644 index 6c8be70c77..a7a5f6a5a4 --- a/sa_profile/3001.xml +++ b/sa_profile/3001.xml @@ -14,7 +14,7 @@ limitations under the License. --> - audio_service + pulseaudio /system/lib/libaudio_service.z.so diff --git a/sa_profile/3009.xml b/sa_profile/3009.xml new file mode 100644 index 0000000000..aeed3091e7 --- /dev/null +++ b/sa_profile/3009.xml @@ -0,0 +1,28 @@ + + + + audio_policy + + /system/lib/libaudio_policy_service.z.so + + + 3009 + /system/lib/libaudio_policy_service.z.so + true + false + 1 + + diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn index f284c01d86..d1d4f42379 100644 --- a/sa_profile/BUILD.gn +++ b/sa_profile/BUILD.gn @@ -18,3 +18,9 @@ ohos_sa_profile("audio_service_sa_profile") { part_name = "multimedia_audio_standard" } + +ohos_sa_profile("audio_policy_service_sa_profile") { + sources = [ "3009.xml" ] + + part_name = "multimedia_audio_standard" +} diff --git a/services/BUILD.gn b/services/BUILD.gn old mode 100755 new mode 100644 index 210d594f88..f1b95c51d5 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -12,12 +12,13 @@ # limitations under the License. import("//build/ohos.gni") +AUDIO_POLICY_SERVER_DIR = "//foundation/multimedia/audio_standard/services/src/audio_policy/server" -ohos_prebuilt_etc("audio_service.rc") { - source = "etc/audio_service.rc" - relative_install_dir = "init" - part_name = "multimedia_audio_standard" - subsystem_name = "multimedia" +ohos_prebuilt_etc("pulseaudio.rc") { + source = "etc/pulseaudio.rc" + relative_install_dir = "init" + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" } config("audio_service_config") { @@ -27,6 +28,9 @@ config("audio_service_config") { "include", "include/server", "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer/include", + "//drivers/peripheral/audio/interfaces/include" ] if (target_cpu == "arm") { @@ -45,17 +49,110 @@ ohos_shared_library("audio_service") { configs = [ ":audio_service_config" ] deps = [ - "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", - "//utils/native/base:utils", + "//utils/native/base:utils", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", + "//foundation/multimedia/audio_standard/pulseaudio/src/daemon:pulseaudio", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer:audio_capturer_source", ] external_deps = [ - "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", + "samgr_L2:samgr_proxy", "safwk:system_ability_fwk", + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +group("audio_policy_service_packages") { + deps = [ + ":audio_policy.rc", + ":audio_policy_service", + ":audio_policy_config", + ] +} + +ohos_prebuilt_etc("audio_policy.rc") { + source = "etc/audio_policy.rc" + relative_install_dir = "init" + part_name = "multimedia_audio_standard" + subsystem_name = "multimedia" +} + +config("audio_policy_public_config") { + include_dirs = [ + "//foundation/multimedia/audio_standard/services/include", + "//foundation/multimedia/audio_standard/services/include/client", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/include/common", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/include/interface", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/include/manager", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/include/config", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/include", + "//foundation/multimedia/audio_standard/services/include/audio_policy/common", + "//foundation/multimedia/audio_standard/services/include/audio_policy/server", + "//foundation/multimedia/audio_standard/services/include/audio_policy/client", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//third_party/libxml2/include", + "//third_party/pulseaudio/src", + "//third_party/pulseaudio/confgure/src", + "//foundation/multimedia/audio_standard/pulseaudio/include", + "//utils/system/safwk/native/include", + "//utils/native/base/include", + "//third_party/bounds_checking_function/include", + ] + + cflags = [ + "-Wall", + "-Werror", + ] + + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } +} + +ohos_shared_library("audio_policy_service") { + install_enable = true + sources = [ + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/audio_policy_server.cpp", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/audio_policy_manager_stub.cpp", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/src/audio_policy_service.cpp", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp", + "//foundation/multimedia/audio_standard/services/src/audio_policy/server/service/src/config/xml_parser.cpp", + ] + + public_configs = [ + ":audio_policy_public_config", + ] + + deps = [ + "//utils/native/base:utils", + "//foundation/multimedia/audio_standard/pulseaudio/src/pulse:pulse", + "//third_party/libxml2:xml2", + ] + + external_deps = [ + "ipc:ipc_core", "samgr_L2:samgr_proxy", + "safwk:system_ability_fwk", + "hiviewdfx_hilog_native:libhilog", ] + subsystem_name = "multimedia" + part_name = "multimedia_audio_standard" +} + +ohos_prebuilt_etc("audio_policy_config") { + source = "$AUDIO_POLICY_SERVER_DIR/etc/audio_policy_config.xml" subsystem_name = "multimedia" + module_install_dir = "etc/audio" part_name = "multimedia_audio_standard" } diff --git a/services/etc/audio_service.rc b/services/etc/audio_policy.rc similarity index 81% rename from services/etc/audio_service.rc rename to services/etc/audio_policy.rc index 3cb4b53f29..9e9f3f594a 100644 --- a/services/etc/audio_service.rc +++ b/services/etc/audio_policy.rc @@ -11,12 +11,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -service audio_service /system/bin/sa_main /system/profile/audio_service.xml +service audio_policy /system/bin/sa_main /system/profile/audio_policy.xml class z_core - user audioserver - group system shell seclabel u:r:audiodistributedservice:s0 + disabled -on boot - start audio_service +on audio_policy_start + start audio_policy diff --git a/services/etc/pulseaudio.rc b/services/etc/pulseaudio.rc new file mode 100644 index 0000000000..cec5b2a6d8 --- /dev/null +++ b/services/etc/pulseaudio.rc @@ -0,0 +1,27 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +service pulseaudio /system/bin/sa_main /system/profile/pulseaudio.xml + class z_core + seclabel u:r:audiodistributedservice:s0 + disabled + +on post-fs-data + mkdir /data/local/.pulse_dir + chmod 755 /data/local/.pulse_dir + chown system shell /data/local/.pulse_dir + export PULSE_STATE_PATH "/data/local/.pulse_dir" + export PULSE_RUNTIME_PATH "/data/local/.pulse_dir" + start pulseaudio + exec /system/bin/sleep 4 + trigger audio_policy_start diff --git a/services/include/audio_device_descriptor.h b/services/include/audio_device_descriptor.h old mode 100755 new mode 100644 index 7b62c3ec87..d60ced9e40 --- a/services/include/audio_device_descriptor.h +++ b/services/include/audio_device_descriptor.h @@ -1,95 +1,97 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * 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 ST_AUDIO_DEVICE_DESCRIPTOR_H -#define ST_AUDIO_DEVICE_DESCRIPTOR_H - -#include "parcel.h" - -namespace OHOS { -/** - * @brief The AudioDeviceDescriptor class provides different sets of audio devices and their roles - */ - -class AudioDeviceDescriptor : public Parcelable { -public: -enum DeviceFlag { - /** - * Indicates all output audio devices. - */ - OUTPUT_DEVICES_FLAG = 0, - /** - * Indicates all input audio devices. - */ - INPUT_DEVICES_FLAG = 1, - /** - * Indicates all audio devices. - */ - ALL_DEVICES_FLAG = 2 -}; - -enum DeviceRole { - /** - * Device role none. - */ - DEVICE_ROLE_NONE = -1, - /** - * Input device role. - */ - INPUT_DEVICE = 0, - /** - * Output device role. - */ - OUTPUT_DEVICE = 1 -}; - -enum DeviceType { - /** - * Indicates device type none. - */ - DEVICE_TYPE_NONE = -1, - /** - * Indicates a speaker built in a device. - */ - SPEAKER = 0, - /** - * Indicates a headset, which is the combination of a pair of headphones and a microphone. - */ - WIRED_HEADSET = 1, - /** - * Indicates a Bluetooth device used for telephony. - */ - BLUETOOTH_SCO = 2, - /** - * Indicates a Bluetooth device supporting the Advanced Audio Distribution Profile (A2DP). - */ - BLUETOOTH_A2DP = 3, - /** - * Indicates a microphone built in a device. - */ - MIC = 4 -}; - - DeviceType getType(); - DeviceRole getRole(); - DeviceType deviceType_; - DeviceRole deviceRole_; - AudioDeviceDescriptor(); - virtual ~AudioDeviceDescriptor(); - bool Marshalling(Parcel &parcel) const override; - static AudioDeviceDescriptor* Unmarshalling(Parcel &parcel); -}; -} // namespace OHOS -#endif // ST_AUDIO_DEVICE_DESCRIPTOR_H +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_DEVICE_DESCRIPTOR_H +#define ST_AUDIO_DEVICE_DESCRIPTOR_H + +#include "parcel.h" + +namespace OHOS { +namespace AudioStandard { +/** + * @brief The AudioDeviceDescriptor class provides different sets of audio devices and their roles + */ + +class AudioDeviceDescriptor : public Parcelable { +public: +enum DeviceFlag { + /** + * Indicates all output audio devices. + */ + OUTPUT_DEVICES_FLAG = 0, + /** + * Indicates all input audio devices. + */ + INPUT_DEVICES_FLAG = 1, + /** + * Indicates all audio devices. + */ + ALL_DEVICES_FLAG = 2 +}; + +enum DeviceRole { + /** + * Device role none. + */ + DEVICE_ROLE_NONE = -1, + /** + * Input device role. + */ + INPUT_DEVICE = 0, + /** + * Output device role. + */ + OUTPUT_DEVICE = 1 +}; + +enum DeviceType { + /** + * Indicates device type none. + */ + DEVICE_TYPE_NONE = -1, + /** + * Indicates a speaker built in a device. + */ + SPEAKER = 0, + /** + * Indicates a headset, which is the combination of a pair of headphones and a microphone. + */ + WIRED_HEADSET = 1, + /** + * Indicates a Bluetooth device used for telephony. + */ + BLUETOOTH_SCO = 2, + /** + * Indicates a Bluetooth device supporting the Advanced Audio Distribution Profile (A2DP). + */ + BLUETOOTH_A2DP = 3, + /** + * Indicates a microphone built in a device. + */ + MIC = 4 +}; + + DeviceType getType(); + DeviceRole getRole(); + DeviceType deviceType_; + DeviceRole deviceRole_; + AudioDeviceDescriptor(); + virtual ~AudioDeviceDescriptor(); + bool Marshalling(Parcel &parcel) const override; + static AudioDeviceDescriptor* Unmarshalling(Parcel &parcel); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // ST_AUDIO_DEVICE_DESCRIPTOR_H diff --git a/services/include/audio_error.h b/services/include/audio_error.h new file mode 100644 index 0000000000..0a4a5f2431 --- /dev/null +++ b/services/include/audio_error.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_ERROR_H +#define AUDIO_ERROR_H + +namespace OHOS { +namespace AudioStandard { +enum AudioServiceErrorCodes { +}; + +enum AudioServiceEventTypes { +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_ERROR_H diff --git a/services/include/audio_manager_base.h b/services/include/audio_manager_base.h old mode 100755 new mode 100644 index aac47da54c..2927bae0d9 --- a/services/include/audio_manager_base.h +++ b/services/include/audio_manager_base.h @@ -20,38 +20,40 @@ #include "iremote_broker.h" #include "iremote_proxy.h" #include "iremote_stub.h" -#include "audio_svc_manager.h" +#include "audio_system_manager.h" namespace OHOS { +namespace AudioStandard { class IStandardAudioService : public IRemoteBroker { public: /** - * Set Volume. + * Obtains max volume. * - * @return Returns ERR_OK on success, others on failure. + * @return Returns the max volume. */ - virtual void SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) = 0; + virtual float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; /** - * Obtains current volume. + * Obtains min volume. * - * @return Returns the current volume. + * @return Returns the min volume. */ - virtual int GetVolume(AudioSvcManager::AudioVolumeType volumeType) = 0; - + virtual float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; + /** - * Obtains max volume. + * Sets Microphone Mute status. * - * @return Returns the max volume. + * @param isMute Mute status true or false to be set. + * @return Returns 0 if success. Otherise returns Errocode defined in audio_errors.h. */ - virtual int GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) = 0; + virtual int32_t SetMicrophoneMute(bool isMute) = 0; - /** - * Obtains min volume. + /** + * Gets Microphone Mute status. * - * @return Returns the min volume. + * @return Returns true or false */ - virtual int GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) = 0; + virtual bool IsMicrophoneMute() = 0; /** * Obtains device array. @@ -60,12 +62,31 @@ public: */ virtual std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) = 0; + /** + * Set Audio Parameter. + * + * @param key for the audio parameter to be set + * @param value associated with the key for the audio parameter to be set + * @return none. + */ + virtual void SetAudioParameter(const std::string key, const std::string value) = 0; + + /** + * Get Audio Parameter. + * + * @param key for the audio parameter to be set + * @return Returns value associated to the key requested. + */ + virtual const std::string GetAudioParameter(const std::string key) = 0; + enum { - SET_VOLUME = 0, - GET_VOLUME = 1, - GET_MAX_VOLUME = 2, - GET_MIN_VOLUME = 3, - GET_DEVICES = 4, + GET_MAX_VOLUME = 0, + GET_MIN_VOLUME = 1, + GET_DEVICES = 2, + GET_AUDIO_PARAMETER = 3, + SET_AUDIO_PARAMETER = 4, + SET_MICROPHONE_MUTE = 5, + IS_MICROPHONE_MUTE = 6 }; public: @@ -78,5 +99,6 @@ public: MessageParcel &reply, MessageOption &option) override; bool IsPermissionValid(); }; +} // namespace AudioStandard } // namespace OHOS #endif // I_ST_AUDIO_MANAGER_BASE_H diff --git a/services/include/audio_policy/client/audio_policy_base.h b/services/include/audio_policy/client/audio_policy_base.h new file mode 100644 index 0000000000..a3db6c0776 --- /dev/null +++ b/services/include/audio_policy/client/audio_policy_base.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 I_ST_AUDIO_POLICY_BASE_H +#define I_ST_AUDIO_POLICY_BASE_H + +#include "audio_policy_types.h" +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AudioStandard { +class IAudioPolicy : public IRemoteBroker { +public: + + virtual int32_t SetStreamVolume(AudioStreamType streamType, float volume) = 0; + + virtual float GetStreamVolume(AudioStreamType streamType) = 0; + + virtual int32_t SetStreamMute(AudioStreamType streamType, bool mute) = 0; + + virtual bool GetStreamMute(AudioStreamType streamType) = 0; + + virtual bool IsStreamActive(AudioStreamType streamType) = 0; + + virtual int32_t SetDeviceActive(DeviceType deviceType, bool active) = 0; + + virtual bool IsDeviceActive(DeviceType deviceType) = 0; + + virtual int32_t SetRingerMode(AudioRingerMode ringMode) = 0; + + virtual AudioRingerMode GetRingerMode() = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"IAudioPolicy"); +}; + +class AudioPolicyManagerStub : public IRemoteStub { +public: + virtual int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) override; + bool IsPermissionValid(); +}; +} // AudioStandard +} // namespace OHOS + +#endif // I_ST_AUDIO_POLICY_BASE_H diff --git a/services/include/audio_policy/client/audio_policy_proxy.h b/services/include/audio_policy/client/audio_policy_proxy.h new file mode 100644 index 0000000000..913ee455ae --- /dev/null +++ b/services/include/audio_policy/client/audio_policy_proxy.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_PROXY_H +#define ST_AUDIO_POLICY_PROXY_H + +#include "iremote_proxy.h" +#include "audio_policy_base.h" + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyProxy : public IRemoteProxy { +public: + explicit AudioPolicyProxy(const sptr &impl); + virtual ~AudioPolicyProxy() = default; + + int32_t SetStreamVolume(AudioStreamType streamType, float volume) override; + + float GetStreamVolume(AudioStreamType streamType) override; + + int32_t SetStreamMute(AudioStreamType streamType, bool mute) override; + + bool GetStreamMute(AudioStreamType streamType) override; + + bool IsStreamActive(AudioStreamType streamType) override; + + int32_t SetDeviceActive(DeviceType deviceType, bool active) override; + + bool IsDeviceActive(DeviceType deviceType) override; + + int32_t SetRingerMode(AudioRingerMode ringMode) override; + + AudioRingerMode GetRingerMode() override; +private: + static inline BrokerDelegator mDdelegator; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // ST_AUDIO_POLICY_PROXY_H diff --git a/services/include/audio_policy/common/audio_policy_types.h b/services/include/audio_policy/common/audio_policy_types.h new file mode 100644 index 0000000000..d9c1a59388 --- /dev/null +++ b/services/include/audio_policy/common/audio_policy_types.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_TYPES_H +#define ST_AUDIO_POLICY_TYPES_H + +#include + +namespace OHOS { +namespace AudioStandard { +enum AudioPolicyCommand { + SET_STREAM_VOLUME, + GET_STREAM_VOLUME, + SET_STREAM_MUTE, + GET_STREAM_MUTE, + IS_STREAM_ACTIVE, + SET_DEVICE_ACTIVE, + IS_DEVICE_ACTIVE, + SET_RINGER_MODE, + GET_RINGER_MODE +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_POLICY_TYPES_H diff --git a/services/include/audio_policy/server/audio_policy_server.h b/services/include/audio_policy/server/audio_policy_server.h new file mode 100644 index 0000000000..a5cb6564fb --- /dev/null +++ b/services/include/audio_policy/server/audio_policy_server.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_SERVER_H +#define ST_AUDIO_POLICY_SERVER_H + +#include +#include + +#include "audio_policy_base.h" +#include "audio_policy_service.h" +#include "iremote_stub.h" +#include "system_ability.h" + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyServer : public SystemAbility, public AudioPolicyManagerStub { + DECLARE_SYSTEM_ABILITY(AudioPolicyServer); +public: + DISALLOW_COPY_AND_MOVE(AudioPolicyServer); + + explicit AudioPolicyServer(int32_t systemAbilityId, bool runOnCreate = true); + + virtual ~AudioPolicyServer() = default; + + void OnDump() override; + void OnStart() override; + void OnStop() override; + + int32_t SetStreamVolume(AudioStreamType streamType, float volume) override; + + float GetStreamVolume(AudioStreamType streamType) override; + + int32_t SetStreamMute(AudioStreamType streamType, bool mute) override; + + bool GetStreamMute(AudioStreamType streamType) override; + + bool IsStreamActive(AudioStreamType streamType) override; + + int32_t SetDeviceActive(DeviceType deviceType, bool active) override; + + bool IsDeviceActive(DeviceType deviceType) override; + + int32_t SetRingerMode(AudioRingerMode ringMode) override; + + AudioRingerMode GetRingerMode() override; + +private: + AudioPolicyService& mPolicyService; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // ST_AUDIO_POLICY_SERVER_H diff --git a/services/include/client/audio_manager_proxy.h b/services/include/client/audio_manager_proxy.h old mode 100755 new mode 100644 index 0b91a84a02..0a7068e3b4 --- a/services/include/client/audio_manager_proxy.h +++ b/services/include/client/audio_manager_proxy.h @@ -17,23 +17,26 @@ #define ST_AUDIO_MANAGER_PROXY_H #include "iremote_proxy.h" -#include "audio_svc_manager.h" +#include "audio_system_manager.h" #include "audio_manager_base.h" #include "audio_device_descriptor.h" namespace OHOS { +namespace AudioStandard { class AudioManagerProxy : public IRemoteProxy { public: explicit AudioManagerProxy(const sptr &impl); virtual ~AudioManagerProxy() = default; - - void SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) override; - int32_t GetVolume(AudioSvcManager::AudioVolumeType volumeType) override; - int32_t GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) override; - int32_t GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) override; + float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; + float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t SetMicrophoneMute(bool isMute) override; + bool IsMicrophoneMute() override; std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) override; + const std::string GetAudioParameter(const std::string key) override; + void SetAudioParameter(const std::string key, const std::string value) override; private: static inline BrokerDelegator delegator_; }; +} // namespace AudioStandard } // namespace OHOS #endif // ST_AUDIO_MANAGER_PROXY_H diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h new file mode 100644 index 0000000000..b7e7102012 --- /dev/null +++ b/services/include/client/audio_service_client.h @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_SERVICE_CLIENT_H +#define AUDIO_SERVICE_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace AudioStandard { +enum ASClientType { + AUDIO_SERVICE_CLIENT_PLAYBACK, + AUDIO_SERVICE_CLIENT_RECORD, + AUDIO_SERVICE_CLIENT_CONTROLLER +}; + +typedef pa_sink_input_info SinkInputInfo; +typedef pa_source_output_info SourceOutputInfo; +typedef pa_sink_info SinkDeviceInfo; +typedef pa_source_info SourceDeviceInfo; +typedef pa_client_info ClientInfo; + +struct StreamBuffer { + uint8_t *buffer; // the virtual address of stream + uint32_t bufferLen; // stream length, by bytes +}; + +class AudioRendererCallbacks { +public: + virtual ~AudioRendererCallbacks(); + virtual void OnSinkDeviceUpdatedCb() const = 0; + // Need to check required state changes to update applications + virtual void OnStreamStateChangeCb() const = 0; + virtual void OnStreamBufferUnderFlowCb() const = 0; + virtual void OnStreamBufferOverFlowCb() const = 0; + virtual void OnErrorCb(AudioServiceErrorCodes error) const = 0; + virtual void OnEventCb(AudioServiceEventTypes error) const = 0; +}; + +class AudioRecorderCallbacks { +public: + virtual ~AudioRecorderCallbacks(); + virtual void OnSourceDeviceUpdatedCb() const = 0; + // Need to check required state changes to update applications + virtual void OnStreamStateChangeCb() const = 0; + virtual void OnStreamBufferUnderFlowCb() const = 0; + virtual void OnStreamBufferOverFlowCb() const = 0; + virtual void OnErrorCb(AudioServiceErrorCodes error) const = 0; + virtual void OnEventCb(AudioServiceEventTypes error) const = 0; +}; + +class AudioServiceClient { +public: + AudioServiceClient(); + virtual ~AudioServiceClient(); + + /** + * Initializes audio service client for the required client type + * + * @param eClientType indicates the client type like playback, record or controller. + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t Initialize(ASClientType eClientType); + + // Stream handling APIs + + /** + * Creates & initializes resources based on the audioParams and audioType + * + * @param audioParams indicate format, sampling rate and number of channels + * @param audioType indicate the stream type like music, system, ringtone etc + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t CreateStream(AudioStreamParams audioParams, AudioStreamType audioType); + + /** + * Starts the stream created using CreateStream + * + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t StartStream(); + + /** + * Stops the stream created using CreateStream + * + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t StopStream(); + + /** + * Flushes the stream created using CreateStream. This is applicable for + * playback only + * + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t FlushStream(); + + /** + * Drains the stream created using CreateStream. This is applicable for + * playback only + * + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t DrainStream(); + + /** + * Pauses the stream using the session ID + * + * @param sessionID indicates the ID for the active stream to be controlled + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t PauseStream(uint32_t sessionID); + + /** + * Sets the volume of the stream associated with session ID + * + * @param sessionID indicates the ID for the active stream to be controlled + * @param volume indicates volume level between 0 to 65536 + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t SetStreamVolume(uint32_t sessionID, uint32_t volume); + + /** + * Get the volume of the stream associated with session ID + * + * @param sessionID indicates the ID for the active stream to be controlled + * @return returns volume level between 0 to 65536 + */ + uint32_t GetStreamVolume(uint32_t sessionID); + + /** + * Writes audio data of the stream created using CreateStream to active sink device + * + * @param buffer contains audio data to write + * @param bufferSize indicates the size of audio data in bytes to write from the buffer + * @param pError indicates pointer to error which will be filled in case of internal errors + * @return returns size of audio data written in bytes. + */ + size_t WriteStream(const StreamBuffer &stream, int32_t &pError); + + /** + * Reads audio data of the stream created using CreateStream from active source device + * + * @param StreamBuffer including buffer to be filled with audio data + * and bufferSize indicating the size of audio data to read into buffer + * @param isBlocking indicates if the read is blocking or not + * @return Returns size read if success; returns {@code -1} failure. + */ + int32_t ReadStream(StreamBuffer &stream, bool isBlocking); + + /** + * Release the resources allocated using CreateStream + * + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t ReleaseStream(); + + /** + * Provides the current timestamp for playback/record stream created using CreateStream + * + * @param timeStamp will be filled up with current timestamp + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t GetCurrentTimeStamp(uint64_t &timeStamp); + + /** + * Provides the playback/record stream parameters created using CreateStream + * + * @param audioParams will be filled up with stream audio parameters + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t GetAudioStreamParams(AudioStreamParams& audioParams); + + /** + * Provides the minimum buffer size required for this audio stream + * created using CreateStream + * @param minBufferSize will be set to minimum buffer size in bytes + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t GetMinimumBufferSize(size_t &minBufferSize); + + /** + * Provides the minimum frame count required for this audio stream + * created using CreateStream + * @param frameCount will be set to minimum number of frames + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t GetMinimumFrameCount(uint32_t &frameCount); + + /** + * Provides the sampling rate for the active audio stream + * created using CreateStream + * + * @return Returns sampling rate in Hz + */ + uint32_t GetSamplingRate(); + + /** + * Provides the channel count for the active audio stream + * created using CreateStream + * + * @return Returns number of channels + */ + uint8_t GetChannelCount(); + + /** + * Provides the sample size for the active audio stream + * created using CreateStream + * + * @return Returns sample size in number of bits + */ + uint8_t GetSampleSize(); + + // Device volume & route handling APIs + + // Audio stream callbacks + + /** + * Register for callbacks associated with the playback stream created using CreateStream + * + * @param cb indicates pointer for registered callbacks + * @return none + */ + void RegisterAudioRendererCallbacks(const AudioRendererCallbacks &cb); + + /** + * Register for callbacks associated with the record stream created using CreateStream + * + * @param cb indicates pointer for registered callbacks + * @return none + */ + void RegisterAudioRecorderCallbacks(const AudioRecorderCallbacks &cb); + +private: + pa_threaded_mainloop *mainLoop; + pa_mainloop_api *api; + pa_context *context; + pa_stream *paStream; + pa_sample_spec sampleSpec; + + const void* internalReadBuffer; + size_t internalRdBufLen; + size_t internalRdBufIndex; + int32_t streamCmdStatus; + bool isMainLoopStarted; + bool isContextConnected; + bool isStreamConnected; + + // To be set while using audio stream + // functionality for callbacks + AudioRendererCallbacks* mAudioRendererCallbacks; + AudioRecorderCallbacks* mAudioRecorderCallbacks; + + std::map sinkDevices; + std::map sourceDevices; + std::map sinkInputs; + std::map sourceOutputs; + std::map clientInfo; + + ASClientType eAudioClientType; + + uint32_t underFlowCount; + int32_t ConnectStreamToPA(); + + // Error code used + static const uint32_t AUDIO_CLIENT_SUCCESS = 0; + static const uint32_t AUDIO_CLIENT_ERR = -1; + static const uint32_t AUDIO_CLIENT_INVALID_PARAMS_ERR = -2; + static const uint32_t AUDIO_CLIENT_INIT_ERR = -3; + static const uint32_t AUDIO_CLIENT_CREATE_STREAM_ERR = -4; + static const uint32_t AUDIO_CLIENT_START_STREAM_ERR = -5; + static const uint32_t AUDIO_CLIENT_READ_STREAM_ERR = -6; + static const uint32_t AUDIO_CLIENT_PA_ERR = -7; + + + // Default values + static const uint32_t DEFAULT_SAMPLING_RATE = 44100; + static const uint8_t DEFAULT_CHANNEL_COUNT = 2; + static const uint8_t DEFAULT_SAMPLE_SIZE = 2; + static const uint32_t DEFAULT_STREAM_VOLUME = 65536; + static const std::string GetStreamName(AudioStreamType audioType); + static pa_sample_spec ConvertToPAAudioParams(AudioStreamParams audioParams); + static AudioStreamParams ConvertFromPAAudioParams(pa_sample_spec paSampleSpec); + + // Resets PA audio client and free up resources if any with this API + void ResetPAAudioClient(); + + + // Callbacks to be implemented + static void PAStreamStateCb(pa_stream *stream, void *userdata); + static void PAStreamUnderFlowCb(pa_stream *stream, void *userdata); + static void PAContextStateCb(pa_context *context, void *userdata); + static void PAStreamRequestCb(pa_stream *stream, size_t length, void *userdata); + static void PAStreamCmdSuccessCb(pa_stream *stream, int32_t success, void *userdata); + static void PAStreamLatencyUpdateCb(pa_stream *stream, void *userdata); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_SERVICE_CLIENT_H diff --git a/services/include/server/audio_server.h b/services/include/server/audio_server.h old mode 100755 new mode 100644 index 2e9de4ec2e..e6541905da --- a/services/include/server/audio_server.h +++ b/services/include/server/audio_server.h @@ -18,14 +18,15 @@ #include #include - +#include #include "iremote_stub.h" #include "system_ability.h" -#include "audio_svc_manager.h" +#include "audio_system_manager.h" #include "audio_manager_base.h" #include "audio_device_descriptor.h" namespace OHOS { +namespace AudioStandard { class AudioServer : public SystemAbility, public AudioManagerStub { DECLARE_SYSTEM_ABILITY(AudioServer); public: @@ -35,16 +36,22 @@ public: void OnDump() override; void OnStart() override; void OnStop() override; - void SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) override; - int32_t GetVolume(AudioSvcManager::AudioVolumeType volumeType) override; - int32_t GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) override; - int32_t GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) override; + float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; + float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t SetMicrophoneMute(bool isMute) override; + bool IsMicrophoneMute() override; std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) override; + static void* paDaemonThread(void* arg); + void SetAudioParameter(const std::string key, const std::string value) override; + const std::string GetAudioParameter(const std::string key) override; private: - static const int32_t MAX_VOLUME = 15; - static const int32_t MIN_VOLUME = 0; - static std::unordered_map AudioStreamVolumeMap; + static constexpr float MAX_VOLUME = 1.0; + static constexpr float MIN_VOLUME = 0; + static std::unordered_map AudioStreamVolumeMap; std::vector> audioDeviceDescriptor_; + static std::map audioParameters; + pthread_t m_paDaemonThread; }; +} // namespace AudioStandard } // namespace OHOS #endif // ST_AUDIO_SERVER_H diff --git a/services/src/audio_device_descriptor.cpp b/services/src/audio_device_descriptor.cpp old mode 100755 new mode 100644 index c89d98ca62..44e9b33ec6 --- a/services/src/audio_device_descriptor.cpp +++ b/services/src/audio_device_descriptor.cpp @@ -1,53 +1,55 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * 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_device_descriptor.h" -#include "media_log.h" - -namespace OHOS { -/** - * @brief The AudioDeviceDescriptor class provides - * different sets of audio devices and their roles - */ -AudioDeviceDescriptor::AudioDeviceDescriptor() -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor constructor"); - deviceType_ = DEVICE_TYPE_NONE; - deviceRole_ = DEVICE_ROLE_NONE; -} - -AudioDeviceDescriptor::~AudioDeviceDescriptor() -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::~AudioDeviceDescriptor"); -} - -bool AudioDeviceDescriptor::Marshalling(Parcel &parcel) const -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Marshalling called"); - return parcel.WriteInt32(deviceType_) && parcel.WriteInt32(deviceRole_); -} - -AudioDeviceDescriptor *AudioDeviceDescriptor::Unmarshalling(Parcel &in) -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Unmarshalling called"); - AudioDeviceDescriptor *audioDeviceDescriptor = new(std::nothrow) AudioDeviceDescriptor(); - if (audioDeviceDescriptor == nullptr) { - return nullptr; - } - audioDeviceDescriptor->deviceType_ = static_cast(in.ReadInt32()); - audioDeviceDescriptor->deviceRole_ = static_cast(in.ReadInt32()); - return audioDeviceDescriptor; -} -} // namespace OHOS +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_device_descriptor.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +/** + * @brief The AudioDeviceDescriptor class provides + * different sets of audio devices and their roles + */ +AudioDeviceDescriptor::AudioDeviceDescriptor() +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor constructor"); + deviceType_ = DEVICE_TYPE_NONE; + deviceRole_ = DEVICE_ROLE_NONE; +} + +AudioDeviceDescriptor::~AudioDeviceDescriptor() +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::~AudioDeviceDescriptor"); +} + +bool AudioDeviceDescriptor::Marshalling(Parcel &parcel) const +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Marshalling called"); + return parcel.WriteInt32(deviceType_) && parcel.WriteInt32(deviceRole_); +} + +AudioDeviceDescriptor *AudioDeviceDescriptor::Unmarshalling(Parcel &in) +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Unmarshalling called"); + AudioDeviceDescriptor *audioDeviceDescriptor = new(std::nothrow) AudioDeviceDescriptor(); + if (audioDeviceDescriptor == nullptr) { + return nullptr; + } + audioDeviceDescriptor->deviceType_ = static_cast(in.ReadInt32()); + audioDeviceDescriptor->deviceRole_ = static_cast(in.ReadInt32()); + return audioDeviceDescriptor; +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/client/audio_svc_manager.cpp b/services/src/audio_policy/client/audio_policy_manager.cpp old mode 100755 new mode 100644 similarity index 34% rename from services/src/client/audio_svc_manager.cpp rename to services/src/audio_policy/client/audio_policy_manager.cpp index e03c9f1e6c..aafbd0b7bf --- a/services/src/client/audio_svc_manager.cpp +++ b/services/src/audio_policy/client/audio_policy_manager.cpp @@ -13,80 +13,79 @@ * limitations under the License. */ +#include "audio_policy_manager.h" +#include "audio_policy_proxy.h" #include "iservice_registry.h" -#include "audio_manager_proxy.h" -#include "audio_svc_manager.h" #include "media_log.h" #include "system_ability_definition.h" namespace OHOS { -static sptr g_sProxy = nullptr; +namespace AudioStandard { +static sptr g_sProxy = nullptr; +void AudioPolicyManager::Init() +{ + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + MEDIA_ERR_LOG("AudioPolicyManager::init failed"); + return; + } + + sptr object = samgr->GetSystemAbility(AUDIO_POLICY_SERVICE_ID); + if (object == nullptr) { + MEDIA_DEBUG_LOG("AudioPolicyManager::object is NULL."); + } + + g_sProxy = iface_cast(object); + if (g_sProxy == nullptr) { + MEDIA_DEBUG_LOG("AudioPolicyManager::init g_sProxy is NULL."); + } else { + MEDIA_DEBUG_LOG("AudioPolicyManager::init g_sProxy is assigned."); + } +} -AudioSvcManager::AudioSvcManager() +int32_t AudioPolicyManager::SetStreamVolume(AudioStreamType streamType, float volume) { - MEDIA_DEBUG_LOG("AudioSvcManager start"); - init(); + return g_sProxy->SetStreamVolume(streamType, volume); } -AudioSvcManager::~AudioSvcManager() +int32_t AudioPolicyManager::SetRingerMode(AudioRingerMode ringMode) { - MEDIA_DEBUG_LOG("AudioSvcManager::~AudioSvcManager"); + return g_sProxy->SetRingerMode(ringMode); } -AudioSvcManager* AudioSvcManager::GetInstance() +AudioRingerMode AudioPolicyManager::GetRingerMode() { - static AudioSvcManager audioManager; - return &audioManager; + return g_sProxy->GetRingerMode(); } -void AudioSvcManager::init() +float AudioPolicyManager::GetStreamVolume(AudioStreamType streamType) { - MEDIA_DEBUG_LOG("AudioSvcManager::init start"); - auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (samgr == nullptr) { - MEDIA_ERR_LOG("AudioSvcManager::init failed"); - return; - } - sptr object = samgr->GetSystemAbility(AUDIO_DISTRIBUTED_SERVICE_ID); - if (object == nullptr) { - MEDIA_DEBUG_LOG("AudioSvcManager::object is NULL."); - } - g_sProxy = iface_cast(object); - if (g_sProxy == nullptr) { - MEDIA_DEBUG_LOG("AudioSvcManager::init g_sProxy is NULL."); - } else { - MEDIA_DEBUG_LOG("AudioSvcManager::init g_sProxy is assigned."); - } - MEDIA_ERR_LOG("AudioSvcManager::init end"); + return g_sProxy->GetStreamVolume(streamType); } -void AudioSvcManager::SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) +int32_t AudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool mute) { - MEDIA_DEBUG_LOG("AudioSvcManager::SetVolume Client"); - g_sProxy->SetVolume(volumeType, volume); + return g_sProxy->SetStreamMute(streamType, mute); } -int AudioSvcManager::GetVolume(AudioSvcManager::AudioVolumeType volumeType) +bool AudioPolicyManager::GetStreamMute(AudioStreamType streamType) { - MEDIA_DEBUG_LOG("AudioSvcManager::GetVolume Client"); - return g_sProxy->GetVolume(volumeType); + return g_sProxy->GetStreamMute(streamType); } -int AudioSvcManager::GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) +bool AudioPolicyManager::IsStreamActive(AudioStreamType streamType) { - MEDIA_DEBUG_LOG("AudioSvcManager::GetMaxVolume Client"); - return g_sProxy->GetMaxVolume(volumeType); + return g_sProxy->IsStreamActive(streamType); } -int AudioSvcManager::GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) +int32_t AudioPolicyManager::SetDeviceActive(DeviceType deviceType, bool active) { - MEDIA_DEBUG_LOG("AudioSvcManager::GetMinVolume Client"); - return g_sProxy->GetMinVolume(volumeType); + return g_sProxy->SetDeviceActive(deviceType, active); } -std::vector> AudioSvcManager::GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) +bool AudioPolicyManager::IsDeviceActive(DeviceType deviceType) { - MEDIA_DEBUG_LOG("AudioSvcManager::GetDevices Client"); - return g_sProxy->GetDevices(deviceFlag); + return g_sProxy->IsDeviceActive(deviceType); } +} // namespace AudioStandard } // namespace OHOS diff --git a/services/src/audio_policy/client/audio_policy_proxy.cpp b/services/src/audio_policy/client/audio_policy_proxy.cpp new file mode 100644 index 0000000000..b5b59b099b --- /dev/null +++ b/services/src/audio_policy/client/audio_policy_proxy.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_policy_manager.h" +#include "audio_policy_proxy.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +AudioPolicyProxy::AudioPolicyProxy(const sptr &impl) + : IRemoteProxy(impl) +{ +} + +int32_t AudioPolicyProxy::SetStreamVolume(AudioStreamType streamType, float volume) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(streamType)); + data.WriteFloat(volume); + + int32_t error = Remote()->SendRequest(SET_STREAM_VOLUME, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("set volume failed, error: %d", error); + return error; + } + return reply.ReadInt32(); +} + +int32_t AudioPolicyProxy::SetRingerMode(AudioRingerMode ringMode) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(ringMode)); + + int32_t error = Remote()->SendRequest(SET_RINGER_MODE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("set ringermode failed, error: %d", error); + return error; + } + + return reply.ReadInt32(); +} + +AudioRingerMode AudioPolicyProxy::GetRingerMode() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + int32_t error = Remote()->SendRequest(GET_RINGER_MODE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("get ringermode failed, error: %d", error); + } + return static_cast(reply.ReadInt32()); +} + +float AudioPolicyProxy::GetStreamVolume(AudioStreamType streamType) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(streamType)); + + int32_t error = Remote()->SendRequest(GET_STREAM_VOLUME, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("get volume failed, error: %d", error); + return error; + } + return reply.ReadFloat(); +} + +int32_t AudioPolicyProxy::SetStreamMute(AudioStreamType streamType, bool mute) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(streamType)); + data.WriteBool(mute); + + int32_t error = Remote()->SendRequest(SET_STREAM_MUTE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("set mute failed, error: %d", error); + return error; + } + return reply.ReadInt32(); +} + +bool AudioPolicyProxy::GetStreamMute(AudioStreamType streamType) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(streamType)); + + int32_t error = Remote()->SendRequest(GET_STREAM_MUTE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("get mute failed, error: %d", error); + return error; + } + return reply.ReadBool(); +} + +bool AudioPolicyProxy::IsStreamActive(AudioStreamType streamType) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(streamType)); + + int32_t error = Remote()->SendRequest(IS_STREAM_ACTIVE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("isStreamActive failed, error: %d", error); + return false; + } + return reply.ReadBool(); +} + +int32_t AudioPolicyProxy::SetDeviceActive(DeviceType deviceType, bool active) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(deviceType)); + data.WriteBool(active); + + int32_t error = Remote()->SendRequest(SET_DEVICE_ACTIVE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("set device active failed, error: %d", error); + return error; + } + return reply.ReadInt32(); +} + +bool AudioPolicyProxy::IsDeviceActive(DeviceType deviceType) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInt32(static_cast(deviceType)); + + int32_t error = Remote()->SendRequest(IS_DEVICE_ACTIVE, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("is device active failed, error: %d", error); + return false; + } + return reply.ReadBool(); +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/audio_policy/server/audio_policy_manager_stub.cpp b/services/src/audio_policy/server/audio_policy_manager_stub.cpp new file mode 100644 index 0000000000..1b76750036 --- /dev/null +++ b/services/src/audio_policy/server/audio_policy_manager_stub.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_errors.h" +#include "audio_policy_base.h" +#include "audio_policy_server.h" +#include "audio_policy_types.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +int AudioPolicyManagerStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case SET_STREAM_VOLUME: { + AudioStreamType streamType = static_cast(data.ReadInt32()); + float volume = data.ReadFloat(); + int result = SetStreamVolume(streamType, volume); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); + break; + } + + case SET_RINGER_MODE: { + AudioRingerMode rMode = static_cast(data.ReadInt32()); + int32_t result = SetRingerMode(rMode); + reply.WriteInt32(result); + break; + } + + case GET_RINGER_MODE: { + AudioRingerMode rMode = GetRingerMode(); + reply.WriteInt32(static_cast(rMode)); + break; + } + + case GET_STREAM_VOLUME: { + AudioStreamType streamType = static_cast(data.ReadInt32()); + float volume = GetStreamVolume(streamType); + reply.WriteFloat(volume); + break; + } + + case SET_STREAM_MUTE: { + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool mute = data.ReadBool(); + int result = SetStreamMute(streamType, mute); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); + break; + } + + case GET_STREAM_MUTE: { + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool mute = GetStreamMute(streamType); + reply.WriteBool(mute); + break; + } + + case IS_STREAM_ACTIVE: { + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool isActive = IsStreamActive(streamType); + reply.WriteBool(isActive); + break; + } + + case SET_DEVICE_ACTIVE: { + DeviceType deviceType = static_cast(data.ReadInt32()); + bool active = data.ReadBool(); + int32_t result = SetDeviceActive(deviceType, active); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); + break; + } + + case IS_DEVICE_ACTIVE: { + DeviceType deviceType = static_cast(data.ReadInt32()); + bool result = IsDeviceActive(deviceType); + reply.WriteBool(result); + break; + } + + default: { + MEDIA_ERR_LOG("default case, need check AudioPolicyManagerStub"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } + return MEDIA_OK; +} + +bool AudioPolicyManagerStub::IsPermissionValid() +{ + return true; +} +} // namespace audio_policy +} // namespace OHOS diff --git a/services/src/audio_policy/server/audio_policy_server.cpp b/services/src/audio_policy/server/audio_policy_server.cpp new file mode 100644 index 0000000000..0cfcdb5816 --- /dev/null +++ b/services/src/audio_policy/server/audio_policy_server.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_policy_server.h" +#include "iservice_registry.h" +#include "media_log.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AudioStandard { +REGISTER_SYSTEM_ABILITY_BY_ID(AudioPolicyServer, AUDIO_POLICY_SERVICE_ID, true) + +AudioPolicyServer::AudioPolicyServer(int32_t systemAbilityId, bool runOnCreate) + : SystemAbility(systemAbilityId, runOnCreate), + mPolicyService(AudioPolicyService::GetAudioPolicyService()) +{ +} + +void AudioPolicyServer::OnDump() +{ + return; +} + +void AudioPolicyServer::OnStart() +{ + bool res = Publish(this); + if (res) { + MEDIA_DEBUG_LOG("AudioPolicyService OnStart res=%d", res); + } + + mPolicyService.Init(); + return; +} + +void AudioPolicyServer::OnStop() +{ + mPolicyService.Deinit(); + return; +} + +int32_t AudioPolicyServer::SetStreamVolume(AudioStreamType streamType, float volume) +{ + return mPolicyService.SetStreamVolume(streamType, volume); +} + +float AudioPolicyServer::GetStreamVolume(AudioStreamType streamType) +{ + return mPolicyService.GetStreamVolume(streamType); +} + +int32_t AudioPolicyServer::SetStreamMute(AudioStreamType streamType, bool mute) +{ + return mPolicyService.SetStreamMute(streamType, mute); +} + +bool AudioPolicyServer::GetStreamMute(AudioStreamType streamType) +{ + return mPolicyService.GetStreamMute(streamType); +} + +bool AudioPolicyServer::IsStreamActive(AudioStreamType streamType) +{ + return mPolicyService.IsStreamActive(streamType); +} + +int32_t AudioPolicyServer::SetDeviceActive(DeviceType deviceType, bool active) +{ + return mPolicyService.SetDeviceActive(deviceType, active); +} + +bool AudioPolicyServer::IsDeviceActive(DeviceType deviceType) +{ + return mPolicyService.IsDeviceActive(deviceType); +} + +int32_t AudioPolicyServer::SetRingerMode(AudioRingerMode ringMode) +{ + return mPolicyService.SetRingerMode(ringMode); +} + +AudioRingerMode AudioPolicyServer::GetRingerMode() +{ + return mPolicyService.GetRingerMode(); +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/audio_policy/server/etc/audio_policy_config.xml b/services/src/audio_policy/server/etc/audio_policy_config.xml new file mode 100644 index 0000000000..20a1794dbc --- /dev/null +++ b/services/src/audio_policy/server/etc/audio_policy_config.xml @@ -0,0 +1,35 @@ + + + + + + + + Speaker + Built-In Mic + + + + + + + + + Speaker + Built-In Mic + + + + + + + + + + + + + + + + diff --git a/services/src/audio_policy/server/service/include/audio_policy_service.h b/services/src/audio_policy/server/service/include/audio_policy_service.h new file mode 100644 index 0000000000..ba558f5fad --- /dev/null +++ b/services/src/audio_policy/server/service/include/audio_policy_service.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_SERVICE_H +#define ST_AUDIO_POLICY_SERVICE_H + +#include "audio_info.h" +#include "audio_policy_manager_factory.h" +#include "iaudio_policy.h" +#include "iport_observer.h" +#include "parser_factory.h" + +#include +#include +#include + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyService : public IPortObserver { +public: + static constexpr char HDI_SINK[] = "hdi_output"; + static constexpr char HDI_SOURCE[] = "hdi_input"; + static constexpr char BLUEZ_SINK[] = "fifo_output"; + + static AudioPolicyService& GetAudioPolicyService() + { + static AudioPolicyService audioPolicyService; + return audioPolicyService; + } + + bool Init(void); + void Deinit(void); + + int32_t SetStreamVolume(AudioStreamType streamType, float volume) const; + + float GetStreamVolume(AudioStreamType streamType) const; + + int32_t SetStreamMute(AudioStreamType streamType, bool mute) const; + + bool GetStreamMute(AudioStreamType streamType) const; + + bool IsStreamActive(AudioStreamType streamType) const; + + int32_t SetDeviceActive(DeviceType deviceType, bool active); + + bool IsDeviceActive(DeviceType deviceType) const; + + int32_t SetRingerMode(AudioRingerMode ringMode); + + AudioRingerMode GetRingerMode() const; + + // Parser callbacks + void OnAudioPortAvailable(std::shared_ptr portInfo); + + void OnAudioPortPinAvailable(std::shared_ptr portInfo); + + void OnDefaultOutputPortPin(DeviceType device); + + void OnDefaultInputPortPin(DeviceType device); + +private: + + AudioPolicyService() + : mAudioPolicyManager(AudioPolicyManagerFactory::GetAudioPolicyManager()), + mConfigParser(ParserFactory::GetInstance().CreateParser(*this)) + { + } + + virtual ~AudioPolicyService() {} + + AudioIOHandle GetAudioIOHandle(DeviceType deviceType); + std::list& GetActiveDevicesList(DeviceType deviceType) + { + switch (deviceType) { + case SPEAKER: + return mActiveOutputDevices; + case MIC: + return mActiveInputDevices; + default: + return mActiveOutputDevices; // Default case return Output device + } + } + IAudioPolicyInterface& mAudioPolicyManager; + Parser& mConfigParser; + std::unordered_map mIOHandles; + std::list mActiveOutputDevices; + std::list mActiveInputDevices; +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_POLICY_SERVICE_H diff --git a/services/src/audio_policy/server/service/include/common/audio_config.h b/services/src/audio_policy/server/service/include/common/audio_config.h new file mode 100644 index 0000000000..68f7c907f3 --- /dev/null +++ b/services/src/audio_policy/server/service/include/common/audio_config.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_CONFIG_H +#define ST_AUDIO_CONFIG_H + +#include "audio_info.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#ifdef __cplusplus +} +#endif + +namespace OHOS { +namespace AudioStandard { +enum NodeName { + MODULES, + MODULE, + BUILT_IN_DEVICES, + DEFAULT_OUTPUT_DEVICE, + DEFAULT_INPUT_DEVICE, + AUDIO_PORTS, + AUDIO_PORT, + AUDIO_PORT_PINS, + AUDIO_PORT_PIN, + UNKNOWN +}; + +enum PortType { + TYPE_AUDIO_PORT, + TYPE_AUDIO_PORT_PIN, +}; + +class PortInfo { +public: + PortType type; + char* name; + char* role; + char* rate; + char* channels; + char* buffer_size; + char* fileName; + + PortInfo() + : name (nullptr), + role (nullptr), + rate (nullptr), + channels (nullptr), + buffer_size (nullptr), + fileName (nullptr) + { + } + + ~PortInfo() + { + if (name != nullptr) + xmlFree(reinterpret_cast(name)); + if (role != nullptr) + xmlFree(reinterpret_cast(role)); + if (rate != nullptr) + xmlFree(reinterpret_cast(rate)); + if (channels != nullptr) + xmlFree(reinterpret_cast(channels)); + if (buffer_size != nullptr) + xmlFree(reinterpret_cast(buffer_size)); + if (fileName != nullptr) + xmlFree(reinterpret_cast(fileName)); + } +}; + +class AudioPortInfo : public PortInfo { +public: + AudioPortInfo() {} + + virtual ~AudioPortInfo() {} +}; + +struct AudioPortPinInfo : public PortInfo +{ +public: + char* pinType; + AudioPortPinInfo() + : pinType(nullptr) + { + } + + virtual ~AudioPortPinInfo() {} +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_CONFIG_H diff --git a/services/src/audio_policy/server/service/include/config/parser.h b/services/src/audio_policy/server/service/include/config/parser.h new file mode 100644 index 0000000000..5d0140f37c --- /dev/null +++ b/services/src/audio_policy/server/service/include/config/parser.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_PARSER_H +#define ST_PARSER_H + +namespace OHOS { +namespace AudioStandard { +class Parser { +public: + virtual ~Parser() {} + virtual bool LoadConfiguration() = 0; + virtual bool Parse() = 0; + virtual void Destroy() = 0; +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_PARSER_H diff --git a/services/src/audio_policy/server/service/include/config/parser_factory.h b/services/src/audio_policy/server/service/include/config/parser_factory.h new file mode 100644 index 0000000000..038759aad4 --- /dev/null +++ b/services/src/audio_policy/server/service/include/config/parser_factory.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_PARSER_FACTORY_H +#define ST_PARSER_FACTORY_H + +#include "xml_parser.h" + +namespace OHOS { +namespace AudioStandard { +class ParserFactory { +public: + static ParserFactory& GetInstance() + { + static ParserFactory instance; + return instance; + } + + Parser& CreateParser(IPortObserver& observer) + { + static XMLParser parser(observer); + return parser; + } +private: + ParserFactory(ParserFactory&) = delete; + ParserFactory() {} +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_PARSER_FACTORY_H diff --git a/services/src/audio_policy/server/service/include/config/xml_parser.h b/services/src/audio_policy/server/service/include/config/xml_parser.h new file mode 100644 index 0000000000..b9a117f4c6 --- /dev/null +++ b/services/src/audio_policy/server/service/include/config/xml_parser.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_XML_PARSER_H +#define ST_XML_PARSER_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#ifdef __cplusplus +} +#endif + +#include "audio_config.h" +#include "iport_observer.h" +#include "parser.h" + +namespace OHOS { +namespace AudioStandard { +class XMLParser : public Parser { +public: + static constexpr char CONFIG_FILE[] = "/etc/audio/audio_policy_config.xml"; + + bool LoadConfiguration() final; + bool Parse() final; + void Destroy() final; + + explicit XMLParser(IPortObserver& observer) + : mPortObserver(observer), + mDoc(nullptr) + { + } + + virtual ~XMLParser() + { + Destroy(); + } +private: + bool ParseInternal(xmlNode* node); + NodeName GetNodeNameAsInt(xmlNode* node); + void ParseBuiltInDevices(xmlNode* node); + void ParseDefaultOutputDevice(xmlNode* node); + void ParseDefaultInputDevice(xmlNode* node); + void ParseAudioPorts(xmlNode* node); + void ParseAudioPortPins(xmlNode* node); + DeviceType GetDeviceType(xmlChar* device); + + IPortObserver& mPortObserver; + xmlDoc* mDoc; +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_XML_PARSER_H diff --git a/services/src/audio_policy/server/service/include/interface/iaudio_policy.h b/services/src/audio_policy/server/service/include/interface/iaudio_policy.h new file mode 100644 index 0000000000..b026d2e097 --- /dev/null +++ b/services/src/audio_policy/server/service/include/interface/iaudio_policy.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_INTERFACE_H +#define ST_AUDIO_POLICY_INTERFACE_H + +#include "audio_config.h" +#include "audio_info.h" +#include "audio_policy_types.h" + +#include +#include + +namespace OHOS { +namespace AudioStandard { +class IAudioPolicyInterface { +public: + virtual ~IAudioPolicyInterface() {} + + virtual bool Init() = 0; + + virtual int32_t SetStreamVolume(AudioStreamType streamType, float volume) = 0; + + virtual float GetStreamVolume(AudioStreamType streamType) = 0; + + virtual int32_t SetStreamMute(AudioStreamType streamType, bool mute) = 0; + + virtual bool GetStreamMute(AudioStreamType streamType) = 0; + + virtual bool IsStreamActive(AudioStreamType streamType) = 0; + + virtual AudioIOHandle OpenAudioPort(std::shared_ptr audioPortInfo) = 0; + + virtual int32_t CloseAudioPort(AudioIOHandle ioHandle) = 0; + + virtual int32_t SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, std::string name, bool active) = 0; + + virtual int32_t SetRingerMode(AudioRingerMode ringerMode) = 0; + + virtual AudioRingerMode GetRingerMode() = 0; +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_POLICY_INTERFACE_H diff --git a/services/src/audio_policy/server/service/include/interface/iport_observer.h b/services/src/audio_policy/server/service/include/interface/iport_observer.h new file mode 100644 index 0000000000..ca97ee3ac2 --- /dev/null +++ b/services/src/audio_policy/server/service/include/interface/iport_observer.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_PORT_OBSERVER_H +#define ST_AUDIO_PORT_OBSERVER_H + +#include "audio_info.h" +#include "iaudio_policy.h" + +namespace OHOS { +namespace AudioStandard { +class IPortObserver { +public: + virtual void OnAudioPortAvailable(std::shared_ptr portInfo) = 0; + virtual void OnAudioPortPinAvailable(std::shared_ptr portInfo) = 0; + virtual void OnDefaultOutputPortPin(DeviceType device) = 0; + virtual void OnDefaultInputPortPin(DeviceType device) = 0; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif diff --git a/services/src/audio_policy/server/service/include/manager/audio_policy_manager_factory.h b/services/src/audio_policy/server/service/include/manager/audio_policy_manager_factory.h new file mode 100644 index 0000000000..f9867aaa10 --- /dev/null +++ b/services/src/audio_policy/server/service/include/manager/audio_policy_manager_factory.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_AUDIO_POLICY_MANAGER_FACTORY_H +#define ST_AUDIO_POLICY_MANAGER_FACTORY_H + +#include +#include "pulseaudio_policy_manager.h" + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyManagerFactory { +public: + static IAudioPolicyInterface& GetAudioPolicyManager(void) + { + return PulseAudioPolicyManager::GetInstance(); + } +}; +} // namespace AudioStandard +} // namespace OHOS + +#endif // ST_AUDIO_POLICY_MANAGER_FACTORY_H diff --git a/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h new file mode 100644 index 0000000000..ae1fdd9cb6 --- /dev/null +++ b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 ST_PULSEAUDIO_POLICY_MANAGER_H +#define ST_PULSEAUDIO_POLICY_MANAGER_H + +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif + +#include +#include + +#include "iaudio_policy.h" + +namespace OHOS { +namespace AudioStandard { +class PulseAudioPolicyManager : public IAudioPolicyInterface { +public: + static constexpr char HDI_SINK[] = "libmodule-hdi-sink.z.so"; + static constexpr char HDI_SOURCE[] = "libmodule-hdi-source.z.so"; + static constexpr char PIPE_SINK[] = "libmodule-pipe-sink.z.so"; + static constexpr char PIPE_SOURCE[] = "libmodule-pipe-source.z.so"; + + static constexpr uint32_t PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS = 500000; + + bool Init(); + void Deinit(void); + + std::string GetPolicyManagerName(); + + static IAudioPolicyInterface& GetInstance() + { + static PulseAudioPolicyManager policyManager; + return policyManager; + } + + int32_t SetStreamVolume(AudioStreamType streamType, float volume); + + float GetStreamVolume(AudioStreamType streamType); + + int32_t SetStreamMute(AudioStreamType streamType, bool mute); + + bool GetStreamMute(AudioStreamType streamType); + + bool IsStreamActive(AudioStreamType streamType); + + AudioIOHandle OpenAudioPort(std::shared_ptr audioPortInfo); + + int32_t CloseAudioPort(AudioIOHandle ioHandle); + + int32_t SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, std::string name, bool active); + + int32_t SetRingerMode(AudioRingerMode ringerMode); + + AudioRingerMode GetRingerMode() + { + return mRingerMode; + } + + // Static Member functions + static void ContextStateCb(pa_context *c, void *userdata); + + static void SubscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + + static void ModuleLoadCb(pa_context *c, uint32_t idx, void *userdata); + + static void GetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + + static void GetSinkInputInfoCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + + static void GetSinkInputInfoMuteCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + + static void GetSinkInputInfoMuteStatusCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); + + static void GetSinkInputInfoCorkStatusCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); +private: + struct UserData { + PulseAudioPolicyManager* thiz; + AudioStreamType streamType; + float volume; + bool mute; + bool isCorked; + uint32_t idx; + }; + + PulseAudioPolicyManager() + : mContext(nullptr), + mMainLoop(nullptr), + mRingerMode(RINGER_MODE_NORMAL) + { + } + + virtual ~PulseAudioPolicyManager() {} + + bool ConnectToPulseAudio(void); + void HandleSinkInputEvent(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); + std::string GetModuleArgs(std::shared_ptr audioPortInfo); + std::string GetStreamNameByStreamType(AudioStreamType streamType); + AudioStreamType GetStreamIDByType(std::string streamType); + void InitVolumeMap(void); + + pa_context* mContext; + pa_threaded_mainloop* mMainLoop; + std::unordered_map mVolumeMap; + AudioRingerMode mRingerMode; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // ST_PULSEAUDIO_POLICY_MANAGER_H diff --git a/services/src/audio_policy/server/service/src/audio_policy_service.cpp b/services/src/audio_policy/server/service/src/audio_policy_service.cpp new file mode 100644 index 0000000000..bcd6b0e20c --- /dev/null +++ b/services/src/audio_policy/server/service/src/audio_policy_service.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_errors.h" +#include "audio_policy_service.h" +#include "media_log.h" + +namespace OHOS { +namespace AudioStandard { +using namespace std; +bool AudioPolicyService::Init(void) +{ + mAudioPolicyManager.Init(); + if (!mConfigParser.LoadConfiguration()) { + MEDIA_ERR_LOG("Audio Config Load Configuration failed"); + return false; + } + if (!mConfigParser.Parse()) { + MEDIA_ERR_LOG("Audio Config Parse failed"); + return false; + } + + return true; +} + +void AudioPolicyService::Deinit(void) +{ + mAudioPolicyManager.CloseAudioPort(mIOHandles[HDI_SINK]); + mAudioPolicyManager.CloseAudioPort(mIOHandles[HDI_SOURCE]); + return; +} + +int32_t AudioPolicyService::SetStreamVolume(AudioStreamType streamType, float volume) const +{ + return mAudioPolicyManager.SetStreamVolume(streamType, volume); +} + +float AudioPolicyService::GetStreamVolume(AudioStreamType streamType) const +{ + return mAudioPolicyManager.GetStreamVolume(streamType); +} + +int32_t AudioPolicyService::SetStreamMute(AudioStreamType streamType, bool mute) const +{ + return mAudioPolicyManager.SetStreamMute(streamType, mute); +} + +bool AudioPolicyService::GetStreamMute(AudioStreamType streamType) const +{ + return mAudioPolicyManager.GetStreamMute(streamType); +} + +bool AudioPolicyService::IsStreamActive(AudioStreamType streamType) const +{ + return mAudioPolicyManager.IsStreamActive(streamType); +} + +int32_t AudioPolicyService::SetDeviceActive(DeviceType deviceType, bool active) +{ + MEDIA_DEBUG_LOG("SetDeviceActive - Policy Service: deviceType %d", deviceType); + + if (deviceType == DEVICE_TYPE_NONE) + return ERR_DEVICE_NOT_SUPPORTED; + + bool updateActiveDevices = true; + AudioIOHandle ioHandle = GetAudioIOHandle(deviceType); + list& activeDevices = GetActiveDevicesList(deviceType); + + if (active && deviceType == activeDevices.front()) { + MEDIA_DEBUG_LOG("[Policy Service] SetDeviceActive: deviceType %d already active", deviceType); + return SUCCESS; + } + + if (!active) { + for (list::const_iterator iter = activeDevices.begin(); + iter != activeDevices.end(); ++iter) { + if (*iter == deviceType) { + activeDevices.erase(iter); + } + } + + deviceType = activeDevices.front(); + + updateActiveDevices = false; + } + + int32_t result = 0; + + switch (deviceType) { + case BLUETOOTH_A2DP: + result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, BLUEZ_SINK, active); + break; + case SPEAKER: + result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, HDI_SINK, active); + break; + case MIC: + result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, HDI_SOURCE, active); + break; + default: + result = ERR_DEVICE_NOT_SUPPORTED; + break; + } + + if (!result) { + if (updateActiveDevices) { + for (list::const_iterator iter = activeDevices.begin(); + iter != activeDevices.end(); ++iter) { + if (*iter == deviceType) { + activeDevices.erase(iter); + } + } + activeDevices.push_front(deviceType); + } + return SUCCESS; + } else { + MEDIA_ERR_LOG("SetDeviceActive - Policy Service: returned:%{public}d", result); + return ERROR; + } +} + +bool AudioPolicyService::IsDeviceActive(DeviceType deviceType) const +{ + bool result = false; + + switch (deviceType) { + case SPEAKER: + if (deviceType == mActiveOutputDevices.front()) + return true; + break; + case MIC: + if (deviceType == mActiveInputDevices.front()) + return true; + break; + case BLUETOOTH_A2DP: + if (deviceType == mActiveOutputDevices.front()) + return true; + break; + default: + break; + } + + return result; +} + +int32_t AudioPolicyService::SetRingerMode(AudioRingerMode ringMode) +{ + return mAudioPolicyManager.SetRingerMode(ringMode); +} + +AudioRingerMode AudioPolicyService::GetRingerMode() const +{ + return mAudioPolicyManager.GetRingerMode(); +} + +// Parser callbacks + +void AudioPolicyService::OnAudioPortAvailable(shared_ptr portInfo) +{ + AudioIOHandle ioHandle = mAudioPolicyManager.OpenAudioPort(portInfo); + mIOHandles[portInfo->name] = ioHandle; + return; +} + +void AudioPolicyService::OnAudioPortPinAvailable(shared_ptr portInfo) +{ + return; +} + +void AudioPolicyService::OnDefaultOutputPortPin(DeviceType deviceType) +{ + AudioIOHandle ioHandle = GetAudioIOHandle(deviceType); + mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, HDI_SINK, true); + mActiveOutputDevices.push_front(deviceType); + MEDIA_DEBUG_LOG("OnDefaultOutputPortPin DeviceType: %{public}d", deviceType); + return; +} + +void AudioPolicyService::OnDefaultInputPortPin(DeviceType deviceType) +{ + MEDIA_DEBUG_LOG("OnDefaultInputPortPin DeviceType: %{public}d", deviceType); + AudioIOHandle ioHandle = GetAudioIOHandle(deviceType); + mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, HDI_SOURCE, true); + mActiveInputDevices.push_front(deviceType); + return; +} + +// private methods +AudioIOHandle AudioPolicyService::GetAudioIOHandle(DeviceType deviceType) +{ + AudioIOHandle ioHandle; + switch (deviceType) { + case SPEAKER: + case WIRED_HEADSET: + ioHandle = mIOHandles[HDI_SINK]; + break; + case BLUETOOTH_A2DP: + ioHandle = mIOHandles[BLUEZ_SINK]; + break; + case MIC: + ioHandle = mIOHandles[HDI_SOURCE]; + break; + default: + ioHandle = mIOHandles[HDI_SINK]; + break; + } + return ioHandle; +} +} +} diff --git a/services/src/audio_policy/server/service/src/config/xml_parser.cpp b/services/src/audio_policy/server/service/src/config/xml_parser.cpp new file mode 100644 index 0000000000..a05d13b296 --- /dev/null +++ b/services/src/audio_policy/server/service/src/config/xml_parser.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "media_log.h" +#include "xml_parser.h" + +namespace OHOS { +namespace AudioStandard { +bool XMLParser::LoadConfiguration() +{ + mDoc = xmlReadFile(CONFIG_FILE, NULL, 0); + if (mDoc == NULL) { + MEDIA_ERR_LOG("xmlReadFile Failed"); + return false; + } + + return true; +} + +bool XMLParser::Parse() +{ + xmlNode* root = xmlDocGetRootElement(mDoc); + if (root == NULL) { + MEDIA_ERR_LOG("xmlDocGetRootElement Failed"); + return false; + } + + if (!ParseInternal(root)) + return false; + + return true; +} + +void XMLParser::Destroy() +{ + if (mDoc != NULL) { + xmlFreeDoc(mDoc); + } + return; +} + +bool XMLParser::ParseInternal(xmlNode* node) +{ + xmlNode* currNode = node; + for (; currNode; currNode = currNode->next) { + if (XML_ELEMENT_NODE == currNode->type) { + switch (GetNodeNameAsInt(currNode)) { + case BUILT_IN_DEVICES: + ParseBuiltInDevices(currNode); + break; + case DEFAULT_OUTPUT_DEVICE: + ParseDefaultOutputDevice(currNode); + break; + case DEFAULT_INPUT_DEVICE: + ParseDefaultInputDevice(currNode); + break; + case AUDIO_PORTS: + ParseAudioPorts(currNode); + break; + case AUDIO_PORT_PINS: + ParseAudioPortPins(currNode); + break; + default: + ParseInternal(currNode->children); + break; + } + } + } + + return true; +} + +NodeName XMLParser::GetNodeNameAsInt(xmlNode* node) +{ + if (!xmlStrcmp(node->name, reinterpret_cast("BuiltInDevices"))) + return BUILT_IN_DEVICES; + if (!xmlStrcmp(node->name, reinterpret_cast("DefaultOutputDevice"))) + return DEFAULT_OUTPUT_DEVICE; + if (!xmlStrcmp(node->name, reinterpret_cast("DefaultInputDevice"))) + return DEFAULT_INPUT_DEVICE; + if (!xmlStrcmp(node->name, reinterpret_cast("AudioPorts"))) + return AUDIO_PORTS; + if (!xmlStrcmp(node->name, reinterpret_cast("AudioPort"))) + return AUDIO_PORT; + if (!xmlStrcmp(node->name, reinterpret_cast("AudioPortPins"))) + return AUDIO_PORT_PINS; + if (!xmlStrcmp(node->name, reinterpret_cast("AudioPortPin"))) + return AUDIO_PORT_PIN; + + return UNKNOWN; +} + +void XMLParser::ParseBuiltInDevices(xmlNode* node) +{ + while (node) { + xmlNode* child = node->children; + xmlChar* device = xmlNodeGetContent(child); + + if (device != NULL) { + MEDIA_DEBUG_LOG("Trigger Cb"); + } + + node = node->next; + } + return; +} + +void XMLParser::ParseDefaultOutputDevice(xmlNode* node) +{ + xmlNode* child = node->children; + xmlChar* device = xmlNodeGetContent(child); + + if (device != NULL) { + MEDIA_DEBUG_LOG("DefaultOutputDevice %{public}s", device); + mPortObserver.OnDefaultOutputPortPin(GetDeviceType(device)); + } + return; +} + + +void XMLParser::ParseDefaultInputDevice(xmlNode* node) +{ + xmlNode* child = node->children; + xmlChar* device = xmlNodeGetContent(child); + + MEDIA_DEBUG_LOG("DefaultInputDevice"); + if (device != NULL) { + MEDIA_DEBUG_LOG("DefaultInputDevice %{public}s", device); + mPortObserver.OnDefaultInputPortPin(GetDeviceType(device)); + } + return; +} + +void XMLParser::ParseAudioPorts(xmlNode* node) +{ + xmlNode* child = node->xmlChildrenNode; + + for (; child; child = child->next) { + if (!xmlStrcmp(child->name, reinterpret_cast("AudioPort"))) { + std::shared_ptr portInfo = std::make_unique(); + portInfo->type = TYPE_AUDIO_PORT; + + if (xmlHasProp(child, reinterpret_cast(const_cast("role")))) { + portInfo->role = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("role")))); + } + + if (xmlHasProp(child, reinterpret_cast(const_cast("name")))) { + portInfo->name = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("name")))); + } + + if (xmlHasProp(child, reinterpret_cast(const_cast("channels")))) { + portInfo->channels = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("channels")))); + } + + if (xmlHasProp(child, reinterpret_cast(const_cast("buffer_size")))) { + portInfo->buffer_size = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("buffer_size")))); + } + + if (xmlHasProp(child, reinterpret_cast(const_cast("rate")))) { + portInfo->rate = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("rate")))); + } + + if (xmlHasProp(child, reinterpret_cast(const_cast("file")))) { + portInfo->fileName = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("file")))); + } + + mPortObserver.OnAudioPortAvailable(portInfo); + } + } + + return; +} + +void XMLParser::ParseAudioPortPins(xmlNode* node) +{ + xmlNode* child = node->xmlChildrenNode; + + for (; child; child = child->next) { + if (!xmlStrcmp(child->name, reinterpret_cast("AudioPortPin"))) { + std::shared_ptr portInfo = std::make_unique(); + portInfo->type = TYPE_AUDIO_PORT_PIN; + + if (xmlHasProp(child, reinterpret_cast(const_cast("role")))) + portInfo->role = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("role")))); + if (xmlHasProp(child, reinterpret_cast(const_cast("name")))) + portInfo->name = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("name")))); + if (xmlHasProp(child, reinterpret_cast(const_cast("type")))) + portInfo->pinType = reinterpret_cast(xmlGetProp( + child, + reinterpret_cast(const_cast("type")))); + + MEDIA_INFO_LOG("AudioPort:Role: %s, Name: %s, Type: %s", portInfo->role, portInfo->name, portInfo->pinType); + + mPortObserver.OnAudioPortPinAvailable(portInfo); + } + } + + return; +} + +DeviceType XMLParser::GetDeviceType(xmlChar* device) +{ + if (!xmlStrcmp(device, reinterpret_cast("Speaker"))) + return SPEAKER; + if (!xmlStrcmp(device, reinterpret_cast("Built-In Mic"))) + return MIC; + return DEVICE_TYPE_NONE; +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp new file mode 100644 index 0000000000..596d22fb24 --- /dev/null +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -0,0 +1,734 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_errors.h" +#include "media_log.h" +#include "pulseaudio_policy_manager.h" + +namespace OHOS { +namespace AudioStandard { + +const float MAX_VOLUME = 1.0f; +const float MIN_VOLUME = 0.0f; + +bool PulseAudioPolicyManager::Init() +{ + mMainLoop = pa_threaded_mainloop_new(); + if (!mMainLoop) { + MEDIA_ERR_LOG("[PolicyManager] MainLoop creation failed"); + return false; + } + + if (pa_threaded_mainloop_start(mMainLoop) < 0) { + MEDIA_ERR_LOG("[PolicyManager] Failed to start mainloop"); + pa_threaded_mainloop_free (mMainLoop); + return false; + } + pa_threaded_mainloop_lock(mMainLoop); + + while (true) { + pa_context_state_t state; + + if (mContext != NULL) { + state = pa_context_get_state(mContext); + if (state == PA_CONTEXT_READY) + break; + // if pulseaudio is ready, retry connect to pulseaudio. before retry wait for sometime. reduce sleep later + usleep(PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS); + } + + bool result = ConnectToPulseAudio(); + if (!result || !PA_CONTEXT_IS_GOOD(pa_context_get_state(mContext))) { + continue; + } + + MEDIA_DEBUG_LOG("[PolicyManager] pa context not ready... wait"); + + // Wait for the context to be ready + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_threaded_mainloop_unlock(mMainLoop); + InitVolumeMap(); + return true; +} + +void PulseAudioPolicyManager::Deinit(void) +{ + if (mContext != NULL) { + pa_context_disconnect (mContext); + + /* Make sure we don't get any further callbacks */ + pa_context_set_state_callback (mContext, NULL, NULL); + pa_context_set_subscribe_callback (mContext, NULL, NULL); + + pa_context_unref (mContext); + } + + if (mMainLoop != NULL) { + pa_threaded_mainloop_stop (mMainLoop); + pa_threaded_mainloop_free (mMainLoop); + } + + return; +} + +int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, float volume) +{ + pa_threaded_mainloop_lock(mMainLoop); + + UserData* userData = new UserData; + userData->thiz = this; + userData->volume = volume; + userData->streamType = streamType; + + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return ERROR; + } + + mVolumeMap[streamType] = volume; + + pa_operation *operation = pa_context_get_sink_input_info_list(mContext, + PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + return ERROR; + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + return SUCCESS; +} + +float PulseAudioPolicyManager::GetStreamVolume(AudioStreamType streamType) +{ + return mVolumeMap[streamType]; +} + +int32_t PulseAudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool mute) +{ + pa_threaded_mainloop_lock(mMainLoop); + + std::shared_ptr userData = std::make_shared(); + userData->thiz = this; + userData->mute = mute; + userData->streamType = streamType; + + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return ERROR; + } + + pa_operation* operation = pa_context_get_sink_input_info_list(mContext, + PulseAudioPolicyManager::GetSinkInputInfoMuteCb, reinterpret_cast(userData.get())); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + return ERROR; + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + return SUCCESS; +} + +bool PulseAudioPolicyManager::GetStreamMute(AudioStreamType streamType) +{ + pa_threaded_mainloop_lock(mMainLoop); + + std::shared_ptr userData = std::make_shared(); + userData->thiz = this; + userData->streamType = streamType; + userData->mute = false; + + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return false; + } + + pa_operation *operation = pa_context_get_sink_input_info_list(mContext, + PulseAudioPolicyManager::GetSinkInputInfoMuteStatusCb, reinterpret_cast(userData.get())); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + return false; + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + return (userData->mute) ? true : false; +} + +bool PulseAudioPolicyManager::IsStreamActive(AudioStreamType streamType) +{ + pa_threaded_mainloop_lock(mMainLoop); + + std::shared_ptr userData = std::make_shared(); + userData->thiz = this; + userData->streamType = streamType; + userData->isCorked = true; + + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return false; + } + + pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoCorkStatusCb, + reinterpret_cast(userData.get())); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + return false; + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + MEDIA_INFO_LOG("[PolicyManager] cork for stream %s : %d", + GetStreamNameByStreamType(streamType).c_str(), userData->isCorked); + + return (userData->isCorked) ? false : true; +} + + +int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, std::string name, bool active) +{ + pa_threaded_mainloop_lock(mMainLoop); + + switch (deviceType) { + case SPEAKER: + case BLUETOOTH_A2DP: { + pa_operation* operation = pa_context_set_default_sink(mContext, name.c_str(), NULL, NULL); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] set default sink failed"); + return ERR_OPERATION_FAILED; + } + pa_operation_unref(operation); + break; + } + case MIC: { + pa_operation* operation = pa_context_set_default_source(mContext, name.c_str(), NULL, NULL); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] set default sink failed"); + return ERR_OPERATION_FAILED; + } + pa_operation_unref(operation); + break; + } + default: + break; + } + pa_threaded_mainloop_unlock(mMainLoop); + + return SUCCESS; +} + +int32_t PulseAudioPolicyManager::SetRingerMode(AudioRingerMode ringerMode) +{ + mRingerMode = ringerMode; + return 0; +} + +AudioIOHandle PulseAudioPolicyManager::OpenAudioPort(std::shared_ptr audioPortInfo) +{ + std::string moduleArgs = GetModuleArgs(audioPortInfo); + + MEDIA_INFO_LOG("[PolicyManager] load-module %{public}s %{public}s", audioPortInfo->name, moduleArgs.c_str()); + + pa_threaded_mainloop_lock(mMainLoop); + + std::shared_ptr userData = std::make_shared(); + userData->thiz = this; + + pa_operation* operation = pa_context_load_module(mContext, audioPortInfo->name, moduleArgs.c_str(), ModuleLoadCb, + reinterpret_cast(userData.get())); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_load_module returned nullptr"); + return reinterpret_cast(ERR_INVALID_HANDLE); + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mMainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + AudioIOHandle ioHandle = reinterpret_cast(userData->idx); + return ioHandle; +} + +int32_t PulseAudioPolicyManager::CloseAudioPort(AudioIOHandle ioHandle) +{ + pa_threaded_mainloop_lock(mMainLoop); + + pa_operation* operation = pa_context_unload_module(mContext, reinterpret_cast(ioHandle), NULL, NULL); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_unload_module returned nullptr"); + return ERROR; + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mMainLoop); + + return SUCCESS; +} + +// Private Members + +bool PulseAudioPolicyManager::ConnectToPulseAudio(void) +{ + MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio++"); + + if (mContext != NULL) { + pa_context_disconnect (mContext); + pa_context_set_state_callback (mContext, NULL, NULL); + pa_context_set_subscribe_callback (mContext, NULL, NULL); + + pa_context_unref (mContext); + } + + pa_proplist *proplist = pa_proplist_new(); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service"); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.huawei.pulseaudio.service"); + mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), NULL, proplist); + + pa_proplist_free(proplist); + + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] creating pa context failed"); + return false; + } + + pa_context_set_state_callback(mContext, PulseAudioPolicyManager::ContextStateCb, this); + + if (pa_context_connect(mContext, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) { + if (pa_context_errno(mContext) == PA_ERR_INVALID) { + MEDIA_ERR_LOG("[PolicyManager] pa context connect failed: %{public}s", + pa_strerror(pa_context_errno(mContext))); + goto Fail; + } + } + + MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio--"); + + return true; + +Fail: + /* Make sure we don't get any further callbacks */ + pa_context_set_state_callback (mContext, NULL, NULL); + pa_context_set_subscribe_callback (mContext, NULL, NULL); + + pa_context_unref (mContext); + + MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio--"); + + return false; +} + +std::string PulseAudioPolicyManager::GetModuleArgs(std::shared_ptr audioPortInfo) +{ + std::string args; + + if (!strcmp(audioPortInfo->name, HDI_SINK)) { + if (audioPortInfo->rate != nullptr) { + args = "rate="; + args.append(audioPortInfo->rate); + } + if (audioPortInfo->channels != nullptr) { + args.append(" channels="); + args.append(audioPortInfo->channels); + } + if (audioPortInfo->buffer_size != nullptr) { + args.append(" buffer_size="); + args.append(audioPortInfo->buffer_size); + } + } else if (!strcmp(audioPortInfo->name, HDI_SOURCE)) { + if (audioPortInfo->rate != nullptr) { + args = "rate="; + args.append(audioPortInfo->rate); + } + if (audioPortInfo->channels != nullptr) { + args.append(" channels="); + args.append(audioPortInfo->channels); + } + if (audioPortInfo->buffer_size != nullptr) { + args.append(" buffer_size="); + args.append(audioPortInfo->buffer_size); + } + } else if (!strcmp(audioPortInfo->name, PIPE_SINK)) { + if (audioPortInfo->fileName != nullptr) { + args = "file="; + args.append(audioPortInfo->fileName); + } + } else if (!strcmp(audioPortInfo->name, PIPE_SOURCE)) { + if (audioPortInfo->fileName != nullptr) { + args = "file="; + args.append(audioPortInfo->fileName); + } + } + + return args; +} + +std::string PulseAudioPolicyManager::GetStreamNameByStreamType(AudioStreamType streamType) +{ + switch (streamType) { + case STREAM_MUSIC: + return "music"; + case STREAM_RING: + return "ring"; + case STREAM_SYSTEM: + return "system"; + case STREAM_NOTIFICATION: + return "notification"; + case STREAM_ALARM: + return "alarm"; + case STREAM_DTMF: + return "dtmf"; + default: + return ""; + } +} + +AudioStreamType PulseAudioPolicyManager::GetStreamIDByType(std::string streamType) +{ + AudioStreamType stream = STREAM_MUSIC; + + if (!streamType.compare(std::string("music"))) + stream = STREAM_MUSIC; + else if (!streamType.compare(std::string("ring"))) + stream = STREAM_RING; + else if (!streamType.compare(std::string("system"))) + stream = STREAM_SYSTEM; + else if (!streamType.compare(std::string("notification"))) + stream = STREAM_NOTIFICATION; + else if (!streamType.compare(std::string("alarm"))) + stream = STREAM_ALARM; + + return stream; +} + +void PulseAudioPolicyManager::InitVolumeMap(void) +{ + mVolumeMap[STREAM_MUSIC] = MAX_VOLUME; + mVolumeMap[STREAM_RING] = MAX_VOLUME; + return; +} + +void PulseAudioPolicyManager::HandleSinkInputEvent(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, + void *userdata) +{ + UserData* userData = new UserData; + userData->thiz = this; + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { + pa_operation* operation = pa_context_get_sink_input_info(c, idx, + PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + return; + } + + pa_operation_unref(operation); + } + + return; +} + +void PulseAudioPolicyManager::ContextStateCb(pa_context *c, void *userdata) +{ + PulseAudioPolicyManager* thiz = reinterpret_cast(userdata); + + MEDIA_DEBUG_LOG("[PolicyManager] ContextStateCb %d", pa_context_get_state(c)); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + pa_context_set_subscribe_callback(c, PulseAudioPolicyManager::SubscribeCb, thiz); + + pa_operation* operation = pa_context_subscribe(c, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE | + PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT | + PA_SUBSCRIPTION_MASK_CARD), NULL, NULL); + if (operation == NULL) { + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + return; + } + pa_operation_unref(operation); + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + break; + } + + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + return; + + case PA_CONTEXT_TERMINATED: + default: + return; + } +} + +void PulseAudioPolicyManager::SubscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) +{ + PulseAudioPolicyManager* thiz = reinterpret_cast(userdata); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE: + break; + + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + thiz->HandleSinkInputEvent(c, t, idx, userdata); + break; + + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + break; + + default: + break; + } + + return; +} + +void PulseAudioPolicyManager::ModuleLoadCb(pa_context *c, uint32_t idx, void *userdata) +{ + UserData *userData = reinterpret_cast(userdata); + + if (idx == PA_INVALID_INDEX) { + MEDIA_ERR_LOG("[PolicyManager] Failure: %s", pa_strerror(pa_context_errno(c))); + userData->idx = PA_INVALID_INDEX; + } else { + userData->idx = idx; + } + pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0); + + return; +} + +void PulseAudioPolicyManager::GetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol, + void *userdata) +{ + UserData* userData = reinterpret_cast(userdata); + PulseAudioPolicyManager* thiz = userData->thiz; + + MEDIA_ERR_LOG("[PolicyManager] GetSinkInputInfoVolumeCb"); + if (eol < 0) { + delete userData; + MEDIA_ERR_LOG("[PolicyManager] Failed to get sink input information: %s", pa_strerror(pa_context_errno(c))); + return; + } + + if (eol) { + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + delete userData; + return; + } + + if (i->proplist == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid Proplist for sink input (%{public}d).", i->index); + return; + } + + const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); + if (streamtype == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid StreamType."); + return; + } + + std::string streamType(streamtype); + + AudioStreamType streamID = thiz->GetStreamIDByType(streamType); + float vol = thiz->mVolumeMap[streamID]; + + if (thiz->mRingerMode != RINGER_MODE_NORMAL) { + if (!streamType.compare("ring")) { + vol = MIN_VOLUME; + } + } + pa_cvolume cv = i->volume; + int32_t volume = pa_sw_volume_from_linear(vol); + pa_cvolume_set(&cv, i->channel_map.channels, volume); + pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL)); + + MEDIA_INFO_LOG("[PolicyManager] Applied volume : %{public}f for stream : %{public}s, volumeInt%{public}d", + userData->volume, i->name, volume); + + return; +} + +void PulseAudioPolicyManager::GetSinkInputInfoCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) +{ + UserData* userData = reinterpret_cast(userdata); + + if (eol < 0) { + MEDIA_ERR_LOG("[PolicyManager] Failed to get sink input information: %{public}s", + pa_strerror(pa_context_errno(c))); + return; + } + + pa_operation* operation = pa_context_move_sink_input_by_index(c, i->index, userData->idx, NULL, NULL); + if (operation == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Moving Sink Input %{public}d to Sink %{public}d Failed", + i->index, userData->idx); + } + MEDIA_ERR_LOG("[PolicyManager] Moving Sink Input %{public}d to Sink %{public}d", i->index, userData->idx); + + if (eol) { + MEDIA_DEBUG_LOG("[PolicyManager] All inputs moved"); + pa_threaded_mainloop_signal(userData->thiz->mMainLoop, 0); + return; + } + + return; +} + +void PulseAudioPolicyManager::GetSinkInputInfoMuteCb(pa_context *c, const pa_sink_input_info *i, + int eol, void *userdata) +{ + UserData* userData = reinterpret_cast(userdata); + PulseAudioPolicyManager* thiz = userData->thiz; + + if (eol < 0) { + MEDIA_ERR_LOG("[PolicyManager] Failed to get sink input information: %s", pa_strerror(pa_context_errno(c))); + return; + } + + if (eol) { + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + return; + } + + if (i->proplist == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid Proplist for sink input (%{public}d).", i->index); + return; + } + + const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); + if (streamtype == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid StreamType."); + return; + } + + std::string streamType(streamtype); + if (!streamType.compare(thiz->GetStreamNameByStreamType(userData->streamType))) { + pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, (userData->mute) ? 1 : 0, NULL, NULL)); + + MEDIA_INFO_LOG("[PolicyManager] Applied Mute : %{public}d for stream : %{public}s", userData->mute, i->name); + } + + return; +} + +void PulseAudioPolicyManager::GetSinkInputInfoMuteStatusCb(pa_context *c, const pa_sink_input_info *i, int eol, + void *userdata) +{ + UserData* userData = reinterpret_cast(userdata); + PulseAudioPolicyManager* thiz = userData->thiz; + + if (eol < 0) { + MEDIA_ERR_LOG("[PolicyManager] Failed to get sink input information: %s", pa_strerror(pa_context_errno(c))); + return; + } + + if (eol) { + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + return; + } + + if (i->proplist == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid Proplist for sink input (%{public}d).", i->index); + return; + } + + const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); + if (streamtype == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid StreamType."); + return; + } + + std::string streamType(streamtype); + if (!streamType.compare(thiz->GetStreamNameByStreamType(userData->streamType))) { + userData->mute = i->mute; + MEDIA_INFO_LOG("[PolicyManager] Mute : %{public}d for stream : %{public}s", userData->mute, i->name); + } + + return; +} + +void PulseAudioPolicyManager::GetSinkInputInfoCorkStatusCb(pa_context *c, const pa_sink_input_info *i, int eol, + void *userdata) +{ + UserData* userData = reinterpret_cast(userdata); + PulseAudioPolicyManager* thiz = userData->thiz; + + if (eol < 0) { + MEDIA_ERR_LOG("[PolicyManager] Failed to get sink input information: %s", pa_strerror(pa_context_errno(c))); + return; + } + + if (eol) { + pa_threaded_mainloop_signal(thiz->mMainLoop, 0); + return; + } + + if (i->proplist == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid Proplist for sink input (%{public}d).", i->index); + return; + } + + const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); + if (streamtype == NULL) { + MEDIA_ERR_LOG("[PolicyManager] Invalid StreamType."); + return; + } + + std::string streamType(streamtype); + if (!streamType.compare(thiz->GetStreamNameByStreamType(userData->streamType))) { + userData->isCorked = i->corked; + MEDIA_INFO_LOG("[PolicyManager] corked : %{public}d for stream : %{public}s", userData->isCorked, i->name); + } + + return; +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/client/audio_manager_proxy.cpp b/services/src/client/audio_manager_proxy.cpp old mode 100755 new mode 100644 index fc7389a6df..81627e9450 --- a/services/src/client/audio_manager_proxy.cpp +++ b/services/src/client/audio_manager_proxy.cpp @@ -14,72 +14,77 @@ */ #include "audio_manager_proxy.h" -#include "audio_svc_manager.h" +#include "audio_system_manager.h" #include "media_log.h" namespace OHOS { +namespace AudioStandard { AudioManagerProxy::AudioManagerProxy(const sptr &impl) : IRemoteProxy(impl) { } -void AudioManagerProxy::SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) +float AudioManagerProxy::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) { MessageParcel data; MessageParcel reply; MessageOption option; data.WriteInt32(static_cast(volumeType)); - data.WriteInt32(volume); - int error = Remote()->SendRequest(SET_VOLUME, data, reply, option); + int32_t error = Remote()->SendRequest(GET_MAX_VOLUME, data, reply, option); if (error != ERR_NONE) { - MEDIA_ERR_LOG("set volume failed, error: %d", error); - return; + MEDIA_ERR_LOG("Get max volume failed, error: %d", error); + return error; } + float volume = reply.ReadFloat(); + return volume; } -int32_t AudioManagerProxy::GetVolume(AudioSvcManager::AudioVolumeType volumeType) +float AudioManagerProxy::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) { MessageParcel data; MessageParcel reply; MessageOption option; - data.WriteInt32(static_cast(volumeType)); - int error = Remote()->SendRequest(GET_VOLUME, data, reply, option); + data.WriteInt32(static_cast(volumeType)); + + int32_t error = Remote()->SendRequest(GET_MIN_VOLUME, data, reply, option); if (error != ERR_NONE) { - MEDIA_ERR_LOG("Get volume failed, error: %d", error); + MEDIA_ERR_LOG("Get min volume failed, error: %d", error); return error; } - int volume = reply.ReadInt32(); + + float volume = reply.ReadFloat(); return volume; } -int32_t AudioManagerProxy::GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) +int32_t AudioManagerProxy::SetMicrophoneMute(bool isMute) { MessageParcel data; MessageParcel reply; MessageOption option; - data.WriteInt32(static_cast(volumeType)); - int error = Remote()->SendRequest(GET_MAX_VOLUME, data, reply, option); + data.WriteBool(isMute); + int32_t error = Remote()->SendRequest(SET_MICROPHONE_MUTE, data, reply, option); if (error != ERR_NONE) { - MEDIA_ERR_LOG("Get max volume failed, error: %d", error); + MEDIA_ERR_LOG("SetMicrophoneMute failed, error: %d", error); return error; } - int volume = reply.ReadInt32(); - return volume; + int32_t result = reply.ReadInt32(); + + return result; } -int32_t AudioManagerProxy::GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) +bool AudioManagerProxy::IsMicrophoneMute() { MessageParcel data; MessageParcel reply; MessageOption option; - data.WriteInt32(static_cast(volumeType)); - int error = Remote()->SendRequest(GET_MIN_VOLUME, data, reply, option); + int32_t error = Remote()->SendRequest(IS_MICROPHONE_MUTE, data, reply, option); if (error != ERR_NONE) { - MEDIA_ERR_LOG("Get min volume failed, error: %d", error); - return error; + MEDIA_ERR_LOG("IsMicrophoneMute failed, error: %d", error); + return false; } - int volume = reply.ReadInt32(); - return volume; + bool isMute = reply.ReadBool(); + + return isMute; } std::vector> AudioManagerProxy::GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) @@ -87,17 +92,53 @@ std::vector> AudioManagerProxy::GetDevices(AudioDevi MessageParcel data; MessageParcel reply; MessageOption option; - data.WriteInt32(static_cast(deviceFlag)); - int error = Remote()->SendRequest(GET_DEVICES, data, reply, option); + data.WriteInt32(static_cast(deviceFlag)); + + int32_t error = Remote()->SendRequest(GET_DEVICES, data, reply, option); std::vector> deviceInfo; if (error != ERR_NONE) { - MEDIA_ERR_LOG("Get device failed, error: %d", error); + MEDIA_ERR_LOG("Get devices failed, error: %d", error); return deviceInfo; } - int size = reply.ReadInt32(); - for (int i = 0; i < size; i++) { + + int32_t size = reply.ReadInt32(); + for (int32_t i = 0; i < size; i++) { deviceInfo.push_back(AudioDeviceDescriptor::Unmarshalling(reply)); } return deviceInfo; } + +const std::string AudioManagerProxy::GetAudioParameter(const std::string key) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteString(static_cast(key)); + int32_t error = Remote()->SendRequest(GET_AUDIO_PARAMETER, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("Get audio parameter failed, error: %d", error); + const std::string value = ""; + return value; + } + + const std::string value = reply.ReadString(); + return value; +} + +void AudioManagerProxy::SetAudioParameter(const std::string key, const std::string value) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteString(static_cast(key)); + data.WriteString(static_cast(value)); + int32_t error = Remote()->SendRequest(SET_AUDIO_PARAMETER, data, reply, option); + if (error != ERR_NONE) { + MEDIA_ERR_LOG("Get audio parameter failed, error: %d", error); + return; + } +} +} // namespace AudioStandard } // namespace OHOS diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp new file mode 100644 index 0000000000..9c0cda5636 --- /dev/null +++ b/services/src/client/audio_service_client.cpp @@ -0,0 +1,850 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_service_client.h" +#include "media_log.h" +#include "securec.h" + +namespace OHOS { +namespace AudioStandard { +AudioRendererCallbacks::~AudioRendererCallbacks() = default; +AudioRecorderCallbacks::~AudioRecorderCallbacks() = default; + +const uint64_t LATENCY_IN_MSEC = 200UL; + +#define CHECK_AND_RETURN_IFINVALID(expr) \ + if (!(expr)) { \ + return AUDIO_CLIENT_ERR; \ + } + +#define CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, error) \ + if (!context || !paStream || !mainLoop \ + || !PA_CONTEXT_IS_GOOD(pa_context_get_state(context)) \ + || !PA_STREAM_IS_GOOD(pa_stream_get_state(paStream))) { \ + return error; \ + } + +#define CHECK_PA_STATUS_FOR_WRITE(mainLoop, context, paStream, pError, retVal) \ + if (!context || !paStream || !mainLoop \ + || !PA_CONTEXT_IS_GOOD(pa_context_get_state(context)) \ + || !PA_STREAM_IS_GOOD(pa_stream_get_state(paStream))) { \ + pError = pa_context_errno(context); \ + return retVal; \ + } + +AudioStreamParams AudioServiceClient::ConvertFromPAAudioParams(pa_sample_spec paSampleSpec) +{ + AudioStreamParams audioParams; + + audioParams.channels = paSampleSpec.channels; + audioParams.samplingRate = paSampleSpec.rate; + + switch (paSampleSpec.format) { + case PA_SAMPLE_U8: + audioParams.format = SAMPLE_U8; + break; + case PA_SAMPLE_S16LE: + audioParams.format = SAMPLE_S16LE; + break; + case PA_SAMPLE_S24LE: + audioParams.format = SAMPLE_S24LE; + break; + case PA_SAMPLE_S32LE: + audioParams.format = SAMPLE_S32LE; + break; + default: + audioParams.format = INVALID_WIDTH; + break; + } + + return audioParams; +} + +pa_sample_spec AudioServiceClient::ConvertToPAAudioParams(AudioStreamParams audioParams) +{ + pa_sample_spec paSampleSpec; + + paSampleSpec.channels = audioParams.channels; + paSampleSpec.rate = audioParams.samplingRate; + + switch ((AudioSampleFormat)audioParams.format) { + case SAMPLE_U8: + paSampleSpec.format = (pa_sample_format_t) PA_SAMPLE_U8; + break; + case SAMPLE_S16LE: + paSampleSpec.format = (pa_sample_format_t) PA_SAMPLE_S16LE; + break; + case SAMPLE_S24LE: + paSampleSpec.format = (pa_sample_format_t) PA_SAMPLE_S24LE; + break; + case SAMPLE_S32LE: + paSampleSpec.format = (pa_sample_format_t) PA_SAMPLE_S32LE; + break; + default: + paSampleSpec.format = (pa_sample_format_t) PA_SAMPLE_INVALID; + break; + } + + return paSampleSpec; +} + +static size_t AlignToAudioFrameSize(size_t l, const pa_sample_spec &ss) +{ + size_t fs; + + fs = pa_frame_size(&ss); + if (fs == 0) { + MEDIA_ERR_LOG(" Error: pa_frame_size returned 0"); + return 0; + } + + return (l / fs) * fs; +} + +void AudioServiceClient::PAStreamCmdSuccessCb(pa_stream *stream, int32_t success, void *userdata) +{ + AudioServiceClient *asClient = (AudioServiceClient *)userdata; + pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *) asClient->mainLoop; + + asClient->streamCmdStatus = success; + pa_threaded_mainloop_signal(mainLoop, 0); +} + +void AudioServiceClient::PAStreamRequestCb(pa_stream *stream, size_t length, void *userdata) +{ + pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *) userdata; + pa_threaded_mainloop_signal(mainLoop, 0); +} + +void AudioServiceClient::PAStreamUnderFlowCb(pa_stream *stream, void *userdata) +{ + AudioServiceClient *asClient = (AudioServiceClient *)userdata; + asClient->underFlowCount++; +} + +void AudioServiceClient::PAStreamLatencyUpdateCb(pa_stream *stream, void *userdata) +{ + pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *) userdata; + MEDIA_INFO_LOG("Inside latency update callback"); + pa_threaded_mainloop_signal(mainLoop, 0); +} + +void AudioServiceClient::PAStreamStateCb(pa_stream *stream, void *userdata) +{ + AudioServiceClient *asClient = (AudioServiceClient *)userdata; + pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *) asClient->mainLoop; + + if (asClient->mAudioRendererCallbacks) + asClient->mAudioRendererCallbacks->OnStreamStateChangeCb(); + + MEDIA_INFO_LOG("Current Stream State: %d", pa_stream_get_state(stream)); + + switch (pa_stream_get_state(stream)) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(mainLoop, 0); + break; + + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + default: + break; + } +} + +void AudioServiceClient::PAContextStateCb(pa_context *context, void *userdata) +{ + pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *) userdata; + + MEDIA_INFO_LOG("Current Context State: %d", pa_context_get_state(context)); + + switch (pa_context_get_state(context)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(mainLoop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + default: + break; + } +} + +AudioServiceClient::AudioServiceClient() +{ + isMainLoopStarted = false; + isContextConnected = false; + isStreamConnected = false; + + sinkDevices.clear(); + sourceDevices.clear(); + sinkInputs.clear(); + sourceOutputs.clear(); + clientInfo.clear(); + + mAudioRendererCallbacks = NULL; + mAudioRecorderCallbacks = NULL; + internalReadBuffer = NULL; + mainLoop = NULL; + paStream = NULL; + context = NULL; + api = NULL; + + internalRdBufIndex = 0; + internalRdBufLen = 0; + underFlowCount = 0; +} + +void AudioServiceClient::ResetPAAudioClient() +{ + if (mainLoop && (isMainLoopStarted == true)) + pa_threaded_mainloop_stop(mainLoop); + + if (paStream) { + pa_stream_set_state_callback(paStream, NULL, NULL); + pa_stream_set_write_callback(paStream, NULL, NULL); + pa_stream_set_read_callback(paStream, NULL, NULL); + pa_stream_set_latency_update_callback(paStream, NULL, NULL); + pa_stream_set_underflow_callback(paStream, NULL, NULL); + + if (isStreamConnected == true) + pa_stream_disconnect(paStream); + pa_stream_unref(paStream); + } + + if (context) { + pa_context_set_state_callback(context, NULL, NULL); + if (isContextConnected == true) + pa_context_disconnect(context); + pa_context_unref(context); + } + + if (mainLoop) + pa_threaded_mainloop_free(mainLoop); + + isMainLoopStarted = false; + isContextConnected = false; + isStreamConnected = false; + + sinkDevices.clear(); + sourceDevices.clear(); + sinkInputs.clear(); + sourceOutputs.clear(); + clientInfo.clear(); + + mAudioRendererCallbacks = NULL; + mAudioRecorderCallbacks = NULL; + internalReadBuffer = NULL; + + mainLoop = NULL; + paStream = NULL; + context = NULL; + api = NULL; + + internalRdBufIndex = 0; + internalRdBufLen = 0; + underFlowCount = 0; +} + +AudioServiceClient::~AudioServiceClient() +{ + ResetPAAudioClient(); +} + +int32_t AudioServiceClient::Initialize(ASClientType eClientType) +{ + int error = PA_ERR_INTERNAL; + eAudioClientType = eClientType; + + mainLoop = pa_threaded_mainloop_new(); + if (mainLoop == NULL) + return AUDIO_CLIENT_INIT_ERR; + + api = pa_threaded_mainloop_get_api(mainLoop); + if (api == NULL) { + ResetPAAudioClient(); + return AUDIO_CLIENT_INIT_ERR; + } + + context = pa_context_new(api, "AudioServiceClient"); + if (context == NULL) { + ResetPAAudioClient(); + return AUDIO_CLIENT_INIT_ERR; + } + + pa_context_set_state_callback(context, PAContextStateCb, mainLoop); + + if (pa_context_connect(context, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) { + error = pa_context_errno(context); + ResetPAAudioClient(); + return AUDIO_CLIENT_INIT_ERR; + } + + isContextConnected = true; + pa_threaded_mainloop_lock(mainLoop); + + if (pa_threaded_mainloop_start(mainLoop) < 0) { + pa_threaded_mainloop_unlock(mainLoop); + ResetPAAudioClient(); + return AUDIO_CLIENT_INIT_ERR; + } + + isMainLoopStarted = true; + while (true) { + pa_context_state_t state = pa_context_get_state(context); + if (state == PA_CONTEXT_READY) + break; + + if (!PA_CONTEXT_IS_GOOD(state)) { + error = pa_context_errno(context); + // log the error + pa_threaded_mainloop_unlock(mainLoop); + ResetPAAudioClient(); + return AUDIO_CLIENT_INIT_ERR; + } + + pa_threaded_mainloop_wait(mainLoop); + } + + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_SUCCESS; +} + +const std::string AudioServiceClient::GetStreamName(AudioStreamType audioType) +{ + std::string name; + switch (audioType) { + case STREAM_VOICE_CALL: + name = "voice_call"; + break; + case STREAM_SYSTEM: + name = "system"; + break; + case STREAM_RING: + name = "ring"; + break; + case STREAM_MUSIC: + name = "music"; + break; + case STREAM_ALARM: + name = "alarm"; + break; + case STREAM_NOTIFICATION: + name = "notification"; + break; + case STREAM_BLUETOOTH_SCO: + name = "bluetooth_sco"; + break; + case STREAM_DTMF: + name = "dtmf"; + break; + case STREAM_TTS: + name = "tts"; + break; + case STREAM_ACCESSIBILITY: + name = "accessibility"; + break; + default: + name = "unknown"; + } + + const std::string streamName = name; + return streamName; +} + +int32_t AudioServiceClient::ConnectStreamToPA() +{ + int error, result; + + CHECK_AND_RETURN_IFINVALID(mainLoop && context && paStream); + pa_threaded_mainloop_lock(mainLoop); + + pa_buffer_attr bufferAttr; + bufferAttr.fragsize = (uint32_t) -1; + bufferAttr.prebuf = (uint32_t) -1; + bufferAttr.maxlength = (uint32_t) -1; + bufferAttr.tlength = (uint32_t) -1; + bufferAttr.minreq = pa_usec_to_bytes(LATENCY_IN_MSEC * PA_USEC_PER_MSEC, &sampleSpec); + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) + result = pa_stream_connect_playback(paStream, NULL, &bufferAttr, + (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY + | PA_STREAM_INTERPOLATE_TIMING + | PA_STREAM_START_CORKED + | PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); + else + result = pa_stream_connect_record(paStream, NULL, NULL, + (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING + | PA_STREAM_ADJUST_LATENCY + | PA_STREAM_START_CORKED + | PA_STREAM_AUTO_TIMING_UPDATE)); + + if (result < 0) { + error = pa_context_errno(context); + MEDIA_ERR_LOG("error in connection to stream"); + pa_threaded_mainloop_unlock(mainLoop); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } + + while (true) { + pa_stream_state_t state = pa_stream_get_state(paStream); + if (state == PA_STREAM_READY) + break; + + if (!PA_STREAM_IS_GOOD(state)) { + error = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainLoop); + MEDIA_ERR_LOG("error in connection to stream"); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } + + pa_threaded_mainloop_wait(mainLoop); + } + + isStreamConnected = true; + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_SUCCESS; +} + +int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStreamType audioType) +{ + int error; + + CHECK_AND_RETURN_IFINVALID(mainLoop && context); + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_CONTROLLER) { + return AUDIO_CLIENT_INVALID_PARAMS_ERR; + } + + pa_threaded_mainloop_lock(mainLoop); + const std::string streamName = GetStreamName(audioType); + + sampleSpec = ConvertToPAAudioParams(audioParams); + + pa_proplist *propList = pa_proplist_new(); + if (propList == NULL) { + MEDIA_ERR_LOG("pa_proplist_new failed"); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } + + pa_proplist_sets(propList, "stream.type", streamName.c_str()); + + if (!(paStream = pa_stream_new_with_proplist(context, streamName.c_str(), &sampleSpec, NULL, propList))) { + error = pa_context_errno(context); + pa_proplist_free(propList); + pa_threaded_mainloop_unlock(mainLoop); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } + + pa_proplist_free(propList); + pa_stream_set_state_callback(paStream, PAStreamStateCb, (void *) this); + pa_stream_set_write_callback(paStream, PAStreamRequestCb, mainLoop); + pa_stream_set_read_callback(paStream, PAStreamRequestCb, mainLoop); + pa_stream_set_latency_update_callback(paStream, PAStreamLatencyUpdateCb, mainLoop); + pa_stream_set_underflow_callback(paStream, PAStreamUnderFlowCb, (void *) this); + + pa_threaded_mainloop_unlock(mainLoop); + + error = ConnectStreamToPA(); + if (error < 0) { + MEDIA_ERR_LOG("Create Stream Failed"); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } + + MEDIA_INFO_LOG("Created Stream"); + return AUDIO_CLIENT_SUCCESS; +} + +int32_t AudioServiceClient::StartStream() +{ + int error; + + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_operation *operation = NULL; + + pa_threaded_mainloop_lock(mainLoop); + + pa_stream_state_t state = pa_stream_get_state(paStream); + if (state != PA_STREAM_READY) { + error = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainLoop); + MEDIA_ERR_LOG("Stream Start Failed"); + ResetPAAudioClient(); + return AUDIO_CLIENT_START_STREAM_ERR; + } + + streamCmdStatus = 0; + operation = pa_stream_cork(paStream, 0, PAStreamCmdSuccessCb, (void *) this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mainLoop); + + if (!streamCmdStatus) { + MEDIA_ERR_LOG("Stream Start Failed"); + ResetPAAudioClient(); + return AUDIO_CLIENT_START_STREAM_ERR; + } else { + MEDIA_INFO_LOG("Stream Started Successfully"); + return AUDIO_CLIENT_SUCCESS; + } +} + +int32_t AudioServiceClient::PauseStream(uint32_t sessionID) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + return AUDIO_CLIENT_SUCCESS; +} + +int32_t AudioServiceClient::StopStream() +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_operation *operation = NULL; + + pa_threaded_mainloop_lock(mainLoop); + pa_stream_state_t state = pa_stream_get_state(paStream); + if (state != PA_STREAM_READY) { + int32_t error = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainLoop); + MEDIA_ERR_LOG("Stream Stop Failed : %{public}d", error); + return AUDIO_CLIENT_ERR; + } + + streamCmdStatus = 0; + operation = pa_stream_cork(paStream, 1, PAStreamCmdSuccessCb, (void *) this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mainLoop); + + if (!streamCmdStatus) { + MEDIA_ERR_LOG("Stream Stop Failed"); + return AUDIO_CLIENT_ERR; + } else { + MEDIA_INFO_LOG("Stream Stopped Successfully"); + return AUDIO_CLIENT_SUCCESS; + } +} + +int32_t AudioServiceClient::FlushStream() +{ + int error; + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_operation *operation = NULL; + + pa_threaded_mainloop_lock(mainLoop); + + pa_stream_state_t state = pa_stream_get_state(paStream); + if (state != PA_STREAM_READY) { + error = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainLoop); + MEDIA_ERR_LOG("Stream Flush Failed"); + return AUDIO_CLIENT_ERR; + } + + streamCmdStatus = 0; + operation = pa_stream_flush(paStream, PAStreamCmdSuccessCb, (void *) this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mainLoop); + + if (!streamCmdStatus) { + MEDIA_ERR_LOG("Stream Flush Failed"); + return AUDIO_CLIENT_ERR; + } else { + MEDIA_INFO_LOG("Stream Flushed Successfully"); + return AUDIO_CLIENT_SUCCESS; + } +} + +int32_t AudioServiceClient::DrainStream() +{ + int error; + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_operation *operation = NULL; + + pa_threaded_mainloop_lock(mainLoop); + + pa_stream_state_t state = pa_stream_get_state(paStream); + if (state != PA_STREAM_READY) { + error = pa_context_errno(context); + pa_threaded_mainloop_unlock(mainLoop); + MEDIA_ERR_LOG("Stream Drain Failed"); + return AUDIO_CLIENT_ERR; + } + + streamCmdStatus = 0; + operation = pa_stream_drain(paStream, PAStreamCmdSuccessCb, (void *) this); + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mainLoop); + + if (!streamCmdStatus) { + MEDIA_ERR_LOG("Stream Drain Failed"); + return AUDIO_CLIENT_ERR; + } else { + MEDIA_INFO_LOG("Stream Drained Successfully"); + return AUDIO_CLIENT_SUCCESS; + } +} + +int32_t AudioServiceClient::SetStreamVolume(uint32_t sessionID, uint32_t volume) +{ + return AUDIO_CLIENT_SUCCESS; +} + +size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pError) +{ + const uint8_t* buffer = stream.buffer; + size_t length = stream.bufferLen; + int error = 0; + + CHECK_PA_STATUS_FOR_WRITE(mainLoop, context, paStream, pError, 0); + + pa_threaded_mainloop_lock(mainLoop); + + while (length > 0) { + size_t writableSize; + + while (!(writableSize = pa_stream_writable_size(paStream))) { + pa_threaded_mainloop_wait(mainLoop); + } + + if (writableSize > length) + writableSize = length; + + writableSize = AlignToAudioFrameSize(writableSize, sampleSpec); + if (writableSize == 0) { + break; + } + + error = pa_stream_write(paStream, (void *)buffer, writableSize, NULL, 0LL, PA_SEEK_RELATIVE); + if (error < 0) { + break; + } + + MEDIA_INFO_LOG("writable size: %{public}zu bytes to write: %{public}zu return val: %{public}d ", writableSize, length, error); + + buffer = (const uint8_t*) buffer + writableSize; + length -= writableSize; + } + + pa_threaded_mainloop_unlock(mainLoop); + pError = error; + return (stream.bufferLen - length); +} + +int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) +{ + uint8_t* buffer = stream.buffer; + size_t length = stream.bufferLen; + size_t readSize = 0; + + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + + pa_threaded_mainloop_lock(mainLoop); + while (length > 0) { + size_t l; + + while (!internalReadBuffer) { + int retVal = pa_stream_peek(paStream, &internalReadBuffer, &internalRdBufLen); + if (retVal < 0) { + MEDIA_ERR_LOG("pa_stream_peek failed, retVal: %d", retVal); + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_READ_STREAM_ERR; + } + + if (internalRdBufLen <= 0) { + if (isBlocking) + pa_threaded_mainloop_wait(mainLoop); + else { + pa_threaded_mainloop_unlock(mainLoop); + return 0; + } + } else if (!internalReadBuffer) { + retVal = pa_stream_drop(paStream); + if (retVal < 0) { + MEDIA_ERR_LOG("pa_stream_drop failed, retVal: %d", retVal); + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_READ_STREAM_ERR; + } + } else { + internalRdBufIndex = 0; + MEDIA_INFO_LOG("buffer size from PA: %zu", internalRdBufLen); + } + } + + l = (internalRdBufLen < length) ? internalRdBufLen : length; + memcpy_s(buffer, length, (const uint8_t*) internalReadBuffer + internalRdBufIndex, l); + + buffer = (uint8_t*) buffer + l; + length -= l; + + internalRdBufIndex += l; + internalRdBufLen -= l; + readSize += l; + + if (!internalRdBufLen) { + int retVal = pa_stream_drop(paStream); + internalReadBuffer = NULL; + internalRdBufLen = 0; + internalRdBufIndex = 0; + if (retVal < 0) { + MEDIA_ERR_LOG("pa_stream_drop failed, retVal: %d", retVal); + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_READ_STREAM_ERR; + } + } + } + pa_threaded_mainloop_unlock(mainLoop); + return readSize; +} + +int32_t AudioServiceClient::ReleaseStream() +{ + ResetPAAudioClient(); + return AUDIO_CLIENT_SUCCESS; +} + +int32_t AudioServiceClient::GetMinimumBufferSize(size_t &minBufferSize) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + + const pa_buffer_attr* bufferAttr = pa_stream_get_buffer_attr(paStream); + + if (bufferAttr == NULL) { + MEDIA_ERR_LOG("pa_stream_get_buffer_attr returned NULL"); + return AUDIO_CLIENT_ERR; + } + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + minBufferSize = (size_t) bufferAttr->minreq; + } + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { + minBufferSize = (size_t) bufferAttr->fragsize; + } + + MEDIA_INFO_LOG("buffer size: %zu", minBufferSize); + return AUDIO_CLIENT_SUCCESS; +} + +int32_t AudioServiceClient::GetMinimumFrameCount(uint32_t &frameCount) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + size_t minBufferSize = 0; + + const pa_buffer_attr* bufferAttr = pa_stream_get_buffer_attr(paStream); + + if (bufferAttr == NULL) { + MEDIA_ERR_LOG("pa_stream_get_buffer_attr returned NULL"); + return AUDIO_CLIENT_ERR; + } + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + minBufferSize = (size_t) bufferAttr->minreq; + } + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { + minBufferSize = (size_t) bufferAttr->fragsize; + } + + uint32_t bytesPerSample = pa_frame_size(&sampleSpec); + if (bytesPerSample == 0) { + MEDIA_ERR_LOG("GetMinimumFrameCount Failed"); + return AUDIO_CLIENT_ERR; + } + + frameCount = minBufferSize / bytesPerSample; + MEDIA_INFO_LOG("frame count: %d", frameCount); + return AUDIO_CLIENT_SUCCESS; +} + +uint32_t AudioServiceClient::GetSamplingRate() +{ + return DEFAULT_SAMPLING_RATE; +} + +uint8_t AudioServiceClient::GetChannelCount() +{ + return DEFAULT_CHANNEL_COUNT; +} + +uint8_t AudioServiceClient::GetSampleSize() +{ + return DEFAULT_SAMPLE_SIZE; +} + +int32_t AudioServiceClient::GetAudioStreamParams(AudioStreamParams& audioParams) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + const pa_sample_spec* paSampleSpec = pa_stream_get_sample_spec(paStream); + + audioParams = ConvertFromPAAudioParams(*paSampleSpec); + return AUDIO_CLIENT_SUCCESS; +} + +uint32_t AudioServiceClient::GetStreamVolume(uint32_t sessionID) +{ + return DEFAULT_STREAM_VOLUME; +} + +int32_t AudioServiceClient::GetCurrentTimeStamp(uint64_t &timeStamp) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + int32_t retVal = 0; + + pa_threaded_mainloop_lock(mainLoop); + retVal = pa_stream_get_time(paStream, &timeStamp); + pa_threaded_mainloop_unlock(mainLoop); + + if (retVal >= 0) + return AUDIO_CLIENT_SUCCESS; + else + return AUDIO_CLIENT_ERR; +} + +void AudioServiceClient::RegisterAudioRendererCallbacks(const AudioRendererCallbacks &cb) +{ + MEDIA_INFO_LOG("Registering audio render callbacks"); + mAudioRendererCallbacks = (AudioRendererCallbacks *) &cb; +} + +void AudioServiceClient::RegisterAudioRecorderCallbacks(const AudioRecorderCallbacks &cb) +{ + MEDIA_INFO_LOG("Registering audio record callbacks"); + mAudioRecorderCallbacks = (AudioRecorderCallbacks *) &cb; +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/client/audio_session.cpp b/services/src/client/audio_session.cpp new file mode 100644 index 0000000000..abc4fa75f8 --- /dev/null +++ b/services/src/client/audio_session.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_session.h" diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp new file mode 100644 index 0000000000..b1f4ed7c4f --- /dev/null +++ b/services/src/client/audio_stream.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_stream.h" +#include +#include "audio_errors.h" +#include "media_log.h" + +using namespace std; + +namespace OHOS { +namespace AudioStandard { +const unsigned long long TIME_CONVERSION_US_S = 1000000ULL; /* us to s */ +const unsigned long long TIME_CONVERSION_NS_US = 1000ULL; /* ns to us */ + +// Supported audio parameters for both renderer and recorder +const vector SUPPORTED_FORMATS { + SAMPLE_U8, + SAMPLE_S16LE, + SAMPLE_S24LE, + SAMPLE_S32LE +}; + +const vector SUPPORTED_CHANNELS { + MONO, + STEREO +}; + +const vector SUPPORTED_ENCODING_TYPES { + ENCODING_PCM +}; + +const vector SUPPORTED_SAMPLING_RATES { + SAMPLE_RATE_8000, + SAMPLE_RATE_11025, + SAMPLE_RATE_16000, + SAMPLE_RATE_22050, + SAMPLE_RATE_32000, + SAMPLE_RATE_44100, + SAMPLE_RATE_48000 +}; + +AudioStream::AudioStream(AudioStreamType eStreamType, AudioMode eMode) : eStreamType_(eStreamType), + eMode_(eMode), + state_(NEW) +{ + MEDIA_DEBUG_LOG("AudioStream ctor"); +} + +AudioStream::~AudioStream() +{ + ReleaseAudioStream(); +} + +State AudioStream::GetState() +{ + return state_; +} + +bool AudioStream::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) +{ + uint64_t paTimeStamp; + if (GetCurrentTimeStamp(paTimeStamp) == SUCCESS) { + MEDIA_DEBUG_LOG("AudioStream: GetAudioTime in microseconds: %{public}lld", paTimeStamp); + timestamp.time.tv_sec = static_cast(paTimeStamp / TIME_CONVERSION_US_S); + timestamp.time.tv_nsec + = static_cast((paTimeStamp - (timestamp.time.tv_sec * TIME_CONVERSION_US_S)) + * TIME_CONVERSION_NS_US); + return true; + } + return false; +} + +int32_t AudioStream::GetBufferSize(size_t &bufferSize) +{ + MEDIA_INFO_LOG("AudioStream: Get Buffer size"); + if (GetMinimumBufferSize(bufferSize) != 0) { + return ERR_OPERATION_FAILED; + } + + return SUCCESS; +} + +int32_t AudioStream::GetFrameCount(uint32_t &frameCount) +{ + MEDIA_INFO_LOG("AudioStream: Get frame count"); + if (GetMinimumFrameCount(frameCount) != 0) { + return ERR_OPERATION_FAILED; + } + + return SUCCESS; +} + +vector AudioStream::GetSupportedFormats() +{ + return SUPPORTED_FORMATS; +} + +vector AudioStream::GetSupportedChannels() +{ + return SUPPORTED_CHANNELS; +} + +vector AudioStream::GetSupportedEncodingTypes() +{ + return SUPPORTED_ENCODING_TYPES; +} + +vector AudioStream::GetSupportedSamplingRates() +{ + return SUPPORTED_SAMPLING_RATES; +} + +bool IsFormatValid(uint8_t format) +{ + bool isValidFormat = (find(SUPPORTED_FORMATS.begin(), SUPPORTED_FORMATS.end(), format) + != SUPPORTED_FORMATS.end()); + MEDIA_DEBUG_LOG("AudioStream: IsFormatValid: %{public}s", isValidFormat ? "true" : "false"); + return isValidFormat; +} + +bool IsChannelValid(uint8_t channel) +{ + bool isValidChannel = (find(SUPPORTED_CHANNELS.begin(), SUPPORTED_CHANNELS.end(), channel) + != SUPPORTED_CHANNELS.end()); + MEDIA_DEBUG_LOG("AudioStream: IsChannelValid: %{public}s", isValidChannel ? "true" : "false"); + return isValidChannel; +} + +bool IsEncodingTypeValid(uint8_t encodingType) +{ + bool isValidEncodingType + = (find(SUPPORTED_ENCODING_TYPES.begin(), SUPPORTED_ENCODING_TYPES.end(), encodingType) + != SUPPORTED_ENCODING_TYPES.end()); + MEDIA_DEBUG_LOG("AudioStream: IsEncodingTypeValid: %{public}s", + isValidEncodingType ? "true" : "false"); + return isValidEncodingType; +} + +bool IsSamplingRateValid(uint32_t samplingRate) +{ + bool isValidSamplingRate + = (find(SUPPORTED_SAMPLING_RATES.begin(), SUPPORTED_SAMPLING_RATES.end(), samplingRate) + != SUPPORTED_SAMPLING_RATES.end()); + MEDIA_DEBUG_LOG("AudioStream: IsSamplingRateValid: %{public}s", + isValidSamplingRate ? "true" : "false"); + return isValidSamplingRate; +} + +int32_t AudioStream::GetAudioStreamInfo(AudioStreamParams &audioStreamInfo) +{ + MEDIA_INFO_LOG("AudioStream: GetAudioStreamInfo"); + if(GetAudioStreamParams(audioStreamInfo) != 0) { + return ERR_OPERATION_FAILED; + } + + return SUCCESS; +} + +int32_t AudioStream::SetAudioStreamInfo(const AudioStreamParams info) +{ + MEDIA_INFO_LOG("AudioStream: SetAudioParams"); + + MEDIA_DEBUG_LOG("AudioStream: Sampling rate: %{public}d", info.samplingRate); + MEDIA_DEBUG_LOG("AudioStream: channels: %{public}d", info.channels); + MEDIA_DEBUG_LOG("AudioStream: format: %{public}d", info.format); + MEDIA_DEBUG_LOG("AudioStream: stream type: %{public}d", eStreamType_); + + if (!IsFormatValid(info.format) || !IsChannelValid(info.channels) + || !IsSamplingRateValid(info.samplingRate) || !IsEncodingTypeValid(info.encoding)) { + MEDIA_ERR_LOG("AudioStream: Unsupported audio parameter"); + return ERR_NOT_SUPPORTED; + } + if (state_ != NEW) { + MEDIA_DEBUG_LOG("AudioStream: State is not new, release existing stream"); + StopAudioStream(); + ReleaseAudioStream(); + } + + int32_t ret = 0; + switch (eMode_) { + case AUDIO_MODE_PLAYBACK: + MEDIA_DEBUG_LOG("AudioStream: Initialize playback"); + ret = Initialize(AUDIO_SERVICE_CLIENT_PLAYBACK); + break; + case AUDIO_MODE_RECORD: + MEDIA_DEBUG_LOG("AudioStream: Initialize recorder"); + ret = Initialize(AUDIO_SERVICE_CLIENT_RECORD); + break; + default: + return ERR_INVALID_OPERATION; + } + + if (ret) { + MEDIA_DEBUG_LOG("AudioStream: Error initializing!"); + return ret; + } + + if (CreateStream(info, eStreamType_) != SUCCESS) { + MEDIA_ERR_LOG("AudioStream:Create stream failed"); + return ERROR; + } + + state_ = PREPARED; + MEDIA_INFO_LOG("AudioStream:Set stream Info SUCCESS"); + return SUCCESS; +} + +bool AudioStream::StartAudioStream() +{ + if ((state_ != PREPARED) && (state_ != STOPPED)) { + MEDIA_ERR_LOG("StartAudioStream ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + int32_t ret = StartStream(); + if (ret != SUCCESS) { + MEDIA_ERR_LOG("StartStream Start failed:0x%x", ret); + return false; + } + + state_ = RUNNING; + MEDIA_INFO_LOG("StartAudioStream SUCCESS"); + return true; +} + +int32_t AudioStream::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) +{ + if (userSize <= 0) { + MEDIA_ERR_LOG("Invalid userSize:%zu", userSize); + return ERR_INVALID_PARAM; + } + + if (state_ != RUNNING) { + MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + + StreamBuffer stream; + stream.buffer = &buffer; + stream.bufferLen = userSize; + int32_t readLen = ReadStream(stream, isBlockingRead); + if (readLen < 0) { + MEDIA_ERR_LOG("ReadStream fail,ret:0x%x", readLen); + return ERR_INVALID_READ; + } + + return readLen; +} + +size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size) +{ + if ((buffer == nullptr) || (buffer_size <= 0)) { + MEDIA_ERR_LOG("Invalid buffer size:%zu", buffer_size); + return ERR_INVALID_PARAM; + } + + if (state_ != RUNNING) { + MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + + int32_t writeError; + StreamBuffer stream; + stream.buffer = buffer; + stream.bufferLen = buffer_size; + size_t bytesWritten = WriteStream(stream, writeError); + if (writeError != 0) { + MEDIA_ERR_LOG("WriteStream fail,writeError:%{public}d", writeError); + return ERR_WRITE_FAILED; + } + if (bytesWritten < 0) { + MEDIA_ERR_LOG("WriteStream fail,bytesWritten:0x%x", bytesWritten); + return ERR_INVALID_WRITE; + } + + return bytesWritten; +} + +bool AudioStream::StopAudioStream() +{ + if (state_ != RUNNING) { + MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + + int32_t ret = StopStream(); + if (ret != SUCCESS) { + MEDIA_DEBUG_LOG("StreamStop fail,ret:0x%x", ret); + return false; + } + + MEDIA_INFO_LOG("StopAudioStream SUCCESS"); + state_ = STOPPED; + return true; +} + +bool AudioStream::FlushAudioStream() +{ + if (state_ != RUNNING) { + MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + + int32_t ret = FlushStream(); + if (ret != SUCCESS) { + MEDIA_DEBUG_LOG("Flush stream fail,ret:0x%x", ret); + return false; + } + + MEDIA_INFO_LOG("Flush stream SUCCESS"); + return true; +} + +bool AudioStream::DrainAudioStream() +{ + if (state_ != RUNNING) { + MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + return ERR_ILLEGAL_STATE; + } + + int32_t ret = DrainStream(); + if (ret != SUCCESS) { + MEDIA_DEBUG_LOG("Drain stream fail,ret:0x%x", ret); + return false; + } + + MEDIA_INFO_LOG("Drain stream SUCCESS"); + return true; +} + +bool AudioStream::ReleaseAudioStream() +{ + if (state_ == RELEASED) { + MEDIA_ERR_LOG("illegal state: state = %u", state_); + return false; + } + + if (state_ == RUNNING && StopAudioStream()) { + MEDIA_ERR_LOG("Stop failed: %u", state_); + return false; + } + + FlushStream(); + ReleaseStream(); + state_ = RELEASED; + MEDIA_INFO_LOG("Release Audio stream SUCCESS"); + return true; +} +} +} diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp new file mode 100644 index 0000000000..6d1a840ed3 --- /dev/null +++ b/services/src/client/audio_system_manager.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_errors.h" +#include "audio_info.h" +#include "audio_manager_proxy.h" +#include "audio_system_manager.h" +#include "iservice_registry.h" +#include "media_log.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace AudioStandard { +using namespace std; +static sptr g_sProxy = nullptr; + +AudioSystemManager::AudioSystemManager() +{ + MEDIA_DEBUG_LOG("AudioSystemManager start"); + init(); +} + +AudioSystemManager::~AudioSystemManager() +{ + MEDIA_DEBUG_LOG("AudioSystemManager::~AudioSystemManager"); +} + +AudioSystemManager* AudioSystemManager::GetInstance() +{ + static AudioSystemManager audioManager; + return &audioManager; +} + +void AudioSystemManager::init() +{ + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + MEDIA_ERR_LOG("AudioSystemManager::init failed"); + return; + } + + sptr object = samgr->GetSystemAbility(AUDIO_DISTRIBUTED_SERVICE_ID); + if (object == nullptr) { + MEDIA_DEBUG_LOG("AudioSystemManager::object is NULL."); + } + g_sProxy = iface_cast(object); + if (g_sProxy == nullptr) { + MEDIA_DEBUG_LOG("AudioSystemManager::init g_sProxy is NULL."); + } else { + MEDIA_DEBUG_LOG("AudioSystemManager::init g_sProxy is assigned."); + } +} + +bool AudioSystemManager::SetRingerMode(AudioRingerMode ringMode) +{ + /* Call Audio Policy SetRingerMode */ + return AudioPolicyManager::GetInstance().SetRingerMode(ringMode); +} + +AudioRingerMode AudioSystemManager::GetRingerMode() +{ + /* Call Audio Policy GetRingerMode */ + return (AudioPolicyManager::GetInstance().GetRingerMode()); +} + +int32_t AudioSystemManager::SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag) +{ + switch (deviceType) { + case SPEAKER: + case BLUETOOTH_A2DP: + case MIC: + break; + default: + MEDIA_ERR_LOG("SetDeviceActive device=%{public}d not supported", deviceType); + return ERR_NOT_SUPPORTED; + } + + /* Call Audio Policy SetDeviceActive */ + DeviceType devType = (DeviceType)deviceType; + return (AudioPolicyManager::GetInstance().SetDeviceActive(devType, flag)); +} + +bool AudioSystemManager::IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType) +{ + switch (deviceType) { + case SPEAKER: + case BLUETOOTH_A2DP: + case MIC: + break; + default: + MEDIA_ERR_LOG("IsDeviceActive device=%{public}d not supported", deviceType); + return false; + } + + /* Call Audio Policy IsDeviceActive */ + DeviceType devType = (DeviceType)deviceType; + return (AudioPolicyManager::GetInstance().IsDeviceActive(devType)); +} + +bool AudioSystemManager::IsStreamActive(AudioSystemManager::AudioVolumeType volumeType) +{ + switch (volumeType) { + case STREAM_MUSIC: + case STREAM_RING: + break; + default: + MEDIA_ERR_LOG("IsStreamActive volumeType=%{public}d not supported", volumeType); + return false; + } + + AudioStreamType StreamVolType = (AudioStreamType)volumeType; + return AudioPolicyManager::GetInstance().IsStreamActive(StreamVolType); +} + +const std::string AudioSystemManager::GetAudioParameter(const std::string key) +{ + return g_sProxy->GetAudioParameter(key); +} + +void AudioSystemManager::SetAudioParameter(const std::string key, const std::string value) +{ + g_sProxy->SetAudioParameter(key, value); +} + +int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) +{ + /* Validate and return INVALID_PARAMS error */ + if ((volume < 0) || (volume > 1)) { + MEDIA_ERR_LOG("Invalid Volume Input!"); + return ERR_INVALID_PARAM; + } + + switch (volumeType) { + case STREAM_MUSIC: + case STREAM_RING: + break; + default: + MEDIA_ERR_LOG("SetVolume volumeType=%{public}d not supported", volumeType); + return ERR_NOT_SUPPORTED; + } + + /* Call Audio Policy SetStreamVolume */ + AudioStreamType StreamVolType = (AudioStreamType)volumeType; + return AudioPolicyManager::GetInstance().SetStreamVolume(StreamVolType, volume); +} + +float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeType) +{ + switch (volumeType) { + case STREAM_MUSIC: + case STREAM_RING: + break; + default: + MEDIA_ERR_LOG("GetVolume volumeType=%{public}d not supported", volumeType); + return ERR_NOT_SUPPORTED; + } + + /* Call Audio Policy SetStreamMute */ + AudioStreamType StreamVolType = (AudioStreamType)volumeType; + return AudioPolicyManager::GetInstance().GetStreamVolume(StreamVolType); +} + +float AudioSystemManager::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) +{ + return g_sProxy->GetMaxVolume(volumeType); +} + +float AudioSystemManager::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) +{ + return g_sProxy->GetMinVolume(volumeType); +} + +int32_t AudioSystemManager::SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute) +{ + switch (volumeType) { + case STREAM_MUSIC: + case STREAM_RING: + break; + default: + MEDIA_ERR_LOG("SetMute volumeType=%{public}d not supported", volumeType); + return ERR_NOT_SUPPORTED; + } + + /* Call Audio Policy SetStreamMute */ + AudioStreamType StreamVolType = (AudioStreamType)volumeType; + return AudioPolicyManager::GetInstance().SetStreamMute(StreamVolType, mute); +} + +bool AudioSystemManager::IsStreamMute(AudioSystemManager::AudioVolumeType volumeType) +{ + MEDIA_DEBUG_LOG("AudioSystemManager::GetMute Client"); + + switch (volumeType) { + case STREAM_MUSIC: + case STREAM_RING: + break; + default: + MEDIA_ERR_LOG("IsStreamMute volumeType=%{public}d not supported", volumeType); + return false; + } + + /* Call Audio Policy SetStreamVolume */ + AudioStreamType StreamVolType = (AudioStreamType)volumeType; + return AudioPolicyManager::GetInstance().GetStreamMute(StreamVolType); +} + +int32_t AudioSystemManager::SetMicrophoneMute(bool isMute) +{ + return g_sProxy->SetMicrophoneMute(isMute); +} + +bool AudioSystemManager::IsMicrophoneMute() +{ + return g_sProxy->IsMicrophoneMute(); +} + +std::vector> AudioSystemManager::GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) +{ + return g_sProxy->GetDevices(deviceFlag); +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/src/server/audio_manager_stub.cpp b/services/src/server/audio_manager_stub.cpp old mode 100755 new mode 100644 index c5bf50ced2..c3c783a3a7 --- a/services/src/server/audio_manager_stub.cpp +++ b/services/src/server/audio_manager_stub.cpp @@ -13,12 +13,13 @@ * limitations under the License. */ -#include "audio_manager_base.h" -#include "audio_svc_manager.h" #include "audio_device_descriptor.h" +#include "audio_manager_base.h" +#include "audio_system_manager.h" #include "media_log.h" namespace OHOS { +namespace AudioStandard { int AudioManagerStub::OnRemoteRequest( uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) { @@ -27,49 +28,28 @@ int AudioManagerStub::OnRemoteRequest( MEDIA_ERR_LOG("caller app not acquired audio permission"); return MEDIA_PERMISSION_DENIED; } + switch (code) { - case SET_VOLUME: { - MEDIA_DEBUG_LOG("SET_VOLUME AudioManagerStub"); - int volumeType = data.ReadInt32(); - MEDIA_DEBUG_LOG("SET_VOLUME volumeType received from client= %{public}d", volumeType); - AudioSvcManager::AudioVolumeType volumeStreamConfig = - static_cast(volumeType); - MEDIA_DEBUG_LOG("SET_VOLUME volumeType= %{public}d", volumeStreamConfig); - int vol = data.ReadInt32(); - SetVolume(volumeStreamConfig, vol); - return MEDIA_OK; - } - case GET_VOLUME: { - MEDIA_DEBUG_LOG("GET_VOLUME AudioManagerStub"); - int volumeType = data.ReadInt32(); - MEDIA_DEBUG_LOG("GET_VOLUME volumeType received from client= %{public}d", volumeType); - AudioSvcManager::AudioVolumeType volumeStreamConfig = - static_cast(volumeType); - MEDIA_DEBUG_LOG("GET_VOLUME volumeType= %{public}d", volumeStreamConfig); - int ret = GetVolume(volumeStreamConfig); - reply.WriteInt32(ret); - return MEDIA_OK; - } case GET_MAX_VOLUME: { MEDIA_DEBUG_LOG("GET_MAX_VOLUME AudioManagerStub"); int volumeType = data.ReadInt32(); MEDIA_DEBUG_LOG("GET_MAX_VOLUME volumeType received from client= %{public}d", volumeType); - AudioSvcManager::AudioVolumeType volumeStreamConfig = - static_cast(volumeType); + AudioSystemManager::AudioVolumeType volumeStreamConfig = + static_cast(volumeType); MEDIA_DEBUG_LOG("GET_MAX_VOLUME volumeType= %{public}d", volumeStreamConfig); - int ret = GetMaxVolume(volumeStreamConfig); - reply.WriteInt32(ret); + float ret = GetMaxVolume(volumeStreamConfig); + reply.WriteFloat(ret); return MEDIA_OK; } case GET_MIN_VOLUME: { MEDIA_DEBUG_LOG("GET_MIN_VOLUME AudioManagerStub"); int volumeType = data.ReadInt32(); MEDIA_DEBUG_LOG("GET_MIN_VOLUME volumeType received from client= %{public}d", volumeType); - AudioSvcManager::AudioVolumeType volumeStreamConfig = - static_cast(volumeType); + AudioSystemManager::AudioVolumeType volumeStreamConfig = + static_cast(volumeType); MEDIA_DEBUG_LOG("GET_MIN_VOLUME volumeType= %{public}d", volumeStreamConfig); - int ret = GetMinVolume(volumeStreamConfig); - reply.WriteInt32(ret); + float ret = GetMinVolume(volumeStreamConfig); + reply.WriteFloat(ret); return MEDIA_OK; } case GET_DEVICES: { @@ -86,6 +66,37 @@ int AudioManagerStub::OnRemoteRequest( } return MEDIA_OK; } + case SET_AUDIO_PARAMETER: { + MEDIA_DEBUG_LOG("SET_AUDIO_PARAMETER AudioManagerStub"); + const std::string key = data.ReadString(); + const std::string value = data.ReadString(); + MEDIA_DEBUG_LOG("SET_AUDIO_PARAMETER key-value pair from client= %{public}s, %{public}s", + key.c_str(), value.c_str()); + SetAudioParameter(key, value); + return MEDIA_OK; + } + case GET_AUDIO_PARAMETER: { + MEDIA_DEBUG_LOG("GET_AUDIO_PARAMETER AudioManagerStub"); + const std::string key = data.ReadString(); + MEDIA_DEBUG_LOG("GET_AUDIO_PARAMETER key received from client= %{public}s", key.c_str()); + const std::string value = GetAudioParameter(key); + reply.WriteString(value); + return MEDIA_OK; + } + case SET_MICROPHONE_MUTE: { + MEDIA_DEBUG_LOG("SET_MICROPHONE_MUTE AudioManagerStub"); + bool isMute = data.ReadBool(); + MEDIA_DEBUG_LOG("SET_MICROPHONE_MUTE isMute value from client= %{public}d", isMute); + int32_t result = SetMicrophoneMute(isMute); + reply.WriteInt32(result); + return MEDIA_OK; + } + case IS_MICROPHONE_MUTE: { + MEDIA_DEBUG_LOG("IS_MICROPHONE_MUTE AudioManagerStub"); + bool isMute = IsMicrophoneMute(); + reply.WriteBool(isMute); + return MEDIA_OK; + } default: { MEDIA_ERR_LOG("default case, need check AudioManagerStub"); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); @@ -97,4 +108,5 @@ bool AudioManagerStub::IsPermissionValid() { return true; } +} // namespace AudioStandard } // namespace OHOS diff --git a/services/src/server/audio_server.cpp b/services/src/server/audio_server.cpp old mode 100755 new mode 100644 index 4f47133672..efb79a635c --- a/services/src/server/audio_server.cpp +++ b/services/src/server/audio_server.cpp @@ -13,31 +13,46 @@ * limitations under the License. */ +#include "audio_capturer_source.h" #include "audio_server.h" #include "iservice_registry.h" #include "media_log.h" #include "system_ability_definition.h" -using namespace std; +#define PA +#ifdef PA +extern "C" { + extern int ohos_pa_main(int argc, char *argv[]); +} +#endif namespace OHOS { - std::unordered_map AudioServer::AudioStreamVolumeMap = { - {AudioSvcManager::AudioVolumeType::STREAM_VOICE_CALL, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_SYSTEM, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_RING, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_MUSIC, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_ALARM, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_NOTIFICATION, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_BLUETOOTH_SCO, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_DTMF, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_TTS, MAX_VOLUME}, - {AudioSvcManager::AudioVolumeType::STREAM_ACCESSIBILITY, MAX_VOLUME} - }; +namespace AudioStandard { +std::map AudioServer::audioParameters; REGISTER_SYSTEM_ABILITY_BY_ID(AudioServer, AUDIO_DISTRIBUTED_SERVICE_ID, true) +#ifdef PA +constexpr int PA_ARG_COUNT = 1; +const int PA_DAEMON_THREAD_NAME_BUFFER = 15; + +void* AudioServer::paDaemonThread(void* arg) +{ + /* Load the mandatory pulseaudio modules at start */ + char *argv[] = { + (char*)"pulseaudio", + }; + + MEDIA_INFO_LOG("Calling ohos_pa_main\n"); + ohos_pa_main(PA_ARG_COUNT, argv); + MEDIA_INFO_LOG("Exiting ohos_pa_main\n"); + + return nullptr; +} +#endif + AudioServer::AudioServer(int32_t systemAbilityId, bool runOnCreate) - : SystemAbility(systemAbilityId, runOnCreate) + : SystemAbility(systemAbilityId, runOnCreate) {} void AudioServer::OnDump() @@ -50,40 +65,90 @@ void AudioServer::OnStart() if (res) { MEDIA_DEBUG_LOG("AudioService OnStart res=%{public}d", res); } + +#ifdef PA + char thread_name[PA_DAEMON_THREAD_NAME_BUFFER]; + + int32_t ret = pthread_create(&m_paDaemonThread, nullptr, AudioServer::paDaemonThread, nullptr); + if (ret != 0) { + MEDIA_ERR_LOG("pthread_create failed %d", ret); + } + MEDIA_INFO_LOG("Created paDaemonThread\n"); + + ret = pthread_getname_np(m_paDaemonThread, thread_name, PA_DAEMON_THREAD_NAME_BUFFER - 1); + if (ret != 0) { + MEDIA_ERR_LOG("pthread_getname failed %d", ret); + } + + ret = pthread_setname_np(m_paDaemonThread, "pulseaudio"); + if (ret != 0) { + MEDIA_ERR_LOG("pthread_setname failed %d", ret); + } +#endif } void AudioServer::OnStop() { MEDIA_DEBUG_LOG("AudioService OnStop"); -} +} -void AudioServer::SetVolume(AudioSvcManager::AudioVolumeType volumeType, int32_t volume) +void AudioServer::SetAudioParameter(const std::string key, const std::string value) { - MEDIA_DEBUG_LOG("set volume server"); - AudioServer::AudioStreamVolumeMap[volumeType] = volume; + MEDIA_DEBUG_LOG("server: set audio parameter"); + AudioServer::audioParameters[key] = value; } -int32_t AudioServer::GetVolume(AudioSvcManager::AudioVolumeType volumeType) +const std::string AudioServer::GetAudioParameter(const std::string key) { - MEDIA_DEBUG_LOG("GetVolume server volumeType=%{public}d", volumeType); - int volume = AudioServer::AudioStreamVolumeMap[volumeType]; - MEDIA_DEBUG_LOG("GetVolume server volume=%{public}d", volume); - return volume; + MEDIA_DEBUG_LOG("server: get audio parameter"); + + if (AudioServer::audioParameters.count(key)) { + return AudioServer::audioParameters[key]; + } else { + const std::string value = ""; + return value; + } } -int32_t AudioServer::GetMaxVolume(AudioSvcManager::AudioVolumeType volumeType) +float AudioServer::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) { MEDIA_DEBUG_LOG("GetMaxVolume server"); return MAX_VOLUME; } -int32_t AudioServer::GetMinVolume(AudioSvcManager::AudioVolumeType volumeType) +float AudioServer::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) { MEDIA_DEBUG_LOG("GetMinVolume server"); return MIN_VOLUME; } +int32_t AudioServer::SetMicrophoneMute(bool isMute) +{ + AudioCapturerSource* audioCapturerSourceInstance = AudioCapturerSource::GetInstance(); + + if (audioCapturerSourceInstance->capturerInited_ == false) { + MEDIA_ERR_LOG("Capturer is not initialized. Start the recording first !"); + return ERR_INVALID_OPERATION; + } + + return audioCapturerSourceInstance->SetMute(isMute); +} + +bool AudioServer::IsMicrophoneMute() +{ + AudioCapturerSource* audioCapturerSourceInstance = AudioCapturerSource::GetInstance(); + bool isMute = false; + + if (audioCapturerSourceInstance->capturerInited_ == false) { + MEDIA_ERR_LOG("Capturer is not initialized. Start the recording first !"); + } else if (audioCapturerSourceInstance->GetMute(isMute)) { + MEDIA_ERR_LOG("GetMute status in capturer returned Error !"); + } + + return isMute; +} + std::vector> AudioServer::GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) { MEDIA_DEBUG_LOG("GetDevices server"); @@ -93,9 +158,25 @@ std::vector> AudioServer::GetDevices(AudioDeviceDesc MEDIA_ERR_LOG("new AudioDeviceDescriptor fail"); return audioDeviceDescriptor_; } - audioDescriptor->deviceType_ = AudioDeviceDescriptor::DeviceType::MIC; - audioDescriptor->deviceRole_ = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE; + if (AudioDeviceDescriptor::DeviceFlag::INPUT_DEVICES_FLAG == deviceFlag) { + audioDescriptor->deviceType_ = AudioDeviceDescriptor::DeviceType::MIC; + audioDescriptor->deviceRole_ = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE; + } else if (AudioDeviceDescriptor::DeviceFlag::OUTPUT_DEVICES_FLAG == deviceFlag) { + audioDescriptor->deviceType_ = AudioDeviceDescriptor::DeviceType::SPEAKER; + audioDescriptor->deviceRole_ = AudioDeviceDescriptor::DeviceRole::OUTPUT_DEVICE; + } else if (AudioDeviceDescriptor::DeviceFlag::ALL_DEVICES_FLAG == deviceFlag) { + AudioDeviceDescriptor *audioDescriptor_inputDevice = new(std::nothrow) AudioDeviceDescriptor(); + AudioDeviceDescriptor *audioDescriptor_outputDevice = new(std::nothrow) AudioDeviceDescriptor(); + audioDescriptor_inputDevice->deviceType_ = AudioDeviceDescriptor::DeviceType::MIC; + audioDescriptor_inputDevice->deviceRole_ = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE; + audioDeviceDescriptor_.push_back(audioDescriptor_inputDevice); + audioDescriptor_outputDevice->deviceType_ = AudioDeviceDescriptor::DeviceType::SPEAKER; + audioDescriptor_outputDevice->deviceRole_ = AudioDeviceDescriptor::DeviceRole::OUTPUT_DEVICE; + audioDeviceDescriptor_.push_back(audioDescriptor_outputDevice); + return audioDeviceDescriptor_; + } audioDeviceDescriptor_.push_back(audioDescriptor); return audioDeviceDescriptor_; } +} // namespace AudioStandard } // namespace OHOS diff --git a/services/test/audio_policy_test.cpp b/services/test/audio_policy_test.cpp new file mode 100644 index 0000000000..58a7524dd3 --- /dev/null +++ b/services/test/audio_policy_test.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 + +#include "audio_errors.h" +#include "audio_system_manager.h" +#include "media_log.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::AudioStandard; + +namespace AudioPolicyTest { + const int FIRST_ARG = 1; + const int SECOND_ARG = 2; + const int OPT_ARG_BASE = 10; + const int OPT_SHORT_LEN = 3; + const float VOLUME = 0.5f; +} + +static void PrintUsage(void) +{ + cout << "NAME" << endl << endl; + cout << "\taudio_policy_test - Audio Policy Test " << endl << endl; + cout << "SYNOPSIS" << endl << endl; + cout << "\t#include " << endl << endl; + cout << "\t./audio_playback_test [OPTIONS]..." << endl << endl; + cout << "DESCRIPTION" << endl << endl; + cout << "\tControls audio volume, audio routing, audio mute" << endl << endl; + cout << "-V\n\tSets Volume for streams, -S to setStream" << endl << endl; + cout << "-v\n\tGets Volume for streams, -S to setStream" << endl << endl; + cout << "-S\n\tSet stream type" << endl << endl; + cout << "\tSupported Streams are" << endl << endl; + cout << "\t4\tMUSIC" << endl << endl; + cout << "\t3\tRING" << endl << endl; + cout << "-D\n\tSets Device Active" << endl << endl; + cout << "\tSupported Devices are" << endl << endl; + cout << "\t0\tSPEAKER" << endl << endl; + cout << "\t3\tBLUETOOTH_A2DP" << endl << endl; + cout << "\t4\tMIC" << endl << endl; + cout << "-d\n\tGets Device Active" << endl << endl; + cout << "-M\n\tSets Mute for streams, -S to setStream" << endl << endl; + cout << "-m\n\tGets Mute for streams, -S to setStream" << endl << endl; + cout << "-R\n\tSets RingerMode" << endl << endl; + cout << "-r\n\tGets RingerMode status" << endl << endl; + cout << "-s\n\tGet Stream Status" << endl << endl; + cout << "AUTHOR" << endl << endl; + cout << "\tWritten by Sajeesh Sidharthan and Anurup M" << endl << endl; +} + +int main(int argc, char* argv[]) +{ + int32_t result; + float volume = AudioPolicyTest::VOLUME; + int device = -1; + int active = -1; + int mute = -1; + bool muteStatus = false; + bool devActiveStatus = false; + int opt = 0; + int ringMode = 0; + int streamType = static_cast(AudioSystemManager::AudioVolumeType::STREAM_MUSIC); + + if (((argc >= AudioPolicyTest::SECOND_ARG) && !strcmp(argv[AudioPolicyTest::FIRST_ARG], "--help")) || + (argc == AudioPolicyTest::FIRST_ARG)) { + PrintUsage(); + return ERR_INVALID_PARAM; + } + + AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance(); + + while ((opt = getopt(argc, argv, ":V:S:D:M:R:d:s:vmr")) != -1) { + switch (opt) { + case 'V': + volume = strtof(optarg, nullptr); + cout << "Set Volume : " << volume << endl; + result = audioSystemMgr->SetVolume(static_cast(streamType), + volume); + cout << "Set Volume Result: " << result << endl; + break; + case 'v': + volume = audioSystemMgr->GetVolume(static_cast(streamType)); + cout << "Get Volume : " << volume << endl; + break; + case 'M': + mute = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Mute : " << mute << endl; + result = audioSystemMgr->SetMute(static_cast(streamType), + (mute) ? true : false); + cout << "Set Mute Result: " << result << endl; + break; + case 'm': + muteStatus = audioSystemMgr->IsStreamMute( + static_cast(streamType)); + cout << "Get Mute : " << muteStatus << endl; + break; + case 'S': + streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Stream : " << streamType << endl; + break; + case 's': + streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Stream Active: " << audioSystemMgr->IsStreamActive( + static_cast(streamType)) << endl; + break; + case 'D': + device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Device : " << device << endl; + + if (optind < argc && *argv[optind] != '-') { + active = strtol(argv[optind], nullptr, AudioPolicyTest::OPT_ARG_BASE); + optind++; + } + cout << "Active : " << active << endl << endl; + + result = audioSystemMgr->SetDeviceActive(AudioDeviceDescriptor::DeviceType(device), + (active) ? true : false); + cout << "Set DeviceActive Result: " << result << endl; + break; + case 'd': + device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + devActiveStatus = audioSystemMgr->IsDeviceActive(AudioDeviceDescriptor::DeviceType(device)); + cout << "GetDevice Active : " << devActiveStatus << endl; + break; + case 'R': + ringMode = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Ringer Mode : " << ringMode << endl; + audioSystemMgr->SetRingerMode(static_cast(ringMode)); + break; + case 'r': + ringMode = static_cast(audioSystemMgr->GetRingerMode()); + cout << "Get Ringer Mode : " << ringMode << endl; + break; + case ':': + char option[AudioPolicyTest::OPT_SHORT_LEN]; + cout << "option "; + snprintf(option, AudioPolicyTest::OPT_SHORT_LEN, "-%c", optopt); + cout << option << " needs a value" << endl << endl; + PrintUsage(); + break; + case '?': { + char option[AudioPolicyTest::OPT_SHORT_LEN]; + snprintf(option, AudioPolicyTest::OPT_SHORT_LEN, "-%c", optopt); + cout << "unknown option: " << option << endl << endl; + PrintUsage(); + break; + } + default: + break; + } + } + + cout<<"Exit from test app"<< endl; + return 0; +} diff --git a/services/test/audio_recorder_test.cpp b/services/test/audio_recorder_test.cpp new file mode 100644 index 0000000000..5576fb1704 --- /dev/null +++ b/services/test/audio_recorder_test.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_recorder.h" +#include "media_log.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::AudioStandard; + +namespace AudioTestConstants { + constexpr int32_t SECOND_ARG_IDX = 2; + constexpr int32_t THIRD_ARG_IDX = 3; + constexpr int32_t PAUSE_BUFFER_POSITION = 512; + constexpr int32_t PAUSE_READ_TIME_SECONDS = 2; + constexpr int32_t SUCCESS = 0; +} + +class StreamRecorderTest { +public: + bool TestRecord(int argc, char *argv[]) const + { + MEDIA_INFO_LOG("TestCapture start "); + + unique_ptr audioRecorder = AudioRecorder::Create(AudioStreamType::STREAM_MUSIC); + vector supportedFormatList = audioRecorder->GetSupportedFormats(); + MEDIA_INFO_LOG("Supported formats:"); + for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { + MEDIA_INFO_LOG("Format %{public}d", *i); + } + + vector supportedChannelList = audioRecorder->GetSupportedChannels(); + MEDIA_INFO_LOG("Supported channels:"); + for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) { + MEDIA_INFO_LOG("channel %{public}d", *i); + } + + vector supportedEncodingTypes + = audioRecorder->GetSupportedEncodingTypes(); + MEDIA_INFO_LOG("Supported encoding types:"); + for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) { + MEDIA_INFO_LOG("encoding type %{public}d", *i); + } + + vector supportedSamplingRates = audioRecorder->GetSupportedSamplingRates(); + MEDIA_INFO_LOG("Supported sampling rates:"); + for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { + MEDIA_INFO_LOG("sampling rate %{public}d", *i); + } + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = static_cast(atoi(argv[AudioTestConstants::SECOND_ARG_IDX])); + recorderParams.audioChannel = AudioChannel::STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + if (audioRecorder->SetParams(recorderParams) != AudioTestConstants::SUCCESS) { + MEDIA_ERR_LOG("Set audio stream parameters failed"); + audioRecorder->Release(); + return false; + } + MEDIA_INFO_LOG("Record stream created"); + + MEDIA_INFO_LOG("Starting Stream"); + if (!audioRecorder->Start()) { + MEDIA_ERR_LOG("Start stream failed"); + audioRecorder->Release(); + return false; + } + MEDIA_INFO_LOG("Recording started"); + + MEDIA_INFO_LOG("Get Audio parameters:"); + AudioRecorderParams getRecorderParams; + if (audioRecorder->GetParams(getRecorderParams) == AudioTestConstants::SUCCESS) { + MEDIA_INFO_LOG("Get Audio format: %{public}d", getRecorderParams.audioSampleFormat); + MEDIA_INFO_LOG("Get Audio sampling rate: %{public}d", getRecorderParams.samplingRate); + MEDIA_INFO_LOG("Get Audio channels: %{public}d", getRecorderParams.audioChannel); + } + + size_t bufferLen; + if (audioRecorder->GetBufferSize(bufferLen) < 0) { + MEDIA_ERR_LOG(" GetMinimumBufferSize failed"); + return false; + } + MEDIA_INFO_LOG("Buffer size: %{public}d", bufferLen); + + uint32_t frameCount; + if (audioRecorder->GetFrameCount(frameCount) < 0) { + MEDIA_ERR_LOG(" GetMinimumFrameCount failed"); + return false; + } + MEDIA_INFO_LOG("Frame count: %{public}d", frameCount); + + bool isBlocking = (atoi(argv[AudioTestConstants::THIRD_ARG_IDX]) == 1); + MEDIA_INFO_LOG("Is blocking read: %{public}s", isBlocking ? "true" : "false"); + + uint8_t* buffer = nullptr; + buffer = (uint8_t *) malloc(bufferLen); + FILE *pFile = fopen(argv[AudioTestConstants::SECOND_ARG_IDX - 1], "wb"); + + size_t size = 1; + size_t numBuffersToRecord = 1024; + int32_t bytesRead = 0; + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlocking); + MEDIA_INFO_LOG("Bytes read: %{public}d", bytesRead); + if (bytesRead < 0) { + break; + } + if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, pFile); + numBuffersToRecord--; + MEDIA_INFO_LOG("Number of buffers to record: %{public}d", numBuffersToRecord); + if ((numBuffersToRecord == AudioTestConstants::PAUSE_BUFFER_POSITION) + && (audioRecorder->Stop())) { + MEDIA_INFO_LOG("Audio record stopped for 2 seconds"); + sleep(AudioTestConstants::PAUSE_READ_TIME_SECONDS); + MEDIA_INFO_LOG("Audio record resume"); + if (!audioRecorder->Start()) { + MEDIA_ERR_LOG("resume stream failed"); + audioRecorder->Release(); + return false; + } + } + } + } + + Timestamp timestamp; + if (audioRecorder->GetAudioTime(timestamp, Timestamp::Timestampbase::MONOTONIC)) { + MEDIA_INFO_LOG("Timestamp seconds: %{public}ld", timestamp.time.tv_sec); + MEDIA_INFO_LOG("Timestamp nanoseconds: %{public}ld", timestamp.time.tv_nsec); + } + + fflush(pFile); + if(!audioRecorder->Flush()) { + MEDIA_ERR_LOG("AudioRecorderTest: flush failed"); + } + + if(!audioRecorder->Stop()) { + MEDIA_ERR_LOG("AudioRecorderTest: Stop failed"); + } + + if(!audioRecorder->Release()) { + MEDIA_ERR_LOG("AudioRecorderTest: Release failed"); + } + free(buffer); + fclose(pFile); + MEDIA_INFO_LOG("TestCapture end"); + + return true; + } +}; + +int main(int argc, char *argv[]) +{ + MEDIA_INFO_LOG("capture test in"); + + if ((argv == nullptr) || (argc <= AudioTestConstants::THIRD_ARG_IDX)) { + MEDIA_ERR_LOG("argv is null"); + return 0; + } + + MEDIA_INFO_LOG("argc=%d", argc); + MEDIA_INFO_LOG("argv[1]=%{public}s", argv[1]); + MEDIA_INFO_LOG("argv[2]=%{public}s", argv[AudioTestConstants::SECOND_ARG_IDX]); + MEDIA_INFO_LOG("argv[3]=%{public}s", argv[AudioTestConstants::THIRD_ARG_IDX]); + + StreamRecorderTest testObj; + bool ret = testObj.TestRecord(argc, argv); + + return ret; +} diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp new file mode 100644 index 0000000000..9679c2c662 --- /dev/null +++ b/services/test/audio_renderer_test.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_renderer.h" +#include "media_log.h" +#include "pcm2wav.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::AudioStandard; + +namespace AudioTestConstants { + constexpr int32_t SECOND_ARG_IDX = 2; + constexpr int32_t SUCCESS = 0; +} + +class AudioRendererTest { +public: + bool TestPlayback(int argc, char *argv[]) const + { + MEDIA_INFO_LOG("AudioRendererTest: TestPlayback start "); + + wav_hdr wavHeader; + size_t headerSize = sizeof(wav_hdr); + FILE* wavFile = fopen(argv[1], "rb"); + if (wavFile == nullptr) { + MEDIA_INFO_LOG("AudioRendererTest: Unable to open wave file"); + return false; + } + size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); + MEDIA_INFO_LOG("AudioRendererTest: Header Read in bytes %{public}d", bytesRead); + + AudioStreamType streamType = AudioStreamType::STREAM_MUSIC; + if (argc > 2) + streamType = static_cast(strtol(argv[AudioTestConstants::SECOND_ARG_IDX], NULL, 10)); + unique_ptr audioRenderer = AudioRenderer::Create(streamType); + + vector supportedFormatList = audioRenderer->GetSupportedFormats(); + MEDIA_INFO_LOG("AudioRendererTest: Supported formats:"); + for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { + MEDIA_INFO_LOG("AudioRendererTest: Format %{public}d", *i); + } + + vector supportedChannelList = audioRenderer->GetSupportedChannels(); + MEDIA_INFO_LOG("AudioRendererTest: Supported channels:"); + for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) { + MEDIA_INFO_LOG("AudioRendererTest: channel %{public}d", *i); + } + + vector supportedEncodingTypes + = audioRenderer->GetSupportedEncodingTypes(); + MEDIA_INFO_LOG("AudioRendererTest: Supported encoding types:"); + for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) { + MEDIA_INFO_LOG("AudioRendererTest: encoding type %{public}d", *i); + } + + vector supportedSamplingRates = audioRenderer->GetSupportedSamplingRates(); + MEDIA_INFO_LOG("AudioRendererTest: Supported sampling rates:"); + for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { + MEDIA_INFO_LOG("AudioRendererTest: sampling rate %{public}d", *i); + } + + AudioRendererParams rendererParams; + rendererParams.sampleFormat = static_cast(wavHeader.bitsPerSample); + rendererParams.sampleRate = static_cast(wavHeader.SamplesPerSec); + rendererParams.channelCount = static_cast(wavHeader.NumOfChan); + rendererParams.encodingType = static_cast(ENCODING_PCM); + if (audioRenderer->SetParams(rendererParams) != AudioTestConstants::SUCCESS) { + MEDIA_ERR_LOG("AudioRendererTest: Set audio renderer parameters failed"); + if(!audioRenderer->Release()) { + MEDIA_ERR_LOG("AudioRendererTest: Release failed"); + } + return false; + } + MEDIA_INFO_LOG("AudioRendererTest: Playback renderer created"); + + MEDIA_INFO_LOG("AudioRendererTest: Starting renderer"); + if (!audioRenderer->Start()) { + MEDIA_ERR_LOG("AudioRendererTest: Start failed"); + if(!audioRenderer->Release()) { + MEDIA_ERR_LOG("AudioRendererTest: Release failed"); + } + return false; + } + MEDIA_INFO_LOG("AudioRendererTest: Playback started"); + + MEDIA_INFO_LOG("AudioRendererTest: Get Audio parameters:"); + AudioRendererParams paRendererParams; + if (audioRenderer->GetParams(paRendererParams) == AudioTestConstants::SUCCESS) { + MEDIA_INFO_LOG("AudioRendererTest: Get Audio format: %{public}d", paRendererParams.sampleFormat); + MEDIA_INFO_LOG("AudioRendererTest: Get Audio sampling rate: %{public}d", paRendererParams.sampleRate); + MEDIA_INFO_LOG("AudioRendererTest: Get Audio channels: %{public}d", paRendererParams.channelCount); + } + else { + MEDIA_ERR_LOG("AudioRendererTest: Get Audio parameters failed"); + } + size_t bufferLen; + if (audioRenderer->GetBufferSize(bufferLen)) { + MEDIA_ERR_LOG("AudioRendererTest: GetMinimumBufferSize failed"); + return false; + } + MEDIA_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen); + + uint32_t frameCount; + if (audioRenderer->GetFrameCount(frameCount)) { + MEDIA_ERR_LOG("AudioRendererTest: GetMinimumFrameCount failed"); + return false; + } + MEDIA_INFO_LOG("AudioRendererTest: Frame count: %{public}d", frameCount); + + uint8_t* buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + MEDIA_INFO_LOG("AudioRendererTest: Bytes to write: %{public}d", bytesToWrite); + + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + bytesWritten += audioRenderer->Write(buffer + bytesWritten, + bytesToWrite - bytesWritten); + MEDIA_INFO_LOG("AudioRendererTest: Bytes written: %{public}d", bytesWritten); + } + } + + if(!audioRenderer->Drain()) { + MEDIA_ERR_LOG("AudioRendererTest: Drain failed"); + } + Timestamp timeStamp; + if (audioRenderer->GetAudioTime(timeStamp, Timestamp::Timestampbase::MONOTONIC)) { + MEDIA_INFO_LOG("AudioRendererTest: Timestamp seconds: %{public}ld", timeStamp.time.tv_sec); + MEDIA_INFO_LOG("AudioRendererTest: Timestamp nanoseconds: %{public}ld", timeStamp.time.tv_nsec); + } + + if(!audioRenderer->Stop()) { + MEDIA_ERR_LOG("AudioRendererTest: Stop failed"); + } + + if(!audioRenderer->Release()) { + MEDIA_ERR_LOG("AudioRendererTest: Release failed"); + } + + free(buffer); + fclose(wavFile); + MEDIA_INFO_LOG("AudioRendererTest: TestPlayback end"); + + return true; + } +}; + +int main(int argc, char *argv[]) +{ + MEDIA_INFO_LOG("AudioRendererTest: Render test in"); + + if ((argv == nullptr) || (argc < AudioTestConstants::SECOND_ARG_IDX)) { + MEDIA_ERR_LOG("AudioRendererTest: argv is null"); + return 0; + } + + MEDIA_INFO_LOG("AudioRendererTest: argc=%d", argc); + MEDIA_INFO_LOG("AudioRendererTest: argv[1]=%{public}s", argv[1]); + + AudioRendererTest testObj; + bool ret = testObj.TestPlayback(argc, argv); + + return ret; +} diff --git a/services/test/pcm2wav.h b/services/test/pcm2wav.h new file mode 100644 index 0000000000..29f8accb3f --- /dev/null +++ b/services/test/pcm2wav.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 PCM_2_WAV_H +#define PCM_2_WAV_H +typedef struct WAV_HEADER { + /* RIFF Chunk Descriptor */ + uint8_t RIFF[4] = {'R', 'I', 'F', 'F'}; // RIFF Header Magic header + uint32_t ChunkSize; // RIFF Chunk Size + uint8_t WAVE[4] = {'W', 'A', 'V', 'E'}; // WAVE Header + /* "fmt" sub-chunk */ + uint8_t fmt[4] = {'f', 'm', 't', ' '}; // FMT header + uint32_t Subchunk1Size = 16; // Size of the fmt chunk + uint16_t AudioFormat = 1; // Audio format 1=PCM + uint16_t NumOfChan = 2; // Number of channels 1=Mono 2=Sterio + uint32_t SamplesPerSec = 44100; // Sampling Frequency in Hz + uint32_t bytesPerSec = 176400; // bytes per second + uint16_t blockAlign = 2; // 2=16-bit mono, 4=16-bit stereo + uint16_t bitsPerSample = 16; // Number of bits per sample + /* "data" sub-chunk */ + uint8_t Subchunk2ID[4] = {'d', 'a', 't', 'a'}; // "data" string + uint32_t Subchunk2Size; // Sampled data length +} wav_hdr; +#endif // PCM_2_WAV_H \ No newline at end of file diff --git a/services/test/playback_test.cpp b/services/test/playback_test.cpp new file mode 100644 index 0000000000..2fb09a8272 --- /dev/null +++ b/services/test/playback_test.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_service_client.h" +#include "audio_system_manager.h" +#include "media_log.h" +#include "pcm2wav.h" + +using namespace OHOS::AudioStandard; + +namespace { +constexpr uint8_t DEFAULT_FORMAT = SAMPLE_S16LE; +constexpr uint8_t DEFAULT_CHANNELS = 2; +} // namespace + +class PlaybackTest : public AudioRendererCallbacks { +public: + void OnSinkDeviceUpdatedCb() const + { + MEDIA_INFO_LOG("My custom callback OnSinkDeviceUpdatedCb"); + } + virtual void OnStreamStateChangeCb() const + { + MEDIA_INFO_LOG("My custom callback OnStreamStateChangeCb"); + } + + virtual void OnStreamBufferUnderFlowCb() const{} + virtual void OnStreamBufferOverFlowCb() const{} + virtual void OnErrorCb(AudioServiceErrorCodes error) const{} + virtual void OnEventCb(AudioServiceEventTypes error) const{} +}; + +int main(int argc, char* argv[]) +{ + wav_hdr wavHeader; + size_t headerSize = sizeof(wav_hdr); + FILE* wavFile = fopen(argv[1], "rb"); + if (wavFile == nullptr) { + fprintf(stderr, "Unable to open wave file"); + return -1; + } + + float volume = 0.5; + if (argc >= 3) + volume = strtof(argv[2], nullptr); + + size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); + MEDIA_INFO_LOG("Header Read in bytes %{public}d", bytesRead); + AudioStreamParams audioParams; + audioParams.format = DEFAULT_FORMAT; + audioParams.samplingRate = wavHeader.SamplesPerSec; + audioParams.channels = DEFAULT_CHANNELS; + StreamBuffer stream; + PlaybackTest customCb; + + std::unique_ptr client = std::make_unique(); + if (client == nullptr) { + MEDIA_ERR_LOG("Create AudioServiceClient instance failed"); + return -1; + } + + MEDIA_INFO_LOG("Initializing of AudioServiceClient"); + if (client->Initialize(AUDIO_SERVICE_CLIENT_PLAYBACK) < 0) + return -1; + + client->RegisterAudioRendererCallbacks(customCb); + + MEDIA_INFO_LOG("Creating Stream"); + if (client->CreateStream(audioParams, STREAM_MUSIC) < 0) + return -1; + + MEDIA_INFO_LOG("Starting Stream"); + if (client->StartStream() < 0) + return -1; + + AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance(); + audioSystemMgr->SetVolume(AudioSystemManager::AudioVolumeType::STREAM_MUSIC, volume); + + size_t bufferLen; + if (client->GetMinimumBufferSize(bufferLen) < 0) { + MEDIA_ERR_LOG(" GetMinimumBufferSize failed"); + return -1; + } + + MEDIA_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen); + + uint8_t* buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + int32_t writeError; + uint64_t timeStamp; + + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + stream.buffer = buffer + bytesWritten; + stream.bufferLen = bytesToWrite - bytesWritten; + bytesWritten += client->WriteStream(stream, writeError); + if (client->GetCurrentTimeStamp(timeStamp) >= 0) + MEDIA_DEBUG_LOG("current timestamp: %{public}llu", timeStamp); + } + } + + client->FlushStream(); + client->StopStream(); + client->ReleaseStream(); + free(buffer); + fclose(wavFile); + MEDIA_INFO_LOG("Exit from test app"); + return 0; +} diff --git a/services/test/record_test.cpp b/services/test/record_test.cpp new file mode 100644 index 0000000000..506b8878a1 --- /dev/null +++ b/services/test/record_test.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "audio_service_client.h" +#include "media_log.h" + +using namespace OHOS::AudioStandard; + +namespace { +constexpr uint8_t DEFAULT_FORMAT = SAMPLE_S16LE; +constexpr uint8_t DEFAULT_CHANNELS = 2; +} // namespace + +class RecordTest : public AudioRecorderCallbacks { +public: + void OnSourceDeviceUpdatedCb() const + { + MEDIA_INFO_LOG("My custom callback OnSourceDeviceUpdatedCb"); + } + // Need to check required state changes to update applications + virtual void OnStreamStateChangeCb() const + { + MEDIA_INFO_LOG("My custom callback OnStreamStateChangeCb"); + } + + virtual void OnStreamBufferUnderFlowCb() const{} + virtual void OnStreamBufferOverFlowCb() const{} + virtual void OnErrorCb(AudioServiceErrorCodes error) const{} + virtual void OnEventCb(AudioServiceEventTypes error) const{} +}; + +int main(int argc, char* argv[]) +{ + int32_t rateArgIndex = 2; + + AudioStreamParams audioParams; + audioParams.format = DEFAULT_FORMAT; + audioParams.samplingRate = atoi(argv[rateArgIndex]); + audioParams.channels = DEFAULT_CHANNELS; + StreamBuffer stream; + + RecordTest customCb; + + std::unique_ptr client = std::make_unique(); + if (client == nullptr) { + MEDIA_ERR_LOG("Create AudioServiceClient instance failed"); + return -1; + } + + MEDIA_INFO_LOG("Initializing of AudioServiceClient"); + if (client->Initialize(AUDIO_SERVICE_CLIENT_RECORD) < 0) + return -1; + + client->RegisterAudioRecorderCallbacks(customCb); + + MEDIA_INFO_LOG("Creating Stream"); + if (client->CreateStream(audioParams, STREAM_MUSIC) < 0) { + client->ReleaseStream(); + return -1; + } + + MEDIA_INFO_LOG("Starting Stream"); + if (client->StartStream() < 0) + return -1; + + size_t bufferLen; + if (client->GetMinimumBufferSize(bufferLen) < 0) { + MEDIA_ERR_LOG(" GetMinimumBufferSize failed"); + return -1; + } + + MEDIA_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen); + + uint8_t* buffer = nullptr; + buffer = (uint8_t *) malloc(bufferLen); + FILE *pFile = fopen(argv[1], "wb"); + + size_t size = 1; + size_t numBuffersToRecord = 1024; + uint64_t timeStamp; + stream.buffer = buffer; + stream.bufferLen = bufferLen; + int32_t bytesRead = 0; + + while (numBuffersToRecord) { + bytesRead = client->ReadStream(stream, false); + if (bytesRead < 0) { + break; + } + + if (bytesRead > 0) { + fwrite(stream.buffer, size, bytesRead, pFile); + if (client->GetCurrentTimeStamp(timeStamp) >= 0) + MEDIA_DEBUG_LOG("current timestamp: %{public}llu", timeStamp); + numBuffersToRecord--; + } + } + + fflush(pFile); + client->FlushStream(); + client->StopStream(); + client->ReleaseStream(); + free(buffer); + fclose(pFile); + MEDIA_INFO_LOG("Exit from test app"); + return 0; +} -- Gitee From 53214aa84ae85a12078d6431fdcbabf82300743e Mon Sep 17 00:00:00 2001 From: Anurup M Date: Wed, 30 Jun 2021 20:40:19 +0530 Subject: [PATCH 02/32] Add Audio cache support for accepting lower buffer sizes Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../include/client/audio_service_client.h | 15 ++ services/src/client/audio_service_client.cpp | 162 +++++++++++++++++- 2 files changed, 171 insertions(+), 6 deletions(-) diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h index b7e7102012..aa7495c1ff 100644 --- a/services/include/client/audio_service_client.h +++ b/services/include/client/audio_service_client.h @@ -45,6 +45,14 @@ struct StreamBuffer { uint32_t bufferLen; // stream length, by bytes }; +struct AudioCache { + uint8_t *buffer; + uint32_t readIndex; + uint32_t writeIndex; + uint32_t totalCacheSize; + bool isFull; +}; + class AudioRendererCallbacks { public: virtual ~AudioRendererCallbacks(); @@ -258,6 +266,7 @@ private: pa_stream *paStream; pa_sample_spec sampleSpec; + AudioCache acache; const void* internalReadBuffer; size_t internalRdBufLen; size_t internalRdBufIndex; @@ -282,6 +291,11 @@ private: uint32_t underFlowCount; int32_t ConnectStreamToPA(); + // Audio cache related functions. These APIs are applicable only for playback scenarios + int32_t InitializeAudioCache(); + size_t WriteToAudioCache(const StreamBuffer &stream); + int32_t DrainAudioCache(); + // Error code used static const uint32_t AUDIO_CLIENT_SUCCESS = 0; static const uint32_t AUDIO_CLIENT_ERR = -1; @@ -294,6 +308,7 @@ private: // Default values + static const uint32_t MINIMUM_BUFFER_SIZE = 1024; static const uint32_t DEFAULT_SAMPLING_RATE = 44100; static const uint8_t DEFAULT_CHANNEL_COUNT = 2; static const uint8_t DEFAULT_SAMPLE_SIZE = 2; diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index 9c0cda5636..d5ea15865d 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -210,6 +210,12 @@ AudioServiceClient::AudioServiceClient() internalRdBufIndex = 0; internalRdBufLen = 0; underFlowCount = 0; + + acache.readIndex = 0; + acache.writeIndex = 0; + acache.isFull = false; + acache.totalCacheSize = 0; + acache.buffer = NULL; } void AudioServiceClient::ResetPAAudioClient() @@ -261,6 +267,16 @@ void AudioServiceClient::ResetPAAudioClient() internalRdBufIndex = 0; internalRdBufLen = 0; underFlowCount = 0; + + if (acache.buffer) { + free(acache.buffer); + } + + acache.buffer = NULL; + acache.readIndex = 0; + acache.writeIndex = 0; + acache.isFull = false; + acache.totalCacheSize = 0; } AudioServiceClient::~AudioServiceClient() @@ -424,6 +440,21 @@ int32_t AudioServiceClient::ConnectStreamToPA() return AUDIO_CLIENT_SUCCESS; } +int32_t AudioServiceClient::InitializeAudioCache() +{ + MEDIA_INFO_LOG("Initializing internal audio cache"); + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(paStream); + + acache.buffer = (uint8_t *) malloc(bufferAttr->minreq); + acache.readIndex = 0; + acache.writeIndex = 0; + acache.totalCacheSize = bufferAttr->minreq; + acache.isFull = false; + return AUDIO_CLIENT_SUCCESS; +} + int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStreamType audioType) { int error; @@ -472,6 +503,10 @@ int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStr return AUDIO_CLIENT_CREATE_STREAM_ERR; } + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + InitializeAudioCache(); + } + MEDIA_INFO_LOG("Created Stream"); return AUDIO_CLIENT_SUCCESS; } @@ -588,6 +623,13 @@ int32_t AudioServiceClient::FlushStream() int32_t AudioServiceClient::DrainStream() { int error; + + error = DrainAudioCache(); + if (error != AUDIO_CLIENT_SUCCESS) { + MEDIA_ERR_LOG("Audio cache drain failed"); + return AUDIO_CLIENT_ERR; + } + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); pa_operation *operation = NULL; @@ -624,16 +666,101 @@ int32_t AudioServiceClient::SetStreamVolume(uint32_t sessionID, uint32_t volume) return AUDIO_CLIENT_SUCCESS; } +int32_t AudioServiceClient::DrainAudioCache() +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_threaded_mainloop_lock(mainLoop); + + int32_t error; + size_t length = acache.writeIndex - acache.readIndex; + const uint8_t *buffer = acache.buffer; + + while (length > 0) { + size_t writableSize; + + while (!(writableSize = pa_stream_writable_size(paStream))) { + pa_threaded_mainloop_wait(mainLoop); + } + + if (writableSize > length) { + writableSize = length; + } + + writableSize = AlignToAudioFrameSize(writableSize, sampleSpec); + if (writableSize == 0) { + break; + } + + error = pa_stream_write(paStream, (void *)buffer, writableSize, NULL, 0LL, PA_SEEK_RELATIVE); + if (error < 0) { + break; + } + + MEDIA_INFO_LOG("writable size: %{public}zu bytes to write: %{public}zu return val: %{public}d", writableSize, length, error); + + buffer = (const uint8_t *)buffer + writableSize; + length -= writableSize; + acache.readIndex += writableSize; + acache.isFull = false; + } + + acache.readIndex = 0; + acache.writeIndex = 0; + acache.isFull = false; + + pa_threaded_mainloop_unlock(mainLoop); + return error; +} + +size_t AudioServiceClient::WriteToAudioCache(const StreamBuffer &stream) +{ + const uint8_t *inputBuffer = stream.buffer; + uint8_t *cacheBuffer = acache.buffer + acache.writeIndex; + + size_t inputLen = stream.bufferLen; + + while (inputLen > 0) { + size_t writableSize = acache.totalCacheSize - acache.writeIndex; + + if (writableSize > inputLen) { + writableSize = inputLen; + } + + if (writableSize == 0) { + break; + } + + memcpy_s(cacheBuffer, acache.totalCacheSize, (const uint8_t *)inputBuffer, writableSize); + + inputBuffer = (const uint8_t *)inputBuffer + writableSize; + cacheBuffer = cacheBuffer + writableSize; + inputLen -= writableSize; + acache.writeIndex += writableSize; + } + + if ((acache.writeIndex - acache.readIndex) == acache.totalCacheSize) { + acache.isFull = true; + } + + return (stream.bufferLen - inputLen); +} + size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pError) { - const uint8_t* buffer = stream.buffer; - size_t length = stream.bufferLen; int error = 0; + size_t cachedLen = WriteToAudioCache(stream); - CHECK_PA_STATUS_FOR_WRITE(mainLoop, context, paStream, pError, 0); + if (!acache.isFull) { + pError = error; + return cachedLen; + } + CHECK_PA_STATUS_FOR_WRITE(mainLoop, context, paStream, pError, 0); pa_threaded_mainloop_lock(mainLoop); + const uint8_t *buffer = acache.buffer; + size_t length = acache.totalCacheSize; + while (length > 0) { size_t writableSize; @@ -641,6 +768,7 @@ size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pErr pa_threaded_mainloop_wait(mainLoop); } + MEDIA_INFO_LOG("WriteStream writableSize = %{public}zu length = %{public}zu", writableSize, length); if (writableSize > length) writableSize = length; @@ -658,11 +786,33 @@ size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pErr buffer = (const uint8_t*) buffer + writableSize; length -= writableSize; + acache.readIndex += writableSize; + acache.isFull = false; + } + + if ((length >= 0) && !acache.isFull) { + uint8_t *cacheBuffer = acache.buffer; + uint32_t offset = acache.readIndex; + uint32_t size = (acache.writeIndex - acache.readIndex); + if (size > 0) { + memcpy_s(cacheBuffer, acache.totalCacheSize, (const uint8_t *)cacheBuffer + offset, size); + MEDIA_INFO_LOG("rearranging the audio cache"); + } + acache.readIndex = 0; + acache.writeIndex = 0; + + if (cachedLen < stream.bufferLen) { + StreamBuffer str; + str.buffer = stream.buffer + cachedLen; + str.bufferLen = stream.bufferLen - cachedLen; + MEDIA_INFO_LOG("writing pending data to audio cache: %{public}d", str.bufferLen); + cachedLen += WriteToAudioCache(str); + } } pa_threaded_mainloop_unlock(mainLoop); pError = error; - return (stream.bufferLen - length); + return cachedLen; } int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) @@ -749,7 +899,7 @@ int32_t AudioServiceClient::GetMinimumBufferSize(size_t &minBufferSize) } if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { - minBufferSize = (size_t) bufferAttr->minreq; + minBufferSize = (size_t) MINIMUM_BUFFER_SIZE; } if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { @@ -773,7 +923,7 @@ int32_t AudioServiceClient::GetMinimumFrameCount(uint32_t &frameCount) } if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { - minBufferSize = (size_t) bufferAttr->minreq; + minBufferSize = (size_t) MINIMUM_BUFFER_SIZE; } if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { -- Gitee From 2c26d904addfce7d4f2d087ecd66e87b524d6f58 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Thu, 1 Jul 2021 12:58:45 +0530 Subject: [PATCH 03/32] Fix compilation errors when using musl lib Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../native/audiocommon/include/audio_info.h | 6 +- pulseaudio/src/BUILD.gn | 6 +- pulseaudio/src/daemon/BUILD.gn | 30 +- pulseaudio/src/pulse/BUILD.gn | 2 +- pulseaudio/src/pulse/ohos_pa_volume.c | 1007 +++++++++++++++++ services/src/server/audio_server.cpp | 13 - 6 files changed, 1031 insertions(+), 33 deletions(-) create mode 100644 pulseaudio/src/pulse/ohos_pa_volume.c diff --git a/interfaces/innerkits/native/audiocommon/include/audio_info.h b/interfaces/innerkits/native/audiocommon/include/audio_info.h index 392a15e782..9d2a4a5c3d 100644 --- a/interfaces/innerkits/native/audiocommon/include/audio_info.h +++ b/interfaces/innerkits/native/audiocommon/include/audio_info.h @@ -15,6 +15,11 @@ #ifndef AUDIO_INFO_H #define AUDIO_INFO_H +#ifdef __MUSL__ +#include +#include +#endif // __MUSL__ + #include namespace OHOS { @@ -223,7 +228,6 @@ public: }; }; typedef void* AudioIOHandle; - } // namespace AudioStandard } // namespace OHOS #endif // AUDIO_INFO_H diff --git a/pulseaudio/src/BUILD.gn b/pulseaudio/src/BUILD.gn index 13c67f5ec9..1876f93574 100644 --- a/pulseaudio/src/BUILD.gn +++ b/pulseaudio/src/BUILD.gn @@ -23,9 +23,11 @@ config("pulsecommon_config") { include_dirs = [ "$pulseaudio_dir/src", "$pulseaudio_dir/include", - "$pulseaudio_build_path", + "$pulseaudio_dir", "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", "$libsndfile_build_path/include", + "$pulseaudio_dir/src/pulse", ] cflags = [ @@ -54,7 +56,7 @@ ohos_source_set("pulsecommon_sources") { "$pulseaudio_dir/src/pulse/util.c", "$pulseaudio_dir/src/pulse/timeval.c", "$pulseaudio_dir/src/pulse/rtclock.c", - "$pulseaudio_dir/src/pulse/volume.c", + "$pulseaudio_build_path/src/pulse/ohos_pa_volume.c", "$pulseaudio_dir/src/pulsecore/authkey.c", "$pulseaudio_dir/src/pulsecore/conf-parser.c", "$pulseaudio_dir/src/pulsecore/core-error.c", diff --git a/pulseaudio/src/daemon/BUILD.gn b/pulseaudio/src/daemon/BUILD.gn index 34e167d9d4..e72361f3ce 100644 --- a/pulseaudio/src/daemon/BUILD.gn +++ b/pulseaudio/src/daemon/BUILD.gn @@ -13,19 +13,17 @@ import("//build/ohos.gni") -pulseaudio_dir = "//foundation/multimedia/audio_standard/pulseaudio" -pulseaudio_src_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//third_party/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_dir = "//third_party/pulseaudio" config("daemon_config") { visibility = [ ":*" ] include_dirs = [ - "$pulseaudio_dir/include", - "$pulseaudio_src_dir/src/daemon", - "$pulseaudio_src_dir/src", - "$pulseaudio_build_path", - "$pulseaudio_build_path/src", + "$pulseaudio_build_path/include", + "$pulseaudio_dir/src/daemon", + "$pulseaudio_dir/src", + "$pulseaudio_dir", ] cflags = [ @@ -39,11 +37,11 @@ config("daemon_config") { ohos_source_set("pulseaudio_sources") { sources = [ - "$pulseaudio_src_dir/src/daemon/caps.c", - "$pulseaudio_src_dir/src/daemon/cmdline.c", - "$pulseaudio_src_dir/src/daemon/cpulimit.c", - "$pulseaudio_dir/src/daemon/ohos_daemon-conf.c", - "$pulseaudio_dir/src/daemon/ohos_pa_main.c", + "$pulseaudio_dir/src/daemon/caps.c", + "$pulseaudio_dir/src/daemon/cmdline.c", + "$pulseaudio_dir/src/daemon/cpulimit.c", + "$pulseaudio_build_path/src/daemon/ohos_daemon-conf.c", + "$pulseaudio_build_path/src/daemon/ohos_pa_main.c", ] configs = [ ":daemon_config" ] @@ -53,9 +51,9 @@ ohos_shared_library("pulseaudio") { ldflags = [ "-ffast-math" ] deps = [ ":pulseaudio_sources", - "$pulseaudio_dir/src/pulse:pulse", - "$pulseaudio_dir/src/pulsecore:pulsecore", - "$pulseaudio_dir/src:pulsecommon", + "$pulseaudio_build_path/src/pulse:pulse", + "$pulseaudio_build_path/src/pulsecore:pulsecore", + "$pulseaudio_build_path/src:pulsecommon", ] part_name = "multimedia_audio_standard" diff --git a/pulseaudio/src/pulse/BUILD.gn b/pulseaudio/src/pulse/BUILD.gn index fddf966aff..08c1f4ca6b 100644 --- a/pulseaudio/src/pulse/BUILD.gn +++ b/pulseaudio/src/pulse/BUILD.gn @@ -66,7 +66,7 @@ ohos_source_set("pulse_sources") { "$pulseaudio_dir/src/pulse/timeval.c", "$pulseaudio_dir/src/pulse/utf8.c", "$pulseaudio_dir/src/pulse/util.c", - "$pulseaudio_dir/src/pulse/volume.c", + "$pulseaudio_build_path/src/pulse/ohos_pa_volume.c", "$pulseaudio_dir/src/pulse/xmalloc.c", ] diff --git a/pulseaudio/src/pulse/ohos_pa_volume.c b/pulseaudio/src/pulse/ohos_pa_volume.c new file mode 100644 index 0000000000..88feeff22f --- /dev/null +++ b/pulseaudio/src/pulse/ohos_pa_volume.c @@ -0,0 +1,1007 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include "volume.h" + +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { + int i; + pa_assert(a); + pa_assert(b); + + pa_return_val_if_fail(pa_cvolume_valid(a), 0); + + if (PA_UNLIKELY(a == b)) + return 1; + + pa_return_val_if_fail(pa_cvolume_valid(b), 0); + + if (a->channels != b->channels) + return 0; + + for (i = 0; i < a->channels; i++) + if (a->values[i] != b->values[i]) + return 0; + + return 1; +} + +pa_cvolume* pa_cvolume_init(pa_cvolume *a) { + unsigned c; + + pa_assert(a); + + a->channels = 0; + + for (c = 0; c < PA_CHANNELS_MAX; c++) + a->values[c] = PA_VOLUME_INVALID; + + return a; +} + +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { + int i; + + pa_assert(a); + pa_assert(pa_channels_valid(channels)); + + a->channels = (uint8_t) channels; + + for (i = 0; i < a->channels; i++) + /* Clamp in case there is stale data that exceeds the current + * PA_VOLUME_MAX */ + a->values[i] = PA_CLAMP_VOLUME(v); + + return a; +} + +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { + uint64_t sum = 0; + unsigned c; + + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) + sum += a->values[c]; + + sum /= a->channels; + + return (pa_volume_t) sum; +} + +pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { + uint64_t sum = 0; + unsigned c, n; + + pa_assert(a); + + if (!cm) + return pa_cvolume_avg(a); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); + + for (c = n = 0; c < a->channels; c++) { + + if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) + continue; + + sum += a->values[c]; + n ++; + } + + if (n > 0) + sum /= n; + + return (pa_volume_t) sum; +} + +pa_volume_t pa_cvolume_max(const pa_cvolume *a) { + pa_volume_t m = PA_VOLUME_MUTED; + unsigned c; + + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) + if (a->values[c] > m) + m = a->values[c]; + + return m; +} + +pa_volume_t pa_cvolume_min(const pa_cvolume *a) { + pa_volume_t m = PA_VOLUME_MAX; + unsigned c; + + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) + if (a->values[c] < m) + m = a->values[c]; + + return m; +} + +pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { + pa_volume_t m = PA_VOLUME_MUTED; + unsigned c; + + pa_assert(a); + + if (!cm) + return pa_cvolume_max(a); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) { + + if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) + continue; + + if (a->values[c] > m) + m = a->values[c]; + } + + return m; +} + +pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { + pa_volume_t m = PA_VOLUME_MAX; + unsigned c; + + pa_assert(a); + + if (!cm) + return pa_cvolume_min(a); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) { + + if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) + continue; + + if (a->values[c] < m) + m = a->values[c]; + } + + return m; +} + +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { + uint64_t result; + + pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); + + /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ + + result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM; + + if (result > (uint64_t)PA_VOLUME_MAX) + pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); + + return (pa_volume_t) PA_CLAMP_VOLUME(result); +} + +pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { + uint64_t result; + + pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); + + if (b <= PA_VOLUME_MUTED) + return 0; + + result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b; + + if (result > (uint64_t)PA_VOLUME_MAX) + pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); + + return (pa_volume_t) PA_CLAMP_VOLUME(result); +} + +/* Amplitude, not power */ +static double linear_to_dB(double v) { + return 20.0 * log10(v); +} + +static double dB_to_linear(double v) { + return pow(10.0, v / 20.0); +} + +pa_volume_t pa_sw_volume_from_dB(double dB) { +#ifdef __MUSL__ + if (dB == -INFINITY || dB <= PA_DECIBEL_MININFTY) + return PA_VOLUME_MUTED; +#else + if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY) + return PA_VOLUME_MUTED; +#endif // __MUSL__ + + return pa_sw_volume_from_linear(dB_to_linear(dB)); +} + +double pa_sw_volume_to_dB(pa_volume_t v) { + + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY); + + if (v <= PA_VOLUME_MUTED) + return PA_DECIBEL_MININFTY; + + return linear_to_dB(pa_sw_volume_to_linear(v)); +} + +pa_volume_t pa_sw_volume_from_linear(double v) { + + if (v <= 0.0) + return PA_VOLUME_MUTED; + + /* + * We use a cubic mapping here, as suggested and discussed here: + * + * http://www.robotplanet.dk/audio/audio_gui_design/ + * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151 + * + * We make sure that the conversion to linear and back yields the + * same volume value! That's why we need the lround() below! + */ + + return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM)); +} + +double pa_sw_volume_to_linear(pa_volume_t v) { + double f; + + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0); + + if (v <= PA_VOLUME_MUTED) + return 0.0; + + if (v == PA_VOLUME_NORM) + return 1.0; + + f = ((double) v / PA_VOLUME_NORM); + + return f*f*f; +} + +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { + unsigned channel; + bool first = true; + char *e; + + pa_assert(s); + pa_assert(l > 0); + pa_assert(c); + + pa_init_i18n(); + + if (!pa_cvolume_valid(c)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + *(e = s) = 0; + + for (channel = 0; channel < c->channels && l > 1; channel++) { + l -= pa_snprintf(e, l, "%s%u: %3u%%", + first ? "" : " ", + channel, + (unsigned)(((uint64_t)c->values[channel] * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); + + e = strchr(e, 0); + first = false; + } + + return s; +} + +char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { + pa_assert(s); + pa_assert(l > 0); + + pa_init_i18n(); + + if (!PA_VOLUME_IS_VALID(v)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + pa_snprintf(s, l, "%3u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); + return s; +} + +char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) { + unsigned channel; + bool first = true; + char *e; + + pa_assert(s); + pa_assert(l > 0); + pa_assert(c); + + pa_init_i18n(); + + if (!pa_cvolume_valid(c)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + *(e = s) = 0; + + for (channel = 0; channel < c->channels && l > 1; channel++) { + double f = pa_sw_volume_to_dB(c->values[channel]); + +#ifdef __MUSL__ + l -= pa_snprintf(e, l, "%s%u: %0.2f dB", + first ? "" : " ", + channel, + f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); +#else + l -= pa_snprintf(e, l, "%s%u: %0.2f dB", + first ? "" : " ", + channel, + isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); +#endif // __MUSL__ + + e = strchr(e, 0); + first = false; + } + + return s; +} + +char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) { + char *current = s; + bool first = true; + + pa_assert(s); + pa_assert(l > 0); + pa_assert(c); + + pa_init_i18n(); + + if (!pa_cvolume_valid(c)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + pa_assert(!map || (map->channels == c->channels)); + pa_assert(!map || pa_channel_map_valid(map)); + + current[0] = 0; + + for (unsigned channel = 0; channel < c->channels && l > 1; channel++) { + char channel_position[32]; + size_t bytes_printed; + char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX]; + + if (map) + pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel])); + else + pa_snprintf(channel_position, sizeof(channel_position), "%u", channel); + + bytes_printed = pa_snprintf(current, l, "%s%s: %s", + first ? "" : ", ", + channel_position, + pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB)); + l -= bytes_printed; + current += bytes_printed; + first = false; + } + + return s; +} + +char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { + double f; + + pa_assert(s); + pa_assert(l > 0); + + pa_init_i18n(); + + if (!PA_VOLUME_IS_VALID(v)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + f = pa_sw_volume_to_dB(v); +#ifdef __MUSL__ + pa_snprintf(s, l, "%0.2f dB", f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); +#else + pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); +#endif // __MUSL__ + + return s; +} + +char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) { + char dB[PA_SW_VOLUME_SNPRINT_DB_MAX]; + + pa_assert(s); + pa_assert(l > 0); + + pa_init_i18n(); + + if (!PA_VOLUME_IS_VALID(v)) { + pa_snprintf(s, l, _("(invalid)")); + return s; + } + + pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s", + v, + (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM), + print_dB ? " / " : "", + print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : ""); + + return s; +} + +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { + unsigned c; + pa_assert(a); + + pa_return_val_if_fail(pa_cvolume_valid(a), 0); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); + + for (c = 0; c < a->channels; c++) + if (a->values[c] != v) + return 0; + + return 1; +} + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + pa_assert(b); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(pa_cvolume_valid(b), NULL); + + dest->channels = PA_MIN(a->channels, b->channels); + + for (i = 0; i < dest->channels; i++) + dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]); + + return dest; +} + +pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); + + for (i = 0; i < a->channels; i++) + dest->values[i] = pa_sw_volume_multiply(a->values[i], b); + + dest->channels = (uint8_t) i; + + return dest; +} + +pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + pa_assert(b); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(pa_cvolume_valid(b), NULL); + + dest->channels = PA_MIN(a->channels, b->channels); + + for (i = 0; i < dest->channels; i++) + dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]); + + return dest; +} + +pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); + + for (i = 0; i < a->channels; i++) + dest->values[i] = pa_sw_volume_divide(a->values[i], b); + + dest->channels = (uint8_t) i; + + return dest; +} + +int pa_cvolume_valid(const pa_cvolume *v) { + unsigned c; + + pa_assert(v); + + if (!pa_channels_valid(v->channels)) + return 0; + + for (c = 0; c < v->channels; c++) + if (!PA_VOLUME_IS_VALID(v->values[c])) + return 0; + + return 1; +} + +static bool on_left(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT); +} + +static bool on_right(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT); +} + +static bool on_center(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER); +} + +static bool on_hfe(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_HFE); +} + +static bool on_lfe(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LFE); +} + +static bool on_front(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT); +} + +static bool on_rear(pa_channel_position_t p) { + return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR); +} + +pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { + int a, b; + pa_cvolume result; + + pa_assert(v); + pa_assert(from); + pa_assert(to); + + pa_return_val_if_fail(pa_channel_map_valid(to), NULL); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); + + if (pa_channel_map_equal(from, to)) + return v; + + result.channels = to->channels; + + for (b = 0; b < to->channels; b++) { + pa_volume_t k = 0; + int n = 0; + + for (a = 0; a < from->channels; a++) + if (from->map[a] == to->map[b]) { + k += v->values[a]; + n ++; + } + + if (n <= 0) { + for (a = 0; a < from->channels; a++) + if ((on_left(from->map[a]) && on_left(to->map[b])) || + (on_right(from->map[a]) && on_right(to->map[b])) || + (on_center(from->map[a]) && on_center(to->map[b])) || + (on_lfe(from->map[a]) && on_lfe(to->map[b]))) { + + k += v->values[a]; + n ++; + } + } + + if (n <= 0) + k = pa_cvolume_avg(v); + else + k /= n; + + result.values[b] = k; + } + + *v = result; + return v; +} + +int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { + + pa_assert(v); + pa_assert(ss); + + pa_return_val_if_fail(pa_cvolume_valid(v), 0); + pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); + + return v->channels == ss->channels; +} + +int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { + pa_assert(v); + pa_assert(cm); + + pa_return_val_if_fail(pa_cvolume_valid(v), 0); + pa_return_val_if_fail(pa_channel_map_valid(cm), 0); + + return v->channels == cm->channels; +} + +/* + * Returns the average volume of l and r, where l and r are two disjoint sets of channels + * (e g left and right, or front and rear). + */ +static void get_avg(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r, + bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { + int c; + pa_volume_t left = 0, right = 0; + unsigned n_left = 0, n_right = 0; + + pa_assert(v); + pa_assert(map); + pa_assert(map->channels == v->channels); + pa_assert(l); + pa_assert(r); + + for (c = 0; c < map->channels; c++) { + if (on_l(map->map[c])) { + left += v->values[c]; + n_left++; + } else if (on_r(map->map[c])) { + right += v->values[c]; + n_right++; + } + } + + if (n_left <= 0) + *l = PA_VOLUME_NORM; + else + *l = left / n_left; + + if (n_right <= 0) + *r = PA_VOLUME_NORM; + else + *r = right / n_right; +} + +float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { + pa_volume_t left, right; + + pa_assert(v); + pa_assert(map); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); + + if (!pa_channel_map_can_balance(map)) + return 0.0f; + + get_avg(map, v, &left, &right, on_left, on_right); + + if (left == right) + return 0.0f; + + /* 1.0, 0.0 => -1.0 + 0.0, 1.0 => 1.0 + 0.0, 0.0 => 0.0 + 0.5, 0.5 => 0.0 + 1.0, 0.5 => -0.5 + 1.0, 0.25 => -0.75 + 0.75, 0.25 => -0.66 + 0.5, 0.25 => -0.5 */ + + if (left > right) + return -1.0f + ((float) right / (float) left); + else + return 1.0f - ((float) left / (float) right); +} + +static pa_cvolume* set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance, + bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { + + pa_volume_t left, nleft, right, nright, m; + unsigned c; + + get_avg(map, v, &left, &right, on_l, on_r); + + m = PA_MAX(left, right); + + if (new_balance <= 0) { + nright = (new_balance + 1.0f) * m; + nleft = m; + } else { + nleft = (1.0f - new_balance) * m; + nright = m; + } + + for (c = 0; c < map->channels; c++) { + if (on_l(map->map[c])) { + if (left == 0) + v->values[c] = nleft; + else + v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left); + } else if (on_r(map->map[c])) { + if (right == 0) + v->values[c] = nright; + else + v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right); + } + } + + return v; +} + + +pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { + pa_assert(map); + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + pa_return_val_if_fail(new_balance >= -1.0f, NULL); + pa_return_val_if_fail(new_balance <= 1.0f, NULL); + + if (!pa_channel_map_can_balance(map)) + return v; + + return set_balance(v, map, new_balance, on_left, on_right); +} + +pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { + unsigned c; + pa_volume_t t = 0; + + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); + + t = pa_cvolume_max(v); + + if (t <= PA_VOLUME_MUTED) + return pa_cvolume_set(v, v->channels, max); + + for (c = 0; c < v->channels; c++) + v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); + + return v; +} + +pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, const pa_channel_map *cm, pa_channel_position_mask_t mask) { + unsigned c; + pa_volume_t t = 0; + + pa_assert(v); + + pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); + + if (!cm) + return pa_cvolume_scale(v, max); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); + + t = pa_cvolume_max_mask(v, cm, mask); + + if (t <= PA_VOLUME_MUTED) + return pa_cvolume_set(v, v->channels, max); + + for (c = 0; c < v->channels; c++) + v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); + + return v; +} + +float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { + pa_volume_t rear, front; + + pa_assert(v); + pa_assert(map); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); + + if (!pa_channel_map_can_fade(map)) + return 0.0f; + + get_avg(map, v, &rear, &front, on_rear, on_front); + + if (front == rear) + return 0.0f; + + if (rear > front) + return -1.0f + ((float) front / (float) rear); + else + return 1.0f - ((float) rear / (float) front); +} + +pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { + pa_assert(map); + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + pa_return_val_if_fail(new_fade >= -1.0f, NULL); + pa_return_val_if_fail(new_fade <= 1.0f, NULL); + + if (!pa_channel_map_can_fade(map)) + return v; + + return set_balance(v, map, new_fade, on_rear, on_front); +} + +float pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) { + pa_volume_t hfe, lfe; + + pa_assert(v); + pa_assert(map); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); + + if (!pa_channel_map_can_lfe_balance(map)) + return 0.0f; + + get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe); + + if (hfe == lfe) + return 0.0f; + + if (hfe > lfe) + return -1.0f + ((float) lfe / (float) hfe); + else + return 1.0f - ((float) hfe / (float) lfe); +} + +pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { + pa_assert(map); + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + pa_return_val_if_fail(new_balance >= -1.0f, NULL); + pa_return_val_if_fail(new_balance <= 1.0f, NULL); + + if (!pa_channel_map_can_lfe_balance(map)) + return v; + + return set_balance(v, map, new_balance, on_hfe, on_lfe); +} + +pa_cvolume* pa_cvolume_set_position( + pa_cvolume *cv, + const pa_channel_map *map, + pa_channel_position_t t, + pa_volume_t v) { + + unsigned c; + bool good = false; + + pa_assert(cv); + pa_assert(map); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); + pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL); + + for (c = 0; c < map->channels; c++) + if (map->map[c] == t) { + cv->values[c] = v; + good = true; + } + + return good ? cv : NULL; +} + +pa_volume_t pa_cvolume_get_position( + const pa_cvolume *cv, + const pa_channel_map *map, + pa_channel_position_t t) { + + unsigned c; + pa_volume_t v = PA_VOLUME_MUTED; + + pa_assert(cv); + pa_assert(map); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED); + pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED); + + for (c = 0; c < map->channels; c++) + if (map->map[c] == t) + if (cv->values[c] > v) + v = cv->values[c]; + + return v; +} + +pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + pa_assert(b); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(pa_cvolume_valid(b), NULL); + + dest->channels = PA_MIN(a->channels, b->channels); + + for (i = 0; i < dest->channels; i++) + dest->values[i] = PA_MAX(a->values[i], b->values[i]); + + return dest; +} + +pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { + pa_volume_t m; + + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL); + + m = pa_cvolume_max(v); + + if (m >= limit - inc) + m = limit; + else + m += inc; + + return pa_cvolume_scale(v, m); +} + +pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { + return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX); +} + +pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { + pa_volume_t m; + + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL); + + m = pa_cvolume_max(v); + + if (m <= PA_VOLUME_MUTED + dec) + m = PA_VOLUME_MUTED; + else + m -= dec; + + return pa_cvolume_scale(v, m); +} diff --git a/services/src/server/audio_server.cpp b/services/src/server/audio_server.cpp index efb79a635c..faf80e8324 100644 --- a/services/src/server/audio_server.cpp +++ b/services/src/server/audio_server.cpp @@ -34,7 +34,6 @@ REGISTER_SYSTEM_ABILITY_BY_ID(AudioServer, AUDIO_DISTRIBUTED_SERVICE_ID, true) #ifdef PA constexpr int PA_ARG_COUNT = 1; -const int PA_DAEMON_THREAD_NAME_BUFFER = 15; void* AudioServer::paDaemonThread(void* arg) { @@ -67,23 +66,11 @@ void AudioServer::OnStart() } #ifdef PA - char thread_name[PA_DAEMON_THREAD_NAME_BUFFER]; - int32_t ret = pthread_create(&m_paDaemonThread, nullptr, AudioServer::paDaemonThread, nullptr); if (ret != 0) { MEDIA_ERR_LOG("pthread_create failed %d", ret); } MEDIA_INFO_LOG("Created paDaemonThread\n"); - - ret = pthread_getname_np(m_paDaemonThread, thread_name, PA_DAEMON_THREAD_NAME_BUFFER - 1); - if (ret != 0) { - MEDIA_ERR_LOG("pthread_getname failed %d", ret); - } - - ret = pthread_setname_np(m_paDaemonThread, "pulseaudio"); - if (ret != 0) { - MEDIA_ERR_LOG("pthread_setname failed %d", ret); - } #endif } -- Gitee From 0a9e066e08ec95e3ccb26e8e0846063609921cfd Mon Sep 17 00:00:00 2001 From: Anurup M Date: Mon, 19 Jul 2021 18:15:32 +0530 Subject: [PATCH 04/32] Remove nested dependency in audio_system_manager header Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../audiorecorder/src/audio_recorder.cpp | 20 ++-- .../audiorenderer/src/audio_renderer.cpp | 20 ++-- .../native/audiocommon/include/audio_info.h | 28 ++++++ .../innerkits/native/audiomanager/BUILD.gn | 1 - .../include/audio_system_manager.h | 76 ++++++++++++++- .../audiorecorder/include/audio_recorder.h | 8 +- .../audiorenderer/include/audio_renderer.h | 8 +- .../include/audio_device_descriptor_napi.h | 2 +- ohos.build | 6 +- services/include/audio_device_descriptor.h | 97 ------------------- services/include/client/audio_manager_proxy.h | 1 - services/include/server/audio_server.h | 1 - services/src/audio_device_descriptor.cpp | 55 ----------- services/src/client/audio_system_manager.cpp | 37 ++++++- services/src/server/audio_manager_stub.cpp | 1 - services/test/audio_recorder_test.cpp | 8 +- services/test/audio_renderer_test.cpp | 8 +- 17 files changed, 174 insertions(+), 203 deletions(-) delete mode 100644 services/include/audio_device_descriptor.h delete mode 100644 services/src/audio_device_descriptor.cpp diff --git a/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp index ce7ec0ca60..8416566ed7 100644 --- a/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp +++ b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp @@ -35,10 +35,6 @@ public: bool Flush() override; bool Release() override; int32_t GetBufferSize(size_t &bufferSize) override; - std::vector GetSupportedFormats() override; - std::vector GetSupportedChannels() override; - std::vector GetSupportedEncodingTypes() override; - std::vector GetSupportedSamplingRates() override; std::unique_ptr audioRecorder; @@ -129,24 +125,24 @@ int32_t AudioRecorderPrivate::GetBufferSize(size_t &bufferSize) return audioRecorder->GetBufferSize(bufferSize); } -std::vector AudioRecorderPrivate::GetSupportedFormats() +std::vector AudioRecorder::GetSupportedFormats() { - return audioRecorder->GetSupportedFormats(); + return AUDIO_SUPPORTED_FORMATS; } -std::vector AudioRecorderPrivate::GetSupportedChannels() +std::vector AudioRecorder::GetSupportedChannels() { - return audioRecorder->GetSupportedChannels(); + return AUDIO_SUPPORTED_CHANNELS; } -std::vector AudioRecorderPrivate::GetSupportedEncodingTypes() +std::vector AudioRecorder::GetSupportedEncodingTypes() { - return audioRecorder->GetSupportedEncodingTypes(); + return AUDIO_SUPPORTED_ENCODING_TYPES; } -std::vector AudioRecorderPrivate::GetSupportedSamplingRates() +std::vector AudioRecorder::GetSupportedSamplingRates() { - return audioRecorder->GetSupportedSamplingRates(); + return AUDIO_SUPPORTED_SAMPLING_RATES; } } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp index 75807233c4..f41ddcc8b2 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp @@ -35,10 +35,6 @@ public: bool Stop() override; bool Release() override; int32_t GetBufferSize(size_t &bufferSize) override; - std::vector GetSupportedFormats() override; - std::vector GetSupportedChannels() override; - std::vector GetSupportedEncodingTypes() override; - std::vector GetSupportedSamplingRates() override; std::unique_ptr audioRenderer; @@ -129,24 +125,24 @@ int32_t AudioRendererPrivate::GetBufferSize(size_t &bufferSize) return audioRenderer->GetBufferSize(bufferSize); } -std::vector AudioRendererPrivate::GetSupportedFormats() +std::vector AudioRenderer::GetSupportedFormats() { - return audioRenderer->GetSupportedFormats(); + return AUDIO_SUPPORTED_FORMATS; } -std::vector AudioRendererPrivate::GetSupportedSamplingRates() +std::vector AudioRenderer::GetSupportedSamplingRates() { - return audioRenderer->GetSupportedSamplingRates(); + return AUDIO_SUPPORTED_SAMPLING_RATES; } -std::vector AudioRendererPrivate::GetSupportedChannels() +std::vector AudioRenderer::GetSupportedChannels() { - return audioRenderer->GetSupportedChannels(); + return AUDIO_SUPPORTED_CHANNELS; } -std::vector AudioRendererPrivate::GetSupportedEncodingTypes() +std::vector AudioRenderer::GetSupportedEncodingTypes() { - return audioRenderer->GetSupportedEncodingTypes(); + return AUDIO_SUPPORTED_ENCODING_TYPES; } } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/native/audiocommon/include/audio_info.h b/interfaces/innerkits/native/audiocommon/include/audio_info.h index 9d2a4a5c3d..dbf6d58b84 100644 --- a/interfaces/innerkits/native/audiocommon/include/audio_info.h +++ b/interfaces/innerkits/native/audiocommon/include/audio_info.h @@ -20,6 +20,7 @@ #include #endif // __MUSL__ +#include #include namespace OHOS { @@ -227,6 +228,33 @@ public: MONOTONIC = 0 }; }; + +// Supported audio parameters for both renderer and recorder +const std::vector AUDIO_SUPPORTED_FORMATS { + SAMPLE_U8, + SAMPLE_S16LE, + SAMPLE_S24LE, + SAMPLE_S32LE +}; + +const std::vector AUDIO_SUPPORTED_CHANNELS { + MONO, + STEREO +}; + +const std::vector AUDIO_SUPPORTED_ENCODING_TYPES { + ENCODING_PCM +}; + +const std::vector AUDIO_SUPPORTED_SAMPLING_RATES { + SAMPLE_RATE_8000, + SAMPLE_RATE_11025, + SAMPLE_RATE_16000, + SAMPLE_RATE_22050, + SAMPLE_RATE_32000, + SAMPLE_RATE_44100, + SAMPLE_RATE_48000 +}; typedef void* AudioIOHandle; } // namespace AudioStandard } // namespace OHOS diff --git a/interfaces/innerkits/native/audiomanager/BUILD.gn b/interfaces/innerkits/native/audiomanager/BUILD.gn index 36e5a75a26..9eb2044ff8 100644 --- a/interfaces/innerkits/native/audiomanager/BUILD.gn +++ b/interfaces/innerkits/native/audiomanager/BUILD.gn @@ -56,7 +56,6 @@ config("audio_client_public_config") { ohos_shared_library("audio_client") { install_enable = true sources = [ - "//foundation/multimedia/audio_standard/services/src/audio_device_descriptor.cpp", "//foundation/multimedia/audio_standard/services/src/client/audio_manager_proxy.cpp", "//foundation/multimedia/audio_standard/services/src/client/audio_service_client.cpp", "//foundation/multimedia/audio_standard/services/src/client/audio_session.cpp", diff --git a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h index d6c14364f1..27c9de1225 100644 --- a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h +++ b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h @@ -18,12 +18,82 @@ #include -#include "audio_device_descriptor.h" -#include "audio_stream.h" -#include "audio_policy_manager.h" +#include "parcel.h" +#include "audio_info.h" namespace OHOS { namespace AudioStandard { +class AudioDeviceDescriptor; +class AudioDeviceDescriptor : public Parcelable { + friend class AudioSystemManager; +public: +enum DeviceFlag { + /** + * Indicates all output audio devices. + */ + OUTPUT_DEVICES_FLAG = 0, + /** + * Indicates all input audio devices. + */ + INPUT_DEVICES_FLAG = 1, + /** + * Indicates all audio devices. + */ + ALL_DEVICES_FLAG = 2 +}; + +enum DeviceRole { + /** + * Device role none. + */ + DEVICE_ROLE_NONE = -1, + /** + * Input device role. + */ + INPUT_DEVICE = 0, + /** + * Output device role. + */ + OUTPUT_DEVICE = 1 +}; + +enum DeviceType { + /** + * Indicates device type none. + */ + DEVICE_TYPE_NONE = -1, + /** + * Indicates a speaker built in a device. + */ + SPEAKER = 0, + /** + * Indicates a headset, which is the combination of a pair of headphones and a microphone. + */ + WIRED_HEADSET = 1, + /** + * Indicates a Bluetooth device used for telephony. + */ + BLUETOOTH_SCO = 2, + /** + * Indicates a Bluetooth device supporting the Advanced Audio Distribution Profile (A2DP). + */ + BLUETOOTH_A2DP = 3, + /** + * Indicates a microphone built in a device. + */ + MIC = 4 +}; + + DeviceType getType(); + DeviceRole getRole(); + DeviceType deviceType_; + DeviceRole deviceRole_; + AudioDeviceDescriptor(); + virtual ~AudioDeviceDescriptor(); + bool Marshalling(Parcel &parcel) const override; + static AudioDeviceDescriptor* Unmarshalling(Parcel &parcel); +}; + /** * @brief The AudioSystemManager class is an abstract definition of audio manager. * Provides a series of client/interfaces for audio management diff --git a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h index 407303bcb4..29d64a978c 100644 --- a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h +++ b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h @@ -172,28 +172,28 @@ public: * * @return vector with recorder supported formats. */ - virtual std::vector GetSupportedFormats() = 0; + static std::vector GetSupportedFormats(); /** * @brief Obtains the recorder supported channels. * * @return vector with recorder supported channels. */ - virtual std::vector GetSupportedChannels() = 0; + static std::vector GetSupportedChannels(); /** * @brief Obtains the recorder supported encoding types. * * @return vector with recorder supported encoding types. */ - virtual std::vector GetSupportedEncodingTypes() = 0; + static std::vector GetSupportedEncodingTypes(); /** * @brief Obtains the recorder supported SupportedSamplingRates. * * @return vector with recorder supported SupportedSamplingRates. */ - virtual std::vector GetSupportedSamplingRates() = 0; + static std::vector GetSupportedSamplingRates(); virtual ~AudioRecorder(); }; diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h index 98a861155f..d442634d8c 100644 --- a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -171,28 +171,28 @@ public: * * @return Returns vector with supported formats. */ - virtual std::vector GetSupportedFormats() = 0; + static std::vector GetSupportedFormats(); /** * @brief Obtains the SupportedSamplingRates supported by renderer. * * @return Returns vector with supported SupportedSamplingRates. */ - virtual std::vector GetSupportedSamplingRates() = 0; + static std::vector GetSupportedSamplingRates(); /** * @brief Obtains the channels supported by renderer. * * @return Returns vector with supported channels. */ - virtual std::vector GetSupportedChannels() = 0; + static std::vector GetSupportedChannels(); /** * @brief Obtains the encoding types supported by renderer. * * @return Returns vector with supported encoding types. */ - virtual std::vector GetSupportedEncodingTypes() = 0; + static std::vector GetSupportedEncodingTypes(); virtual ~AudioRenderer(); }; diff --git a/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h b/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h index af973338e9..9b9bcbb864 100644 --- a/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h +++ b/interfaces/kits/js/audio_manager/include/audio_device_descriptor_napi.h @@ -18,7 +18,7 @@ #include #include -#include "audio_device_descriptor.h" +#include "audio_system_manager.h" #include "napi/native_api.h" #include "napi/native_node_api.h" diff --git a/ohos.build b/ohos.build index 77f4837708..f84d36fe1f 100644 --- a/ohos.build +++ b/ohos.build @@ -29,12 +29,14 @@ "header_files": [ "audio_system_manager.h", "audio_session.h", - "audio_stream.h" + "audio_stream.h", + "audio_info.h" ], "header_base": [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiosession/include", - "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include" + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include" ] } }, diff --git a/services/include/audio_device_descriptor.h b/services/include/audio_device_descriptor.h deleted file mode 100644 index d60ced9e40..0000000000 --- a/services/include/audio_device_descriptor.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * 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 ST_AUDIO_DEVICE_DESCRIPTOR_H -#define ST_AUDIO_DEVICE_DESCRIPTOR_H - -#include "parcel.h" - -namespace OHOS { -namespace AudioStandard { -/** - * @brief The AudioDeviceDescriptor class provides different sets of audio devices and their roles - */ - -class AudioDeviceDescriptor : public Parcelable { -public: -enum DeviceFlag { - /** - * Indicates all output audio devices. - */ - OUTPUT_DEVICES_FLAG = 0, - /** - * Indicates all input audio devices. - */ - INPUT_DEVICES_FLAG = 1, - /** - * Indicates all audio devices. - */ - ALL_DEVICES_FLAG = 2 -}; - -enum DeviceRole { - /** - * Device role none. - */ - DEVICE_ROLE_NONE = -1, - /** - * Input device role. - */ - INPUT_DEVICE = 0, - /** - * Output device role. - */ - OUTPUT_DEVICE = 1 -}; - -enum DeviceType { - /** - * Indicates device type none. - */ - DEVICE_TYPE_NONE = -1, - /** - * Indicates a speaker built in a device. - */ - SPEAKER = 0, - /** - * Indicates a headset, which is the combination of a pair of headphones and a microphone. - */ - WIRED_HEADSET = 1, - /** - * Indicates a Bluetooth device used for telephony. - */ - BLUETOOTH_SCO = 2, - /** - * Indicates a Bluetooth device supporting the Advanced Audio Distribution Profile (A2DP). - */ - BLUETOOTH_A2DP = 3, - /** - * Indicates a microphone built in a device. - */ - MIC = 4 -}; - - DeviceType getType(); - DeviceRole getRole(); - DeviceType deviceType_; - DeviceRole deviceRole_; - AudioDeviceDescriptor(); - virtual ~AudioDeviceDescriptor(); - bool Marshalling(Parcel &parcel) const override; - static AudioDeviceDescriptor* Unmarshalling(Parcel &parcel); -}; -} // namespace AudioStandard -} // namespace OHOS -#endif // ST_AUDIO_DEVICE_DESCRIPTOR_H diff --git a/services/include/client/audio_manager_proxy.h b/services/include/client/audio_manager_proxy.h index 0a7068e3b4..3b82f08d82 100644 --- a/services/include/client/audio_manager_proxy.h +++ b/services/include/client/audio_manager_proxy.h @@ -19,7 +19,6 @@ #include "iremote_proxy.h" #include "audio_system_manager.h" #include "audio_manager_base.h" -#include "audio_device_descriptor.h" namespace OHOS { namespace AudioStandard { diff --git a/services/include/server/audio_server.h b/services/include/server/audio_server.h index e6541905da..2909574a07 100644 --- a/services/include/server/audio_server.h +++ b/services/include/server/audio_server.h @@ -23,7 +23,6 @@ #include "system_ability.h" #include "audio_system_manager.h" #include "audio_manager_base.h" -#include "audio_device_descriptor.h" namespace OHOS { namespace AudioStandard { diff --git a/services/src/audio_device_descriptor.cpp b/services/src/audio_device_descriptor.cpp deleted file mode 100644 index 44e9b33ec6..0000000000 --- a/services/src/audio_device_descriptor.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2021 Huawei Device Co., Ltd. - * 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_device_descriptor.h" -#include "media_log.h" - -namespace OHOS { -namespace AudioStandard { -/** - * @brief The AudioDeviceDescriptor class provides - * different sets of audio devices and their roles - */ -AudioDeviceDescriptor::AudioDeviceDescriptor() -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor constructor"); - deviceType_ = DEVICE_TYPE_NONE; - deviceRole_ = DEVICE_ROLE_NONE; -} - -AudioDeviceDescriptor::~AudioDeviceDescriptor() -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::~AudioDeviceDescriptor"); -} - -bool AudioDeviceDescriptor::Marshalling(Parcel &parcel) const -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Marshalling called"); - return parcel.WriteInt32(deviceType_) && parcel.WriteInt32(deviceRole_); -} - -AudioDeviceDescriptor *AudioDeviceDescriptor::Unmarshalling(Parcel &in) -{ - MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Unmarshalling called"); - AudioDeviceDescriptor *audioDeviceDescriptor = new(std::nothrow) AudioDeviceDescriptor(); - if (audioDeviceDescriptor == nullptr) { - return nullptr; - } - audioDeviceDescriptor->deviceType_ = static_cast(in.ReadInt32()); - audioDeviceDescriptor->deviceRole_ = static_cast(in.ReadInt32()); - return audioDeviceDescriptor; -} -} // namespace AudioStandard -} // namespace OHOS diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp index 6d1a840ed3..818f297073 100644 --- a/services/src/client/audio_system_manager.cpp +++ b/services/src/client/audio_system_manager.cpp @@ -14,9 +14,10 @@ */ #include "audio_errors.h" -#include "audio_info.h" #include "audio_manager_proxy.h" +#include "audio_policy_manager.h" #include "audio_system_manager.h" +#include "audio_stream.h" #include "iservice_registry.h" #include "media_log.h" #include "system_ability_definition.h" @@ -230,5 +231,39 @@ std::vector> AudioSystemManager::GetDevices(AudioDev { return g_sProxy->GetDevices(deviceFlag); } + +/** + * @brief The AudioDeviceDescriptor provides + * different sets of audio devices and their roles + */ +AudioDeviceDescriptor::AudioDeviceDescriptor() +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor constructor"); + deviceType_ = DEVICE_TYPE_NONE; + deviceRole_ = DEVICE_ROLE_NONE; +} + +AudioDeviceDescriptor::~AudioDeviceDescriptor() +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::~AudioDeviceDescriptor"); +} + +bool AudioDeviceDescriptor::Marshalling(Parcel &parcel) const +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Marshalling called"); + return parcel.WriteInt32(deviceType_) && parcel.WriteInt32(deviceRole_); +} + +AudioDeviceDescriptor *AudioDeviceDescriptor::Unmarshalling(Parcel &in) +{ + MEDIA_DEBUG_LOG("AudioDeviceDescriptor::Unmarshalling called"); + AudioDeviceDescriptor *audioDeviceDescriptor = new(std::nothrow) AudioDeviceDescriptor(); + if (audioDeviceDescriptor == nullptr) { + return nullptr; + } + audioDeviceDescriptor->deviceType_ = static_cast(in.ReadInt32()); + audioDeviceDescriptor->deviceRole_ = static_cast(in.ReadInt32()); + return audioDeviceDescriptor; +} } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/server/audio_manager_stub.cpp b/services/src/server/audio_manager_stub.cpp index c3c783a3a7..f8a7853f83 100644 --- a/services/src/server/audio_manager_stub.cpp +++ b/services/src/server/audio_manager_stub.cpp @@ -13,7 +13,6 @@ * limitations under the License. */ -#include "audio_device_descriptor.h" #include "audio_manager_base.h" #include "audio_system_manager.h" #include "media_log.h" diff --git a/services/test/audio_recorder_test.cpp b/services/test/audio_recorder_test.cpp index 5576fb1704..d9f10ea0a0 100644 --- a/services/test/audio_recorder_test.cpp +++ b/services/test/audio_recorder_test.cpp @@ -37,26 +37,26 @@ public: MEDIA_INFO_LOG("TestCapture start "); unique_ptr audioRecorder = AudioRecorder::Create(AudioStreamType::STREAM_MUSIC); - vector supportedFormatList = audioRecorder->GetSupportedFormats(); + vector supportedFormatList = AudioRecorder::GetSupportedFormats(); MEDIA_INFO_LOG("Supported formats:"); for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { MEDIA_INFO_LOG("Format %{public}d", *i); } - vector supportedChannelList = audioRecorder->GetSupportedChannels(); + vector supportedChannelList = AudioRecorder::GetSupportedChannels(); MEDIA_INFO_LOG("Supported channels:"); for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) { MEDIA_INFO_LOG("channel %{public}d", *i); } vector supportedEncodingTypes - = audioRecorder->GetSupportedEncodingTypes(); + = AudioRecorder::GetSupportedEncodingTypes(); MEDIA_INFO_LOG("Supported encoding types:"); for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) { MEDIA_INFO_LOG("encoding type %{public}d", *i); } - vector supportedSamplingRates = audioRecorder->GetSupportedSamplingRates(); + vector supportedSamplingRates = AudioRecorder::GetSupportedSamplingRates(); MEDIA_INFO_LOG("Supported sampling rates:"); for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { MEDIA_INFO_LOG("sampling rate %{public}d", *i); diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 9679c2c662..1509d47b71 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -48,26 +48,26 @@ public: streamType = static_cast(strtol(argv[AudioTestConstants::SECOND_ARG_IDX], NULL, 10)); unique_ptr audioRenderer = AudioRenderer::Create(streamType); - vector supportedFormatList = audioRenderer->GetSupportedFormats(); + vector supportedFormatList = AudioRenderer::GetSupportedFormats(); MEDIA_INFO_LOG("AudioRendererTest: Supported formats:"); for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { MEDIA_INFO_LOG("AudioRendererTest: Format %{public}d", *i); } - vector supportedChannelList = audioRenderer->GetSupportedChannels(); + vector supportedChannelList = AudioRenderer::GetSupportedChannels(); MEDIA_INFO_LOG("AudioRendererTest: Supported channels:"); for (auto i = supportedChannelList.begin(); i != supportedChannelList.end(); ++i) { MEDIA_INFO_LOG("AudioRendererTest: channel %{public}d", *i); } vector supportedEncodingTypes - = audioRenderer->GetSupportedEncodingTypes(); + = AudioRenderer::GetSupportedEncodingTypes(); MEDIA_INFO_LOG("AudioRendererTest: Supported encoding types:"); for (auto i = supportedEncodingTypes.begin(); i != supportedEncodingTypes.end(); ++i) { MEDIA_INFO_LOG("AudioRendererTest: encoding type %{public}d", *i); } - vector supportedSamplingRates = audioRenderer->GetSupportedSamplingRates(); + vector supportedSamplingRates = AudioRenderer::GetSupportedSamplingRates(); MEDIA_INFO_LOG("AudioRendererTest: Supported sampling rates:"); for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { MEDIA_INFO_LOG("AudioRendererTest: sampling rate %{public}d", *i); -- Gitee From bf3119cde7f7bc3dd0cd1aa18e91d1cc047bd5c6 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Thu, 1 Jul 2021 17:40:26 +0530 Subject: [PATCH 05/32] Protect Audio cache write with mutex and handle other errors Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../audiorecorder/include/audio_recorder.h | 3 +- .../audiorenderer/include/audio_renderer.h | 3 +- .../include/client/audio_service_client.h | 8 +- services/src/client/audio_service_client.cpp | 133 +++++++++++------- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h index 29d64a978c..c36435812f 100644 --- a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h +++ b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h @@ -159,7 +159,8 @@ public: virtual bool Release() = 0; /** - * @brief Obtains the recorder buffer size. + * @brief Obtains a reasonable minimum buffer size for recorder, however, the recorder can + * accept other read sizes as well. * * @param bufferSize Indicates a buffersize pointer value that wil be written. * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h index d442634d8c..4190da16c7 100644 --- a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -158,7 +158,8 @@ public: virtual bool Release() = 0; /** - * @brief Obtains the renderer buffer size. + * @brief Obtains a reasonable minimum buffer size for rendering, however, the renderer can + * accept other write sizes as well. * * @param bufferSize Indicates the reference variable into which buffer size value wil be written. * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h index aa7495c1ff..2958267a9c 100644 --- a/services/include/client/audio_service_client.h +++ b/services/include/client/audio_service_client.h @@ -46,7 +46,7 @@ struct StreamBuffer { }; struct AudioCache { - uint8_t *buffer; + std::unique_ptr buffer; uint32_t readIndex; uint32_t writeIndex; uint32_t totalCacheSize; @@ -266,6 +266,8 @@ private: pa_stream *paStream; pa_sample_spec sampleSpec; + std::mutex mtx; + AudioCache acache; const void* internalReadBuffer; size_t internalRdBufLen; @@ -295,6 +297,7 @@ private: int32_t InitializeAudioCache(); size_t WriteToAudioCache(const StreamBuffer &stream); int32_t DrainAudioCache(); + int32_t PaWriteStream(const uint8_t *buffer, size_t &length); // Error code used static const uint32_t AUDIO_CLIENT_SUCCESS = 0; @@ -304,7 +307,8 @@ private: static const uint32_t AUDIO_CLIENT_CREATE_STREAM_ERR = -4; static const uint32_t AUDIO_CLIENT_START_STREAM_ERR = -5; static const uint32_t AUDIO_CLIENT_READ_STREAM_ERR = -6; - static const uint32_t AUDIO_CLIENT_PA_ERR = -7; + static const uint32_t AUDIO_CLIENT_WRITE_STREAM_ERR = -7; + static const uint32_t AUDIO_CLIENT_PA_ERR = -8; // Default values diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index d5ea15865d..fe99c05916 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -17,6 +17,8 @@ #include "media_log.h" #include "securec.h" +using namespace std; + namespace OHOS { namespace AudioStandard { AudioRendererCallbacks::~AudioRendererCallbacks() = default; @@ -268,10 +270,6 @@ void AudioServiceClient::ResetPAAudioClient() internalRdBufLen = 0; underFlowCount = 0; - if (acache.buffer) { - free(acache.buffer); - } - acache.buffer = NULL; acache.readIndex = 0; acache.writeIndex = 0; @@ -446,8 +444,17 @@ int32_t AudioServiceClient::InitializeAudioCache() CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(paStream); + if (bufferAttr == NULL) { + MEDIA_ERR_LOG("pa stream get buffer attribute returned null"); + return AUDIO_CLIENT_INIT_ERR; + } + + acache.buffer = make_unique(bufferAttr->minreq); + if (acache.buffer == NULL) { + MEDIA_ERR_LOG("Allocate memory for buffer failed"); + return AUDIO_CLIENT_INIT_ERR; + } - acache.buffer = (uint8_t *) malloc(bufferAttr->minreq); acache.readIndex = 0; acache.writeIndex = 0; acache.totalCacheSize = bufferAttr->minreq; @@ -504,7 +511,12 @@ int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStr } if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { - InitializeAudioCache(); + error = InitializeAudioCache(); + if (error < 0) { + MEDIA_ERR_LOG("Initialize audio cache failed"); + ResetPAAudioClient(); + return AUDIO_CLIENT_CREATE_STREAM_ERR; + } } MEDIA_INFO_LOG("Created Stream"); @@ -624,6 +636,11 @@ int32_t AudioServiceClient::DrainStream() { int error; + if (eAudioClientType != AUDIO_SERVICE_CLIENT_PLAYBACK) { + MEDIA_ERR_LOG("Drain is not supported"); + return AUDIO_CLIENT_ERR; + } + error = DrainAudioCache(); if (error != AUDIO_CLIENT_SUCCESS) { MEDIA_ERR_LOG("Audio cache drain failed"); @@ -666,14 +683,9 @@ int32_t AudioServiceClient::SetStreamVolume(uint32_t sessionID, uint32_t volume) return AUDIO_CLIENT_SUCCESS; } -int32_t AudioServiceClient::DrainAudioCache() +int32_t AudioServiceClient::PaWriteStream(const uint8_t *buffer, size_t &length) { - CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); - pa_threaded_mainloop_lock(mainLoop); - - int32_t error; - size_t length = acache.writeIndex - acache.readIndex; - const uint8_t *buffer = acache.buffer; + int error = 0; while (length > 0) { size_t writableSize; @@ -682,31 +694,56 @@ int32_t AudioServiceClient::DrainAudioCache() pa_threaded_mainloop_wait(mainLoop); } + MEDIA_INFO_LOG("Write stream: writable size = %{public}zu, length = %{public}zu", + writableSize, length); if (writableSize > length) { writableSize = length; } writableSize = AlignToAudioFrameSize(writableSize, sampleSpec); if (writableSize == 0) { + MEDIA_ERR_LOG("Align to frame size failed"); + error = AUDIO_CLIENT_WRITE_STREAM_ERR; break; } - error = pa_stream_write(paStream, (void *)buffer, writableSize, NULL, 0LL, PA_SEEK_RELATIVE); + error = pa_stream_write(paStream, (void *)buffer, writableSize, NULL, 0LL, + PA_SEEK_RELATIVE); if (error < 0) { + MEDIA_ERR_LOG("Write stream failed"); + error = AUDIO_CLIENT_WRITE_STREAM_ERR; break; } - MEDIA_INFO_LOG("writable size: %{public}zu bytes to write: %{public}zu return val: %{public}d", writableSize, length, error); - - buffer = (const uint8_t *)buffer + writableSize; + MEDIA_INFO_LOG("Writable size: %{public}zu, bytes to write: %{public}zu, return val: %{public}d", + writableSize, length, error); + buffer = buffer + writableSize; length -= writableSize; acache.readIndex += writableSize; acache.isFull = false; } + return error; +} + +int32_t AudioServiceClient::DrainAudioCache() +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_threaded_mainloop_lock(mainLoop); + + int32_t error = 0; + if (acache.buffer == NULL) { + MEDIA_ERR_LOG("Drain cache failed"); + return AUDIO_CLIENT_ERR; + } + + size_t length = acache.writeIndex - acache.readIndex; + const uint8_t *buffer = acache.buffer.get(); + + error = PaWriteStream(buffer, length); + acache.readIndex = 0; acache.writeIndex = 0; - acache.isFull = false; pa_threaded_mainloop_unlock(mainLoop); return error; @@ -714,8 +751,12 @@ int32_t AudioServiceClient::DrainAudioCache() size_t AudioServiceClient::WriteToAudioCache(const StreamBuffer &stream) { + if (stream.buffer == NULL) { + return 0; + } + const uint8_t *inputBuffer = stream.buffer; - uint8_t *cacheBuffer = acache.buffer + acache.writeIndex; + uint8_t *cacheBuffer = acache.buffer.get() + acache.writeIndex; size_t inputLen = stream.bufferLen; @@ -730,9 +771,11 @@ size_t AudioServiceClient::WriteToAudioCache(const StreamBuffer &stream) break; } - memcpy_s(cacheBuffer, acache.totalCacheSize, (const uint8_t *)inputBuffer, writableSize); + if (memcpy_s(cacheBuffer, acache.totalCacheSize, inputBuffer, writableSize)) { + break; + } - inputBuffer = (const uint8_t *)inputBuffer + writableSize; + inputBuffer = inputBuffer + writableSize; cacheBuffer = cacheBuffer + writableSize; inputLen -= writableSize; acache.writeIndex += writableSize; @@ -747,6 +790,7 @@ size_t AudioServiceClient::WriteToAudioCache(const StreamBuffer &stream) size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pError) { + lock_guard lock(mtx); int error = 0; size_t cachedLen = WriteToAudioCache(stream); @@ -758,44 +802,27 @@ size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pErr CHECK_PA_STATUS_FOR_WRITE(mainLoop, context, paStream, pError, 0); pa_threaded_mainloop_lock(mainLoop); - const uint8_t *buffer = acache.buffer; - size_t length = acache.totalCacheSize; - - while (length > 0) { - size_t writableSize; - - while (!(writableSize = pa_stream_writable_size(paStream))) { - pa_threaded_mainloop_wait(mainLoop); - } - - MEDIA_INFO_LOG("WriteStream writableSize = %{public}zu length = %{public}zu", writableSize, length); - if (writableSize > length) - writableSize = length; - - writableSize = AlignToAudioFrameSize(writableSize, sampleSpec); - if (writableSize == 0) { - break; - } - - error = pa_stream_write(paStream, (void *)buffer, writableSize, NULL, 0LL, PA_SEEK_RELATIVE); - if (error < 0) { - break; - } + if (acache.buffer == NULL) { + MEDIA_ERR_LOG("Buffer is null"); + pError = AUDIO_CLIENT_WRITE_STREAM_ERR; + return cachedLen; + } - MEDIA_INFO_LOG("writable size: %{public}zu bytes to write: %{public}zu return val: %{public}d ", writableSize, length, error); + const uint8_t *buffer = acache.buffer.get(); + size_t length = acache.totalCacheSize; - buffer = (const uint8_t*) buffer + writableSize; - length -= writableSize; - acache.readIndex += writableSize; - acache.isFull = false; - } + error = PaWriteStream(buffer, length); - if ((length >= 0) && !acache.isFull) { - uint8_t *cacheBuffer = acache.buffer; + if (!error && (length >= 0) && !acache.isFull) { + uint8_t *cacheBuffer = acache.buffer.get(); uint32_t offset = acache.readIndex; uint32_t size = (acache.writeIndex - acache.readIndex); if (size > 0) { - memcpy_s(cacheBuffer, acache.totalCacheSize, (const uint8_t *)cacheBuffer + offset, size); + if (memcpy_s(cacheBuffer, acache.totalCacheSize, cacheBuffer + offset, size)) { + MEDIA_ERR_LOG("Update cache failed"); + pError = AUDIO_CLIENT_WRITE_STREAM_ERR; + return cachedLen; + } MEDIA_INFO_LOG("rearranging the audio cache"); } acache.readIndex = 0; -- Gitee From 899ce4a2c0b5859c993028d73610be5f38f253d9 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Sat, 3 Jul 2021 11:32:48 +0530 Subject: [PATCH 06/32] Init and deinit capturer when suspend and resume to avoid HDI wrong state Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../include/audio_capturer_source.h | 2 +- pulseaudio/src/modules/hdi/hdi_source.c | 104 ++++++++++++------ pulseaudio/src/modules/hdi/hdi_source.h | 9 +- 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h index 3620af3860..2405d0c3c5 100644 --- a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h @@ -60,7 +60,7 @@ public: private: const int32_t HALF_FACTOR = 2; const int32_t MAX_AUDIO_ADAPTER_NUM = 3; - const float MAX_VOLUME_LEVEL = 100.0f; + const float MAX_VOLUME_LEVEL = 15.0f; AudioSourceAttr attr_; bool started_; diff --git a/pulseaudio/src/modules/hdi/hdi_source.c b/pulseaudio/src/modules/hdi/hdi_source.c index 03fbd803e6..3edf2bae6d 100644 --- a/pulseaudio/src/modules/hdi/hdi_source.c +++ b/pulseaudio/src/modules/hdi/hdi_source.c @@ -37,12 +37,12 @@ #include #include -#include -#include - #include "hdi_source.h" #include "media_log.h" +static int pa_capturer_init(struct userdata *u); +static void pa_capturer_exit(void); + static void userdata_free(struct userdata *u) { pa_assert(u); if (u->source) @@ -98,6 +98,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { + int ret; MEDIA_DEBUG_LOG("HDI Source: Detected source output"); pa_assert(data); pa_assert(u); @@ -106,8 +107,17 @@ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_outpu // Signal Ready when a Source Output is connected if (!u->IsReady) u->IsReady = true; + + ret = pa_capturer_init(u); + if (ret != 0) { + MEDIA_DEBUG_LOG("HDI Source: Cannot initialize Capturer! ret=%d", ret); + return PA_HOOK_OK; + } + + u->timestamp = pa_rtclock_now(); pa_source_suspend(u->source, false, PA_SUSPEND_IDLE); } + return PA_HOOK_OK; } @@ -126,21 +136,18 @@ static void thread_func(void *userdata) { for (;;) { int ret = 0; - int32_t retries = 0; + int retries = 0; uint64_t requestBytes; uint64_t replyBytes = 0; void *p; - MEDIA_DEBUG_LOG("HDI Source: replyBytes before read : %{public}llu", replyBytes); if (PA_SOURCE_IS_OPENED(u->source->thread_info.state) && - (u->source->thread_info.state != PA_SOURCE_SUSPENDED && u->IsReady)) { - MEDIA_DEBUG_LOG("HDI Source: PA_SOURCE_IS_OPENED"); + (u->source->thread_info.state != PA_SOURCE_SUSPENDED) && u->IsReady && u->IsCapturerInit) { pa_usec_t now; pa_memchunk chunk; now = pa_rtclock_now(); - MEDIA_DEBUG_LOG("HDI Source: now : %{public}llu", now); - MEDIA_DEBUG_LOG("HDI Source: Is timer_elapsed : %{public}d", timer_elapsed); + MEDIA_DEBUG_LOG("HDI Source: now: %{public}llu timer_elapsed: %{public}d", now, timer_elapsed); if (timer_elapsed && (chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec)) > 0) { chunk.length = u->buffer_size; @@ -160,6 +167,7 @@ static void thread_func(void *userdata) { pa_memblock_unref(chunk.memblock); break; } + if (replyBytes == 0) { MEDIA_INFO_LOG("HDI Source: reply bytes 0"); if (retries < MAX_RETRIES) { @@ -185,6 +193,12 @@ static void thread_func(void *userdata) { pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->block_usec); } else { + if (u->IsCapturerInit) { + u->IsCapturerInit = false; + pa_capturer_exit(); + MEDIA_INFO_LOG("HDI Source: Capturer exit done"); + } + pa_rtpoll_set_timer_disabled(u->rtpoll); MEDIA_INFO_LOG("HDI Source: pa_rtpoll_set_timer_disabled done "); } @@ -208,13 +222,47 @@ static void thread_func(void *userdata) { } } +static int pa_capturer_init(struct userdata *u) { + int ret; + + ret = AudioCapturerSourceInit(&u->attrs); + if (ret != 0) { + MEDIA_INFO_LOG("Audio capturer init failed!"); + return ret; + } + + ret = AudioCapturerSourceStart(); + if (ret != 0) { + MEDIA_INFO_LOG("Audio capturer start failed!"); + goto fail; + } + + ret = AudioCapturerSourceSetVolume(DEFAULT_LEFT_VOLUME, DEFAULT_RIGHT_VOLUME); + if (ret != 0) { + MEDIA_INFO_LOG("audio capturer set volume failed!"); + goto fail; + } + + u->IsCapturerInit = true; + return ret; + +fail: + pa_capturer_exit(); + return ret; +} + +static void pa_capturer_exit() { + AudioCapturerSourceStop(); + AudioCapturerSourceDeInit(); +} + pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { struct userdata *u = NULL; pa_sample_spec ss; char *thread_name = NULL; pa_channel_map map; pa_source_new_data data; - int32_t ret; + int ret; pa_assert(m); pa_assert(ma); @@ -242,33 +290,13 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { } u->buffer_size = DEFAULT_BUFFER_SIZE; - - AudioSourceAttr attrs; - attrs.format = AUDIO_FORMAT_PCM_16_BIT; - attrs.channel = ss.channels; - attrs.sampleRate = ss.rate; - + u->attrs.format = AUDIO_FORMAT_PCM_16_BIT; + u->attrs.channel = ss.channels; + u->attrs.sampleRate = ss.rate; MEDIA_INFO_LOG("AudioDeviceCreateCapture format: %{public}d, channel: %{public}d, sampleRate: %{public}d", - attrs.format, attrs.channel, attrs.sampleRate); - - ret = AudioCapturerSourceInit(&attrs); + u->attrs.format, u->attrs.channel, u->attrs.sampleRate); + ret = pa_capturer_init(u); if (ret != 0) { - MEDIA_INFO_LOG("Audio capture init failed!"); - goto fail; - } - - ret = AudioCapturerSourceStart(); - if (ret != 0) { - MEDIA_INFO_LOG("Audio capture start failed!"); - AudioCapturerSourceDeInit(); - goto fail; - } - - ret = AudioCapturerSourceSetVolume(VOLUME_VALUE, VOLUME_VALUE); - if (ret != 0) { - MEDIA_INFO_LOG("audio capture set volume failed!"); - AudioCapturerSourceStop(); - AudioCapturerSourceDeInit(); goto fail; } @@ -317,9 +345,10 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { thread_name = pa_sprintf_malloc("hdi-source-record"); if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) { - MEDIA_INFO_LOG("Failed to create thread."); + MEDIA_INFO_LOG("Failed to create hdi-source-record thread!"); goto fail; } + pa_xfree(thread_name); thread_name = NULL; pa_source_put(u->source); @@ -328,6 +357,9 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { fail: pa_xfree(thread_name); + if (u->IsCapturerInit) + pa_capturer_exit(); + if (u) userdata_free(u); diff --git a/pulseaudio/src/modules/hdi/hdi_source.h b/pulseaudio/src/modules/hdi/hdi_source.h index 2bb66a0099..fd12658f3e 100644 --- a/pulseaudio/src/modules/hdi/hdi_source.h +++ b/pulseaudio/src/modules/hdi/hdi_source.h @@ -20,11 +20,16 @@ #include #include +#include +#include + #define DEFAULT_SOURCE_NAME "hdi_input" #define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic" #define DEFAULT_BUFFER_SIZE (1024 * 16) -#define VOLUME_VALUE 100.0 +#define MAX_VOLUME_VALUE 15.0 +#define DEFAULT_LEFT_VOLUME MAX_VOLUME_VALUE +#define DEFAULT_RIGHT_VOLUME MAX_VOLUME_VALUE #define FIVE_MSEC 5000 #define MAX_RETRIES 5 #define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2) @@ -42,8 +47,10 @@ struct userdata { size_t buffer_size; pa_usec_t block_usec; pa_usec_t timestamp; + AudioSourceAttr attrs; // A flag to signal us to prevent silent record during bootup bool IsReady; + bool IsCapturerInit; }; pa_source* pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver); -- Gitee From 4fe82b86f4e63a6034384b276b1e43c19dd9d960 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Tue, 6 Jul 2021 16:25:20 +0530 Subject: [PATCH 07/32] Move out of Mute mode when volume is modified Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../server/service/src/manager/pulseaudio_policy_manager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp index 596d22fb24..b633cc2c78 100644 --- a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -585,11 +585,16 @@ void PulseAudioPolicyManager::GetSinkInputInfoVolumeCb(pa_context *c, const pa_s vol = MIN_VOLUME; } } + pa_cvolume cv = i->volume; int32_t volume = pa_sw_volume_from_linear(vol); pa_cvolume_set(&cv, i->channel_map.channels, volume); pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL)); + if (i->mute) { + pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, 0, NULL, NULL)); + } + MEDIA_INFO_LOG("[PolicyManager] Applied volume : %{public}f for stream : %{public}s, volumeInt%{public}d", userData->volume, i->name, volume); -- Gitee From ccfb2e856b8876c0ddfab909e35a13f88646d2f7 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Sun, 4 Jul 2021 12:36:46 +0530 Subject: [PATCH 08/32] Use KvStore to save and restore volume and Ringermode Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- services/BUILD.gn | 4 + .../manager/pulseaudio_policy_manager.h | 28 +- .../src/manager/pulseaudio_policy_manager.cpp | 252 ++++++++++++++++-- 3 files changed, 254 insertions(+), 30 deletions(-) diff --git a/services/BUILD.gn b/services/BUILD.gn index f1b95c51d5..e51e4bea8c 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -99,6 +99,8 @@ config("audio_policy_public_config") { "//foundation/multimedia/audio_standard/services/include/audio_policy/client", "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata/include", "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", "//third_party/libxml2/include", "//third_party/pulseaudio/src", @@ -137,6 +139,8 @@ ohos_shared_library("audio_policy_service") { "//utils/native/base:utils", "//foundation/multimedia/audio_standard/pulseaudio/src/pulse:pulse", "//third_party/libxml2:xml2", + "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", + "//foundation/distributeddatamgr/distributeddatamgr/services/distributeddataservice/adapter:distributeddata_adapter", ] external_deps = [ diff --git a/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h index ae1fdd9cb6..1056ace7a7 100644 --- a/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h +++ b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h @@ -27,17 +27,22 @@ extern "C" { #include #include +#include "distributed_kv_data_manager.h" #include "iaudio_policy.h" +#include "types.h" namespace OHOS { namespace AudioStandard { +using namespace OHOS::DistributedKv; + class PulseAudioPolicyManager : public IAudioPolicyInterface { public: static constexpr char HDI_SINK[] = "libmodule-hdi-sink.z.so"; static constexpr char HDI_SOURCE[] = "libmodule-hdi-source.z.so"; static constexpr char PIPE_SINK[] = "libmodule-pipe-sink.z.so"; static constexpr char PIPE_SOURCE[] = "libmodule-pipe-source.z.so"; - + static constexpr float MAX_VOLUME = 1.0f; + static constexpr float MIN_VOLUME = 0.0f; static constexpr uint32_t PA_CONNECT_RETRY_SLEEP_IN_MICRO_SECONDS = 500000; bool Init(); @@ -69,10 +74,7 @@ public: int32_t SetRingerMode(AudioRingerMode ringerMode); - AudioRingerMode GetRingerMode() - { - return mRingerMode; - } + AudioRingerMode GetRingerMode(void); // Static Member functions static void ContextStateCb(pa_context *c, void *userdata); @@ -103,8 +105,11 @@ private: PulseAudioPolicyManager() : mContext(nullptr), mMainLoop(nullptr), - mRingerMode(RINGER_MODE_NORMAL) + mRingerMode(RINGER_MODE_NORMAL), + mAudioPolicyKvStore(nullptr) { + mVolumeMap[STREAM_MUSIC] = MAX_VOLUME; + mVolumeMap[STREAM_RING] = MAX_VOLUME; } virtual ~PulseAudioPolicyManager() {} @@ -114,12 +119,21 @@ private: std::string GetModuleArgs(std::shared_ptr audioPortInfo); std::string GetStreamNameByStreamType(AudioStreamType streamType); AudioStreamType GetStreamIDByType(std::string streamType); - void InitVolumeMap(void); + bool InitAudioPolicyKvStore(bool& isFirstBoot); + void InitVolumeMap(bool isFirstBoot); + bool LoadVolumeMap(void); + void WriteVolumeToKvStore(AudioStreamType streamType, float volume); + bool LoadVolumeFromKvStore(std::unique_ptr& audioPolicyKvStoreSnapshot, + AudioStreamType streamType); + void InitRingerMode(bool isFirstBoot); + bool LoadRingerMode(void); + void WriteRingerModeToKvStore(AudioRingerMode ringerMode); pa_context* mContext; pa_threaded_mainloop* mMainLoop; std::unordered_map mVolumeMap; AudioRingerMode mRingerMode; + std::unique_ptr mAudioPolicyKvStore; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp index b633cc2c78..e3abf2acd8 100644 --- a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -20,10 +20,6 @@ namespace OHOS { namespace AudioStandard { - -const float MAX_VOLUME = 1.0f; -const float MIN_VOLUME = 0.0f; - bool PulseAudioPolicyManager::Init() { mMainLoop = pa_threaded_mainloop_new(); @@ -62,7 +58,12 @@ bool PulseAudioPolicyManager::Init() } pa_threaded_mainloop_unlock(mMainLoop); - InitVolumeMap(); + + bool isFirstBoot = false; + InitAudioPolicyKvStore(isFirstBoot); + InitVolumeMap(isFirstBoot); + InitRingerMode(isFirstBoot); + return true; } @@ -100,7 +101,14 @@ int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, flo return ERROR; } + // Incase if KvStore didnot connect during bootup + if (mAudioPolicyKvStore == nullptr) { + bool isFirstBoot = false; + InitAudioPolicyKvStore(isFirstBoot); + } + mVolumeMap[streamType] = volume; + WriteVolumeToKvStore(streamType, volume); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); @@ -220,7 +228,6 @@ bool PulseAudioPolicyManager::IsStreamActive(AudioStreamType streamType) return (userData->isCorked) ? false : true; } - int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, std::string name, bool active) { pa_threaded_mainloop_lock(mMainLoop); @@ -256,15 +263,26 @@ int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceT int32_t PulseAudioPolicyManager::SetRingerMode(AudioRingerMode ringerMode) { mRingerMode = ringerMode; - return 0; + + // Incase if KvStore didnot connect during bootup + if (mAudioPolicyKvStore == nullptr) { + bool isFirstBoot = false; + InitAudioPolicyKvStore(isFirstBoot); + } + + WriteRingerModeToKvStore(ringerMode); + return SUCCESS; +} + +AudioRingerMode PulseAudioPolicyManager::GetRingerMode() +{ + return mRingerMode; } AudioIOHandle PulseAudioPolicyManager::OpenAudioPort(std::shared_ptr audioPortInfo) { std::string moduleArgs = GetModuleArgs(audioPortInfo); - MEDIA_INFO_LOG("[PolicyManager] load-module %{public}s %{public}s", audioPortInfo->name, moduleArgs.c_str()); - pa_threaded_mainloop_lock(mMainLoop); std::shared_ptr userData = std::make_shared(); @@ -300,16 +318,12 @@ int32_t PulseAudioPolicyManager::CloseAudioPort(AudioIOHandle ioHandle) pa_operation_unref(operation); pa_threaded_mainloop_unlock(mMainLoop); - return SUCCESS; } // Private Members - bool PulseAudioPolicyManager::ConnectToPulseAudio(void) { - MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio++"); - if (mContext != NULL) { pa_context_disconnect (mContext); pa_context_set_state_callback (mContext, NULL, NULL); @@ -322,7 +336,6 @@ bool PulseAudioPolicyManager::ConnectToPulseAudio(void) pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service"); pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.huawei.pulseaudio.service"); mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), NULL, proplist); - pa_proplist_free(proplist); if (mContext == NULL) { @@ -340,19 +353,13 @@ bool PulseAudioPolicyManager::ConnectToPulseAudio(void) } } - MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio--"); - return true; Fail: /* Make sure we don't get any further callbacks */ pa_context_set_state_callback (mContext, NULL, NULL); pa_context_set_subscribe_callback (mContext, NULL, NULL); - pa_context_unref (mContext); - - MEDIA_DEBUG_LOG("[PolicyManager] ConnectToPulseAudio--"); - return false; } @@ -439,10 +446,209 @@ AudioStreamType PulseAudioPolicyManager::GetStreamIDByType(std::string streamTyp return stream; } -void PulseAudioPolicyManager::InitVolumeMap(void) +bool PulseAudioPolicyManager::InitAudioPolicyKvStore(bool& isFirstBoot) +{ + DistributedKvDataManager manager; + Options options; + + options.createIfMissing = false; + options.encrypt = false; + options.autoSync = true; + options.kvStoreType = KvStoreType::MULTI_VERSION; + + AppId appId; + appId.appId = "policymanager"; + StoreId storeId; + storeId.storeId = "audiopolicy"; + + // open and initialize kvstore instance. + if (mAudioPolicyKvStore == nullptr) { + manager.GetKvStore(options, appId, storeId, [&](Status status, std::unique_ptr kvStore) { + if (status == Status::STORE_NOT_FOUND) { + MEDIA_ERR_LOG("[PolicyManager] InitAudioPolicyKvStore: STORE_NOT_FOUND!"); + return; + } else { + mAudioPolicyKvStore = std::move(kvStore); + } + }); + } + + if (mAudioPolicyKvStore == nullptr) { + MEDIA_INFO_LOG("[PolicyManager] First Boot: Create AudioPolicyKvStore"); + options.createIfMissing = true; + // [create and] open and initialize kvstore instance. + manager.GetKvStore(options, appId, storeId, [&](Status status, std::unique_ptr kvStore) { + if (status != Status::SUCCESS) { + MEDIA_ERR_LOG("[PolicyManager] Create AudioPolicyKvStore Failed!"); + return; + } + + mAudioPolicyKvStore = std::move(kvStore); + isFirstBoot = true; + }); + } + + if (mAudioPolicyKvStore == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] InitAudioPolicyKvStore: Failed!"); + return false; + } + + return true; +} + +void PulseAudioPolicyManager::InitVolumeMap(bool isFirstBoot) +{ + if (isFirstBoot == true) { + WriteVolumeToKvStore(STREAM_MUSIC, MAX_VOLUME); + WriteVolumeToKvStore(STREAM_RING, MAX_VOLUME); + MEDIA_INFO_LOG("[PolicyManager] Wrote default stream volumes to KvStore"); + } else { + LoadVolumeMap(); + } + return; +} + +void PulseAudioPolicyManager::InitRingerMode(bool isFirstBoot) +{ + if (mAudioPolicyKvStore == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] mAudioPolicyKvStore is null!"); + return; + } + + if (isFirstBoot == true) { + mRingerMode = RINGER_MODE_NORMAL; + WriteRingerModeToKvStore(RINGER_MODE_NORMAL); + MEDIA_INFO_LOG("[PolicyManager] Wrote default ringer mode to KvStore"); + } else { + LoadRingerMode(); + } +} + +bool PulseAudioPolicyManager::LoadVolumeFromKvStore(std::unique_ptr& audioPolicyKvStoreSnapshot, + AudioStreamType streamType) { - mVolumeMap[STREAM_MUSIC] = MAX_VOLUME; - mVolumeMap[STREAM_RING] = MAX_VOLUME; + Key key; + Value value; + + switch (streamType) { + case STREAM_MUSIC: + key = "music"; + break; + case STREAM_RING: + key = "ring"; + break; + default: + return false; + } + + Status status = audioPolicyKvStoreSnapshot->Get(key, value); + if (status == Status::SUCCESS) { + float volume = TransferByteArrayToType(value.Data()); + mVolumeMap[streamType] = volume; + MEDIA_DEBUG_LOG("[PolicyManager] volume from kvStore %{public}f for streamType:%{public}d", + volume, streamType); + return true; + } + + return false; +} + +bool PulseAudioPolicyManager::LoadVolumeMap(void) +{ + if (mAudioPolicyKvStore == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] LoadVolumeMap: mAudioPolicyKvStore is null!"); + return false; + } + + std::unique_ptr audioPolicyKvStoreSnapshot; + + // open and initialize kvstore snapshot instance. + mAudioPolicyKvStore->GetKvStoreSnapshot(nullptr, + [&](Status status, std::unique_ptr kvStoreSnapshot) { + audioPolicyKvStoreSnapshot = std::move(kvStoreSnapshot); + }); + if (audioPolicyKvStoreSnapshot == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] LoadVolumeMap: audioPolicyKvStoreSnapshot is null!"); + return false; + } + + if (!LoadVolumeFromKvStore(audioPolicyKvStoreSnapshot, STREAM_MUSIC)) + MEDIA_ERR_LOG("[PolicyManager] LoadVolumeMap: Couldnot load volume for Music from kvStore!"); + + if (!LoadVolumeFromKvStore(audioPolicyKvStoreSnapshot, STREAM_RING)) + MEDIA_ERR_LOG("[PolicyManager] LoadVolumeMap: Couldnot load volume for Ring from kvStore!"); + + mAudioPolicyKvStore->ReleaseKvStoreSnapshot(std::move(audioPolicyKvStoreSnapshot)); + return true; +} + +bool PulseAudioPolicyManager::LoadRingerMode(void) +{ + if (mAudioPolicyKvStore == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] LoadRingerMap: mAudioPolicyKvStore is null!"); + return false; + } + + std::unique_ptr audioPolicyKvStoreSnapshot; + + // open and initialize kvstore snapshot instance. + mAudioPolicyKvStore->GetKvStoreSnapshot(nullptr, + [&](Status status, std::unique_ptr kvStoreSnapshot) { + audioPolicyKvStoreSnapshot = std::move(kvStoreSnapshot); + }); + if (audioPolicyKvStoreSnapshot == nullptr) { + MEDIA_ERR_LOG("[PolicyManager] LoadRingerMap: audioPolicyKvStoreSnapshot is null!"); + return false; + } + + // get ringer mode value from kvstore. + Key key = "ringermode"; + Value value; + Status status = audioPolicyKvStoreSnapshot->Get(key, value); + if (status == Status::SUCCESS) { + mRingerMode = static_cast(TransferByteArrayToType(value.Data())); + MEDIA_DEBUG_LOG("[PolicyManager] Ringer Mode from kvStore %{public}d", mRingerMode); + } + + mAudioPolicyKvStore->ReleaseKvStoreSnapshot(std::move(audioPolicyKvStoreSnapshot)); + return true; +} + +void PulseAudioPolicyManager::WriteVolumeToKvStore(AudioStreamType streamType, float volume) +{ + if (mAudioPolicyKvStore == nullptr) + return; + + Key key = GetStreamNameByStreamType(streamType); + Value value = Value(TransferTypeToByteArray(volume)); + + Status status = mAudioPolicyKvStore->Put(key, value); + if (status == Status::SUCCESS) { + MEDIA_INFO_LOG("[PolicyManager] volume %{public}f for %{public}s updated in kvStore", volume, + GetStreamNameByStreamType(streamType).c_str()); + } else { + MEDIA_ERR_LOG("[PolicyManager] volume %{public}f for %{public}s failed to update in kvStore!", volume, + GetStreamNameByStreamType(streamType).c_str()); + } + + return; +} + +void PulseAudioPolicyManager::WriteRingerModeToKvStore(AudioRingerMode ringerMode) +{ + if (mAudioPolicyKvStore == nullptr) + return; + + Key key = "ringermode"; + Value value = Value(TransferTypeToByteArray(ringerMode)); + + Status status = mAudioPolicyKvStore->Put(key, value); + if (status == Status::SUCCESS) { + MEDIA_INFO_LOG("[PolicyManager] Wrote RingerMode:%d to kvStore", ringerMode); + } else { + MEDIA_ERR_LOG("[PolicyManager] Writing RingerMode:%d to kvStore failed!", ringerMode); + } + return; } -- Gitee From 6e331602a9e8c2ef90def454570f91ab32ee5cbc Mon Sep 17 00:00:00 2001 From: Anurup M Date: Wed, 7 Jul 2021 12:10:21 +0530 Subject: [PATCH 09/32] Support for GetLatency from HDI. Include latency in HDI and pulseaudio Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../include/audio_renderer_sink.h | 4 +- .../include/audio_renderer_sink_intf.h | 3 +- .../audiorenderer/src/audio_renderer.cpp | 8 +++- .../audiorenderer/src/audio_renderer_sink.cpp | 40 +++++++++++++++++ .../audiorenderer/include/audio_renderer.h | 9 ++++ .../native/audiostream/include/audio_stream.h | 1 + pulseaudio/src/modules/hdi/hdi_sink.c | 16 +++++-- .../include/client/audio_service_client.h | 8 ++++ services/src/client/audio_service_client.cpp | 45 +++++++++++++++++++ services/src/client/audio_stream.cpp | 9 ++++ services/test/audio_renderer_test.cpp | 7 +++ 11 files changed, 143 insertions(+), 7 deletions(-) diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h index 1c1cd64ecb..154a2966f3 100644 --- a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h @@ -43,6 +43,7 @@ public: int32_t RenderFrame(char &frame, uint64_t len, uint64_t &writeLen); int32_t SetVolume(float left, float right); int32_t GetVolume(float &left, float &right); + int32_t GetLatency(uint32_t *latency); static AudioRendererSink* GetInstance(void); bool rendererInited_; private: @@ -63,5 +64,4 @@ private: }; } // namespace AudioStandard } // namespace OHOS - -#endif // AUDIO_RENDERER_SINK_H \ No newline at end of file +#endif // AUDIO_RENDERER_SINK_H diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h index ba37198524..6219e31c01 100644 --- a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink_intf.h @@ -33,7 +33,8 @@ int32_t AudioRendererSinkStart(void); int32_t AudioRendererSinkStop(void); int32_t AudioRendererRenderFrame(char*, uint64_t, uint64_t*); int32_t AudioRendererSinkSetVolume(float, float); +int32_t AudioRendererSinkGetLatency(uint32_t *); #ifdef __cplusplus } #endif -#endif // AUDIO_RENDERER_SINK_INTF_H \ No newline at end of file +#endif // AUDIO_RENDERER_SINK_INTF_H diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp index f41ddcc8b2..333249edac 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp @@ -25,6 +25,7 @@ namespace AudioStandard { class AudioRendererPrivate : public AudioRenderer { public: int32_t GetFrameCount(uint32_t &frameCount) override; + int32_t GetLatency(uint64_t &latency) override; int32_t SetParams(const AudioRendererParams params) override; int32_t GetParams(AudioRendererParams ¶ms) override; bool Start() override; @@ -60,6 +61,11 @@ int32_t AudioRendererPrivate::GetFrameCount(uint32_t &frameCount) return audioRenderer->GetFrameCount(frameCount); } +int32_t AudioRendererPrivate::GetLatency(uint64_t &latency) +{ + return audioRenderer->GetLatency(latency); +} + int32_t AudioRendererPrivate::SetParams(const AudioRendererParams params) { AudioStreamParams audioStreamParams; @@ -145,4 +151,4 @@ std::vector AudioRenderer::GetSupportedEncodingTypes() return AUDIO_SUPPORTED_ENCODING_TYPES; } } // namespace AudioStandard -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp index 5d2d4423ee..4e448399ff 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp @@ -273,6 +273,28 @@ int32_t AudioRendererSink::GetVolume(float &left, float &right) return SUCCESS; } +int32_t AudioRendererSink::GetLatency(uint32_t *latency) +{ + if (audioRender_ == nullptr) { + MEDIA_ERR_LOG("AudioRendererSink: GetLatency failed audio render null"); + return ERR_INVALID_HANDLE; + } + + if (!latency) { + MEDIA_ERR_LOG("AudioRendererSink: GetLatency failed latency null"); + return ERR_INVALID_PARAM; + } + + uint32_t hdiLatency; + if (audioRender_->GetLatency(audioRender_, &hdiLatency) == 0) { + *latency = hdiLatency; + MEDIA_INFO_LOG("AudioRendererSink: Latency: %{public}u", *latency); + return SUCCESS; + } else { + return ERR_OPERATION_FAILED; + } +} + int32_t AudioRendererSink::Stop(void) { if (started_ && audioRender_ != nullptr) { @@ -391,6 +413,24 @@ int32_t AudioRendererSinkSetVolume(float left, float right) return ret; } +int32_t AudioRendererSinkGetLatency(uint32_t *latency) +{ + int32_t ret; + + if (!g_audioRendrSinkInstance->rendererInited_) { + MEDIA_ERR_LOG("audioRenderer Not Inited! Init the renderer first\n"); + return ERR_NOT_STARTED; + } + + if (!latency) { + MEDIA_ERR_LOG("AudioRendererSinkGetLatency failed latency null"); + return ERR_INVALID_PARAM; + } + + ret = g_audioRendrSinkInstance->GetLatency(latency); + return ret; +} + #ifdef __cplusplus } #endif diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h index 4190da16c7..227c606bcf 100644 --- a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -136,6 +136,15 @@ public: */ virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) = 0; + /** + * @brief Obtains the latency in microseconds. + * + * @param latency Indicates the reference variable into which latency value will be written. + * @return Returns {@link SUCCESS} if latency is successfully obtained, returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t GetLatency(uint64_t &latency) = 0; + /** * @brief drain renderer buffer. * diff --git a/interfaces/innerkits/native/audiostream/include/audio_stream.h b/interfaces/innerkits/native/audiostream/include/audio_stream.h index 3e185f7460..3c914f1b94 100644 --- a/interfaces/innerkits/native/audiostream/include/audio_stream.h +++ b/interfaces/innerkits/native/audiostream/include/audio_stream.h @@ -58,6 +58,7 @@ public: bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base); int32_t GetBufferSize(size_t &bufferSize); int32_t GetFrameCount(uint32_t &frameCount); + int32_t GetLatency(uint64_t &latency); std::vector GetSupportedFormats(); std::vector GetSupportedChannels(); diff --git a/pulseaudio/src/modules/hdi/hdi_sink.c b/pulseaudio/src/modules/hdi/hdi_sink.c index 8614dab183..db3fe91d44 100644 --- a/pulseaudio/src/modules/hdi/hdi_sink.c +++ b/pulseaudio/src/modules/hdi/hdi_sink.c @@ -219,9 +219,19 @@ static int SinkProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset, struct Userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { - size_t n = 0; - n = n + u->memchunk.length; - *((int64_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); + int64_t latency; + uint32_t hdiLatency; + + // Tries to fetch latency from HDI else will make an estimate based + // on samples to be rendered based on the timestamp and current time + if (AudioRendererSinkGetLatency(&hdiLatency) == 0) { + latency = (PA_USEC_PER_MSEC * hdiLatency); + } else { + pa_usec_t now = pa_rtclock_now(); + latency = (now - u->timestamp); + } + + *((int64_t *)data) = latency; return 0; } default: diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h index 2958267a9c..6acaf3c206 100644 --- a/services/include/client/audio_service_client.h +++ b/services/include/client/audio_service_client.h @@ -191,6 +191,14 @@ public: */ int32_t GetCurrentTimeStamp(uint64_t &timeStamp); + /** + * Provides the current latency for playback/record stream created using CreateStream + * + * @param latency will be filled up with the current latency in microseconds + * @return Returns {@code 0} if success; returns {@code -1} otherwise. + */ + int32_t GetAudioLatency(uint64_t &latency); + /** * Provides the playback/record stream parameters created using CreateStream * diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index fe99c05916..5a905ba9cc 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -1012,6 +1012,51 @@ int32_t AudioServiceClient::GetCurrentTimeStamp(uint64_t &timeStamp) return AUDIO_CLIENT_ERR; } +int32_t AudioServiceClient::GetAudioLatency(uint64_t &latency) +{ + CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); + pa_usec_t paLatency; + pa_usec_t cacheLatency; + int32_t retVal = AUDIO_CLIENT_SUCCESS; + int negative; + bool getPALatency = false; + + // Get PA latency + pa_threaded_mainloop_lock(mainLoop); + while (!getPALatency) { + if (pa_stream_get_latency(paStream, &paLatency, &negative) >= 0) { + if (negative) { + latency = 0; + retVal = AUDIO_CLIENT_ERR; + return retVal; + } + getPALatency = true; + break; + } + MEDIA_INFO_LOG("waiting for audio latency information"); + pa_threaded_mainloop_wait(mainLoop); + } + pa_threaded_mainloop_unlock(mainLoop); + + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + // Get audio write cache latency + cacheLatency = pa_bytes_to_usec((acache.totalCacheSize - acache.writeIndex), &sampleSpec); + + // Total latency will be sum of audio write cache latency + PA latency + latency = paLatency + cacheLatency; + MEDIA_INFO_LOG("total latency: %{public}llu, pa latency: %{public}llu, cache latency: %{public}llu", latency, paLatency, cacheLatency); + } else if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { + // Get audio read cache latency + cacheLatency = pa_bytes_to_usec(internalRdBufLen, &sampleSpec); + + // Total latency will be sum of audio read cache latency + PA latency + latency = paLatency + cacheLatency; + MEDIA_INFO_LOG("total latency: %{public}llu, pa latency: %{public}llu", latency, paLatency); + } + + return retVal; +} + void AudioServiceClient::RegisterAudioRendererCallbacks(const AudioRendererCallbacks &cb) { MEDIA_INFO_LOG("Registering audio render callbacks"); diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp index b1f4ed7c4f..5c7039a906 100644 --- a/services/src/client/audio_stream.cpp +++ b/services/src/client/audio_stream.cpp @@ -103,6 +103,15 @@ int32_t AudioStream::GetFrameCount(uint32_t &frameCount) return SUCCESS; } +int32_t AudioStream::GetLatency(uint64_t &latency) +{ + if (GetAudioLatency(latency) != SUCCESS) { + return ERR_OPERATION_FAILED; + } else { + return SUCCESS; + } +} + vector AudioStream::GetSupportedFormats() { return SUPPORTED_FORMATS; diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 1509d47b71..94501829ba 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -127,12 +127,19 @@ public: size_t bytesToWrite = 0; size_t bytesWritten = 0; size_t minBytes = 4; + uint64_t latency; while (!feof(wavFile)) { bytesToWrite = fread(buffer, 1, bufferLen, wavFile); bytesWritten = 0; MEDIA_INFO_LOG("AudioRendererTest: Bytes to write: %{public}d", bytesToWrite); + if (audioRenderer->GetLatency(latency)) { + MEDIA_ERR_LOG("AudioRendererTest: GetLatency failed"); + return false; + } + MEDIA_INFO_LOG("AudioRendererTest: Latency: %{public}llu", latency); + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten); -- Gitee From fcfa9eceb1c8f1dad91ce41b5fc3e1aa2e98746d Mon Sep 17 00:00:00 2001 From: Anurup M Date: Wed, 7 Jul 2021 19:24:07 +0530 Subject: [PATCH 10/32] Create and destroy Audio renderer handle when PA suspends and resume sink module Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- pulseaudio/src/modules/hdi/hdi_sink.c | 45 ++++++++++++++++++++------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/pulseaudio/src/modules/hdi/hdi_sink.c b/pulseaudio/src/modules/hdi/hdi_sink.c index db3fe91d44..cc9f740656 100644 --- a/pulseaudio/src/modules/hdi/hdi_sink.c +++ b/pulseaudio/src/modules/hdi/hdi_sink.c @@ -53,9 +53,13 @@ struct Userdata { pa_core *core; pa_module *module; pa_sink *sink; + pa_sample_spec ss; + pa_channel_map map; + bool isHDISinkInitialized; }; static void UserdataFree(struct Userdata *u); +static int32_t PrepareDevice(const pa_sample_spec *ss); static ssize_t RenderWrite(pa_memchunk *pchunk) { @@ -250,8 +254,18 @@ static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t newState, pa_assert_se(u = s->userdata); if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) { - if (PA_SINK_IS_OPENED(newState)) + if (PA_SINK_IS_OPENED(newState)) { u->timestamp = pa_rtclock_now(); + if (!u->isHDISinkInitialized) { + pa_log("Reinitializing HDI rendering device with rate: %d, channels: %d", u->ss.rate, u->ss.channels); + if (PrepareDevice(&u->ss) < 0) { + pa_log_error("HDI renderer reinitialization failed"); + } else { + u->isHDISinkInitialized = true; + pa_log("Successfully reinitialized HDI renderer"); + } + } + } } else if (PA_SINK_IS_OPENED(s->thread_info.state)) { if (newState == PA_SINK_SUSPENDED) { // Continuously dropping data (clear counter on entering suspended state. @@ -260,6 +274,12 @@ static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t newState, u->bytes_dropped); u->bytes_dropped = 0; } + if (u->isHDISinkInitialized) { + AudioRendererSinkStop(); + AudioRendererSinkDeInit(); + u->isHDISinkInitialized = false; + pa_log("Deinitialized HDI renderer"); + } } } @@ -300,30 +320,33 @@ static int32_t PrepareDevice(const pa_sample_spec *ss) return 0; } -static pa_sink* PaHdiSinkInit(pa_module *m, pa_modargs *ma, const char *driver) +static pa_sink* PaHdiSinkInit(struct Userdata *u, pa_modargs *ma, const char *driver) { - pa_sample_spec ss; pa_sink_new_data data; - pa_channel_map map; + pa_module *m; pa_sink *sink = NULL; - ss = m->core->default_sample_spec; - map = m->core->default_channel_map; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + m = u->module; + u->ss = m->core->default_sample_spec; + u->map = m->core->default_channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->ss, &u->map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("Failed to parse sample specification and channel map"); goto fail; } - if (PrepareDevice(&ss) < 0) + pa_log("Initializing HDI rendering device with rate: %d, channels: %d", u->ss.rate, u->ss.channels); + if (PrepareDevice(&u->ss) < 0) goto fail; + u->isHDISinkInitialized = true; + pa_log("Initialization of HDI rendering device completed"); pa_sink_new_data_init(&data); data.driver = driver; data.module = m; pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); - pa_sink_new_data_set_sample_spec(&data, &ss); - pa_sink_new_data_set_channel_map(&data, &map); + pa_sink_new_data_set_sample_spec(&data, &u->ss); + pa_sink_new_data_set_channel_map(&data, &u->map); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, DEFAULT_AUDIO_DEVICE_NAME); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI sink is %s", DEFAULT_AUDIO_DEVICE_NAME); @@ -364,7 +387,7 @@ pa_sink *PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver) goto fail; } - u->sink = PaHdiSinkInit(m, ma, driver); + u->sink = PaHdiSinkInit(u, ma, driver); if (!u->sink) { pa_log("Failed to create sink object"); goto fail; -- Gitee From e4139869c0d9294b212c184d5b2fa53f5e58fe26 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Thu, 8 Jul 2021 09:50:59 +0530 Subject: [PATCH 11/32] Enable switch between MIC and PIPE source for SetDeviceActive Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- pulseaudio/src/modules/hdi/hdi_source.c | 28 ++++++ .../service/include/audio_policy_service.h | 4 + .../service/src/audio_policy_service.cpp | 42 ++++++--- .../src/manager/pulseaudio_policy_manager.cpp | 92 +++++++++++++------ services/src/client/audio_system_manager.cpp | 4 +- 5 files changed, 125 insertions(+), 45 deletions(-) diff --git a/pulseaudio/src/modules/hdi/hdi_source.c b/pulseaudio/src/modules/hdi/hdi_source.c index 3edf2bae6d..06391bafc7 100644 --- a/pulseaudio/src/modules/hdi/hdi_source.c +++ b/pulseaudio/src/modules/hdi/hdi_source.c @@ -99,6 +99,7 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { int ret; + MEDIA_DEBUG_LOG("HDI Source: Detected source output"); pa_assert(data); pa_assert(u); @@ -121,6 +122,31 @@ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_outpu return PA_HOOK_OK; } +static pa_hook_result_t source_output_move_finish_hook_cb(pa_core *c, pa_source_output *output, struct userdata *u) { + int ret; + + MEDIA_DEBUG_LOG("HDI Source: Detected source move finish"); + pa_assert(output); + pa_assert(u); + + if (!strcmp(output->source->name, u->source->name)) { + // Signal Ready when a source output is connected + if (!u->IsReady) + u->IsReady = true; + + ret = pa_capturer_init(u); + if (ret != 0) { + pa_log_error("HDI Source: Cannot initialize capturer! ret=%d", ret); + return PA_HOOK_OK; + } + + u->timestamp = pa_rtclock_now(); + pa_source_suspend(u->source, false, PA_SUSPEND_IDLE); + } + + return PA_HOOK_OK; +} + static void thread_func(void *userdata) { struct userdata *u = userdata; bool timer_elapsed = false; @@ -342,6 +368,8 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_fixate_hook_cb, u); + pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_NORMAL, + (pa_hook_cb_t) source_output_move_finish_hook_cb, u); thread_name = pa_sprintf_malloc("hdi-source-record"); if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) { diff --git a/services/src/audio_policy/server/service/include/audio_policy_service.h b/services/src/audio_policy/server/service/include/audio_policy_service.h index ba558f5fad..86d49dbbbd 100644 --- a/services/src/audio_policy/server/service/include/audio_policy_service.h +++ b/services/src/audio_policy/server/service/include/audio_policy_service.h @@ -33,6 +33,7 @@ public: static constexpr char HDI_SINK[] = "hdi_output"; static constexpr char HDI_SOURCE[] = "hdi_input"; static constexpr char BLUEZ_SINK[] = "fifo_output"; + static constexpr char BLUEZ_SOURCE[] = "fifo_input"; static AudioPolicyService& GetAudioPolicyService() { @@ -85,13 +86,16 @@ private: { switch (deviceType) { case SPEAKER: + case BLUETOOTH_A2DP: return mActiveOutputDevices; case MIC: + case BLUETOOTH_SCO: return mActiveInputDevices; default: return mActiveOutputDevices; // Default case return Output device } } + IAudioPolicyInterface& mAudioPolicyManager; Parser& mConfigParser; std::unordered_map mIOHandles; diff --git a/services/src/audio_policy/server/service/src/audio_policy_service.cpp b/services/src/audio_policy/server/service/src/audio_policy_service.cpp index bcd6b0e20c..936b21fcde 100644 --- a/services/src/audio_policy/server/service/src/audio_policy_service.cpp +++ b/services/src/audio_policy/server/service/src/audio_policy_service.cpp @@ -78,12 +78,12 @@ int32_t AudioPolicyService::SetDeviceActive(DeviceType deviceType, bool active) AudioIOHandle ioHandle = GetAudioIOHandle(deviceType); list& activeDevices = GetActiveDevicesList(deviceType); - if (active && deviceType == activeDevices.front()) { - MEDIA_DEBUG_LOG("[Policy Service] SetDeviceActive: deviceType %d already active", deviceType); - return SUCCESS; - } - if (!active) { + if (activeDevices.size() <= 1) { + MEDIA_ERR_LOG("[Policy Service] Only one Active device. So cannot deactivate!"); + return ERROR; + } + for (list::const_iterator iter = activeDevices.begin(); iter != activeDevices.end(); ++iter) { if (*iter == deviceType) { @@ -92,12 +92,10 @@ int32_t AudioPolicyService::SetDeviceActive(DeviceType deviceType, bool active) } deviceType = activeDevices.front(); - updateActiveDevices = false; } int32_t result = 0; - switch (deviceType) { case BLUETOOTH_A2DP: result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, BLUEZ_SINK, active); @@ -108,6 +106,9 @@ int32_t AudioPolicyService::SetDeviceActive(DeviceType deviceType, bool active) case MIC: result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, HDI_SOURCE, active); break; + case BLUETOOTH_SCO: + result = mAudioPolicyManager.SetDeviceActive(ioHandle, deviceType, BLUEZ_SOURCE, active); + break; default: result = ERR_DEVICE_NOT_SUPPORTED; break; @@ -136,16 +137,24 @@ bool AudioPolicyService::IsDeviceActive(DeviceType deviceType) const switch (deviceType) { case SPEAKER: - if (deviceType == mActiveOutputDevices.front()) - return true; + case BLUETOOTH_A2DP: + for (list::const_iterator iter = mActiveOutputDevices.begin(); + iter != mActiveOutputDevices.end(); ++iter) { + if (*iter == deviceType) { + result = true; + break; + } + } break; case MIC: - if (deviceType == mActiveInputDevices.front()) - return true; - break; - case BLUETOOTH_A2DP: - if (deviceType == mActiveOutputDevices.front()) - return true; + case BLUETOOTH_SCO: + for (list::const_iterator iter = mActiveInputDevices.begin(); + iter != mActiveInputDevices.end(); ++iter) { + if (*iter == deviceType) { + result = true; + break; + } + } break; default: break; @@ -211,6 +220,9 @@ AudioIOHandle AudioPolicyService::GetAudioIOHandle(DeviceType deviceType) case MIC: ioHandle = mIOHandles[HDI_SOURCE]; break; + case BLUETOOTH_SCO: + ioHandle = mIOHandles[BLUEZ_SOURCE]; + break; default: ioHandle = mIOHandles[HDI_SINK]; break; diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp index e3abf2acd8..c8d9e8622c 100644 --- a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -33,6 +33,7 @@ bool PulseAudioPolicyManager::Init() pa_threaded_mainloop_free (mMainLoop); return false; } + pa_threaded_mainloop_lock(mMainLoop); while (true) { @@ -63,7 +64,6 @@ bool PulseAudioPolicyManager::Init() InitAudioPolicyKvStore(isFirstBoot); InitVolumeMap(isFirstBoot); InitRingerMode(isFirstBoot); - return true; } @@ -89,18 +89,19 @@ void PulseAudioPolicyManager::Deinit(void) int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, float volume) { - pa_threaded_mainloop_lock(mMainLoop); + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return ERROR; + } UserData* userData = new UserData; + if (userData == nullptr) + return ERROR; + userData->thiz = this; userData->volume = volume; userData->streamType = streamType; - if (mContext == NULL) { - MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); - return ERROR; - } - // Incase if KvStore didnot connect during bootup if (mAudioPolicyKvStore == nullptr) { bool isFirstBoot = false; @@ -110,10 +111,14 @@ int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, flo mVolumeMap[streamType] = volume; WriteVolumeToKvStore(streamType, volume); + pa_threaded_mainloop_lock(mMainLoop); + pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + delete userData; + pa_threaded_mainloop_unlock(mMainLoop); return ERROR; } @@ -123,7 +128,6 @@ int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, flo pa_operation_unref(operation); pa_threaded_mainloop_unlock(mMainLoop); - return SUCCESS; } @@ -134,22 +138,23 @@ float PulseAudioPolicyManager::GetStreamVolume(AudioStreamType streamType) int32_t PulseAudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool mute) { - pa_threaded_mainloop_lock(mMainLoop); + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return ERROR; + } std::shared_ptr userData = std::make_shared(); userData->thiz = this; userData->mute = mute; userData->streamType = streamType; - if (mContext == NULL) { - MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); - return ERROR; - } + pa_threaded_mainloop_lock(mMainLoop); pa_operation* operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoMuteCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + pa_threaded_mainloop_unlock(mMainLoop); return ERROR; } @@ -165,22 +170,23 @@ int32_t PulseAudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool bool PulseAudioPolicyManager::GetStreamMute(AudioStreamType streamType) { - pa_threaded_mainloop_lock(mMainLoop); + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return false; + } std::shared_ptr userData = std::make_shared(); userData->thiz = this; userData->streamType = streamType; userData->mute = false; - if (mContext == NULL) { - MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); - return false; - } + pa_threaded_mainloop_lock(mMainLoop); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoMuteStatusCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + pa_threaded_mainloop_unlock(mMainLoop); return false; } @@ -196,22 +202,23 @@ bool PulseAudioPolicyManager::GetStreamMute(AudioStreamType streamType) bool PulseAudioPolicyManager::IsStreamActive(AudioStreamType streamType) { - pa_threaded_mainloop_lock(mMainLoop); + if (mContext == NULL) { + MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); + return false; + } std::shared_ptr userData = std::make_shared(); userData->thiz = this; userData->streamType = streamType; userData->isCorked = true; - if (mContext == NULL) { - MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); - return false; - } + pa_threaded_mainloop_lock(mMainLoop); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoCorkStatusCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); + pa_threaded_mainloop_unlock(mMainLoop); return false; } @@ -237,26 +244,30 @@ int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceT case BLUETOOTH_A2DP: { pa_operation* operation = pa_context_set_default_sink(mContext, name.c_str(), NULL, NULL); if (operation == NULL) { - MEDIA_ERR_LOG("[PolicyManager] set default sink failed"); + MEDIA_ERR_LOG("[PolicyManager] set default sink failed!"); + pa_threaded_mainloop_unlock(mMainLoop); return ERR_OPERATION_FAILED; } pa_operation_unref(operation); break; } - case MIC: { + case MIC: + case BLUETOOTH_SCO: { pa_operation* operation = pa_context_set_default_source(mContext, name.c_str(), NULL, NULL); if (operation == NULL) { - MEDIA_ERR_LOG("[PolicyManager] set default sink failed"); + MEDIA_ERR_LOG("[PolicyManager] set default source failed!"); + pa_threaded_mainloop_unlock(mMainLoop); return ERR_OPERATION_FAILED; } + pa_operation_unref(operation); break; } default: break; } - pa_threaded_mainloop_unlock(mMainLoop); + pa_threaded_mainloop_unlock(mMainLoop); return SUCCESS; } @@ -283,6 +294,23 @@ AudioIOHandle PulseAudioPolicyManager::OpenAudioPort(std::shared_ptrname, moduleArgs.c_str()); + + if (!strcmp(audioPortInfo->name, PIPE_SOURCE) || !strcmp(audioPortInfo->name, PIPE_SINK)) { + if (audioPortInfo->fileName != nullptr) { + if (access(audioPortInfo->fileName, F_OK) == 0) { + int32_t ret = std::remove(audioPortInfo->fileName); + if(ret) { + MEDIA_ERR_LOG("[PolicyManager] Error Removing file: %{public}s Failed! ret val: %{public}d", + audioPortInfo->fileName, ret); + } + } else { + MEDIA_DEBUG_LOG("[PolicyManager] File: %{public}s does not exist!", audioPortInfo->fileName); + } + } else { + MEDIA_ERR_LOG("[PolicyManager] Error audioPortInfo->fileName is null!"); + } + } + pa_threaded_mainloop_lock(mMainLoop); std::shared_ptr userData = std::make_shared(); @@ -292,6 +320,7 @@ AudioIOHandle PulseAudioPolicyManager::OpenAudioPort(std::shared_ptr(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_load_module returned nullptr"); + pa_threaded_mainloop_unlock(mMainLoop); return reinterpret_cast(ERR_INVALID_HANDLE); } @@ -312,7 +341,8 @@ int32_t PulseAudioPolicyManager::CloseAudioPort(AudioIOHandle ioHandle) pa_operation* operation = pa_context_unload_module(mContext, reinterpret_cast(ioHandle), NULL, NULL); if (operation == NULL) { - MEDIA_ERR_LOG("[PolicyManager] pa_context_unload_module returned nullptr"); + MEDIA_ERR_LOG("[PolicyManager] pa_context_unload_module returned nullptr!"); + pa_threaded_mainloop_unlock(mMainLoop); return ERROR; } @@ -334,7 +364,7 @@ bool PulseAudioPolicyManager::ConnectToPulseAudio(void) pa_proplist *proplist = pa_proplist_new(); pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio Service"); - pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.huawei.pulseaudio.service"); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.ohos.pulseaudio.service"); mContext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mMainLoop), NULL, proplist); pa_proplist_free(proplist); @@ -372,10 +402,12 @@ std::string PulseAudioPolicyManager::GetModuleArgs(std::shared_ptrrate); } + if (audioPortInfo->channels != nullptr) { args.append(" channels="); args.append(audioPortInfo->channels); } + if (audioPortInfo->buffer_size != nullptr) { args.append(" buffer_size="); args.append(audioPortInfo->buffer_size); @@ -385,10 +417,12 @@ std::string PulseAudioPolicyManager::GetModuleArgs(std::shared_ptrrate); } + if (audioPortInfo->channels != nullptr) { args.append(" channels="); args.append(audioPortInfo->channels); } + if (audioPortInfo->buffer_size != nullptr) { args.append(" buffer_size="); args.append(audioPortInfo->buffer_size); diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp index 818f297073..e73928363d 100644 --- a/services/src/client/audio_system_manager.cpp +++ b/services/src/client/audio_system_manager.cpp @@ -82,6 +82,7 @@ int32_t AudioSystemManager::SetDeviceActive(AudioDeviceDescriptor::DeviceType de case SPEAKER: case BLUETOOTH_A2DP: case MIC: + case BLUETOOTH_SCO: break; default: MEDIA_ERR_LOG("SetDeviceActive device=%{public}d not supported", deviceType); @@ -99,6 +100,7 @@ bool AudioSystemManager::IsDeviceActive(AudioDeviceDescriptor::DeviceType device case SPEAKER: case BLUETOOTH_A2DP: case MIC: + case BLUETOOTH_SCO: break; default: MEDIA_ERR_LOG("IsDeviceActive device=%{public}d not supported", deviceType); @@ -165,7 +167,7 @@ float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeTy break; default: MEDIA_ERR_LOG("GetVolume volumeType=%{public}d not supported", volumeType); - return ERR_NOT_SUPPORTED; + return (float)ERR_NOT_SUPPORTED; } /* Call Audio Policy SetStreamMute */ -- Gitee From fd3ac1162a6bd62a7477e503184f9582efb2fce1 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Thu, 8 Jul 2021 15:53:13 +0530 Subject: [PATCH 12/32] Audio renderer and capturer init attributes update Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- .../audiocapturer/include/audio_capturer_source.h | 5 ++++- .../audiocapturer/src/audio_capturer_source.cpp | 12 ++++++------ .../audiorenderer/src/audio_renderer_sink.cpp | 6 ++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h index 2405d0c3c5..9af4396c64 100644 --- a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h @@ -24,10 +24,13 @@ namespace OHOS { namespace AudioStandard { #define AUDIO_CHANNELCOUNT 2 #define AUDIO_SAMPLE_RATE_48K 48000 -#define DEEP_BUFFER_RENDER_PERIOD_SIZE 4096 +#define DEEP_BUFFER_CAPTURE_PERIOD_SIZE 4096 #define INT_32_MAX 0x7fffffff #define PERIOD_SIZE 1024 #define PATH_LEN 256 +#define AUDIO_BUFF_SIZE (16 * 1024) +#define PCM_8_BIT 8 +#define PCM_16_BIT 16 typedef struct { AudioFormat format; diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp index 466b7ae4f0..910114e810 100644 --- a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp @@ -79,16 +79,16 @@ int32_t InitAttrsCapture(struct AudioSampleAttributes *attrs) attrs->sampleRate = AUDIO_SAMPLE_RATE_48K; attrs->interleaved = 0; attrs->type = AUDIO_IN_MEDIA; - attrs->period = DEEP_BUFFER_RENDER_PERIOD_SIZE; - /* PERIOD_SIZE * 16 * attrs->channelCount / 8,Byte */ - attrs->frameSize = 16 * attrs->channelCount / 8; + attrs->period = DEEP_BUFFER_CAPTURE_PERIOD_SIZE; + /* 16 * attrs->channelCount / 8,Byte */ + attrs->frameSize = PCM_16_BIT * attrs->channelCount / PCM_8_BIT; attrs->isBigEndian = false; attrs->isSignedData = true; - /* DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ - attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8); + /* DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ + attrs->startThreshold = DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (attrs->frameSize); attrs->stopThreshold = INT_32_MAX; /* 16 * 1024 */ - attrs->silenceThreshold = 16 * 1024; + attrs->silenceThreshold = AUDIO_BUFF_SIZE; return SUCCESS; } diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp index 4e448399ff..ee93ed2b12 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp @@ -28,6 +28,8 @@ namespace AudioStandard { #define DEEP_BUFFER_RENDER_PERIOD_SIZE 4096 #define INT_32_MAX 0x7fffffff #define PERIOD_SIZE 1024 +#define PCM_8_BIT 8 +#define PCM_16_BIT 16 namespace { const int32_t HALF_FACTOR = 2; @@ -96,11 +98,11 @@ int32_t InitAttrs(struct AudioSampleAttributes *attrs) attrs->type = AUDIO_IN_MEDIA; attrs->period = DEEP_BUFFER_RENDER_PERIOD_SIZE; /* PERIOD_SIZE * 16 * attrs->channelCount / 8 */ - attrs->frameSize = PERIOD_SIZE * 16 * attrs->channelCount / 8; + attrs->frameSize = PCM_16_BIT * attrs->channelCount / PCM_8_BIT; attrs->isBigEndian = false; attrs->isSignedData = true; /* DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ - attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8); + attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (attrs->frameSize); attrs->stopThreshold = INT_32_MAX; attrs->silenceThreshold = 0; -- Gitee From aaba390e14dd4790710642105766048b4d7a57b9 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Fri, 9 Jul 2021 22:42:15 +0530 Subject: [PATCH 13/32] Fix creation of cookie file in root dir, instead write to the path in client.conf Signed-off-by: Anurup M Change-Id: Ia232eb5a8675c512f4c0afe545230b79b62fd8d5 --- pulseaudio/BUILD.gn | 1 + pulseaudio/conf/client.conf | 20 ++++++++++++++++++++ pulseaudio/src/BUILD.gn | 7 +++++++ pulseaudio/src/daemon/ohos_pa_main.c | 2 +- 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 pulseaudio/conf/client.conf diff --git a/pulseaudio/BUILD.gn b/pulseaudio/BUILD.gn index 035f45faf1..d36a841f5e 100644 --- a/pulseaudio/BUILD.gn +++ b/pulseaudio/BUILD.gn @@ -24,6 +24,7 @@ group("pulseaudio_packages") { "$pulseaudio_build_path/src/pulse:pulse", "$pulseaudio_build_path/src:pa_daemon_config", "$pulseaudio_build_path/src:pa_default_config", + "$pulseaudio_build_path/src:pa_client_config", "$pulseaudio_build_path/src/pulse:pulse-simple", "$pulseaudio_build_path/src/pulse:pulse-mainloop-glib", "$pulseaudio_build_path/src/pulsecore:pulsecore", diff --git a/pulseaudio/conf/client.conf b/pulseaudio/conf/client.conf new file mode 100644 index 0000000000..9e40ae269b --- /dev/null +++ b/pulseaudio/conf/client.conf @@ -0,0 +1,20 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +## Configuration file for PulseAudio clients. See pulse-client.conf(5) for +## more information. Default values are commented out. Use either ; or # for +## commenting. +cookie-file = /data/local/.pulse_dir/cookie + diff --git a/pulseaudio/src/BUILD.gn b/pulseaudio/src/BUILD.gn index 1876f93574..063115d247 100644 --- a/pulseaudio/src/BUILD.gn +++ b/pulseaudio/src/BUILD.gn @@ -140,3 +140,10 @@ ohos_prebuilt_etc("pa_default_config") { module_install_dir = "etc/pulse" part_name = "multimedia_audio_standard" } + +ohos_prebuilt_etc("pa_client_config") { + source = "//foundation/multimedia/audio_standard/pulseaudio/conf/client.conf" + subsystem_name = "multimedia" + module_install_dir = "etc/pulse" + part_name = "multimedia_audio_standard" +} diff --git a/pulseaudio/src/daemon/ohos_pa_main.c b/pulseaudio/src/daemon/ohos_pa_main.c index 2d56ad3236..34525aac6f 100644 --- a/pulseaudio/src/daemon/ohos_pa_main.c +++ b/pulseaudio/src/daemon/ohos_pa_main.c @@ -1011,7 +1011,7 @@ int ohos_pa_main(int argc, char *argv[]) { if (conf->use_pid_file) { int z; - + pa_pid_file_remove(); if ((z = pa_pid_file_create("pulseaudio")) != 0) { if (conf->cmd == PA_CMD_START && z > 0) { -- Gitee From 6a77539535ab5a6a59222ca0061caa514b3d200b Mon Sep 17 00:00:00 2001 From: AOL Date: Mon, 12 Jul 2021 02:57:00 +0000 Subject: [PATCH 14/32] =?UTF-8?q?musl=E4=BD=BF=E7=94=A8.cfg=E8=BF=9B?= =?UTF-8?q?=E8=A1=8Cinit=20Signed-off-by:=20aLINEz=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/BUILD.gn | 12 ++++++++++-- services/etc/audio_policy.cfg | 15 +++++++++++++++ services/etc/pulseaudio.cfg | 22 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 services/etc/audio_policy.cfg create mode 100644 services/etc/pulseaudio.cfg diff --git a/services/BUILD.gn b/services/BUILD.gn index e51e4bea8c..77d53bec19 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -15,7 +15,11 @@ import("//build/ohos.gni") AUDIO_POLICY_SERVER_DIR = "//foundation/multimedia/audio_standard/services/src/audio_policy/server" ohos_prebuilt_etc("pulseaudio.rc") { - source = "etc/pulseaudio.rc" + if (use_musl) { + source = "etc/pulseaudio.cfg" + } else { + source = "etc/pulseaudio.rc" + } relative_install_dir = "init" part_name = "multimedia_audio_standard" subsystem_name = "multimedia" @@ -75,7 +79,11 @@ group("audio_policy_service_packages") { } ohos_prebuilt_etc("audio_policy.rc") { - source = "etc/audio_policy.rc" + if (use_musl) { + source = "etc/audio_policy.cfg" + } else { + source = "etc/audio_policy.rc" + } relative_install_dir = "init" part_name = "multimedia_audio_standard" subsystem_name = "multimedia" diff --git a/services/etc/audio_policy.cfg b/services/etc/audio_policy.cfg new file mode 100644 index 0000000000..f76aaaefef --- /dev/null +++ b/services/etc/audio_policy.cfg @@ -0,0 +1,15 @@ +{ + "jobs" : [{ + "name" : "audio_policy_start", + "cmds" : [ + "start audio_policy" + ] + } + ], + "services" : [{ + "name" : "audio_policy", + "path" : ["/system/bin/sa_main", "/system/profile/audio_policy.xml"], + "disabled" : 1 + } + ] +} diff --git a/services/etc/pulseaudio.cfg b/services/etc/pulseaudio.cfg new file mode 100644 index 0000000000..6f8a01137a --- /dev/null +++ b/services/etc/pulseaudio.cfg @@ -0,0 +1,22 @@ +{ + "jobs" : [{ + "name" : "post-fs-data", + "cmds" : [ + "mkdir /data/local/.pulse_dir", + "chmod 755 /data/local/.pulse_dir", + "chown system shell /data/local/.pulse_dir", + "export PULSE_STATE_PATH \"/data/local/.pulse_dir\"", + "export PULSE_RUNTIME_PATH \"/data/local/.pulse_dir\"", + "start pulseaudio", + "exec /system/bin/sleep 4", + "trigger audio_policy_start" + ] + } + ], + "services" : [{ + "name" : "pulseaudio", + "path" : ["/system/bin/sa_main", "/system/profile/pulseaudio.xml"], + "disabled" : 1 + } + ] +} -- Gitee From 881b5f5a4fd9e916f0f7b94a8f405e9cc0d1ea04 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Fri, 16 Jul 2021 11:21:29 +0530 Subject: [PATCH 15/32] Proper handling of Stop/Release and Read/Write when called from different threads Signed-off-by: anurup --- .../native/audiostream/include/audio_stream.h | 2 + services/src/client/audio_stream.cpp | 67 +++++++++++-------- services/test/audio_renderer_test.cpp | 5 +- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/interfaces/innerkits/native/audiostream/include/audio_stream.h b/interfaces/innerkits/native/audiostream/include/audio_stream.h index 3c914f1b94..ea8fbacdcd 100644 --- a/interfaces/innerkits/native/audiostream/include/audio_stream.h +++ b/interfaces/innerkits/native/audiostream/include/audio_stream.h @@ -81,6 +81,8 @@ private: AudioStreamType eStreamType_; AudioMode eMode_; State state_; + std::atomic isReadInProgress_; + std::atomic isWriteInProgress_; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp index 5c7039a906..1fa91a1f27 100644 --- a/services/src/client/audio_stream.cpp +++ b/services/src/client/audio_stream.cpp @@ -54,14 +54,18 @@ const vector SUPPORTED_SAMPLING_RATES { AudioStream::AudioStream(AudioStreamType eStreamType, AudioMode eMode) : eStreamType_(eStreamType), eMode_(eMode), - state_(NEW) + state_(NEW), + isReadInProgress_(false), + isWriteInProgress_(false) { MEDIA_DEBUG_LOG("AudioStream ctor"); } AudioStream::~AudioStream() { - ReleaseAudioStream(); + if (state_ != RELEASED) { + ReleaseAudioStream(); + } } State AudioStream::GetState() @@ -230,12 +234,12 @@ int32_t AudioStream::SetAudioStreamInfo(const AudioStreamParams info) bool AudioStream::StartAudioStream() { if ((state_ != PREPARED) && (state_ != STOPPED)) { - MEDIA_ERR_LOG("StartAudioStream ILLEGAL_STATE state:%u", state_); - return ERR_ILLEGAL_STATE; + MEDIA_ERR_LOG("StartAudioStream Illegal state:%{public}u", state_); + return false; } int32_t ret = StartStream(); if (ret != SUCCESS) { - MEDIA_ERR_LOG("StartStream Start failed:0x%x", ret); + MEDIA_ERR_LOG("StartStream Start failed:0x%{public}x", ret); return false; } @@ -247,21 +251,23 @@ bool AudioStream::StartAudioStream() int32_t AudioStream::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) { if (userSize <= 0) { - MEDIA_ERR_LOG("Invalid userSize:%zu", userSize); + MEDIA_ERR_LOG("Invalid userSize:%{public}zu", userSize); return ERR_INVALID_PARAM; } if (state_ != RUNNING) { - MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + MEDIA_ERR_LOG("Read: State is not RUNNNIG. Illegal state:%{public}u", state_); return ERR_ILLEGAL_STATE; } StreamBuffer stream; stream.buffer = &buffer; stream.bufferLen = userSize; + isReadInProgress_ = true; int32_t readLen = ReadStream(stream, isBlockingRead); + isReadInProgress_ = false; if (readLen < 0) { - MEDIA_ERR_LOG("ReadStream fail,ret:0x%x", readLen); + MEDIA_ERR_LOG("ReadStream fail,ret:0x%{public}x", readLen); return ERR_INVALID_READ; } @@ -271,12 +277,12 @@ int32_t AudioStream::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size) { if ((buffer == nullptr) || (buffer_size <= 0)) { - MEDIA_ERR_LOG("Invalid buffer size:%zu", buffer_size); + MEDIA_ERR_LOG("Invalid buffer size:%{public}zu", buffer_size); return ERR_INVALID_PARAM; } if (state_ != RUNNING) { - MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); + MEDIA_ERR_LOG("Write: Illegal state:%{public}u", state_); return ERR_ILLEGAL_STATE; } @@ -284,13 +290,15 @@ size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size) StreamBuffer stream; stream.buffer = buffer; stream.bufferLen = buffer_size; + isWriteInProgress_ = true; size_t bytesWritten = WriteStream(stream, writeError); + isWriteInProgress_ = false; if (writeError != 0) { MEDIA_ERR_LOG("WriteStream fail,writeError:%{public}d", writeError); return ERR_WRITE_FAILED; } if (bytesWritten < 0) { - MEDIA_ERR_LOG("WriteStream fail,bytesWritten:0x%x", bytesWritten); + MEDIA_ERR_LOG("WriteStream fail,bytesWritten:0x%{public}x", bytesWritten); return ERR_INVALID_WRITE; } @@ -300,31 +308,35 @@ size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size) bool AudioStream::StopAudioStream() { if (state_ != RUNNING) { - MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); - return ERR_ILLEGAL_STATE; + MEDIA_ERR_LOG("StopAudioStream: State is not RUNNING. Illegal state:%{public}u", state_); + return false; + } + State oldState = state_; + state_ = STOPPED; // Set it before stopping as Read/Write and Stop can be called from different threads + while (isReadInProgress_ || isWriteInProgress_) { } int32_t ret = StopStream(); if (ret != SUCCESS) { - MEDIA_DEBUG_LOG("StreamStop fail,ret:0x%x", ret); + MEDIA_DEBUG_LOG("StreamStop fail,ret:0x%{public}x", ret); + state_ = oldState; return false; } - MEDIA_INFO_LOG("StopAudioStream SUCCESS"); - state_ = STOPPED; + return true; } bool AudioStream::FlushAudioStream() { if (state_ != RUNNING) { - MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); - return ERR_ILLEGAL_STATE; + MEDIA_ERR_LOG("FlushAudioStream: State is not RUNNING. Illegal state:%{public}u", state_); + return false; } int32_t ret = FlushStream(); if (ret != SUCCESS) { - MEDIA_DEBUG_LOG("Flush stream fail,ret:0x%x", ret); + MEDIA_DEBUG_LOG("Flush stream fail,ret:0x%{public}x", ret); return false; } @@ -335,13 +347,13 @@ bool AudioStream::FlushAudioStream() bool AudioStream::DrainAudioStream() { if (state_ != RUNNING) { - MEDIA_ERR_LOG("ILLEGAL_STATE state:%u", state_); - return ERR_ILLEGAL_STATE; + MEDIA_ERR_LOG("DrainAudioStream: State is not RUNNING. Illegal state:%{public}u", state_); + return false; } int32_t ret = DrainStream(); if (ret != SUCCESS) { - MEDIA_DEBUG_LOG("Drain stream fail,ret:0x%x", ret); + MEDIA_DEBUG_LOG("Drain stream fail,ret:0x%{public}x", ret); return false; } @@ -352,19 +364,18 @@ bool AudioStream::DrainAudioStream() bool AudioStream::ReleaseAudioStream() { if (state_ == RELEASED) { - MEDIA_ERR_LOG("illegal state: state = %u", state_); + MEDIA_ERR_LOG("Already Released. Illegal state: state = %{public}u", state_); return false; } - - if (state_ == RUNNING && StopAudioStream()) { - MEDIA_ERR_LOG("Stop failed: %u", state_); - return false; + // If state_ is RUNNING try to Stop it first and Release + if (state_ == RUNNING) { + StopAudioStream(); } - FlushStream(); ReleaseStream(); state_ = RELEASED; MEDIA_INFO_LOG("Release Audio stream SUCCESS"); + return true; } } diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 94501829ba..5df0c5b902 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -136,7 +136,7 @@ public: if (audioRenderer->GetLatency(latency)) { MEDIA_ERR_LOG("AudioRendererTest: GetLatency failed"); - return false; + break; } MEDIA_INFO_LOG("AudioRendererTest: Latency: %{public}llu", latency); @@ -144,6 +144,9 @@ public: bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten); MEDIA_INFO_LOG("AudioRendererTest: Bytes written: %{public}d", bytesWritten); + if (bytesWritten < 0) { + break; + } } } -- Gitee From 94b4c9e247d1acb0dae7ba93acf9b145a2664453 Mon Sep 17 00:00:00 2001 From: Sulav Mulmi Date: Wed, 14 Jul 2021 10:18:19 +0530 Subject: [PATCH 16/32] Added gtest cases for audio renderer Signed-off-by: Sulav Mulmi --- frameworks/innerkitsimpl/test/BUILD.gn | 20 + .../test/moduletest/renderer_test/BUILD.gn | 40 ++ .../include/audio_renderer_module_test.h | 28 + .../src/audio_renderer_module_test.cpp | 540 ++++++++++++++++++ ohos.build | 3 + 5 files changed, 631 insertions(+) create mode 100644 frameworks/innerkitsimpl/test/BUILD.gn create mode 100644 frameworks/innerkitsimpl/test/moduletest/renderer_test/BUILD.gn create mode 100644 frameworks/innerkitsimpl/test/moduletest/renderer_test/include/audio_renderer_module_test.h create mode 100644 frameworks/innerkitsimpl/test/moduletest/renderer_test/src/audio_renderer_module_test.cpp diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn new file mode 100644 index 0000000000..c27443d820 --- /dev/null +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +group("audio_test") { + testonly = true + + deps = [ + "moduletest/renderer_test:moduletest" + ] +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/moduletest/renderer_test/BUILD.gn b/frameworks/innerkitsimpl/test/moduletest/renderer_test/BUILD.gn new file mode 100644 index 0000000000..e4a05f69f5 --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/renderer_test/BUILD.gn @@ -0,0 +1,40 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +module_output_path = "audio_standard/audio_renderer" + +group("moduletest") { + testonly = true + + deps = [ + ":audio_renderer_module_test", + ] +} + +ohos_moduletest("audio_renderer_module_test") { + module_out_path = module_output_path + include_dirs = [ + "./include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + ] + + sources = [ + "src/audio_renderer_module_test.cpp", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer:audio_renderer", + ] +} \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/moduletest/renderer_test/include/audio_renderer_module_test.h b/frameworks/innerkitsimpl/test/moduletest/renderer_test/include/audio_renderer_module_test.h new file mode 100644 index 0000000000..d1f535a685 --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/renderer_test/include/audio_renderer_module_test.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 "gtest/gtest.h" + +class AudioRendererModuleTest : public testing::Test { +public: + // SetUpTestCase: Called before all test cases + static void SetUpTestCase(void); + // TearDownTestCase: Called after all test case + static void TearDownTestCase(void); + // SetUp: Called before each test cases + void SetUp(void); + // TearDown: Called after each test cases + void TearDown(void); +}; \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/moduletest/renderer_test/src/audio_renderer_module_test.cpp b/frameworks/innerkitsimpl/test/moduletest/renderer_test/src/audio_renderer_module_test.cpp new file mode 100644 index 0000000000..1d817190de --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/renderer_test/src/audio_renderer_module_test.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_renderer_module_test.h" + +#include "audio_renderer.h" + +using namespace std; +using namespace OHOS::AudioStandard; +using namespace testing::ext; + +namespace RendererModuleTestConstants { + const char *AUDIO_TEST_FILE_PATH = "/data/test_44100_2.wav"; + const unsigned int ZERO = 0; + // Writing only 500 KB of data for test + const uint64_t WRITE_SIZE_LIMIT = 500 * 1024; +} + +void AudioRendererModuleTest::SetUpTestCase(void) {} +void AudioRendererModuleTest::TearDownTestCase(void) {} +void AudioRendererModuleTest::SetUp(void) {} +void AudioRendererModuleTest::TearDown(void) {} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get supported formats + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_supported_formats_001, TestSize.Level1) +{ + vector supportedFormatList = AudioRenderer::GetSupportedFormats(); + EXPECT_EQ(AUDIO_SUPPORTED_FORMATS.size(), supportedFormatList.size()); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get supported channels + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_supported_channels_001, TestSize.Level1) +{ + vector supportedChannelList = AudioRenderer::GetSupportedChannels(); + EXPECT_EQ(AUDIO_SUPPORTED_CHANNELS.size(), supportedChannelList.size()); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get supported channels + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_supported_encoding_types_001, TestSize.Level1) +{ + vector supportedEncodingTypes + = AudioRenderer::GetSupportedEncodingTypes(); + EXPECT_EQ(AUDIO_SUPPORTED_ENCODING_TYPES.size(), supportedEncodingTypes.size()); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get supported sampling rates + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_supported_sampling_rates_001, TestSize.Level1) +{ + vector supportedSamplingRates = AudioRenderer::GetSupportedSamplingRates(); + EXPECT_EQ(AUDIO_SUPPORTED_SAMPLING_RATES.size(), supportedSamplingRates.size()); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Create renderer instance + */ +HWTEST(AudioRendererModuleTest, audio_renderer_create_001, TestSize.Level1) +{ + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + EXPECT_NE(nullptr, audioRenderer); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Set renderer parameters + */ +HWTEST(AudioRendererModuleTest, audio_renderer_set_params_001, TestSize.Level1) +{ + int32_t ret = 0; + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + audioRenderer->Release(); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get renderer parameters + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_params_001, TestSize.Level1) +{ + int32_t ret = 0; + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + + AudioRendererParams paRendererParams; + ret = audioRenderer->GetParams(paRendererParams); + EXPECT_EQ(0, ret); + EXPECT_EQ(paRendererParams.sampleFormat, rendererParams.sampleFormat); + EXPECT_EQ(paRendererParams.sampleRate, rendererParams.sampleRate); + EXPECT_EQ(paRendererParams.channelCount, rendererParams.channelCount); + EXPECT_EQ(paRendererParams.encodingType, rendererParams.encodingType); + + audioRenderer->Release(); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get buffer size + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_buffer_size_001, TestSize.Level1) +{ + int32_t ret = 0; + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + EXPECT_EQ(0, ret); + + audioRenderer->Release(); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get frame count + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_frame_count_001, TestSize.Level1) +{ + int32_t ret = 0; + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + uint32_t frameCount; + ret = audioRenderer->GetFrameCount(frameCount); + EXPECT_EQ(0, ret); + + audioRenderer->Release(); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Start audio renderer + */ +HWTEST(AudioRendererModuleTest, audio_renderer_start_001, TestSize.Level1) +{ + int32_t ret = 0; + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + + audioRenderer->Release(); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: write audio renderer + */ +HWTEST(AudioRendererModuleTest, audio_renderer_write_001, TestSize.Level1) +{ + int32_t ret = 0; + + FILE *wavFile = fopen(RendererModuleTestConstants::AUDIO_TEST_FILE_PATH, "rb"); + EXPECT_NE(nullptr, wavFile); + + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + EXPECT_EQ(0, ret); + + uint8_t *buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + size_t tempBytesWritten = 0; + size_t totalBytesWritten = 0; + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + tempBytesWritten = audioRenderer->Write(buffer + bytesWritten, + bytesToWrite - bytesWritten); + EXPECT_GE(tempBytesWritten, RendererModuleTestConstants::ZERO); + bytesWritten += tempBytesWritten; + } + totalBytesWritten += bytesWritten; + if (totalBytesWritten >= RendererModuleTestConstants::WRITE_SIZE_LIMIT) { + break; + } + } + + audioRenderer->Drain(); + audioRenderer->Release(); + + free(buffer); + fclose(wavFile); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get audio time + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_audio_time_001, TestSize.Level1) +{ + int32_t ret = 0; + + FILE *wavFile = fopen(RendererModuleTestConstants::AUDIO_TEST_FILE_PATH, "rb"); + EXPECT_NE(nullptr, wavFile); + + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + EXPECT_EQ(0, ret); + + uint8_t *buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + size_t tempBytesWritten = 0; + size_t totalBytesWritten = 0; + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + tempBytesWritten = audioRenderer->Write(buffer + bytesWritten, + bytesToWrite - bytesWritten); + EXPECT_GE(tempBytesWritten, RendererModuleTestConstants::ZERO); + bytesWritten += tempBytesWritten; + } + totalBytesWritten += bytesWritten; + if (totalBytesWritten >= RendererModuleTestConstants::WRITE_SIZE_LIMIT) { + break; + } + } + + audioRenderer->Drain(); + + Timestamp timeStamp; + bool getAudioTime = audioRenderer->GetAudioTime(timeStamp, Timestamp::Timestampbase::MONOTONIC); + EXPECT_EQ(true, getAudioTime); + EXPECT_GE(timeStamp.time.tv_sec, (const long)RendererModuleTestConstants::ZERO); + EXPECT_GE(timeStamp.time.tv_nsec, (const long)RendererModuleTestConstants::ZERO); + + audioRenderer->Release(); + + free(buffer); + fclose(wavFile); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Get latency + */ +HWTEST(AudioRendererModuleTest, audio_renderer_get_latency_001, TestSize.Level1) +{ + int32_t ret = 0; + + FILE *wavFile = fopen(RendererModuleTestConstants::AUDIO_TEST_FILE_PATH, "rb"); + EXPECT_NE(nullptr, wavFile); + + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + EXPECT_EQ(0, ret); + + uint8_t *buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + size_t tempBytesWritten = 0; + size_t totalBytesWritten = 0; + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + uint64_t latency; + ret = audioRenderer->GetLatency(latency); + EXPECT_EQ(0, ret); + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + tempBytesWritten = audioRenderer->Write(buffer + bytesWritten, + bytesToWrite - bytesWritten); + EXPECT_GE(tempBytesWritten, RendererModuleTestConstants::ZERO); + bytesWritten += tempBytesWritten; + } + totalBytesWritten += bytesWritten; + if (totalBytesWritten >= RendererModuleTestConstants::WRITE_SIZE_LIMIT) { + break; + } + } + + audioRenderer->Drain(); + audioRenderer->Release(); + + free(buffer); + fclose(wavFile); +} + + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Stop playback + */ +HWTEST(AudioRendererModuleTest, audio_renderer_stop_001, TestSize.Level1) +{ + int32_t ret = 0; + + FILE *wavFile = fopen(RendererModuleTestConstants::AUDIO_TEST_FILE_PATH, "rb"); + EXPECT_NE(nullptr, wavFile); + + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + EXPECT_EQ(0, ret); + + uint8_t *buffer = nullptr; + int32_t n = 2; + buffer = (uint8_t *) malloc(n * bufferLen); + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + size_t tempBytesWritten = 0; + size_t totalBytesWritten = 0; + while (!feof(wavFile)) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + tempBytesWritten = audioRenderer->Write(buffer + bytesWritten, + bytesToWrite - bytesWritten); + EXPECT_GE(tempBytesWritten, RendererModuleTestConstants::ZERO); + bytesWritten += tempBytesWritten; + } + totalBytesWritten += bytesWritten; + if (totalBytesWritten >= RendererModuleTestConstants::WRITE_SIZE_LIMIT) { + break; + } + } + + bool isStopped = audioRenderer->Stop(); + EXPECT_EQ(true, isStopped); + + audioRenderer->Drain(); + audioRenderer->Release(); + + free(buffer); + fclose(wavFile); +} + +/* + * Feature: Audio render + * Function: Playback + * SubFunction: NA + * FunctionPoints: NA + * EnvConditions: NA + * CaseDescription: Check states + */ +HWTEST(AudioRendererModuleTest, audio_renderer_check_status_001, TestSize.Level1) +{ + int32_t ret = 0; + + FILE *wavFile = fopen(RendererModuleTestConstants::AUDIO_TEST_FILE_PATH, "rb"); + EXPECT_NE(nullptr, wavFile); + + unique_ptr audioRenderer = AudioRenderer::Create(AudioStreamType::STREAM_MUSIC); + RendererState state = audioRenderer->GetStatus(); + EXPECT_EQ(RendererState::RENDERER_NEW, state); + + AudioRendererParams rendererParams; + rendererParams.sampleFormat = AudioSampleFormat::SAMPLE_S16LE; + rendererParams.sampleRate = AudioSamplingRate::SAMPLE_RATE_44100; + rendererParams.channelCount = AudioChannel::STEREO; + rendererParams.encodingType = AudioEncodingType::ENCODING_PCM; + + ret = audioRenderer->SetParams(rendererParams); + EXPECT_EQ(0, ret); + state = audioRenderer->GetStatus(); + EXPECT_EQ(RendererState::RENDERER_PREPARED, state); + + bool isStarted = audioRenderer->Start(); + EXPECT_EQ(true, isStarted); + state = audioRenderer->GetStatus(); + EXPECT_EQ(RendererState::RENDERER_RUNNING, state); + + bool isStopped = audioRenderer->Stop(); + EXPECT_EQ(true, isStopped); + state = audioRenderer->GetStatus(); + EXPECT_EQ(RendererState::RENDERER_STOPPED, state); + + bool isReleased = audioRenderer->Release(); + EXPECT_EQ(true, isReleased); + state = audioRenderer->GetStatus(); + EXPECT_EQ(RendererState::RENDERER_RELEASED, state); +} \ No newline at end of file diff --git a/ohos.build b/ohos.build index f84d36fe1f..92ca3e932e 100644 --- a/ohos.build +++ b/ohos.build @@ -86,6 +86,9 @@ "header_base": "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager/include" } } + ], + "test_list": [ + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/test:audio_test" ] } } -- Gitee From 65e09d1867bfc29d097bcd3eafbbc2ce90b81532 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Tue, 20 Jul 2021 12:09:59 +0530 Subject: [PATCH 17/32] gtest app for audio recorder Signed-off-by: Vaidegi B --- frameworks/innerkitsimpl/test/BUILD.gn | 5 +- .../test/moduletest/recorder_test/BUILD.gn | 32 + .../include/audio_recorder_module_test.h | 35 ++ .../src/audio_recorder_module_test.cpp | 568 ++++++++++++++++++ 4 files changed, 638 insertions(+), 2 deletions(-) create mode 100644 frameworks/innerkitsimpl/test/moduletest/recorder_test/BUILD.gn create mode 100644 frameworks/innerkitsimpl/test/moduletest/recorder_test/include/audio_recorder_module_test.h create mode 100644 frameworks/innerkitsimpl/test/moduletest/recorder_test/src/audio_recorder_module_test.cpp diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn index c27443d820..4743d8a688 100644 --- a/frameworks/innerkitsimpl/test/BUILD.gn +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -15,6 +15,7 @@ group("audio_test") { testonly = true deps = [ - "moduletest/renderer_test:moduletest" + "moduletest/renderer_test:moduletest", + "moduletest/recorder_test:audio_recorder_module_test" ] -} \ No newline at end of file +} diff --git a/frameworks/innerkitsimpl/test/moduletest/recorder_test/BUILD.gn b/frameworks/innerkitsimpl/test/moduletest/recorder_test/BUILD.gn new file mode 100644 index 0000000000..2eb2888b5a --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/recorder_test/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +module_output_path = "audio_standard/audio_recorder" + +ohos_moduletest("audio_recorder_module_test") { + module_out_path = module_output_path + include_dirs = [ + "./include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + ] + + sources = [ + "src/audio_recorder_module_test.cpp", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder:audio_recorder", + ] +} diff --git a/frameworks/innerkitsimpl/test/moduletest/recorder_test/include/audio_recorder_module_test.h b/frameworks/innerkitsimpl/test/moduletest/recorder_test/include/audio_recorder_module_test.h new file mode 100644 index 0000000000..a5a11c8d90 --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/recorder_test/include/audio_recorder_module_test.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_recorder.h" +#include "gtest/gtest.h" + +namespace OHOS { +namespace AudioStandard { +class AudioRecorderModuleTest : public testing::Test { +public: + // SetUpTestCase: Called before all test cases + static void SetUpTestCase(void); + // TearDownTestCase: Called after all test case + static void TearDownTestCase(void); + // SetUp: Called before each test cases + void SetUp(void); + // TearDown: Called after each test cases + void TearDown(void); + // Init Recorder + static int32_t InitializeRecorder(std::unique_ptr &audioRecorder); +}; +} // namespace AudioStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/test/moduletest/recorder_test/src/audio_recorder_module_test.cpp b/frameworks/innerkitsimpl/test/moduletest/recorder_test/src/audio_recorder_module_test.cpp new file mode 100644 index 0000000000..bc6446867d --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/recorder_test/src/audio_recorder_module_test.cpp @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_recorder_module_test.h" + + +#include "audio_info.h" +#include "audio_recorder.h" + +using namespace std; +using namespace testing::ext; + +namespace OHOS { +namespace AudioStandard { +namespace { + const string AUDIO_RECORD_FILE1 = "/data/audioreordtest_blocking.pcm"; + const string AUDIO_RECORD_FILE2 = "/data/audioreordtest_nonblocking.pcm"; + const string AUDIO_RECORD_FILE3 = "/data/audioreordtest_out.pcm"; + const int32_t READ_BUFFERS_COUNT = 128; + const int32_t VALUE_ZERO = 0; + const int32_t SUCCESS = 0; +} // namespace + +void AudioRecorderModuleTest::SetUpTestCase(void) {} +void AudioRecorderModuleTest::TearDownTestCase(void) {} +void AudioRecorderModuleTest::SetUp(void) {} +void AudioRecorderModuleTest::TearDown(void) {} + +int32_t AudioRecorderModuleTest::InitializeRecorder(unique_ptr &audioRecorder) +{ + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = SAMPLE_RATE_44100; + recorderParams.audioChannel = STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + + return audioRecorder->SetParams(recorderParams); +} + +/** +* @tc.name : Test GetSupportedFormats API +* @tc.number: Auido_Recorder_GetSupportedFormats_001 +* @tc.desc : test GetSupportedFormats interface, Returns supported Formats on success. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetSupportedFormats_001, TestSize.Level1) +{ + vector supportedFormatList = AudioRecorder::GetSupportedFormats(); + EXPECT_EQ(AUDIO_SUPPORTED_FORMATS.size(), supportedFormatList.size()); +} + +/** +* @tc.name : Test GetSupportedChannels API +* @tc.number: Auido_Recorder_GetSupportedChannels_001 +* @tc.desc : test GetSupportedChannels interface, Returns supported Channels on success. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetSupportedChannels_001, TestSize.Level1) +{ + vector supportedChannelList = AudioRecorder::GetSupportedChannels(); + EXPECT_EQ(AUDIO_SUPPORTED_CHANNELS.size(), supportedChannelList.size()); +} + +/** +* @tc.name : Test GetSupportedEncodingTypes API +* @tc.number: Auido_Recorder_GetSupportedEncodingTypes_001 +* @tc.desc : test GetSupportedEncodingTypes interface, Returns supported Encoding types on success. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetSupportedEncodingTypes_001, TestSize.Level1) +{ + vector supportedEncodingTypes + = AudioRecorder::GetSupportedEncodingTypes(); + EXPECT_EQ(AUDIO_SUPPORTED_ENCODING_TYPES.size(), supportedEncodingTypes.size()); +} + +/** +* @tc.name : Test GetSupportedSamplingRates API +* @tc.number: Auido_Recorder_GetSupportedSamplingRates_001 +* @tc.desc : test GetSupportedSamplingRates interface, Returns supported Sampling rates on success. +*/ +HWTEST(AudioRecoderModuleTest, Auido_Recorder_GetSupportedSamplingRates_001, TestSize.Level1) +{ + vector supportedSamplingRates = AudioRecorder::GetSupportedSamplingRates(); + EXPECT_EQ(AUDIO_SUPPORTED_SAMPLING_RATES.size(), supportedSamplingRates.size()); +} + +/** +* @tc.name : Test Create API via legal input. +* @tc.number: Auido_Recorder_Create_001 +* @tc.desc : test Create interface, Returns audioRecorder instance if create is Successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_Create_001, TestSize.Level1) +{ + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); +} + +/** +* @tc.name : Test SetParams API via legal input. +* @tc.number: Auido_Recorder_SetParams_001 +* @tc.desc : test SetParams interface, Returns 0 {SUCCESS} if the setting is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_SetParams_001, TestSize.Level1) +{ + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + ASSERT_NE(nullptr, audioRecorder); + + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = SAMPLE_RATE_44100; + recorderParams.audioChannel = STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + + int32_t ret = audioRecorder->SetParams(recorderParams); + EXPECT_EQ(SUCCESS, ret); + audioRecorder->Release(); +} + +/** +* @tc.name : Test GetParams API via legal input. +* @tc.number: Auido_Recorder_GetParams_001 +* @tc.desc : test GetParams interface, Returns 0 {SUCCESS} if the getting is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetParams_001, TestSize.Level1) +{ + int32_t ret = -1; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + ASSERT_NE(nullptr, audioRecorder); + + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = SAMPLE_RATE_44100; + recorderParams.audioChannel = STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + ret = audioRecorder->SetParams(recorderParams); + EXPECT_EQ(SUCCESS, ret); + + AudioRecorderParams getRecorderParams; + ret = audioRecorder->GetParams(getRecorderParams); + EXPECT_EQ(SUCCESS, ret); + EXPECT_EQ(recorderParams.audioSampleFormat, getRecorderParams.audioSampleFormat); + EXPECT_EQ(recorderParams.samplingRate, getRecorderParams.samplingRate); + EXPECT_EQ(recorderParams.audioChannel, getRecorderParams.audioChannel); + EXPECT_EQ(recorderParams.audioEncoding, getRecorderParams.audioEncoding); + + audioRecorder->Release(); +} + +/** +* @tc.name : Test GetBufferSize API via legal input. +* @tc.number: Auido_Recorder_GetBufferSize_001 +* @tc.desc : test GetBufferSize interface, Returns 0 {SUCCESS} if the getting is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetBufferSize_001, TestSize.Level1) +{ + int32_t ret = -1; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + audioRecorder->Release(); +} + +/** +* @tc.name : Test GetFrameCount API via legal input. +* @tc.number: Auido_Recorder_GetFrameCount_001 +* @tc.desc : test GetFrameCount interface, Returns 0 {SUCCESS} if the getting is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetFrameCount_001, TestSize.Level1) +{ + int32_t ret = -1; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + uint32_t frameCount; + ret = audioRecorder->GetFrameCount(frameCount); + EXPECT_EQ(SUCCESS, ret); + + audioRecorder->Release(); +} + +/** +* @tc.name : Test Start API. +* @tc.number: Audio_Recorder_Start_001 +* @tc.desc : test Start interface, Returns true if start is successful. +*/ +HWTEST(AudioRecorderModuleTest, Audio_Recorder_Start_001, TestSize.Level1) +{ + int32_t ret = -1; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + audioRecorder->Release(); +} + +/** +* @tc.name : Test Read API via isBlockingRead = true. +* @tc.number: Audio_Recorder_Read_001 +* @tc.desc : test GetFrameCount interface, Returns number of bytes read if the read is successful. +*/ +HWTEST(AudioRecorderModuleTest, Audio_Recorder_Read_001, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = true; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE1.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = READ_BUFFERS_COUNT; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + audioRecorder->Flush(); + audioRecorder->Stop(); + audioRecorder->Release(); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test Read API via isBlockingRead = false. +* @tc.number: Audio_Recorder_Read_002 +* @tc.desc : test GetFrameCount interface, Returns number of bytes read if the read is successful. +*/ +HWTEST(AudioRecorderModuleTest, Audio_Recorder_Read_002, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = false; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE2.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = READ_BUFFERS_COUNT; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + audioRecorder->Flush(); + audioRecorder->Stop(); + audioRecorder->Release(); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test GetAudioTime API via legal input. +* @tc.number: Auido_Recorder_GetAudioTime_001 +* @tc.desc : test GetAudioTime interface, Returns true if the getting is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_GetAudioTime_001, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = true; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE3.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = 5; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + Timestamp timeStamp; + bool getAudioTime = audioRecorder->GetAudioTime(timeStamp, Timestamp::Timestampbase::MONOTONIC); + EXPECT_EQ(true, getAudioTime); + EXPECT_GE(timeStamp.time.tv_sec, (const long)VALUE_ZERO); + EXPECT_GE(timeStamp.time.tv_nsec, (const long)VALUE_ZERO); + + audioRecorder->Flush(); + audioRecorder->Stop(); + audioRecorder->Release(); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test Flush API. +* @tc.number: Auido_Recorder_Flush_001 +* @tc.desc : test Flush interface, Returns true if the flush is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_Flush_001, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = true; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE3.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = 5; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + bool isFlushed = audioRecorder->Flush(); + EXPECT_EQ(true, isFlushed); + + audioRecorder->Stop(); + audioRecorder->Release(); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test Stop API. +* @tc.number: Auido_Recorder_Stop_001 +* @tc.desc : test Stop interface, Returns true if the stop is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_Stop_001, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = true; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE3.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = 5; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + audioRecorder->Flush(); + + bool isStopped = audioRecorder->Stop(); + EXPECT_EQ(true, isStopped); + + audioRecorder->Release(); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test Release API. +* @tc.number: Auido_Recorder_Release_001 +* @tc.desc : test Release interface, Returns true if the release is successful. +*/ +HWTEST(AudioRecorderModuleTest, Auido_Recorder_Release_001, TestSize.Level1) +{ + int32_t ret = -1; + bool isBlockingRead = true; + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + EXPECT_NE(nullptr, audioRecorder); + + ret = AudioRecorderModuleTest::InitializeRecorder(audioRecorder); + EXPECT_EQ(SUCCESS, ret); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + + size_t bufferLen; + ret = audioRecorder->GetBufferSize(bufferLen); + EXPECT_EQ(SUCCESS, ret); + + uint8_t* buffer = (uint8_t *) malloc(bufferLen); + ASSERT_NE(nullptr, buffer); + FILE *recFile = fopen(AUDIO_RECORD_FILE3.c_str(), "wb"); + ASSERT_NE(nullptr, recFile); + + size_t size = 1; + int32_t bytesRead = 0; + int32_t numBuffersToRecord = 5; + + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); + numBuffersToRecord--; + } + } + + audioRecorder->Flush(); + audioRecorder->Stop(); + + bool isReleased = audioRecorder->Release(); + EXPECT_EQ(true, isReleased); + + free(buffer); + fclose(recFile); +} + +/** +* @tc.name : Test GetStatus API. +* @tc.number: Auido_Recorder_GetStatus_001 +* @tc.desc : test GetStatus interface, Returns correct state on success. +*/ +HWTEST(AudioRecorderModuleTest, Audio_Recorder_GetStatus_001, TestSize.Level1) +{ + int32_t ret = -1; + RecorderState state = RECORDER_INVALID; + + unique_ptr audioRecorder = AudioRecorder::Create(STREAM_MUSIC); + ASSERT_NE(nullptr, audioRecorder); + state = audioRecorder->GetStatus(); + EXPECT_EQ(RECORDER_NEW, state); + + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = SAMPLE_RATE_44100; + recorderParams.audioChannel = STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + ret = audioRecorder->SetParams(recorderParams); + EXPECT_EQ(SUCCESS, ret); + state = audioRecorder->GetStatus(); + EXPECT_EQ(RECORDER_PREPARED, state); + + bool isStarted = audioRecorder->Start(); + EXPECT_EQ(true, isStarted); + state = audioRecorder->GetStatus(); + EXPECT_EQ(RECORDER_RUNNING, state); + + bool isStopped = audioRecorder->Stop(); + EXPECT_EQ(true, isStopped); + state = audioRecorder->GetStatus(); + EXPECT_EQ(RECORDER_STOPPED, state); + + bool isReleased = audioRecorder->Release(); + EXPECT_EQ(true, isReleased); + state = audioRecorder->GetStatus(); + EXPECT_EQ(RECORDER_RELEASED, state); +} +} // namespace AudioStandard +} // namespace OHOS -- Gitee From ebe8e30ecff284d0691d2c87afe60c5996031abb Mon Sep 17 00:00:00 2001 From: Murali S R Date: Wed, 21 Jul 2021 15:55:41 +0530 Subject: [PATCH 18/32] GetTimeStamp for playback and record scenario Signed-off-by: Anurup M --- services/src/client/audio_service_client.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index 5a905ba9cc..ef25241bc2 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -1000,16 +1000,22 @@ uint32_t AudioServiceClient::GetStreamVolume(uint32_t sessionID) int32_t AudioServiceClient::GetCurrentTimeStamp(uint64_t &timeStamp) { CHECK_PA_STATUS_RET_IF_FAIL(mainLoop, context, paStream, AUDIO_CLIENT_PA_ERR); - int32_t retVal = 0; + int32_t retVal = AUDIO_CLIENT_SUCCESS; pa_threaded_mainloop_lock(mainLoop); - retVal = pa_stream_get_time(paStream, &timeStamp); + const pa_timing_info *info = pa_stream_get_timing_info(paStream); + if (!info) { + retVal = AUDIO_CLIENT_ERR; + } else { + if(eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + timeStamp = pa_bytes_to_usec(info->write_index, &sampleSpec); + } else if(eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { + timeStamp = pa_bytes_to_usec(info->read_index, &sampleSpec); + } + } pa_threaded_mainloop_unlock(mainLoop); - if (retVal >= 0) - return AUDIO_CLIENT_SUCCESS; - else - return AUDIO_CLIENT_ERR; + return retVal; } int32_t AudioServiceClient::GetAudioLatency(uint64_t &latency) -- Gitee From ff335443f28556a8d46634ca57c36c1278ee96a1 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Wed, 21 Jul 2021 11:11:03 +0530 Subject: [PATCH 19/32] Add support for Samplerates 96KHz, 12KHz, 24KHz and 64KHz Signed-off-by: Vaidegi B --- .../native/audiocommon/include/audio_info.h | 12 ++++- services/src/client/audio_stream.cpp | 52 +++++-------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/interfaces/innerkits/native/audiocommon/include/audio_info.h b/interfaces/innerkits/native/audiocommon/include/audio_info.h index dbf6d58b84..e39e9c99e0 100644 --- a/interfaces/innerkits/native/audiocommon/include/audio_info.h +++ b/interfaces/innerkits/native/audiocommon/include/audio_info.h @@ -156,11 +156,15 @@ enum AudioChannel { enum AudioSamplingRate { SAMPLE_RATE_8000 = 8000, SAMPLE_RATE_11025 = 11025, + SAMPLE_RATE_12000 = 12000, SAMPLE_RATE_16000 = 16000, SAMPLE_RATE_22050 = 22050, + SAMPLE_RATE_24000 = 24000, SAMPLE_RATE_32000 = 32000, SAMPLE_RATE_44100 = 44100, - SAMPLE_RATE_48000 = 48000 + SAMPLE_RATE_48000 = 48000, + SAMPLE_RATE_64000 = 64000, + SAMPLE_RATE_96000 = 96000 }; typedef enum { @@ -249,11 +253,15 @@ const std::vector AUDIO_SUPPORTED_ENCODING_TYPES { const std::vector AUDIO_SUPPORTED_SAMPLING_RATES { SAMPLE_RATE_8000, SAMPLE_RATE_11025, + SAMPLE_RATE_12000, SAMPLE_RATE_16000, SAMPLE_RATE_22050, + SAMPLE_RATE_24000, SAMPLE_RATE_32000, SAMPLE_RATE_44100, - SAMPLE_RATE_48000 + SAMPLE_RATE_48000, + SAMPLE_RATE_64000, + SAMPLE_RATE_96000 }; typedef void* AudioIOHandle; } // namespace AudioStandard diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp index 1fa91a1f27..aa767d8a7d 100644 --- a/services/src/client/audio_stream.cpp +++ b/services/src/client/audio_stream.cpp @@ -16,6 +16,7 @@ #include "audio_stream.h" #include #include "audio_errors.h" +#include "audio_info.h" #include "media_log.h" using namespace std; @@ -25,33 +26,6 @@ namespace AudioStandard { const unsigned long long TIME_CONVERSION_US_S = 1000000ULL; /* us to s */ const unsigned long long TIME_CONVERSION_NS_US = 1000ULL; /* ns to us */ -// Supported audio parameters for both renderer and recorder -const vector SUPPORTED_FORMATS { - SAMPLE_U8, - SAMPLE_S16LE, - SAMPLE_S24LE, - SAMPLE_S32LE -}; - -const vector SUPPORTED_CHANNELS { - MONO, - STEREO -}; - -const vector SUPPORTED_ENCODING_TYPES { - ENCODING_PCM -}; - -const vector SUPPORTED_SAMPLING_RATES { - SAMPLE_RATE_8000, - SAMPLE_RATE_11025, - SAMPLE_RATE_16000, - SAMPLE_RATE_22050, - SAMPLE_RATE_32000, - SAMPLE_RATE_44100, - SAMPLE_RATE_48000 -}; - AudioStream::AudioStream(AudioStreamType eStreamType, AudioMode eMode) : eStreamType_(eStreamType), eMode_(eMode), state_(NEW), @@ -118,36 +92,36 @@ int32_t AudioStream::GetLatency(uint64_t &latency) vector AudioStream::GetSupportedFormats() { - return SUPPORTED_FORMATS; + return AUDIO_SUPPORTED_FORMATS; } vector AudioStream::GetSupportedChannels() { - return SUPPORTED_CHANNELS; + return AUDIO_SUPPORTED_CHANNELS; } vector AudioStream::GetSupportedEncodingTypes() { - return SUPPORTED_ENCODING_TYPES; + return AUDIO_SUPPORTED_ENCODING_TYPES; } vector AudioStream::GetSupportedSamplingRates() { - return SUPPORTED_SAMPLING_RATES; + return AUDIO_SUPPORTED_SAMPLING_RATES; } bool IsFormatValid(uint8_t format) { - bool isValidFormat = (find(SUPPORTED_FORMATS.begin(), SUPPORTED_FORMATS.end(), format) - != SUPPORTED_FORMATS.end()); + bool isValidFormat = (find(AUDIO_SUPPORTED_FORMATS.begin(), AUDIO_SUPPORTED_FORMATS.end(), format) + != AUDIO_SUPPORTED_FORMATS.end()); MEDIA_DEBUG_LOG("AudioStream: IsFormatValid: %{public}s", isValidFormat ? "true" : "false"); return isValidFormat; } bool IsChannelValid(uint8_t channel) { - bool isValidChannel = (find(SUPPORTED_CHANNELS.begin(), SUPPORTED_CHANNELS.end(), channel) - != SUPPORTED_CHANNELS.end()); + bool isValidChannel = (find(AUDIO_SUPPORTED_CHANNELS.begin(), AUDIO_SUPPORTED_CHANNELS.end(), channel) + != AUDIO_SUPPORTED_CHANNELS.end()); MEDIA_DEBUG_LOG("AudioStream: IsChannelValid: %{public}s", isValidChannel ? "true" : "false"); return isValidChannel; } @@ -155,8 +129,8 @@ bool IsChannelValid(uint8_t channel) bool IsEncodingTypeValid(uint8_t encodingType) { bool isValidEncodingType - = (find(SUPPORTED_ENCODING_TYPES.begin(), SUPPORTED_ENCODING_TYPES.end(), encodingType) - != SUPPORTED_ENCODING_TYPES.end()); + = (find(AUDIO_SUPPORTED_ENCODING_TYPES.begin(), AUDIO_SUPPORTED_ENCODING_TYPES.end(), encodingType) + != AUDIO_SUPPORTED_ENCODING_TYPES.end()); MEDIA_DEBUG_LOG("AudioStream: IsEncodingTypeValid: %{public}s", isValidEncodingType ? "true" : "false"); return isValidEncodingType; @@ -165,8 +139,8 @@ bool IsEncodingTypeValid(uint8_t encodingType) bool IsSamplingRateValid(uint32_t samplingRate) { bool isValidSamplingRate - = (find(SUPPORTED_SAMPLING_RATES.begin(), SUPPORTED_SAMPLING_RATES.end(), samplingRate) - != SUPPORTED_SAMPLING_RATES.end()); + = (find(AUDIO_SUPPORTED_SAMPLING_RATES.begin(), AUDIO_SUPPORTED_SAMPLING_RATES.end(), samplingRate) + != AUDIO_SUPPORTED_SAMPLING_RATES.end()); MEDIA_DEBUG_LOG("AudioStream: IsSamplingRateValid: %{public}s", isValidSamplingRate ? "true" : "false"); return isValidSamplingRate; -- Gitee From 2a4bb590dbba6a1c76943e9a261fb7f4805b93ed Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Wed, 21 Jul 2021 19:20:16 +0530 Subject: [PATCH 20/32] Static errors fix for audio_standard Signed-off-by: Vaidegi B --- .../include/audio_capturer_source.h | 3 + .../src/audio_capturer_source.cpp | 119 +++++++----- .../include/audio_recorder_private.h | 41 ++++ .../audiorecorder/src/audio_recorder.cpp | 46 ++--- .../include/audio_renderer_private.h | 64 +++---- .../include/audio_renderer_sink.h | 3 + .../audiorenderer/src/audio_renderer.cpp | 49 ++--- .../audiorenderer/src/audio_renderer_sink.cpp | 124 +++++++------ .../audio_manager/src/audio_manager_napi.cpp | 3 +- .../native/audiocommon/include/audio_info.h | 25 --- .../native/audiocommon/include/timestamp.h | 51 +++++ .../include/audio_system_manager.h | 32 ++-- .../innerkits/native/audiopolicy/BUILD.gn | 1 + .../innerkits/native/audiorecorder/BUILD.gn | 1 + .../audiorecorder/include/audio_recorder.h | 26 +-- .../innerkits/native/audiorenderer/BUILD.gn | 1 + .../audiorenderer/include/audio_renderer.h | 28 +-- .../native/audiostream/include/audio_stream.h | 1 + pulseaudio/src/BUILD.gn | 1 + pulseaudio/src/modules/hdi/hdi_source.c | 90 +++++---- .../src/modules/hdi/module_hdi_source.c | 10 +- .../audio_policy/client/audio_policy_base.h | 14 +- .../client/audio_policy_manager_stub.h | 42 +++++ .../audio_policy/server/audio_policy_server.h | 2 +- .../include/client/audio_service_client.h | 6 +- .../server/audio_policy_manager_stub.cpp | 157 ++++++++++------ .../service/include/audio_policy_service.h | 2 +- .../service/include/common/audio_config.h | 5 +- ...dio_policy.h => iaudio_policy_interface.h} | 0 .../include/interface/iport_observer.h | 2 +- .../manager/pulseaudio_policy_manager.h | 2 +- .../server/service/src/config/xml_parser.cpp | 4 +- .../src/manager/pulseaudio_policy_manager.cpp | 71 +++---- services/src/client/audio_service_client.cpp | 62 ++++--- services/src/client/audio_stream.cpp | 2 +- services/src/client/audio_system_manager.cpp | 33 ++-- services/src/server/audio_server.cpp | 8 +- services/test/audio_policy_test.cpp | 175 +++++++++++------- services/test/audio_recorder_test.cpp | 64 +++++-- services/test/audio_renderer_test.cpp | 94 ++++++---- services/test/pcm2wav.h | 10 +- services/test/playback_test.cpp | 92 +++++---- 42 files changed, 930 insertions(+), 636 deletions(-) create mode 100644 frameworks/innerkitsimpl/audiorecorder/include/audio_recorder_private.h rename pulseaudio/src/modules/hdi/hdi_source.h => frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h (34%) create mode 100644 interfaces/innerkits/native/audiocommon/include/timestamp.h create mode 100644 services/include/audio_policy/client/audio_policy_manager_stub.h rename services/src/audio_policy/server/service/include/interface/{iaudio_policy.h => iaudio_policy_interface.h} (100%) diff --git a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h index 9af4396c64..d2e675cdea 100644 --- a/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h +++ b/frameworks/innerkitsimpl/audiocapturer/include/audio_capturer_source.h @@ -77,6 +77,9 @@ private: void *handle_; + int32_t CreateCapture(struct AudioPort &capturePort); + int32_t InitAudioManager(); + #ifdef CAPTURE_DUMP FILE *pfd; #endif diff --git a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp index 910114e810..915f97e9e0 100644 --- a/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp +++ b/frameworks/innerkitsimpl/audiocapturer/src/audio_capturer_source.cpp @@ -27,7 +27,8 @@ const char *g_audioOutTestFilePath = "/data/local/tmp/audio_capture.pcm"; #endif // CAPTURE_DUMP AudioCapturerSource::AudioCapturerSource() - : capturerInited_(false), started_(false), paused_(false), leftVolume_(MAX_VOLUME_LEVEL), rightVolume_(MAX_VOLUME_LEVEL), + : capturerInited_(false), started_(false), paused_(false), + leftVolume_(MAX_VOLUME_LEVEL), rightVolume_(MAX_VOLUME_LEVEL), audioManager_(nullptr), audioAdapter_(nullptr), audioCapture_(nullptr) { attr_ = {}; @@ -71,24 +72,22 @@ void AudioCapturerSource::DeInit() #endif // CAPTURE_DUMP } -int32_t InitAttrsCapture(struct AudioSampleAttributes *attrs) +int32_t InitAttrsCapture(struct AudioSampleAttributes &attrs) { /* Initialization of audio parameters for playback */ - attrs->format = AUDIO_FORMAT_PCM_16_BIT; - attrs->channelCount = AUDIO_CHANNELCOUNT; - attrs->sampleRate = AUDIO_SAMPLE_RATE_48K; - attrs->interleaved = 0; - attrs->type = AUDIO_IN_MEDIA; - attrs->period = DEEP_BUFFER_CAPTURE_PERIOD_SIZE; - /* 16 * attrs->channelCount / 8,Byte */ - attrs->frameSize = PCM_16_BIT * attrs->channelCount / PCM_8_BIT; - attrs->isBigEndian = false; - attrs->isSignedData = true; - /* DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ - attrs->startThreshold = DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (attrs->frameSize); - attrs->stopThreshold = INT_32_MAX; + attrs.format = AUDIO_FORMAT_PCM_16_BIT; + attrs.channelCount = AUDIO_CHANNELCOUNT; + attrs.sampleRate = AUDIO_SAMPLE_RATE_48K; + attrs.interleaved = 0; + attrs.type = AUDIO_IN_MEDIA; + attrs.period = DEEP_BUFFER_CAPTURE_PERIOD_SIZE; + attrs.frameSize = PCM_16_BIT * attrs.channelCount / PCM_8_BIT; + attrs.isBigEndian = false; + attrs.isSignedData = true; + attrs.startThreshold = DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (attrs.frameSize); + attrs.stopThreshold = INT_32_MAX; /* 16 * 1024 */ - attrs->silenceThreshold = AUDIO_BUFF_SIZE; + attrs.silenceThreshold = AUDIO_BUFF_SIZE; return SUCCESS; } @@ -117,32 +116,72 @@ int32_t SwitchAdapterCapture(struct AudioAdapterDescriptor *descs, const char *a return ERR_INVALID_INDEX; } -int32_t AudioCapturerSource::Init(AudioSourceAttr &attr) +int32_t AudioCapturerSource::InitAudioManager() { - attr_ = attr; - int32_t ret; - int32_t index; - int32_t size = 0; char resolvedPath[100] = "/system/lib/libhdi_audio.z.so"; - struct AudioPort audioPort; - struct AudioAdapterDescriptor *descs = nullptr; - struct AudioPort capturePort; struct AudioManager *(*getAudioManager)() = nullptr; - audioPort.dir = PORT_IN; - audioPort.portId = 0; - audioPort.portName = "AOP"; handle_ = dlopen(resolvedPath, 1); if (handle_ == nullptr) { MEDIA_ERR_LOG("Open Capturer so Fail"); return ERR_INVALID_HANDLE; } + getAudioManager = (struct AudioManager *(*)())(dlsym(handle_, "GetAudioManagerFuncs")); audioManager_ = getAudioManager(); if (audioManager_ == nullptr) { return ERR_INVALID_HANDLE; } + return 0; +} + +int32_t AudioCapturerSource::CreateCapture(struct AudioPort &capturePort) +{ + // Initialization port information, can fill through mode and other parameters + int32_t ret = audioAdapter_->InitAllPorts(audioAdapter_); + if (ret != 0) { + MEDIA_ERR_LOG("InitAllPorts failed"); + return ERR_DEVICE_INIT; + } + + struct AudioSampleAttributes param; + // User needs to set + InitAttrsCapture(param); + param.sampleRate = attr_.sampleRate; + param.format = attr_.format; + param.channelCount = attr_.channel; + + struct AudioDeviceDescriptor deviceDesc; + deviceDesc.portId = capturePort.portId; + deviceDesc.pins = PIN_IN_MIC; + deviceDesc.desc = nullptr; + + ret = audioAdapter_->CreateCapture(audioAdapter_, &deviceDesc, ¶m, &audioCapture_); + if (audioCapture_ == nullptr || ret < 0) { + MEDIA_ERR_LOG("Create capture failed"); + return ERR_NOT_STARTED; + } + + capturerInited_ = true; + + return 0; +} + +int32_t AudioCapturerSource::Init(AudioSourceAttr &attr) +{ + attr_ = attr; + int32_t ret; + int32_t index; + int32_t size = 0; + struct AudioAdapterDescriptor *descs = nullptr; + struct AudioPort capturePort; + + if (InitAudioManager() != 0) { + MEDIA_ERR_LOG("Init audio manager Fail"); + return ERR_INVALID_HANDLE; + } + ret = audioManager_->GetAllAdapters(audioManager_, &descs, &size); // adapters is 0~3 if (size > MAX_AUDIO_ADAPTER_NUM || size == 0 || descs == nullptr || ret < 0) { @@ -152,7 +191,7 @@ int32_t AudioCapturerSource::Init(AudioSourceAttr &attr) // Get qualified sound card and port char adapterNameCase[PATH_LEN] = "internal"; - index = SwitchAdapterCapture(descs, adapterNameCase, audioPort.dir, &capturePort, size); + index = SwitchAdapterCapture(descs, adapterNameCase, PORT_IN, &capturePort, size); if (index < 0) { MEDIA_ERR_LOG("Switch Adapter Fail"); return ERR_NOT_STARTED; @@ -167,33 +206,11 @@ int32_t AudioCapturerSource::Init(AudioSourceAttr &attr) MEDIA_ERR_LOG("Load audio device failed"); return ERR_NOT_STARTED; } - // Initialization port information, can fill through mode and other parameters - ret = audioAdapter_->InitAllPorts(audioAdapter_); - if (ret != 0) { - MEDIA_ERR_LOG("InitAllPorts failed"); - return ERR_DEVICE_INIT; - } - struct AudioSampleAttributes param; - // User needs to set - InitAttrsCapture(¶m); - param.sampleRate = attr_.sampleRate; - param.format = attr_.format; - param.channelCount = attr_.channel; - - struct AudioDeviceDescriptor deviceDesc; - deviceDesc.portId = capturePort.portId; - deviceDesc.pins = PIN_IN_MIC; - deviceDesc.desc = nullptr; - - ret = audioAdapter_->CreateCapture(audioAdapter_, &deviceDesc, ¶m, &audioCapture_); - if (audioCapture_ == nullptr || ret < 0) { + if (CreateCapture(capturePort) != 0) { MEDIA_ERR_LOG("Create capture failed"); return ERR_NOT_STARTED; } - - capturerInited_ = true; - #ifdef CAPTURE_DUMP pfd = fopen(g_audioOutTestFilePath, "wb+"); if (pfd == nullptr) { diff --git a/frameworks/innerkitsimpl/audiorecorder/include/audio_recorder_private.h b/frameworks/innerkitsimpl/audiorecorder/include/audio_recorder_private.h new file mode 100644 index 0000000000..03354f80e7 --- /dev/null +++ b/frameworks/innerkitsimpl/audiorecorder/include/audio_recorder_private.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_recorder.h" +#include "audio_stream.h" + +namespace OHOS { +namespace AudioStandard { +class AudioRecorderPrivate : public AudioRecorder { +public: + int32_t GetFrameCount(uint32_t &frameCount) const override; + int32_t SetParams(const AudioRecorderParams params) const override; + int32_t GetParams(AudioRecorderParams ¶ms) const override; + bool Start() const override; + int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) const override; + RecorderState GetStatus() const override; + bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const override; + bool Stop() const override; + bool Flush() const override; + bool Release() const override; + int32_t GetBufferSize(size_t &bufferSize) const override; + + std::unique_ptr audioRecorder; + + explicit AudioRecorderPrivate(AudioStreamType audioStreamType); + virtual ~AudioRecorderPrivate(); +}; +} // namespace AudioStandard +} // namespace OHOS diff --git a/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp index 8416566ed7..f7346036ce 100644 --- a/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp +++ b/frameworks/innerkitsimpl/audiorecorder/src/audio_recorder.cpp @@ -17,31 +17,11 @@ #include "audio_errors.h" #include "audio_recorder.h" +#include "audio_recorder_private.h" #include "audio_stream.h" namespace OHOS { namespace AudioStandard { - -class AudioRecorderPrivate : public AudioRecorder { -public: - int32_t GetFrameCount(uint32_t &frameCount) override; - int32_t SetParams(const AudioRecorderParams params) override; - int32_t GetParams(AudioRecorderParams ¶ms) override; - bool Start() override; - int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) override; - RecorderState GetStatus() override; - bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) override; - bool Stop() override; - bool Flush() override; - bool Release() override; - int32_t GetBufferSize(size_t &bufferSize) override; - - std::unique_ptr audioRecorder; - - AudioRecorderPrivate(AudioStreamType audioStreamType); - virtual ~AudioRecorderPrivate(); -}; - AudioRecorder::~AudioRecorder() = default; AudioRecorderPrivate::~AudioRecorderPrivate() = default; @@ -55,12 +35,12 @@ AudioRecorderPrivate::AudioRecorderPrivate(AudioStreamType audioStreamType) audioRecorder = std::make_unique(audioStreamType, AUDIO_MODE_RECORD); } -int32_t AudioRecorderPrivate::GetFrameCount(uint32_t &frameCount) +int32_t AudioRecorderPrivate::GetFrameCount(uint32_t &frameCount) const { return audioRecorder->GetFrameCount(frameCount); } -int32_t AudioRecorderPrivate::SetParams(const AudioRecorderParams params) +int32_t AudioRecorderPrivate::SetParams(const AudioRecorderParams params) const { AudioStreamParams audioStreamParams; audioStreamParams.format = params.audioSampleFormat; @@ -71,7 +51,7 @@ int32_t AudioRecorderPrivate::SetParams(const AudioRecorderParams params) return audioRecorder->SetAudioStreamInfo(audioStreamParams); } -int32_t AudioRecorderPrivate::GetParams(AudioRecorderParams ¶ms) +int32_t AudioRecorderPrivate::GetParams(AudioRecorderParams ¶ms) const { AudioStreamParams audioStreamParams; int32_t result = audioRecorder->GetAudioStreamInfo(audioStreamParams); @@ -85,42 +65,42 @@ int32_t AudioRecorderPrivate::GetParams(AudioRecorderParams ¶ms) return result; } -bool AudioRecorderPrivate::Start() +bool AudioRecorderPrivate::Start() const { return audioRecorder->StartAudioStream(); } -int32_t AudioRecorderPrivate::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) +int32_t AudioRecorderPrivate::Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) const { return audioRecorder->Read(buffer, userSize, isBlockingRead); } -RecorderState AudioRecorderPrivate::GetStatus() +RecorderState AudioRecorderPrivate::GetStatus() const { return (RecorderState)audioRecorder->GetState(); } -bool AudioRecorderPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) +bool AudioRecorderPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const { - return audioRecorder->GetAudioTime(timestamp,base); + return audioRecorder->GetAudioTime(timestamp, base); } -bool AudioRecorderPrivate::Stop() +bool AudioRecorderPrivate::Stop() const { return audioRecorder->StopAudioStream(); } -bool AudioRecorderPrivate::Flush() +bool AudioRecorderPrivate::Flush() const { return audioRecorder->FlushAudioStream(); } -bool AudioRecorderPrivate::Release() +bool AudioRecorderPrivate::Release() const { return audioRecorder->ReleaseAudioStream(); } -int32_t AudioRecorderPrivate::GetBufferSize(size_t &bufferSize) +int32_t AudioRecorderPrivate::GetBufferSize(size_t &bufferSize) const { return audioRecorder->GetBufferSize(bufferSize); } diff --git a/pulseaudio/src/modules/hdi/hdi_source.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h similarity index 34% rename from pulseaudio/src/modules/hdi/hdi_source.h rename to frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h index fd12658f3e..78ea1b596c 100644 --- a/pulseaudio/src/modules/hdi/hdi_source.h +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h @@ -13,46 +13,34 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include +#ifndef AUDIO_RECORDER_PRIVATE_H +#define AUDIO_RECORDER_PRIVATE_H -#include -#include +#include "audio_renderer.h" +#include "audio_stream.h" -#define DEFAULT_SOURCE_NAME "hdi_input" -#define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic" +namespace OHOS { +namespace AudioStandard { +class AudioRendererPrivate : public AudioRenderer { +public: + int32_t GetFrameCount(uint32_t &frameCount) const override; + int32_t GetLatency(uint64_t &latency) const override; + int32_t SetParams(const AudioRendererParams params) const override; + int32_t GetParams(AudioRendererParams ¶ms) const override; + bool Start() const override; + int32_t Write(uint8_t *buffer, size_t bufferSize) override; + RendererState GetStatus() const override; + bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const override; + bool Drain() const override; + bool Stop() const override; + bool Release() const override; + int32_t GetBufferSize(size_t &bufferSize) const override; -#define DEFAULT_BUFFER_SIZE (1024 * 16) -#define MAX_VOLUME_VALUE 15.0 -#define DEFAULT_LEFT_VOLUME MAX_VOLUME_VALUE -#define DEFAULT_RIGHT_VOLUME MAX_VOLUME_VALUE -#define FIVE_MSEC 5000 -#define MAX_RETRIES 5 -#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2) -#define MIN_LATENCY_USEC (500) -#define AUDIO_POINT_NUM 1024 -#define AUDIO_FRAME_NUM_IN_BUF 30 + std::unique_ptr audioRenderer; -struct userdata { - pa_core *core; - pa_module *module; - pa_source *source; - pa_thread *thread; - pa_thread_mq thread_mq; - pa_rtpoll *rtpoll; - size_t buffer_size; - pa_usec_t block_usec; - pa_usec_t timestamp; - AudioSourceAttr attrs; - // A flag to signal us to prevent silent record during bootup - bool IsReady; - bool IsCapturerInit; + explicit AudioRendererPrivate(AudioStreamType audioStreamType); + virtual ~AudioRendererPrivate(); }; - -pa_source* pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver); - -void pa_hdi_source_free(pa_source *s); +} // namespace AudioStandard +} // namespace OHOS +#endif // AUDIO_RECORDER_PRIVATE_H diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h index 154a2966f3..b756adfd5c 100644 --- a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_sink.h @@ -58,6 +58,9 @@ private: struct AudioAdapter *audioAdapter_; struct AudioRender *audioRender_; void *handle_; + + int32_t CreateRender(struct AudioPort &renderPort); + int32_t InitAudioManager(); #ifdef DUMPFILE FILE *pfd; #endif // DUMPFILE diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp index 333249edac..87c8fdc339 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp @@ -17,32 +17,11 @@ #include "audio_errors.h" #include "audio_renderer.h" +#include "audio_renderer_private.h" #include "audio_stream.h" namespace OHOS { namespace AudioStandard { - -class AudioRendererPrivate : public AudioRenderer { -public: - int32_t GetFrameCount(uint32_t &frameCount) override; - int32_t GetLatency(uint64_t &latency) override; - int32_t SetParams(const AudioRendererParams params) override; - int32_t GetParams(AudioRendererParams ¶ms) override; - bool Start() override; - int32_t Write(uint8_t *buffer, size_t bufferSize) override; - RendererState GetStatus() override; - bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) override; - bool Drain() override; - bool Stop() override; - bool Release() override; - int32_t GetBufferSize(size_t &bufferSize) override; - - std::unique_ptr audioRenderer; - - AudioRendererPrivate(AudioStreamType audioStreamType); - virtual ~AudioRendererPrivate(); -}; - AudioRenderer::~AudioRenderer() = default; AudioRendererPrivate::~AudioRendererPrivate() = default; @@ -56,17 +35,17 @@ AudioRendererPrivate::AudioRendererPrivate(AudioStreamType audioStreamType) audioRenderer = std::make_unique(audioStreamType, AUDIO_MODE_PLAYBACK); } -int32_t AudioRendererPrivate::GetFrameCount(uint32_t &frameCount) +int32_t AudioRendererPrivate::GetFrameCount(uint32_t &frameCount) const { return audioRenderer->GetFrameCount(frameCount); } -int32_t AudioRendererPrivate::GetLatency(uint64_t &latency) +int32_t AudioRendererPrivate::GetLatency(uint64_t &latency) const { return audioRenderer->GetLatency(latency); } -int32_t AudioRendererPrivate::SetParams(const AudioRendererParams params) +int32_t AudioRendererPrivate::SetParams(const AudioRendererParams params) const { AudioStreamParams audioStreamParams; audioStreamParams.format = params.sampleFormat; @@ -77,11 +56,11 @@ int32_t AudioRendererPrivate::SetParams(const AudioRendererParams params) return audioRenderer->SetAudioStreamInfo(audioStreamParams); } -int32_t AudioRendererPrivate::GetParams(AudioRendererParams ¶ms) +int32_t AudioRendererPrivate::GetParams(AudioRendererParams ¶ms) const { AudioStreamParams audioStreamParams; int32_t result = audioRenderer->GetAudioStreamInfo(audioStreamParams); - if(!result) { + if (!result) { params.sampleFormat = static_cast(audioStreamParams.format); params.sampleRate = static_cast(audioStreamParams.samplingRate); params.channelCount = static_cast(audioStreamParams.channels); @@ -91,7 +70,7 @@ int32_t AudioRendererPrivate::GetParams(AudioRendererParams ¶ms) return result; } -bool AudioRendererPrivate::Start() +bool AudioRendererPrivate::Start() const { return audioRenderer->StartAudioStream(); } @@ -101,32 +80,32 @@ int32_t AudioRendererPrivate::Write(uint8_t *buffer, size_t bufferSize) return audioRenderer->Write(buffer, bufferSize); } -RendererState AudioRendererPrivate::GetStatus() +RendererState AudioRendererPrivate::GetStatus() const { return static_cast(audioRenderer->GetState()); } -bool AudioRendererPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) +bool AudioRendererPrivate::GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const { - return audioRenderer->GetAudioTime(timestamp,base); + return audioRenderer->GetAudioTime(timestamp, base); } -bool AudioRendererPrivate::Drain() +bool AudioRendererPrivate::Drain() const { return audioRenderer->DrainAudioStream(); } -bool AudioRendererPrivate::Stop() +bool AudioRendererPrivate::Stop() const { return audioRenderer->StopAudioStream(); } -bool AudioRendererPrivate::Release() +bool AudioRendererPrivate::Release() const { return audioRenderer->ReleaseAudioStream(); } -int32_t AudioRendererPrivate::GetBufferSize(size_t &bufferSize) +int32_t AudioRendererPrivate::GetBufferSize(size_t &bufferSize) const { return audioRenderer->GetBufferSize(bufferSize); } diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp index ee93ed2b12..c0271f061f 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer_sink.cpp @@ -23,18 +23,16 @@ namespace OHOS { namespace AudioStandard { -#define AUDIO_CHANNELCOUNT 2 -#define AUDIO_SAMPLE_RATE_48K 48000 -#define DEEP_BUFFER_RENDER_PERIOD_SIZE 4096 -#define INT_32_MAX 0x7fffffff -#define PERIOD_SIZE 1024 -#define PCM_8_BIT 8 -#define PCM_16_BIT 16 - namespace { const int32_t HALF_FACTOR = 2; const int32_t MAX_AUDIO_ADAPTER_NUM = 3; const float DEFAULT_VOLUME_LEVEL = 1.0f; +const uint32_t AUDIO_CHANNELCOUNT = 2; +const uint32_t AUDIO_SAMPLE_RATE_48K = 48000; +const uint32_t DEEP_BUFFER_RENDER_PERIOD_SIZE = 4096; +const uint32_t INT_32_MAX = 0x7fffffff; +#define PCM_8_BIT 8 +#define PCM_16_BIT 16 } #ifdef DUMPFILE @@ -88,30 +86,27 @@ void AudioRendererSink::DeInit() #endif // DUMPFILE } -int32_t InitAttrs(struct AudioSampleAttributes *attrs) +int32_t InitAttrs(struct AudioSampleAttributes &attrs) { /* Initialization of audio parameters for playback */ - attrs->format = AUDIO_FORMAT_PCM_16_BIT; - attrs->channelCount = AUDIO_CHANNELCOUNT; - attrs->sampleRate = AUDIO_SAMPLE_RATE_48K; - attrs->interleaved = 0; - attrs->type = AUDIO_IN_MEDIA; - attrs->period = DEEP_BUFFER_RENDER_PERIOD_SIZE; - /* PERIOD_SIZE * 16 * attrs->channelCount / 8 */ - attrs->frameSize = PCM_16_BIT * attrs->channelCount / PCM_8_BIT; - attrs->isBigEndian = false; - attrs->isSignedData = true; - /* DEEP_BUFFER_RENDER_PERIOD_SIZE / (16 * attrs->channelCount / 8) */ - attrs->startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (attrs->frameSize); - attrs->stopThreshold = INT_32_MAX; - attrs->silenceThreshold = 0; + attrs.format = AUDIO_FORMAT_PCM_16_BIT; + attrs.channelCount = AUDIO_CHANNELCOUNT; + attrs.sampleRate = AUDIO_SAMPLE_RATE_48K; + attrs.interleaved = 0; + attrs.type = AUDIO_IN_MEDIA; + attrs.period = DEEP_BUFFER_RENDER_PERIOD_SIZE; + attrs.frameSize = PCM_16_BIT * attrs.channelCount / PCM_8_BIT; + attrs.isBigEndian = false; + attrs.isSignedData = true; + attrs.startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (attrs.frameSize); + attrs.stopThreshold = INT_32_MAX; + attrs.silenceThreshold = 0; return SUCCESS; } -static int32_t SwitchAdapter(struct AudioAdapterDescriptor *descs, - const char *adapterNameCase, enum AudioPortDirection portFlag, - struct AudioPort *renderPort, int32_t size) +static int32_t SwitchAdapter(struct AudioAdapterDescriptor *descs, const char *adapterNameCase, + enum AudioPortDirection portFlag, struct AudioPort *renderPort, int32_t size) { for (int32_t index = 0; index < size; index++) { struct AudioAdapterDescriptor *desc = &descs[index]; @@ -134,12 +129,8 @@ static int32_t SwitchAdapter(struct AudioAdapterDescriptor *descs, return ERR_INVALID_INDEX; } -int32_t AudioRendererSink::Init(AudioSinkAttr &attr) +int32_t AudioRendererSink::InitAudioManager() { - attr_ = attr; - struct AudioPort renderPort; - const char *adapterNameCase = "usb"; // Set sound card information - enum AudioPortDirection port = PORT_OUT; // Set port information char resolvedPath[100] = "/system/lib/libhdi_audio.z.so"; struct AudioManager *(*getAudioManager)() = nullptr; @@ -148,17 +139,61 @@ int32_t AudioRendererSink::Init(AudioSinkAttr &attr) MEDIA_ERR_LOG("Open so Fail"); return ERR_INVALID_HANDLE; } + getAudioManager = (struct AudioManager* (*)())(dlsym(handle_, "GetAudioManagerFuncs")); audioManager_ = getAudioManager(); if (audioManager_ == nullptr) { return ERR_INVALID_HANDLE; } - int32_t ret = 0; + return 0; +} + +int32_t AudioRendererSink::CreateRender(struct AudioPort &renderPort) +{ + // Initialization port information, can fill through mode and other parameters + int32_t ret = audioAdapter_->InitAllPorts(audioAdapter_); + if (ret != 0) { + MEDIA_ERR_LOG("InitAllPorts failed"); + return ERR_NOT_STARTED; + } + + struct AudioSampleAttributes param; + InitAttrs(param); + param.sampleRate = attr_.sampleRate; + param.channelCount = attr_.channel; + + struct AudioDeviceDescriptor deviceDesc; + deviceDesc.portId = renderPort.portId; + deviceDesc.pins = PIN_OUT_SPEAKER; + deviceDesc.desc = nullptr; + ret = audioAdapter_->CreateRender(audioAdapter_, &deviceDesc, ¶m, &audioRender_); + if (ret != 0 || audioRender_ == nullptr) { + MEDIA_ERR_LOG("AudioDeviceCreateRender failed"); + audioManager_->UnloadAdapter(audioManager_, audioAdapter_); + return ERR_NOT_STARTED; + } + + rendererInited_ = true; + return 0; +} + +int32_t AudioRendererSink::Init(AudioSinkAttr &attr) +{ + attr_ = attr; + struct AudioPort renderPort; + const char *adapterNameCase = "usb"; // Set sound card information + enum AudioPortDirection port = PORT_OUT; // Set port information + + if (InitAudioManager() != 0) { + MEDIA_ERR_LOG("Init audio manager Fail"); + return ERR_NOT_STARTED; + } + int32_t size = -1; struct AudioAdapterDescriptor *descs = nullptr; audioManager_->GetAllAdapters(audioManager_, &descs, &size); - if (size > MAX_AUDIO_ADAPTER_NUM || size == 0 || descs == nullptr || ret < 0) { + if (size > MAX_AUDIO_ADAPTER_NUM || size == 0 || descs == nullptr) { MEDIA_ERR_LOG("Get adapters Fail"); return ERR_NOT_STARTED; } @@ -180,30 +215,11 @@ int32_t AudioRendererSink::Init(AudioSinkAttr &attr) return ERR_NOT_STARTED; } - // Initialization port information, can fill through mode and other parameters - ret = audioAdapter_->InitAllPorts(audioAdapter_); - if (ret != 0) { - MEDIA_ERR_LOG("InitAllPorts failed"); + if (CreateRender(renderPort) != 0) { + MEDIA_ERR_LOG("Create render failed"); return ERR_NOT_STARTED; } - struct AudioSampleAttributes param; - InitAttrs(¶m); - param.sampleRate = attr_.sampleRate; - param.channelCount = attr_.channel; - - struct AudioDeviceDescriptor deviceDesc; - deviceDesc.portId = renderPort.portId; - deviceDesc.pins = PIN_OUT_SPEAKER; - deviceDesc.desc = nullptr; - ret = audioAdapter_->CreateRender(audioAdapter_, &deviceDesc, ¶m, &audioRender_); - if (ret != 0 || audioRender_ == nullptr) { - MEDIA_ERR_LOG("AudioDeviceCreateRender failed"); - audioManager_->UnloadAdapter(audioManager_, audioAdapter_); - return ERR_NOT_STARTED; - } - rendererInited_ = true; - #ifdef DUMPFILE pfd = fopen(g_audioOutTestFilePath, "wb+"); if (pfd == nullptr) { diff --git a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp index 0594107853..d6563962b3 100644 --- a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp @@ -799,7 +799,8 @@ napi_value AudioManagerNapi::SetRingerMode(napi_env env, napi_callback_info info env, nullptr, resource, [](napi_env env, void* data) { auto context = static_cast(data); - context->status = context->objectInfo->audioMngr_->SetRingerMode(static_cast(context->ringMode)); + context->status = + context->objectInfo->audioMngr_->SetRingerMode(static_cast(context->ringMode)); }, SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { diff --git a/interfaces/innerkits/native/audiocommon/include/audio_info.h b/interfaces/innerkits/native/audiocommon/include/audio_info.h index e39e9c99e0..21c16df9d7 100644 --- a/interfaces/innerkits/native/audiocommon/include/audio_info.h +++ b/interfaces/innerkits/native/audiocommon/include/audio_info.h @@ -16,7 +16,6 @@ #define AUDIO_INFO_H #ifdef __MUSL__ -#include #include #endif // __MUSL__ @@ -209,30 +208,6 @@ struct AudioStreamParams { uint8_t channels; }; -/** - * @brief Represents Timestamp information, including the frame position information and high-resolution time source. - */ -class Timestamp { -public: - Timestamp() : framePosition(0) - { - time.tv_sec = 0; - time.tv_nsec = 0; - } - virtual ~Timestamp() = default; - uint32_t framePosition; - struct timespec time; - - /** - * @brief Enumerates the time base of this Timestamp. Different timing methods are supported. - * - */ - enum Timestampbase { - /** Monotonically increasing time, excluding the system sleep time */ - MONOTONIC = 0 - }; -}; - // Supported audio parameters for both renderer and recorder const std::vector AUDIO_SUPPORTED_FORMATS { SAMPLE_U8, diff --git a/interfaces/innerkits/native/audiocommon/include/timestamp.h b/interfaces/innerkits/native/audiocommon/include/timestamp.h new file mode 100644 index 0000000000..2295c3b85c --- /dev/null +++ b/interfaces/innerkits/native/audiocommon/include/timestamp.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 TIMESTAMP_H +#define TIMESTAMP_H +#ifdef __MUSL__ +#include + +#include +#endif // __MUSL__ +#include + +namespace OHOS { +namespace AudioStandard { +/** + * @brief Represents Timestamp information, including the frame position information and high-resolution time source. + */ +class Timestamp { +public: + Timestamp() : framePosition(0) + { + time.tv_sec = 0; + time.tv_nsec = 0; + } + virtual ~Timestamp() = default; + uint32_t framePosition; + struct timespec time; + + /** + * @brief Enumerates the time base of this Timestamp. Different timing methods are supported. + * + */ + enum Timestampbase { + /** Monotonically increasing time, excluding the system sleep time */ + MONOTONIC = 0 + }; +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // TIMESTAMP_H diff --git a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h index 27c9de1225..cde085460a 100644 --- a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h +++ b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h @@ -144,22 +144,22 @@ enum AudioVolumeType { STREAM_ACCESSIBILITY = 10 }; static AudioSystemManager* GetInstance(); - int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume); - float GetVolume(AudioSystemManager::AudioVolumeType volumeType); - float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType); - float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType); - int32_t SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute); - bool IsStreamMute(AudioSystemManager::AudioVolumeType volumeType); - int32_t SetMicrophoneMute(bool IsMute); - bool IsMicrophoneMute(void); - std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag); - const std::string GetAudioParameter(const std::string key); - void SetAudioParameter(const std::string key, const std::string value); - int32_t SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag); - bool IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType); - bool IsStreamActive(AudioSystemManager::AudioVolumeType volumeType); - bool SetRingerMode(AudioRingerMode ringMode); - AudioRingerMode GetRingerMode(); + int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) const; + float GetVolume(AudioSystemManager::AudioVolumeType volumeType) const; + float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const; + float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const; + int32_t SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute) const; + bool IsStreamMute(AudioSystemManager::AudioVolumeType volumeType) const; + int32_t SetMicrophoneMute(bool isMute) const; + bool IsMicrophoneMute(void) const; + std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) const; + const std::string GetAudioParameter(const std::string key) const; + void SetAudioParameter(const std::string key, const std::string value) const; + int32_t SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag) const; + bool IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType) const; + bool IsStreamActive(AudioSystemManager::AudioVolumeType volumeType) const; + bool SetRingerMode(AudioRingerMode ringMode) const; + AudioRingerMode GetRingerMode() const; private: AudioSystemManager(); virtual ~AudioSystemManager(); diff --git a/interfaces/innerkits/native/audiopolicy/BUILD.gn b/interfaces/innerkits/native/audiopolicy/BUILD.gn index 4e4ba1a4c7..73aaa57897 100644 --- a/interfaces/innerkits/native/audiopolicy/BUILD.gn +++ b/interfaces/innerkits/native/audiopolicy/BUILD.gn @@ -86,6 +86,7 @@ ohos_executable("audio_policy_test") { deps = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", + "//third_party/bounds_checking_function:libsec_static", ] external_deps = [ "hiviewdfx_hilog_native:libhilog" ] diff --git a/interfaces/innerkits/native/audiorecorder/BUILD.gn b/interfaces/innerkits/native/audiorecorder/BUILD.gn index 5cefb05e3a..12029f9135 100644 --- a/interfaces/innerkits/native/audiorecorder/BUILD.gn +++ b/interfaces/innerkits/native/audiorecorder/BUILD.gn @@ -24,6 +24,7 @@ group("audio_recorder_test_packages") { config("audio_recorder_config") { include_dirs = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorecorder/include", "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", diff --git a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h index c36435812f..f557908842 100644 --- a/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h +++ b/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h @@ -19,6 +19,7 @@ #include #include "audio_info.h" +#include "timestamp.h" namespace OHOS { namespace AudioStandard { @@ -75,7 +76,7 @@ public: * @return Returns {@link SUCCESS} if frameCount is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetFrameCount(uint32_t &frameCount) = 0; + virtual int32_t GetFrameCount(uint32_t &frameCount) const = 0; /** * @brief Sets audio record parameters. @@ -85,25 +86,26 @@ public: * @return Returns {@link SUCCESS} if the setting is successful; returns an error code defined * in {@link audio_errors.h} otherwise. */ - virtual int32_t SetParams(const AudioRecorderParams params) = 0; + virtual int32_t SetParams(const AudioRecorderParams params) const = 0; /** * @brief Obtains audio recorder parameters. * * This function can be called after {@link SetParams} is successful. * - * @param params Indicates information about audio recorder parameters. For details, see {@link AudioRecorderParams}. + * @param params Indicates information about audio recorder parameters.For details,see + * {@link AudioRecorderParams}. * @return Returns {@link SUCCESS} if the parameter information is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetParams(AudioRecorderParams ¶ms) = 0; + virtual int32_t GetParams(AudioRecorderParams ¶ms) const = 0; /** * @brief Starts audio recording. * * @return Returns true if the recording is successfully started; returns false otherwise. */ - virtual bool Start() = 0; + virtual bool Start() const = 0; /** * @brief record audio data. @@ -119,14 +121,14 @@ public: * ERR_ILLEGAL_STATE: The AudioRecorder instance is not initialized. * ERR_INVALID_READ: The read size < 0. */ - virtual int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) = 0; + virtual int32_t Read(uint8_t &buffer, size_t userSize, bool isBlockingRead) const = 0; /** * @brief Obtains the audio record state. * * @return Returns the audio record state defined in {@link RecorderState}. */ - virtual RecorderState GetStatus() = 0; + virtual RecorderState GetStatus() const = 0; /** * @brief Obtains the Timestamp. @@ -136,27 +138,27 @@ public: * {@link Timestamp.Timestampbase#MONOTONIC}. * @return Returns true if the timestamp is successfully obtained; returns false otherwise. */ - virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) = 0; + virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const = 0; /** * @brief Stops audio recording. * * @return Returns true if the recording is successfully stopped; returns false otherwise. */ - virtual bool Stop() = 0; + virtual bool Stop() const = 0; /** * @brief flush record stream. * * @return Returns true if the object is successfully flushed; returns false otherwise. */ - virtual bool Flush() = 0; + virtual bool Flush() const = 0; /** * @brief Releases a local AudioRecorder object. * * @return Returns true if the object is successfully released; returns false otherwise. */ - virtual bool Release() = 0; + virtual bool Release() const = 0; /** * @brief Obtains a reasonable minimum buffer size for recorder, however, the recorder can @@ -166,7 +168,7 @@ public: * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetBufferSize(size_t &bufferSize) = 0; + virtual int32_t GetBufferSize(size_t &bufferSize) const = 0; /** * @brief Obtains the recorder supported formats. diff --git a/interfaces/innerkits/native/audiorenderer/BUILD.gn b/interfaces/innerkits/native/audiorenderer/BUILD.gn index f09ef6b71e..26cb43c9ec 100644 --- a/interfaces/innerkits/native/audiorenderer/BUILD.gn +++ b/interfaces/innerkits/native/audiorenderer/BUILD.gn @@ -18,6 +18,7 @@ pulseaudio_dir = "//third_party/pulseaudio" config("audio_renderer_config") { include_dirs = [ "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiorenderer/include", "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiostream/include", diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h index 227c606bcf..ce6d9e8de6 100644 --- a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -19,6 +19,7 @@ #include #include "audio_info.h" +#include "timestamp.h" namespace OHOS { namespace AudioStandard { @@ -75,7 +76,7 @@ public: * @return Returns {@link SUCCESS} if frameCount is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetFrameCount(uint32_t &frameCount) = 0; + virtual int32_t GetFrameCount(uint32_t &frameCount) const = 0; /** * @brief Sets audio renderer parameters. @@ -85,25 +86,26 @@ public: * @return Returns {@link SUCCESS} if the setting is successful; returns an error code defined * in {@link audio_errors.h} otherwise. */ - virtual int32_t SetParams(const AudioRendererParams params) = 0; + virtual int32_t SetParams(const AudioRendererParams params) const = 0; /** * @brief Obtains audio renderer parameters. * * This function can be called after {@link SetParams} is successful. * - * @param params Indicates information about audio renderer parameters. For details, see {@link AudioRendererParams}. + * @param params Indicates information about audio renderer parameters. For details, see + * {@link AudioRendererParams}. * @return Returns {@link SUCCESS} if the parameter information is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetParams(AudioRendererParams ¶ms) = 0; + virtual int32_t GetParams(AudioRendererParams ¶ms) const = 0; /** * @brief Starts audio rendering. * * @return Returns true if the rendering is successfully started; returns false otherwise. */ - virtual bool Start() = 0; + virtual bool Start() const = 0; /** * @brief Writes audio data. @@ -117,14 +119,14 @@ public: * ERR_INVALID_WRITE: The written audio data size is < 0. * ERR_WRITE_FAILED: The audio data write failed . */ - virtual int32_t Write(uint8_t *buffer, size_t bufferSize) = 0; + virtual int32_t Write(uint8_t *buffer, size_t bufferSize) = 0; /** * @brief Obtains the audio renderer state. * * @return Returns the audio renderer state defined in {@link RendererState}. */ - virtual RendererState GetStatus() = 0; + virtual RendererState GetStatus() const = 0; /** * @brief Obtains the timestamp. @@ -134,7 +136,7 @@ public: * {@link Timestamp.Timestampbase#MONOTONIC}. * @return Returns true if the timestamp is successfully obtained; returns false otherwise. */ - virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) = 0; + virtual bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) const = 0; /** * @brief Obtains the latency in microseconds. @@ -143,28 +145,28 @@ public: * @return Returns {@link SUCCESS} if latency is successfully obtained, returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetLatency(uint64_t &latency) = 0; + virtual int32_t GetLatency(uint64_t &latency) const = 0; /** * @brief drain renderer buffer. * * @return Returns true if the buffer is successfully drained; returns false otherwise. */ - virtual bool Drain() = 0; + virtual bool Drain() const = 0; /** * @brief Stops audio rendering. * * @return Returns true if the rendering is successfully stopped; returns false otherwise. */ - virtual bool Stop() = 0; + virtual bool Stop() const = 0; /** * @brief Releases a local AudioRenderer object. * * @return Returns true if the object is successfully released; returns false otherwise. */ - virtual bool Release() = 0; + virtual bool Release() const = 0; /** * @brief Obtains a reasonable minimum buffer size for rendering, however, the renderer can @@ -174,7 +176,7 @@ public: * @return Returns {@link SUCCESS} if bufferSize is successfully obtained; returns an error code * defined in {@link audio_errors.h} otherwise. */ - virtual int32_t GetBufferSize(size_t &bufferSize) = 0; + virtual int32_t GetBufferSize(size_t &bufferSize) const = 0; /** * @brief Obtains the foramts supported by renderer. diff --git a/interfaces/innerkits/native/audiostream/include/audio_stream.h b/interfaces/innerkits/native/audiostream/include/audio_stream.h index ea8fbacdcd..d24838e832 100644 --- a/interfaces/innerkits/native/audiostream/include/audio_stream.h +++ b/interfaces/innerkits/native/audiostream/include/audio_stream.h @@ -13,6 +13,7 @@ * limitations under the License. */ #include "audio_session.h" +#include "timestamp.h" #ifndef AUDIO_STREAM_H #define AUDIO_STREAM_H diff --git a/pulseaudio/src/BUILD.gn b/pulseaudio/src/BUILD.gn index 063115d247..71c492c355 100644 --- a/pulseaudio/src/BUILD.gn +++ b/pulseaudio/src/BUILD.gn @@ -147,3 +147,4 @@ ohos_prebuilt_etc("pa_client_config") { module_install_dir = "etc/pulse" part_name = "multimedia_audio_standard" } + diff --git a/pulseaudio/src/modules/hdi/hdi_source.c b/pulseaudio/src/modules/hdi/hdi_source.c index 06391bafc7..9b14c5f875 100644 --- a/pulseaudio/src/modules/hdi/hdi_source.c +++ b/pulseaudio/src/modules/hdi/hdi_source.c @@ -17,29 +17,61 @@ #include #endif +#include #include #include -#include #include #include #include #include + #include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include #include #include -#include -#include "hdi_source.h" +#include + +#include + #include "media_log.h" +#define DEFAULT_SOURCE_NAME "hdi_input" +#define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic" + +#define DEFAULT_BUFFER_SIZE (1024 * 16) +#define MAX_VOLUME_VALUE 15.0 +#define DEFAULT_LEFT_VOLUME MAX_VOLUME_VALUE +#define DEFAULT_RIGHT_VOLUME MAX_VOLUME_VALUE +#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2) +#define MIN_LATENCY_USEC 500 +#define AUDIO_POINT_NUM 1024 +#define AUDIO_FRAME_NUM_IN_BUF 30 + +struct userdata { + pa_core *core; + pa_module *module; + pa_source *source; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + size_t buffer_size; + pa_usec_t block_usec; + pa_usec_t timestamp; + AudioSourceAttr attrs; + // A flag to signal us to prevent silent record during bootup + bool IsReady; + bool IsCapturerInit; +}; + static int pa_capturer_init(struct userdata *u); static void pa_capturer_exit(void); @@ -71,21 +103,21 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off switch (code) { case PA_SOURCE_MESSAGE_GET_LATENCY: { - pa_usec_t now; - now = pa_rtclock_now(); - *((int64_t*) data) = (int64_t)now - (int64_t)u->timestamp; - return 0; + pa_usec_t now; + now = pa_rtclock_now(); + *((int64_t*) data) = (int64_t)now - (int64_t)u->timestamp; + return 0; } default: { - pa_log("source_process_msg default case"); - return pa_source_process_msg(o, code, data, offset, chunk); + pa_log("source_process_msg default case"); + return pa_source_process_msg(o, code, data, offset, chunk); } } } /* Called from the IO thread. */ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { - struct userdata *u; + struct userdata *u = NULL; pa_assert(s); pa_assert_se(u = s->userdata); if (s->thread_info.state == PA_SOURCE_SUSPENDED || s->thread_info.state == PA_SOURCE_INIT) { @@ -99,7 +131,6 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_output_new_data *data, struct userdata *u) { int ret; - MEDIA_DEBUG_LOG("HDI Source: Detected source output"); pa_assert(data); pa_assert(u); @@ -160,12 +191,11 @@ static void thread_func(void *userdata) { u->timestamp = pa_rtclock_now(); MEDIA_DEBUG_LOG("HDI Source: u->timestamp : %{public}llu", u->timestamp); - for (;;) { + while(true) { int ret = 0; - int retries = 0; uint64_t requestBytes; uint64_t replyBytes = 0; - void *p; + void *p = NULL; if (PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (u->source->thread_info.state != PA_SOURCE_SUSPENDED) && u->IsReady && u->IsCapturerInit) { @@ -195,20 +225,12 @@ static void thread_func(void *userdata) { } if (replyBytes == 0) { - MEDIA_INFO_LOG("HDI Source: reply bytes 0"); - if (retries < MAX_RETRIES) { - usleep(FIVE_MSEC); - ++retries; - MEDIA_DEBUG_LOG("HDI Source: Requested data Length: %{public}llu bytes, Read: %{public}llu bytes. Sleep: %{public}d usec microseconds. Retry Times %{public}d", requestBytes, replyBytes, FIVE_MSEC, retries); - continue; - } else { - MEDIA_ERR_LOG("HDI Source: Failed to read after %{public}d retries, Requested data Length: %{public}llu bytes, Read: %{public}llu bytes, %{public}d ret", retries, requestBytes, replyBytes, ret); - pa_memblock_unref(chunk.memblock); - break; - } + MEDIA_ERR_LOG("HDI Source: Failed to read, Requested data Length: %{public}llu bytes," + " Read: %{public}llu bytes, %{public}d ret", requestBytes, replyBytes, ret); + pa_memblock_unref(chunk.memblock); + break; } - retries = 0; chunk.index = 0; chunk.length = replyBytes; pa_source_post(u->source, &chunk); @@ -234,7 +256,8 @@ static void thread_func(void *userdata) { /* If this was no regular exit from the loop we have to continue * processing messages until we received PA_MESSAGE_SHUTDOWN */ MEDIA_INFO_LOG("HDI Source: pa_rtpoll_run ret:%{public}d failed", ret ); - pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, + 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); return; } @@ -242,7 +265,6 @@ static void thread_func(void *userdata) { timer_elapsed = pa_rtpoll_timer_elapsed(u->rtpoll); if (ret == 0) { - MEDIA_INFO_LOG("HDI Source: pa_rtpoll_run ret:%{public}d return", ret ); return; } } @@ -320,7 +342,7 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { u->attrs.channel = ss.channels; u->attrs.sampleRate = ss.rate; MEDIA_INFO_LOG("AudioDeviceCreateCapture format: %{public}d, channel: %{public}d, sampleRate: %{public}d", - u->attrs.format, u->attrs.channel, u->attrs.sampleRate); + u->attrs.format, u->attrs.channel, u->attrs.sampleRate); ret = pa_capturer_init(u); if (ret != 0) { goto fail; @@ -333,7 +355,7 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, DEFAULT_AUDIO_DEVICE_NAME); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI source %s", DEFAULT_AUDIO_DEVICE_NAME); pa_source_new_data_set_sample_spec(&data, &ss); - pa_source_new_data_set_channel_map(&data, &map);; + pa_source_new_data_set_channel_map(&data, &map); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long)u->buffer_size); if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { @@ -342,7 +364,7 @@ pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver) { goto fail; } - u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); + u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE | PA_SOURCE_LATENCY); pa_source_new_data_done(&data); if (!u->source) { diff --git a/pulseaudio/src/modules/hdi/module_hdi_source.c b/pulseaudio/src/modules/hdi/module_hdi_source.c index e739bf7ea6..4e8760c937 100644 --- a/pulseaudio/src/modules/hdi/module_hdi_source.c +++ b/pulseaudio/src/modules/hdi/module_hdi_source.c @@ -19,12 +19,14 @@ #include -#include +#include #include +#include #include -#include -#include "hdi_source.h" +pa_source* pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char*driver); + +void pa_hdi_source_free(pa_source *s); PA_MODULE_AUTHOR("OpenHarmony"); PA_MODULE_DESCRIPTION("OpenHarmony HDI Source"); @@ -51,7 +53,7 @@ static const char * const VALID_MODARGS[] = { NULL }; -int pa__init(pa_module*m) +int pa__init(pa_module *m) { pa_modargs *ma = NULL; diff --git a/services/include/audio_policy/client/audio_policy_base.h b/services/include/audio_policy/client/audio_policy_base.h index a3db6c0776..1fd80b4ed0 100644 --- a/services/include/audio_policy/client/audio_policy_base.h +++ b/services/include/audio_policy/client/audio_policy_base.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef I_ST_AUDIO_POLICY_BASE_H -#define I_ST_AUDIO_POLICY_BASE_H +#ifndef I_AUDIO_POLICY_BASE_H +#define I_AUDIO_POLICY_BASE_H #include "audio_policy_types.h" #include "ipc_types.h" @@ -47,14 +47,6 @@ public: public: DECLARE_INTERFACE_DESCRIPTOR(u"IAudioPolicy"); }; - -class AudioPolicyManagerStub : public IRemoteStub { -public: - virtual int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, - MessageParcel &reply, MessageOption &option) override; - bool IsPermissionValid(); -}; } // AudioStandard } // namespace OHOS - -#endif // I_ST_AUDIO_POLICY_BASE_H +#endif // I_AUDIO_POLICY_BASE_H diff --git a/services/include/audio_policy/client/audio_policy_manager_stub.h b/services/include/audio_policy/client/audio_policy_manager_stub.h new file mode 100644 index 0000000000..6bacdadbc0 --- /dev/null +++ b/services/include/audio_policy/client/audio_policy_manager_stub.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 AUDIO_POLICY_MANAGER_STUB_H +#define AUDIO_POLICY_MANAGER_STUB_H + +#include "audio_policy_base.h" + +namespace OHOS { +namespace AudioStandard { +class AudioPolicyManagerStub : public IRemoteStub { +public: + virtual int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) override; + bool IsPermissionValid(); + +private: + void SetStreamVolumeInternal(MessageParcel &data, MessageParcel &reply); + void SetRingerModeInternal(MessageParcel &data, MessageParcel &reply); + void GetRingerModeInternal(MessageParcel &data); + void GetStreamVolumeInternal(MessageParcel &data, MessageParcel &reply); + void SetStreamMuteInternal(MessageParcel &data, MessageParcel &reply); + void GetStreamMuteInternal(MessageParcel &data, MessageParcel &reply); + void IsStreamActiveInternal(MessageParcel &data, MessageParcel &reply); + void SetDeviceActiveInternal(MessageParcel &data, MessageParcel &reply); + void IsDeviceActiveInternal(MessageParcel &data, MessageParcel &reply); +}; +} // AudioStandard +} // namespace OHOS +#endif // AUDIO_POLICY_MANAGER_STUB_H diff --git a/services/include/audio_policy/server/audio_policy_server.h b/services/include/audio_policy/server/audio_policy_server.h index a5cb6564fb..290e35aa3d 100644 --- a/services/include/audio_policy/server/audio_policy_server.h +++ b/services/include/audio_policy/server/audio_policy_server.h @@ -19,7 +19,7 @@ #include #include -#include "audio_policy_base.h" +#include "audio_policy_manager_stub.h" #include "audio_policy_service.h" #include "iremote_stub.h" #include "system_ability.h" diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h index 6acaf3c206..d8b39f7463 100644 --- a/services/include/client/audio_service_client.h +++ b/services/include/client/audio_service_client.h @@ -42,7 +42,7 @@ typedef pa_client_info ClientInfo; struct StreamBuffer { uint8_t *buffer; // the virtual address of stream - uint32_t bufferLen; // stream length, by bytes + uint32_t bufferLen; // stream length in bytes }; struct AudioCache { @@ -305,6 +305,8 @@ private: int32_t InitializeAudioCache(); size_t WriteToAudioCache(const StreamBuffer &stream); int32_t DrainAudioCache(); + + int32_t UpdateReadBuffer(uint8_t *buffer, size_t &length, size_t &readSize); int32_t PaWriteStream(const uint8_t *buffer, size_t &length); // Error code used @@ -318,7 +320,6 @@ private: static const uint32_t AUDIO_CLIENT_WRITE_STREAM_ERR = -7; static const uint32_t AUDIO_CLIENT_PA_ERR = -8; - // Default values static const uint32_t MINIMUM_BUFFER_SIZE = 1024; static const uint32_t DEFAULT_SAMPLING_RATE = 44100; @@ -332,7 +333,6 @@ private: // Resets PA audio client and free up resources if any with this API void ResetPAAudioClient(); - // Callbacks to be implemented static void PAStreamStateCb(pa_stream *stream, void *userdata); static void PAStreamUnderFlowCb(pa_stream *stream, void *userdata); diff --git a/services/src/audio_policy/server/audio_policy_manager_stub.cpp b/services/src/audio_policy/server/audio_policy_manager_stub.cpp index 1b76750036..2594769d58 100644 --- a/services/src/audio_policy/server/audio_policy_manager_stub.cpp +++ b/services/src/audio_policy/server/audio_policy_manager_stub.cpp @@ -14,95 +14,130 @@ */ #include "audio_errors.h" -#include "audio_policy_base.h" +#include "audio_policy_manager_stub.h" #include "audio_policy_server.h" #include "audio_policy_types.h" #include "media_log.h" namespace OHOS { namespace AudioStandard { +void AudioPolicyManagerStub::SetStreamVolumeInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioStreamType streamType = static_cast(data.ReadInt32()); + float volume = data.ReadFloat(); + int result = SetStreamVolume(streamType, volume); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); +} + +void AudioPolicyManagerStub::SetRingerModeInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioRingerMode rMode = static_cast(data.ReadInt32()); + int32_t result = SetRingerMode(rMode); + reply.WriteInt32(result); +} + +void AudioPolicyManagerStub::GetRingerModeInternal(MessageParcel &reply) +{ + AudioRingerMode rMode = GetRingerMode(); + reply.WriteInt32(static_cast(rMode)); +} + +void AudioPolicyManagerStub::GetStreamVolumeInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioStreamType streamType = static_cast(data.ReadInt32()); + float volume = GetStreamVolume(streamType); + reply.WriteFloat(volume); +} + +void AudioPolicyManagerStub::SetStreamMuteInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool mute = data.ReadBool(); + int result = SetStreamMute(streamType, mute); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); +} + +void AudioPolicyManagerStub::GetStreamMuteInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool mute = GetStreamMute(streamType); + reply.WriteBool(mute); +} + +void AudioPolicyManagerStub::IsStreamActiveInternal(MessageParcel &data, MessageParcel &reply) +{ + AudioStreamType streamType = static_cast(data.ReadInt32()); + bool isActive = IsStreamActive(streamType); + reply.WriteBool(isActive); +} + +void AudioPolicyManagerStub::SetDeviceActiveInternal(MessageParcel &data, MessageParcel &reply) +{ + DeviceType deviceType = static_cast(data.ReadInt32()); + bool active = data.ReadBool(); + int32_t result = SetDeviceActive(deviceType, active); + if (result == SUCCESS) + reply.WriteInt32(MEDIA_OK); + else + reply.WriteInt32(MEDIA_ERR); +} + +void AudioPolicyManagerStub::IsDeviceActiveInternal(MessageParcel &data, MessageParcel &reply) +{ + DeviceType deviceType = static_cast(data.ReadInt32()); + bool result = IsDeviceActive(deviceType); + reply.WriteBool(result); +} + int AudioPolicyManagerStub::OnRemoteRequest( uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) { switch (code) { - case SET_STREAM_VOLUME: { - AudioStreamType streamType = static_cast(data.ReadInt32()); - float volume = data.ReadFloat(); - int result = SetStreamVolume(streamType, volume); - if (result == SUCCESS) - reply.WriteInt32(MEDIA_OK); - else - reply.WriteInt32(MEDIA_ERR); + case SET_STREAM_VOLUME: + SetStreamVolumeInternal(data, reply); break; - } - case SET_RINGER_MODE: { - AudioRingerMode rMode = static_cast(data.ReadInt32()); - int32_t result = SetRingerMode(rMode); - reply.WriteInt32(result); + case SET_RINGER_MODE: + SetRingerModeInternal(data, reply); break; - } - case GET_RINGER_MODE: { - AudioRingerMode rMode = GetRingerMode(); - reply.WriteInt32(static_cast(rMode)); + case GET_RINGER_MODE: + GetRingerModeInternal(reply); break; - } - case GET_STREAM_VOLUME: { - AudioStreamType streamType = static_cast(data.ReadInt32()); - float volume = GetStreamVolume(streamType); - reply.WriteFloat(volume); + case GET_STREAM_VOLUME: + GetStreamVolumeInternal(data, reply); break; - } - - case SET_STREAM_MUTE: { - AudioStreamType streamType = static_cast(data.ReadInt32()); - bool mute = data.ReadBool(); - int result = SetStreamMute(streamType, mute); - if (result == SUCCESS) - reply.WriteInt32(MEDIA_OK); - else - reply.WriteInt32(MEDIA_ERR); + + case SET_STREAM_MUTE: + SetStreamMuteInternal(data, reply); break; - } - case GET_STREAM_MUTE: { - AudioStreamType streamType = static_cast(data.ReadInt32()); - bool mute = GetStreamMute(streamType); - reply.WriteBool(mute); + case GET_STREAM_MUTE: + GetStreamMuteInternal(data, reply); break; - } - case IS_STREAM_ACTIVE: { - AudioStreamType streamType = static_cast(data.ReadInt32()); - bool isActive = IsStreamActive(streamType); - reply.WriteBool(isActive); + case IS_STREAM_ACTIVE: + IsStreamActiveInternal(data, reply); break; - } - - case SET_DEVICE_ACTIVE: { - DeviceType deviceType = static_cast(data.ReadInt32()); - bool active = data.ReadBool(); - int32_t result = SetDeviceActive(deviceType, active); - if (result == SUCCESS) - reply.WriteInt32(MEDIA_OK); - else - reply.WriteInt32(MEDIA_ERR); + + case SET_DEVICE_ACTIVE: + SetDeviceActiveInternal(data, reply); break; - } - case IS_DEVICE_ACTIVE: { - DeviceType deviceType = static_cast(data.ReadInt32()); - bool result = IsDeviceActive(deviceType); - reply.WriteBool(result); + case IS_DEVICE_ACTIVE: + IsDeviceActiveInternal(data, reply); break; - } - default: { + default: MEDIA_ERR_LOG("default case, need check AudioPolicyManagerStub"); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); - } } return MEDIA_OK; } diff --git a/services/src/audio_policy/server/service/include/audio_policy_service.h b/services/src/audio_policy/server/service/include/audio_policy_service.h index 86d49dbbbd..124c0dbe35 100644 --- a/services/src/audio_policy/server/service/include/audio_policy_service.h +++ b/services/src/audio_policy/server/service/include/audio_policy_service.h @@ -18,7 +18,7 @@ #include "audio_info.h" #include "audio_policy_manager_factory.h" -#include "iaudio_policy.h" +#include "iaudio_policy_interface.h" #include "iport_observer.h" #include "parser_factory.h" diff --git a/services/src/audio_policy/server/service/include/common/audio_config.h b/services/src/audio_policy/server/service/include/common/audio_config.h index 68f7c907f3..91524a270b 100644 --- a/services/src/audio_policy/server/service/include/common/audio_config.h +++ b/services/src/audio_policy/server/service/include/common/audio_config.h @@ -16,6 +16,8 @@ #ifndef ST_AUDIO_CONFIG_H #define ST_AUDIO_CONFIG_H +#include + #include "audio_info.h" #ifdef __cplusplus @@ -91,8 +93,7 @@ public: virtual ~AudioPortInfo() {} }; -struct AudioPortPinInfo : public PortInfo -{ +struct AudioPortPinInfo : public PortInfo { public: char* pinType; AudioPortPinInfo() diff --git a/services/src/audio_policy/server/service/include/interface/iaudio_policy.h b/services/src/audio_policy/server/service/include/interface/iaudio_policy_interface.h similarity index 100% rename from services/src/audio_policy/server/service/include/interface/iaudio_policy.h rename to services/src/audio_policy/server/service/include/interface/iaudio_policy_interface.h diff --git a/services/src/audio_policy/server/service/include/interface/iport_observer.h b/services/src/audio_policy/server/service/include/interface/iport_observer.h index ca97ee3ac2..af7ef9ab68 100644 --- a/services/src/audio_policy/server/service/include/interface/iport_observer.h +++ b/services/src/audio_policy/server/service/include/interface/iport_observer.h @@ -17,7 +17,7 @@ #define ST_AUDIO_PORT_OBSERVER_H #include "audio_info.h" -#include "iaudio_policy.h" +#include "iaudio_policy_interface.h" namespace OHOS { namespace AudioStandard { diff --git a/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h index 1056ace7a7..dc8eca5bcb 100644 --- a/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h +++ b/services/src/audio_policy/server/service/include/manager/pulseaudio_policy_manager.h @@ -28,7 +28,7 @@ extern "C" { #include #include "distributed_kv_data_manager.h" -#include "iaudio_policy.h" +#include "iaudio_policy_interface.h" #include "types.h" namespace OHOS { diff --git a/services/src/audio_policy/server/service/src/config/xml_parser.cpp b/services/src/audio_policy/server/service/src/config/xml_parser.cpp index a05d13b296..5bb9e7d3e4 100644 --- a/services/src/audio_policy/server/service/src/config/xml_parser.cpp +++ b/services/src/audio_policy/server/service/src/config/xml_parser.cpp @@ -150,7 +150,7 @@ void XMLParser::ParseAudioPorts(xmlNode* node) for (; child; child = child->next) { if (!xmlStrcmp(child->name, reinterpret_cast("AudioPort"))) { - std::shared_ptr portInfo = std::make_unique(); + std::shared_ptr portInfo = std::make_shared(); portInfo->type = TYPE_AUDIO_PORT; if (xmlHasProp(child, reinterpret_cast(const_cast("role")))) { @@ -202,7 +202,7 @@ void XMLParser::ParseAudioPortPins(xmlNode* node) for (; child; child = child->next) { if (!xmlStrcmp(child->name, reinterpret_cast("AudioPortPin"))) { - std::shared_ptr portInfo = std::make_unique(); + std::shared_ptr portInfo = std::make_shared(); portInfo->type = TYPE_AUDIO_PORT_PIN; if (xmlHasProp(child, reinterpret_cast(const_cast("role")))) diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp index c8d9e8622c..8b43169d8e 100644 --- a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -14,6 +14,7 @@ */ #include + #include "audio_errors.h" #include "media_log.h" #include "pulseaudio_policy_manager.h" @@ -89,19 +90,16 @@ void PulseAudioPolicyManager::Deinit(void) int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, float volume) { + std::unique_ptr userData = std::make_unique(); + userData->thiz = this; + userData->volume = volume; + userData->streamType = streamType; + if (mContext == NULL) { MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); return ERROR; } - UserData* userData = new UserData; - if (userData == nullptr) - return ERROR; - - userData->thiz = this; - userData->volume = volume; - userData->streamType = streamType; - // Incase if KvStore didnot connect during bootup if (mAudioPolicyKvStore == nullptr) { bool isFirstBoot = false; @@ -114,13 +112,13 @@ int32_t PulseAudioPolicyManager::SetStreamVolume(AudioStreamType streamType, flo pa_threaded_mainloop_lock(mMainLoop); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, - PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); + PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); - delete userData; pa_threaded_mainloop_unlock(mMainLoop); return ERROR; } + userData.release(); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(mMainLoop); @@ -138,16 +136,16 @@ float PulseAudioPolicyManager::GetStreamVolume(AudioStreamType streamType) int32_t PulseAudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool mute) { + std::unique_ptr userData = std::make_unique(); + userData->thiz = this; + userData->mute = mute; + userData->streamType = streamType; + if (mContext == NULL) { MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); return ERROR; } - std::shared_ptr userData = std::make_shared(); - userData->thiz = this; - userData->mute = mute; - userData->streamType = streamType; - pa_threaded_mainloop_lock(mMainLoop); pa_operation* operation = pa_context_get_sink_input_info_list(mContext, @@ -170,16 +168,16 @@ int32_t PulseAudioPolicyManager::SetStreamMute(AudioStreamType streamType, bool bool PulseAudioPolicyManager::GetStreamMute(AudioStreamType streamType) { + std::unique_ptr userData = std::make_unique(); + userData->thiz = this; + userData->streamType = streamType; + userData->mute = false; + if (mContext == NULL) { MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); return false; } - std::shared_ptr userData = std::make_shared(); - userData->thiz = this; - userData->streamType = streamType; - userData->mute = false; - pa_threaded_mainloop_lock(mMainLoop); pa_operation *operation = pa_context_get_sink_input_info_list(mContext, @@ -202,20 +200,20 @@ bool PulseAudioPolicyManager::GetStreamMute(AudioStreamType streamType) bool PulseAudioPolicyManager::IsStreamActive(AudioStreamType streamType) { + std::unique_ptr userData = std::make_unique(); + userData->thiz = this; + userData->streamType = streamType; + userData->isCorked = true; + if (mContext == NULL) { MEDIA_ERR_LOG("[PolicyManager] mContext is nullptr"); return false; } - std::shared_ptr userData = std::make_shared(); - userData->thiz = this; - userData->streamType = streamType; - userData->isCorked = true; - pa_threaded_mainloop_lock(mMainLoop); - pa_operation *operation = pa_context_get_sink_input_info_list(mContext, PulseAudioPolicyManager::GetSinkInputInfoCorkStatusCb, - reinterpret_cast(userData.get())); + pa_operation *operation = pa_context_get_sink_input_info_list(mContext, + PulseAudioPolicyManager::GetSinkInputInfoCorkStatusCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); pa_threaded_mainloop_unlock(mMainLoop); @@ -235,7 +233,9 @@ bool PulseAudioPolicyManager::IsStreamActive(AudioStreamType streamType) return (userData->isCorked) ? false : true; } -int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, std::string name, bool active) + +int32_t PulseAudioPolicyManager::SetDeviceActive(AudioIOHandle ioHandle, DeviceType deviceType, + std::string name, bool active) { pa_threaded_mainloop_lock(mMainLoop); @@ -313,7 +313,7 @@ AudioIOHandle PulseAudioPolicyManager::OpenAudioPort(std::shared_ptr userData = std::make_shared(); + std::unique_ptr userData = std::make_unique(); userData->thiz = this; pa_operation* operation = pa_context_load_module(mContext, audioPortInfo->name, moduleArgs.c_str(), ModuleLoadCb, @@ -689,16 +689,17 @@ void PulseAudioPolicyManager::WriteRingerModeToKvStore(AudioRingerMode ringerMod void PulseAudioPolicyManager::HandleSinkInputEvent(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { - UserData* userData = new UserData; + std::unique_ptr userData = std::make_unique(); userData->thiz = this; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { pa_operation* operation = pa_context_get_sink_input_info(c, idx, - PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData)); + PulseAudioPolicyManager::GetSinkInputInfoVolumeCb, reinterpret_cast(userData.get())); if (operation == NULL) { MEDIA_ERR_LOG("[PolicyManager] pa_context_get_sink_input_info_list returned nullptr"); return; } + userData.release(); pa_operation_unref(operation); } @@ -831,12 +832,14 @@ void PulseAudioPolicyManager::GetSinkInputInfoVolumeCb(pa_context *c, const pa_s pa_cvolume_set(&cv, i->channel_map.channels, volume); pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL)); - if (i->mute) { - pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, 0, NULL, NULL)); + if (streamID == userData->streamType) { + if (i->mute) { + pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, 0, NULL, NULL)); + } } MEDIA_INFO_LOG("[PolicyManager] Applied volume : %{public}f for stream : %{public}s, volumeInt%{public}d", - userData->volume, i->name, volume); + vol, i->name, volume); return; } diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index ef25241bc2..cc63a15612 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -391,10 +391,10 @@ int32_t AudioServiceClient::ConnectStreamToPA() pa_threaded_mainloop_lock(mainLoop); pa_buffer_attr bufferAttr; - bufferAttr.fragsize = (uint32_t) -1; - bufferAttr.prebuf = (uint32_t) -1; - bufferAttr.maxlength = (uint32_t) -1; - bufferAttr.tlength = (uint32_t) -1; + bufferAttr.fragsize = static_cast(-1); + bufferAttr.prebuf = static_cast(-1); + bufferAttr.maxlength = static_cast(-1); + bufferAttr.tlength = static_cast(-1); bufferAttr.minreq = pa_usec_to_bytes(LATENCY_IN_MSEC * PA_USEC_PER_MSEC, &sampleSpec); if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) result = pa_stream_connect_playback(paStream, NULL, &bufferAttr, @@ -842,6 +842,30 @@ size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pErr return cachedLen; } +int32_t AudioServiceClient::UpdateReadBuffer(uint8_t *buffer, size_t &length, size_t &readSize) +{ + size_t l = (internalRdBufLen < length) ? internalRdBufLen : length; + memcpy_s(buffer, length, (const uint8_t*) internalReadBuffer + internalRdBufIndex, l); + + length -= l; + internalRdBufIndex += l; + internalRdBufLen -= l; + readSize += l; + + if (!internalRdBufLen) { + int retVal = pa_stream_drop(paStream); + internalReadBuffer = NULL; + internalRdBufLen = 0; + internalRdBufIndex = 0; + if (retVal < 0) { + MEDIA_ERR_LOG("pa_stream_drop failed, retVal: %d", retVal); + return AUDIO_CLIENT_READ_STREAM_ERR; + } + } + + return 0; +} + int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) { uint8_t* buffer = stream.buffer; @@ -852,8 +876,6 @@ int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) pa_threaded_mainloop_lock(mainLoop); while (length > 0) { - size_t l; - while (!internalReadBuffer) { int retVal = pa_stream_peek(paStream, &internalReadBuffer, &internalRdBufLen); if (retVal < 0) { @@ -882,27 +904,11 @@ int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) } } - l = (internalRdBufLen < length) ? internalRdBufLen : length; - memcpy_s(buffer, length, (const uint8_t*) internalReadBuffer + internalRdBufIndex, l); - - buffer = (uint8_t*) buffer + l; - length -= l; - - internalRdBufIndex += l; - internalRdBufLen -= l; - readSize += l; - - if (!internalRdBufLen) { - int retVal = pa_stream_drop(paStream); - internalReadBuffer = NULL; - internalRdBufLen = 0; - internalRdBufIndex = 0; - if (retVal < 0) { - MEDIA_ERR_LOG("pa_stream_drop failed, retVal: %d", retVal); - pa_threaded_mainloop_unlock(mainLoop); - return AUDIO_CLIENT_READ_STREAM_ERR; - } + if (UpdateReadBuffer(buffer, length, readSize) != 0) { + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_READ_STREAM_ERR; } + buffer = stream.buffer + readSize; } pa_threaded_mainloop_unlock(mainLoop); return readSize; @@ -1007,9 +1013,9 @@ int32_t AudioServiceClient::GetCurrentTimeStamp(uint64_t &timeStamp) if (!info) { retVal = AUDIO_CLIENT_ERR; } else { - if(eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { timeStamp = pa_bytes_to_usec(info->write_index, &sampleSpec); - } else if(eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { + } else if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { timeStamp = pa_bytes_to_usec(info->read_index, &sampleSpec); } } diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp index aa767d8a7d..22f6c473b3 100644 --- a/services/src/client/audio_stream.cpp +++ b/services/src/client/audio_stream.cpp @@ -149,7 +149,7 @@ bool IsSamplingRateValid(uint32_t samplingRate) int32_t AudioStream::GetAudioStreamInfo(AudioStreamParams &audioStreamInfo) { MEDIA_INFO_LOG("AudioStream: GetAudioStreamInfo"); - if(GetAudioStreamParams(audioStreamInfo) != 0) { + if (GetAudioStreamParams(audioStreamInfo) != 0) { return ERR_OPERATION_FAILED; } diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp index e73928363d..ffe8bfd4d7 100644 --- a/services/src/client/audio_system_manager.cpp +++ b/services/src/client/audio_system_manager.cpp @@ -16,8 +16,8 @@ #include "audio_errors.h" #include "audio_manager_proxy.h" #include "audio_policy_manager.h" -#include "audio_system_manager.h" #include "audio_stream.h" +#include "audio_system_manager.h" #include "iservice_registry.h" #include "media_log.h" #include "system_ability_definition.h" @@ -64,19 +64,19 @@ void AudioSystemManager::init() } } -bool AudioSystemManager::SetRingerMode(AudioRingerMode ringMode) +bool AudioSystemManager::SetRingerMode(AudioRingerMode ringMode) const { /* Call Audio Policy SetRingerMode */ return AudioPolicyManager::GetInstance().SetRingerMode(ringMode); } -AudioRingerMode AudioSystemManager::GetRingerMode() +AudioRingerMode AudioSystemManager::GetRingerMode() const { /* Call Audio Policy GetRingerMode */ return (AudioPolicyManager::GetInstance().GetRingerMode()); } -int32_t AudioSystemManager::SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag) +int32_t AudioSystemManager::SetDeviceActive(AudioDeviceDescriptor::DeviceType deviceType, bool flag) const { switch (deviceType) { case SPEAKER: @@ -94,7 +94,7 @@ int32_t AudioSystemManager::SetDeviceActive(AudioDeviceDescriptor::DeviceType de return (AudioPolicyManager::GetInstance().SetDeviceActive(devType, flag)); } -bool AudioSystemManager::IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType) +bool AudioSystemManager::IsDeviceActive(AudioDeviceDescriptor::DeviceType deviceType) const { switch (deviceType) { case SPEAKER: @@ -112,7 +112,7 @@ bool AudioSystemManager::IsDeviceActive(AudioDeviceDescriptor::DeviceType device return (AudioPolicyManager::GetInstance().IsDeviceActive(devType)); } -bool AudioSystemManager::IsStreamActive(AudioSystemManager::AudioVolumeType volumeType) +bool AudioSystemManager::IsStreamActive(AudioSystemManager::AudioVolumeType volumeType) const { switch (volumeType) { case STREAM_MUSIC: @@ -127,17 +127,17 @@ bool AudioSystemManager::IsStreamActive(AudioSystemManager::AudioVolumeType volu return AudioPolicyManager::GetInstance().IsStreamActive(StreamVolType); } -const std::string AudioSystemManager::GetAudioParameter(const std::string key) +const std::string AudioSystemManager::GetAudioParameter(const std::string key) const { return g_sProxy->GetAudioParameter(key); } -void AudioSystemManager::SetAudioParameter(const std::string key, const std::string value) +void AudioSystemManager::SetAudioParameter(const std::string key, const std::string value) const { g_sProxy->SetAudioParameter(key, value); } -int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) +int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) const { /* Validate and return INVALID_PARAMS error */ if ((volume < 0) || (volume > 1)) { @@ -159,7 +159,7 @@ int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volume return AudioPolicyManager::GetInstance().SetStreamVolume(StreamVolType, volume); } -float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeType) +float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeType) const { switch (volumeType) { case STREAM_MUSIC: @@ -175,17 +175,17 @@ float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeTy return AudioPolicyManager::GetInstance().GetStreamVolume(StreamVolType); } -float AudioSystemManager::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) +float AudioSystemManager::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const { return g_sProxy->GetMaxVolume(volumeType); } -float AudioSystemManager::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) +float AudioSystemManager::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const { return g_sProxy->GetMinVolume(volumeType); } -int32_t AudioSystemManager::SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute) +int32_t AudioSystemManager::SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute) const { switch (volumeType) { case STREAM_MUSIC: @@ -201,7 +201,7 @@ int32_t AudioSystemManager::SetMute(AudioSystemManager::AudioVolumeType volumeTy return AudioPolicyManager::GetInstance().SetStreamMute(StreamVolType, mute); } -bool AudioSystemManager::IsStreamMute(AudioSystemManager::AudioVolumeType volumeType) +bool AudioSystemManager::IsStreamMute(AudioSystemManager::AudioVolumeType volumeType) const { MEDIA_DEBUG_LOG("AudioSystemManager::GetMute Client"); @@ -219,17 +219,18 @@ bool AudioSystemManager::IsStreamMute(AudioSystemManager::AudioVolumeType volume return AudioPolicyManager::GetInstance().GetStreamMute(StreamVolType); } -int32_t AudioSystemManager::SetMicrophoneMute(bool isMute) +int32_t AudioSystemManager::SetMicrophoneMute(bool isMute) const { return g_sProxy->SetMicrophoneMute(isMute); } -bool AudioSystemManager::IsMicrophoneMute() +bool AudioSystemManager::IsMicrophoneMute() const { return g_sProxy->IsMicrophoneMute(); } std::vector> AudioSystemManager::GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) + const { return g_sProxy->GetDevices(deviceFlag); } diff --git a/services/src/server/audio_server.cpp b/services/src/server/audio_server.cpp index faf80e8324..7c92f2bc45 100644 --- a/services/src/server/audio_server.cpp +++ b/services/src/server/audio_server.cpp @@ -130,7 +130,7 @@ bool AudioServer::IsMicrophoneMute() if (audioCapturerSourceInstance->capturerInited_ == false) { MEDIA_ERR_LOG("Capturer is not initialized. Start the recording first !"); } else if (audioCapturerSourceInstance->GetMute(isMute)) { - MEDIA_ERR_LOG("GetMute status in capturer returned Error !"); + MEDIA_ERR_LOG("GetMute status in capturer returned Error !"); } return isMute; @@ -140,7 +140,7 @@ std::vector> AudioServer::GetDevices(AudioDeviceDesc { MEDIA_DEBUG_LOG("GetDevices server"); audioDeviceDescriptor_.clear(); - AudioDeviceDescriptor *audioDescriptor = new(std::nothrow) AudioDeviceDescriptor(); + sptr audioDescriptor = new(std::nothrow) AudioDeviceDescriptor(); if (audioDescriptor == nullptr) { MEDIA_ERR_LOG("new AudioDeviceDescriptor fail"); return audioDeviceDescriptor_; @@ -152,8 +152,8 @@ std::vector> AudioServer::GetDevices(AudioDeviceDesc audioDescriptor->deviceType_ = AudioDeviceDescriptor::DeviceType::SPEAKER; audioDescriptor->deviceRole_ = AudioDeviceDescriptor::DeviceRole::OUTPUT_DEVICE; } else if (AudioDeviceDescriptor::DeviceFlag::ALL_DEVICES_FLAG == deviceFlag) { - AudioDeviceDescriptor *audioDescriptor_inputDevice = new(std::nothrow) AudioDeviceDescriptor(); - AudioDeviceDescriptor *audioDescriptor_outputDevice = new(std::nothrow) AudioDeviceDescriptor(); + sptr audioDescriptor_inputDevice = new(std::nothrow) AudioDeviceDescriptor(); + sptr audioDescriptor_outputDevice = new(std::nothrow) AudioDeviceDescriptor(); audioDescriptor_inputDevice->deviceType_ = AudioDeviceDescriptor::DeviceType::MIC; audioDescriptor_inputDevice->deviceRole_ = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE; audioDeviceDescriptor_.push_back(audioDescriptor_inputDevice); diff --git a/services/test/audio_policy_test.cpp b/services/test/audio_policy_test.cpp index 58a7524dd3..9c0a6c0de4 100644 --- a/services/test/audio_policy_test.cpp +++ b/services/test/audio_policy_test.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "audio_errors.h" @@ -32,7 +33,6 @@ namespace AudioPolicyTest { const int SECOND_ARG = 2; const int OPT_ARG_BASE = 10; const int OPT_SHORT_LEN = 3; - const float VOLUME = 0.5f; } static void PrintUsage(void) @@ -65,108 +65,155 @@ static void PrintUsage(void) cout << "\tWritten by Sajeesh Sidharthan and Anurup M" << endl << endl; } -int main(int argc, char* argv[]) +static void SetStreamVolume(const AudioSystemManager *audioSystemMgr, int streamType) +{ + float volume = strtof(optarg, nullptr); + cout << "Set Volume : " << volume << endl; + int32_t result = audioSystemMgr->SetVolume(static_cast(streamType), volume); + cout << "Set Volume Result: " << result << endl; +} + +static void GetStreamVolume(const AudioSystemManager *audioSystemMgr, int streamType) +{ + float volume = audioSystemMgr->GetVolume(static_cast(streamType)); + cout << "Get Volume : " << volume << endl; +} + +static void SetStreamMute(const AudioSystemManager *audioSystemMgr, int streamType) +{ + int mute = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Mute : " << mute << endl; + int32_t result = audioSystemMgr->SetMute(static_cast(streamType), + (mute) ? true : false); + cout << "Set Mute Result: " << result << endl; +} + +static void IsStreamMute(const AudioSystemManager *audioSystemMgr, int streamType) +{ + bool muteStatus = audioSystemMgr->IsStreamMute(static_cast(streamType)); + cout << "Get Mute : " << muteStatus << endl; +} + +static void SetStreamType(int &streamType) +{ + streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Stream : " << streamType << endl; +} + +static void IsStreamActive(const AudioSystemManager *audioSystemMgr) +{ + int streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Stream Active: " << audioSystemMgr->IsStreamActive( + static_cast(streamType)) << endl; +} + +static void SetDeviceActive(const AudioSystemManager *audioSystemMgr, int argc, char* argv[]) { - int32_t result; - float volume = AudioPolicyTest::VOLUME; - int device = -1; int active = -1; - int mute = -1; - bool muteStatus = false; - bool devActiveStatus = false; - int opt = 0; - int ringMode = 0; - int streamType = static_cast(AudioSystemManager::AudioVolumeType::STREAM_MUSIC); + int device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Device : " << device << endl; + + if (optind < argc && *argv[optind] != '-') { + active = strtol(argv[optind], nullptr, AudioPolicyTest::OPT_ARG_BASE); + optind++; + } + cout << "Active : " << active << endl << endl; + int32_t result = audioSystemMgr->SetDeviceActive(AudioDeviceDescriptor::DeviceType(device), + (active) ? true : false); + cout << "Set DeviceActive Result: " << result << endl; +} + +static void IsDeviceActive(const AudioSystemManager *audioSystemMgr) +{ + int device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + bool devActiveStatus = audioSystemMgr->IsDeviceActive(AudioDeviceDescriptor::DeviceType(device)); + cout << "GetDevice Active : " << devActiveStatus << endl; +} + +static void SetRingerMode(const AudioSystemManager *audioSystemMgr) +{ + int ringMode = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); + cout << "Set Ringer Mode : " << ringMode << endl; + audioSystemMgr->SetRingerMode(static_cast(ringMode)); +} + +static void GetRingerMode(const AudioSystemManager *audioSystemMgr) +{ + int ringMode = static_cast(audioSystemMgr->GetRingerMode()); + cout << "Get Ringer Mode : " << ringMode << endl; +} + +static void NoValueError() +{ + char option[AudioPolicyTest::OPT_SHORT_LEN]; + cout << "option "; + snprintf_s(option, sizeof(option), sizeof(option) - 1, "-%c", optopt); + cout << option << " needs a value" << endl << endl; + PrintUsage(); +} + +static void UnknownOptionError() +{ + char option[AudioPolicyTest::OPT_SHORT_LEN]; + snprintf_s(option, sizeof(option), sizeof(option) - 1, "-%c", optopt); + cout << "unknown option: " << option << endl << endl; + PrintUsage(); +} + +int main(int argc, char* argv[]) +{ + int opt = 0; if (((argc >= AudioPolicyTest::SECOND_ARG) && !strcmp(argv[AudioPolicyTest::FIRST_ARG], "--help")) || (argc == AudioPolicyTest::FIRST_ARG)) { PrintUsage(); return ERR_INVALID_PARAM; } + int streamType = static_cast(AudioSystemManager::AudioVolumeType::STREAM_MUSIC); AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance(); - while ((opt = getopt(argc, argv, ":V:S:D:M:R:d:s:vmr")) != -1) { switch (opt) { case 'V': - volume = strtof(optarg, nullptr); - cout << "Set Volume : " << volume << endl; - result = audioSystemMgr->SetVolume(static_cast(streamType), - volume); - cout << "Set Volume Result: " << result << endl; + SetStreamVolume(audioSystemMgr, streamType); break; case 'v': - volume = audioSystemMgr->GetVolume(static_cast(streamType)); - cout << "Get Volume : " << volume << endl; + GetStreamVolume(audioSystemMgr, streamType); break; case 'M': - mute = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - cout << "Set Mute : " << mute << endl; - result = audioSystemMgr->SetMute(static_cast(streamType), - (mute) ? true : false); - cout << "Set Mute Result: " << result << endl; + SetStreamMute(audioSystemMgr, streamType); break; case 'm': - muteStatus = audioSystemMgr->IsStreamMute( - static_cast(streamType)); - cout << "Get Mute : " << muteStatus << endl; + IsStreamMute(audioSystemMgr, streamType); break; case 'S': - streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - cout << "Set Stream : " << streamType << endl; + SetStreamType(streamType); break; case 's': - streamType = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - cout << "Stream Active: " << audioSystemMgr->IsStreamActive( - static_cast(streamType)) << endl; + IsStreamActive(audioSystemMgr); break; case 'D': - device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - cout << "Set Device : " << device << endl; - - if (optind < argc && *argv[optind] != '-') { - active = strtol(argv[optind], nullptr, AudioPolicyTest::OPT_ARG_BASE); - optind++; - } - cout << "Active : " << active << endl << endl; - - result = audioSystemMgr->SetDeviceActive(AudioDeviceDescriptor::DeviceType(device), - (active) ? true : false); - cout << "Set DeviceActive Result: " << result << endl; + SetDeviceActive(audioSystemMgr, argc, argv); break; case 'd': - device = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - devActiveStatus = audioSystemMgr->IsDeviceActive(AudioDeviceDescriptor::DeviceType(device)); - cout << "GetDevice Active : " << devActiveStatus << endl; + IsDeviceActive(audioSystemMgr); break; case 'R': - ringMode = strtol(optarg, nullptr, AudioPolicyTest::OPT_ARG_BASE); - cout << "Set Ringer Mode : " << ringMode << endl; - audioSystemMgr->SetRingerMode(static_cast(ringMode)); + SetRingerMode(audioSystemMgr); break; case 'r': - ringMode = static_cast(audioSystemMgr->GetRingerMode()); - cout << "Get Ringer Mode : " << ringMode << endl; + GetRingerMode(audioSystemMgr); break; case ':': - char option[AudioPolicyTest::OPT_SHORT_LEN]; - cout << "option "; - snprintf(option, AudioPolicyTest::OPT_SHORT_LEN, "-%c", optopt); - cout << option << " needs a value" << endl << endl; - PrintUsage(); + NoValueError(); break; - case '?': { - char option[AudioPolicyTest::OPT_SHORT_LEN]; - snprintf(option, AudioPolicyTest::OPT_SHORT_LEN, "-%c", optopt); - cout << "unknown option: " << option << endl << endl; - PrintUsage(); + case '?': + UnknownOptionError(); break; - } default: break; } } - cout<<"Exit from test app"<< endl; return 0; } diff --git a/services/test/audio_recorder_test.cpp b/services/test/audio_recorder_test.cpp index d9f10ea0a0..e7640fe605 100644 --- a/services/test/audio_recorder_test.cpp +++ b/services/test/audio_recorder_test.cpp @@ -30,13 +30,10 @@ namespace AudioTestConstants { constexpr int32_t SUCCESS = 0; } -class StreamRecorderTest { +class AudioRecorderTest { public: - bool TestRecord(int argc, char *argv[]) const + void CheckSupportedParams() const { - MEDIA_INFO_LOG("TestCapture start "); - - unique_ptr audioRecorder = AudioRecorder::Create(AudioStreamType::STREAM_MUSIC); vector supportedFormatList = AudioRecorder::GetSupportedFormats(); MEDIA_INFO_LOG("Supported formats:"); for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { @@ -61,11 +58,10 @@ public: for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { MEDIA_INFO_LOG("sampling rate %{public}d", *i); } - AudioRecorderParams recorderParams; - recorderParams.audioSampleFormat = SAMPLE_S16LE; - recorderParams.samplingRate = static_cast(atoi(argv[AudioTestConstants::SECOND_ARG_IDX])); - recorderParams.audioChannel = AudioChannel::STEREO; - recorderParams.audioEncoding = ENCODING_PCM; + } + + bool InitRecord(const unique_ptr &audioRecorder, const AudioRecorderParams &recorderParams) const + { if (audioRecorder->SetParams(recorderParams) != AudioTestConstants::SUCCESS) { MEDIA_ERR_LOG("Set audio stream parameters failed"); audioRecorder->Release(); @@ -89,6 +85,11 @@ public: MEDIA_INFO_LOG("Get Audio channels: %{public}d", getRecorderParams.audioChannel); } + return true; + } + + bool StartRecord(const unique_ptr &audioRecorder, bool isBlocking, FILE *pFile) const + { size_t bufferLen; if (audioRecorder->GetBufferSize(bufferLen) < 0) { MEDIA_ERR_LOG(" GetMinimumBufferSize failed"); @@ -103,12 +104,8 @@ public: } MEDIA_INFO_LOG("Frame count: %{public}d", frameCount); - bool isBlocking = (atoi(argv[AudioTestConstants::THIRD_ARG_IDX]) == 1); - MEDIA_INFO_LOG("Is blocking read: %{public}s", isBlocking ? "true" : "false"); - uint8_t* buffer = nullptr; buffer = (uint8_t *) malloc(bufferLen); - FILE *pFile = fopen(argv[AudioTestConstants::SECOND_ARG_IDX - 1], "wb"); size_t size = 1; size_t numBuffersToRecord = 1024; @@ -136,6 +133,36 @@ public: } } } + free(buffer); + + return true; + } + + bool TestRecord(int argc, char *argv[]) const + { + MEDIA_INFO_LOG("TestCapture start "); + + unique_ptr audioRecorder = AudioRecorder::Create(AudioStreamType::STREAM_MUSIC); + + CheckSupportedParams(); + + AudioRecorderParams recorderParams; + recorderParams.audioSampleFormat = SAMPLE_S16LE; + recorderParams.samplingRate = static_cast(atoi(argv[AudioTestConstants::SECOND_ARG_IDX])); + recorderParams.audioChannel = AudioChannel::STEREO; + recorderParams.audioEncoding = ENCODING_PCM; + if (!InitRecord(audioRecorder, recorderParams)) { + MEDIA_ERR_LOG("Initialize record failed"); + return false; + } + + bool isBlocking = (atoi(argv[AudioTestConstants::THIRD_ARG_IDX]) == 1); + MEDIA_INFO_LOG("Is blocking read: %{public}s", isBlocking ? "true" : "false"); + FILE *pFile = fopen(argv[AudioTestConstants::SECOND_ARG_IDX - 1], "wb"); + if (!StartRecord(audioRecorder, isBlocking, pFile)) { + MEDIA_ERR_LOG("Start record failed"); + return false; + } Timestamp timestamp; if (audioRecorder->GetAudioTime(timestamp, Timestamp::Timestampbase::MONOTONIC)) { @@ -144,18 +171,17 @@ public: } fflush(pFile); - if(!audioRecorder->Flush()) { + if (!audioRecorder->Flush()) { MEDIA_ERR_LOG("AudioRecorderTest: flush failed"); } - if(!audioRecorder->Stop()) { + if (!audioRecorder->Stop()) { MEDIA_ERR_LOG("AudioRecorderTest: Stop failed"); } - if(!audioRecorder->Release()) { + if (!audioRecorder->Release()) { MEDIA_ERR_LOG("AudioRecorderTest: Release failed"); } - free(buffer); fclose(pFile); MEDIA_INFO_LOG("TestCapture end"); @@ -177,7 +203,7 @@ int main(int argc, char *argv[]) MEDIA_INFO_LOG("argv[2]=%{public}s", argv[AudioTestConstants::SECOND_ARG_IDX]); MEDIA_INFO_LOG("argv[3]=%{public}s", argv[AudioTestConstants::THIRD_ARG_IDX]); - StreamRecorderTest testObj; + AudioRecorderTest testObj; bool ret = testObj.TestRecord(argc, argv); return ret; diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 5df0c5b902..7e8418e770 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -23,31 +23,15 @@ using namespace OHOS; using namespace OHOS::AudioStandard; namespace AudioTestConstants { - constexpr int32_t SECOND_ARG_IDX = 2; + constexpr int32_t ARGS_INDEX_TWO = 2; + constexpr int32_t ARGS_COUNT_TWO = 2; constexpr int32_t SUCCESS = 0; } class AudioRendererTest { public: - bool TestPlayback(int argc, char *argv[]) const + void CheckSupportedParams() const { - MEDIA_INFO_LOG("AudioRendererTest: TestPlayback start "); - - wav_hdr wavHeader; - size_t headerSize = sizeof(wav_hdr); - FILE* wavFile = fopen(argv[1], "rb"); - if (wavFile == nullptr) { - MEDIA_INFO_LOG("AudioRendererTest: Unable to open wave file"); - return false; - } - size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); - MEDIA_INFO_LOG("AudioRendererTest: Header Read in bytes %{public}d", bytesRead); - - AudioStreamType streamType = AudioStreamType::STREAM_MUSIC; - if (argc > 2) - streamType = static_cast(strtol(argv[AudioTestConstants::SECOND_ARG_IDX], NULL, 10)); - unique_ptr audioRenderer = AudioRenderer::Create(streamType); - vector supportedFormatList = AudioRenderer::GetSupportedFormats(); MEDIA_INFO_LOG("AudioRendererTest: Supported formats:"); for (auto i = supportedFormatList.begin(); i != supportedFormatList.end(); ++i) { @@ -72,15 +56,13 @@ public: for (auto i = supportedSamplingRates.begin(); i != supportedSamplingRates.end(); ++i) { MEDIA_INFO_LOG("AudioRendererTest: sampling rate %{public}d", *i); } + } - AudioRendererParams rendererParams; - rendererParams.sampleFormat = static_cast(wavHeader.bitsPerSample); - rendererParams.sampleRate = static_cast(wavHeader.SamplesPerSec); - rendererParams.channelCount = static_cast(wavHeader.NumOfChan); - rendererParams.encodingType = static_cast(ENCODING_PCM); + bool InitRender(const unique_ptr &audioRenderer, const AudioRendererParams &rendererParams) const + { if (audioRenderer->SetParams(rendererParams) != AudioTestConstants::SUCCESS) { MEDIA_ERR_LOG("AudioRendererTest: Set audio renderer parameters failed"); - if(!audioRenderer->Release()) { + if (!audioRenderer->Release()) { MEDIA_ERR_LOG("AudioRendererTest: Release failed"); } return false; @@ -90,7 +72,7 @@ public: MEDIA_INFO_LOG("AudioRendererTest: Starting renderer"); if (!audioRenderer->Start()) { MEDIA_ERR_LOG("AudioRendererTest: Start failed"); - if(!audioRenderer->Release()) { + if (!audioRenderer->Release()) { MEDIA_ERR_LOG("AudioRendererTest: Release failed"); } return false; @@ -103,10 +85,15 @@ public: MEDIA_INFO_LOG("AudioRendererTest: Get Audio format: %{public}d", paRendererParams.sampleFormat); MEDIA_INFO_LOG("AudioRendererTest: Get Audio sampling rate: %{public}d", paRendererParams.sampleRate); MEDIA_INFO_LOG("AudioRendererTest: Get Audio channels: %{public}d", paRendererParams.channelCount); - } - else { + } else { MEDIA_ERR_LOG("AudioRendererTest: Get Audio parameters failed"); } + + return true; + } + + bool StartRender(const unique_ptr &audioRenderer, FILE* wavFile) const + { size_t bufferLen; if (audioRenderer->GetBufferSize(bufferLen)) { MEDIA_ERR_LOG("AudioRendererTest: GetMinimumBufferSize failed"); @@ -150,24 +137,65 @@ public: } } - if(!audioRenderer->Drain()) { + if (!audioRenderer->Drain()) { MEDIA_ERR_LOG("AudioRendererTest: Drain failed"); } + Timestamp timeStamp; if (audioRenderer->GetAudioTime(timeStamp, Timestamp::Timestampbase::MONOTONIC)) { MEDIA_INFO_LOG("AudioRendererTest: Timestamp seconds: %{public}ld", timeStamp.time.tv_sec); MEDIA_INFO_LOG("AudioRendererTest: Timestamp nanoseconds: %{public}ld", timeStamp.time.tv_nsec); } + free(buffer); + + return true; + } + + bool TestPlayback(int argc, char *argv[]) const + { + MEDIA_INFO_LOG("AudioRendererTest: TestPlayback start "); + + int numBase = 10; + wav_hdr wavHeader; + size_t headerSize = sizeof(wav_hdr); + FILE* wavFile = fopen(argv[1], "rb"); + if (wavFile == nullptr) { + MEDIA_INFO_LOG("AudioRendererTest: Unable to open wave file"); + return false; + } + size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); + MEDIA_INFO_LOG("AudioRendererTest: Header Read in bytes %{public}d", bytesRead); + + AudioStreamType streamType = AudioStreamType::STREAM_MUSIC; + if (argc > AudioTestConstants::ARGS_COUNT_TWO) + streamType = static_cast(strtol(argv[AudioTestConstants::ARGS_INDEX_TWO], NULL, numBase)); + unique_ptr audioRenderer = AudioRenderer::Create(streamType); + + CheckSupportedParams(); + + AudioRendererParams rendererParams; + rendererParams.sampleFormat = static_cast(wavHeader.bitsPerSample); + rendererParams.sampleRate = static_cast(wavHeader.SamplesPerSec); + rendererParams.channelCount = static_cast(wavHeader.NumOfChan); + rendererParams.encodingType = static_cast(ENCODING_PCM); + if (!InitRender(audioRenderer, rendererParams)) { + MEDIA_ERR_LOG("AudioRendererTest: Init render failed"); + return false; + } - if(!audioRenderer->Stop()) { + if (StartRender(audioRenderer, wavFile)) { + MEDIA_ERR_LOG("AudioRendererTest: Start render failed"); + return false; + } + + if (!audioRenderer->Stop()) { MEDIA_ERR_LOG("AudioRendererTest: Stop failed"); } - if(!audioRenderer->Release()) { + if (!audioRenderer->Release()) { MEDIA_ERR_LOG("AudioRendererTest: Release failed"); } - free(buffer); fclose(wavFile); MEDIA_INFO_LOG("AudioRendererTest: TestPlayback end"); @@ -179,7 +207,7 @@ int main(int argc, char *argv[]) { MEDIA_INFO_LOG("AudioRendererTest: Render test in"); - if ((argv == nullptr) || (argc < AudioTestConstants::SECOND_ARG_IDX)) { + if ((argv == nullptr) || (argc < AudioTestConstants::ARGS_INDEX_TWO)) { MEDIA_ERR_LOG("AudioRendererTest: argv is null"); return 0; } diff --git a/services/test/pcm2wav.h b/services/test/pcm2wav.h index 29f8accb3f..55aec245db 100644 --- a/services/test/pcm2wav.h +++ b/services/test/pcm2wav.h @@ -15,10 +15,10 @@ #ifndef PCM_2_WAV_H #define PCM_2_WAV_H -typedef struct WAV_HEADER { +struct WAV_HEADER { /* RIFF Chunk Descriptor */ uint8_t RIFF[4] = {'R', 'I', 'F', 'F'}; // RIFF Header Magic header - uint32_t ChunkSize; // RIFF Chunk Size + uint32_t ChunkSize = 0; // RIFF Chunk Size uint8_t WAVE[4] = {'W', 'A', 'V', 'E'}; // WAVE Header /* "fmt" sub-chunk */ uint8_t fmt[4] = {'f', 'm', 't', ' '}; // FMT header @@ -31,6 +31,8 @@ typedef struct WAV_HEADER { uint16_t bitsPerSample = 16; // Number of bits per sample /* "data" sub-chunk */ uint8_t Subchunk2ID[4] = {'d', 'a', 't', 'a'}; // "data" string - uint32_t Subchunk2Size; // Sampled data length -} wav_hdr; + uint32_t Subchunk2Size = 0; // Sampled data length +}; + +using wav_hdr = struct WAV_HEADER; #endif // PCM_2_WAV_H \ No newline at end of file diff --git a/services/test/playback_test.cpp b/services/test/playback_test.cpp index 2fb09a8272..5fcd97de55 100644 --- a/services/test/playback_test.cpp +++ b/services/test/playback_test.cpp @@ -25,6 +25,8 @@ using namespace OHOS::AudioStandard; namespace { constexpr uint8_t DEFAULT_FORMAT = SAMPLE_S16LE; constexpr uint8_t DEFAULT_CHANNELS = 2; +constexpr int32_t ARGS_INDEX_TWO = 2; +constexpr int32_t ARGS_INDEX_THREE = 3; } // namespace class PlaybackTest : public AudioRendererCallbacks { @@ -44,30 +46,8 @@ public: virtual void OnEventCb(AudioServiceEventTypes error) const{} }; -int main(int argc, char* argv[]) +static int32_t InitPlayback(std::unique_ptr &client, AudioStreamParams &audioParams) { - wav_hdr wavHeader; - size_t headerSize = sizeof(wav_hdr); - FILE* wavFile = fopen(argv[1], "rb"); - if (wavFile == nullptr) { - fprintf(stderr, "Unable to open wave file"); - return -1; - } - - float volume = 0.5; - if (argc >= 3) - volume = strtof(argv[2], nullptr); - - size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); - MEDIA_INFO_LOG("Header Read in bytes %{public}d", bytesRead); - AudioStreamParams audioParams; - audioParams.format = DEFAULT_FORMAT; - audioParams.samplingRate = wavHeader.SamplesPerSec; - audioParams.channels = DEFAULT_CHANNELS; - StreamBuffer stream; - PlaybackTest customCb; - - std::unique_ptr client = std::make_unique(); if (client == nullptr) { MEDIA_ERR_LOG("Create AudioServiceClient instance failed"); return -1; @@ -77,6 +57,7 @@ int main(int argc, char* argv[]) if (client->Initialize(AUDIO_SERVICE_CLIENT_PLAYBACK) < 0) return -1; + PlaybackTest customCb; client->RegisterAudioRendererCallbacks(customCb); MEDIA_INFO_LOG("Creating Stream"); @@ -87,10 +68,21 @@ int main(int argc, char* argv[]) if (client->StartStream() < 0) return -1; - AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance(); - audioSystemMgr->SetVolume(AudioSystemManager::AudioVolumeType::STREAM_MUSIC, volume); + return 0; +} +int32_t StartPlayback(std::unique_ptr &client, FILE *wavFile) +{ + uint8_t* buffer = nullptr; + int32_t n = 2; + size_t bytesToWrite = 0; + size_t bytesWritten = 0; + size_t minBytes = 4; + int32_t writeError; + uint64_t timeStamp; size_t bufferLen; + StreamBuffer stream; + if (client->GetMinimumBufferSize(bufferLen) < 0) { MEDIA_ERR_LOG(" GetMinimumBufferSize failed"); return -1; @@ -98,15 +90,7 @@ int main(int argc, char* argv[]) MEDIA_DEBUG_LOG("minimum buffer length: %{public}zu", bufferLen); - uint8_t* buffer = nullptr; - int32_t n = 2; buffer = (uint8_t *) malloc(n * bufferLen); - size_t bytesToWrite = 0; - size_t bytesWritten = 0; - size_t minBytes = 4; - int32_t writeError; - uint64_t timeStamp; - while (!feof(wavFile)) { bytesToWrite = fread(buffer, 1, bufferLen, wavFile); bytesWritten = 0; @@ -120,10 +104,50 @@ int main(int argc, char* argv[]) } } + free(buffer); + + return 0; +} + +int main(int argc, char* argv[]) +{ + wav_hdr wavHeader; + size_t headerSize = sizeof(wav_hdr); + FILE* wavFile = fopen(argv[1], "rb"); + if (wavFile == nullptr) { + fprintf(stderr, "Unable to open wave file"); + return -1; + } + + float volume = 0.5; + if (argc >= ARGS_INDEX_THREE) { + volume = strtof(argv[ARGS_INDEX_TWO], nullptr); + } + + size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); + MEDIA_INFO_LOG("Header Read in bytes %{public}d", bytesRead); + AudioStreamParams audioParams; + audioParams.format = DEFAULT_FORMAT; + audioParams.samplingRate = wavHeader.SamplesPerSec; + audioParams.channels = DEFAULT_CHANNELS; + + std::unique_ptr client = std::make_unique(); + if (InitPlayback(client, audioParams) < 0) { + MEDIA_INFO_LOG("Initialize playback failed"); + return -1; + } + + AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance(); + audioSystemMgr->SetVolume(AudioSystemManager::AudioVolumeType::STREAM_MUSIC, volume); + + if (StartPlayback(client, wavFile) < 0) { + MEDIA_INFO_LOG("Start playback failed"); + return -1; + } + client->FlushStream(); client->StopStream(); client->ReleaseStream(); - free(buffer); fclose(wavFile); MEDIA_INFO_LOG("Exit from test app"); return 0; -- Gitee From a6df2c376f5f847c492007651eae9d2f53e5842a Mon Sep 17 00:00:00 2001 From: Anurup M Date: Fri, 23 Jul 2021 16:29:43 +0530 Subject: [PATCH 21/32] Move pulseaudio and libsnd folders to frameworks Change-Id: I45518049fefef75adc02d662b894517282a875ba Signed-off-by: Anurup M --- {libsnd => frameworks/innerkitsimpl/libsnd}/BUILD.gn | 2 +- .../innerkitsimpl/libsnd}/include/config.h | 0 .../innerkitsimpl/libsnd}/include/sndfile.h | 0 .../innerkitsimpl/pulseaudio}/BUILD.gn | 6 +++--- .../innerkitsimpl/pulseaudio}/conf/client.conf | 0 .../innerkitsimpl/pulseaudio}/conf/daemon.conf | 0 .../innerkitsimpl/pulseaudio}/conf/default.pa | 0 .../innerkitsimpl/pulseaudio}/include/config.h | 0 .../innerkitsimpl/pulseaudio}/include/ltdl.h | 0 .../innerkitsimpl/pulseaudio}/include/pulse/version.h | 0 .../innerkitsimpl/pulseaudio}/ohos_paconfig.sh | 0 .../innerkitsimpl/pulseaudio}/src/BUILD.gn | 10 +++++----- .../innerkitsimpl/pulseaudio}/src/daemon/BUILD.gn | 2 +- .../pulseaudio}/src/daemon/ohos_daemon-conf.c | 0 .../pulseaudio}/src/daemon/ohos_pa_main.c | 0 .../innerkitsimpl/pulseaudio}/src/modules/BUILD.gn | 2 +- .../innerkitsimpl/pulseaudio}/src/modules/hdi/BUILD.gn | 2 +- .../pulseaudio}/src/modules/hdi/hdi_sink.c | 0 .../pulseaudio}/src/modules/hdi/hdi_source.c | 0 .../pulseaudio}/src/modules/hdi/module_hdi_sink.c | 0 .../pulseaudio}/src/modules/hdi/module_hdi_source.c | 0 .../innerkitsimpl/pulseaudio}/src/pulse/BUILD.gn | 2 +- .../pulseaudio}/src/pulse/ohos_glib-mainloop.c | 0 .../pulseaudio}/src/pulse/ohos_pa_volume.c | 0 .../innerkitsimpl/pulseaudio}/src/pulsecore/BUILD.gn | 4 ++-- .../pulseaudio}/src/pulsecore/ltdl-stub.c | 0 .../innerkitsimpl/pulseaudio}/src/utils/BUILD.gn | 4 ++-- interfaces/innerkits/native/audiomanager/BUILD.gn | 4 ++-- ohos.build | 2 +- services/BUILD.gn | 6 +++--- 30 files changed, 23 insertions(+), 23 deletions(-) rename {libsnd => frameworks/innerkitsimpl/libsnd}/BUILD.gn (99%) rename {libsnd => frameworks/innerkitsimpl/libsnd}/include/config.h (100%) rename {libsnd => frameworks/innerkitsimpl/libsnd}/include/sndfile.h (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/BUILD.gn (94%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/conf/client.conf (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/conf/daemon.conf (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/conf/default.pa (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/include/config.h (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/include/ltdl.h (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/include/pulse/version.h (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/ohos_paconfig.sh (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/BUILD.gn (95%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/daemon/BUILD.gn (97%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/daemon/ohos_daemon-conf.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/daemon/ohos_pa_main.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/BUILD.gn (99%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/hdi/BUILD.gn (98%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/hdi/hdi_sink.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/hdi/hdi_source.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/hdi/module_hdi_sink.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/modules/hdi/module_hdi_source.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/pulse/BUILD.gn (98%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/pulse/ohos_glib-mainloop.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/pulse/ohos_pa_volume.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/pulsecore/BUILD.gn (98%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/pulsecore/ltdl-stub.c (100%) rename {pulseaudio => frameworks/innerkitsimpl/pulseaudio}/src/utils/BUILD.gn (96%) diff --git a/libsnd/BUILD.gn b/frameworks/innerkitsimpl/libsnd/BUILD.gn similarity index 99% rename from libsnd/BUILD.gn rename to frameworks/innerkitsimpl/libsnd/BUILD.gn index 300fd6e360..df184f0ab1 100644 --- a/libsnd/BUILD.gn +++ b/frameworks/innerkitsimpl/libsnd/BUILD.gn @@ -1,7 +1,7 @@ import("//build/ohos.gni") libsndfile_dir = "//third_party/libsnd" -libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" +libsndfile_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/libsnd" config("sndfile_config") { visibility = [ ":*" ] diff --git a/libsnd/include/config.h b/frameworks/innerkitsimpl/libsnd/include/config.h similarity index 100% rename from libsnd/include/config.h rename to frameworks/innerkitsimpl/libsnd/include/config.h diff --git a/libsnd/include/sndfile.h b/frameworks/innerkitsimpl/libsnd/include/sndfile.h similarity index 100% rename from libsnd/include/sndfile.h rename to frameworks/innerkitsimpl/libsnd/include/sndfile.h diff --git a/pulseaudio/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/BUILD.gn similarity index 94% rename from pulseaudio/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/BUILD.gn index d36a841f5e..86bfbf60f1 100644 --- a/pulseaudio/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/BUILD.gn @@ -13,8 +13,8 @@ import("//build/ohos.gni") -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" -libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/libsnd" group("pulseaudio_packages") { deps = [ @@ -42,7 +42,7 @@ group("pulseaudio_packages") { } action("gen_config_header") { - script = "//foundation/multimedia/audio_standard/pulseaudio/ohos_paconfig.sh" + script = "$pulseaudio_build_path/ohos_paconfig.sh" args = [ rebase_path("//third_party/pulseaudio", root_build_dir), rebase_path( "${target_gen_dir}/", root_build_dir),] diff --git a/pulseaudio/conf/client.conf b/frameworks/innerkitsimpl/pulseaudio/conf/client.conf similarity index 100% rename from pulseaudio/conf/client.conf rename to frameworks/innerkitsimpl/pulseaudio/conf/client.conf diff --git a/pulseaudio/conf/daemon.conf b/frameworks/innerkitsimpl/pulseaudio/conf/daemon.conf similarity index 100% rename from pulseaudio/conf/daemon.conf rename to frameworks/innerkitsimpl/pulseaudio/conf/daemon.conf diff --git a/pulseaudio/conf/default.pa b/frameworks/innerkitsimpl/pulseaudio/conf/default.pa similarity index 100% rename from pulseaudio/conf/default.pa rename to frameworks/innerkitsimpl/pulseaudio/conf/default.pa diff --git a/pulseaudio/include/config.h b/frameworks/innerkitsimpl/pulseaudio/include/config.h similarity index 100% rename from pulseaudio/include/config.h rename to frameworks/innerkitsimpl/pulseaudio/include/config.h diff --git a/pulseaudio/include/ltdl.h b/frameworks/innerkitsimpl/pulseaudio/include/ltdl.h similarity index 100% rename from pulseaudio/include/ltdl.h rename to frameworks/innerkitsimpl/pulseaudio/include/ltdl.h diff --git a/pulseaudio/include/pulse/version.h b/frameworks/innerkitsimpl/pulseaudio/include/pulse/version.h similarity index 100% rename from pulseaudio/include/pulse/version.h rename to frameworks/innerkitsimpl/pulseaudio/include/pulse/version.h diff --git a/pulseaudio/ohos_paconfig.sh b/frameworks/innerkitsimpl/pulseaudio/ohos_paconfig.sh similarity index 100% rename from pulseaudio/ohos_paconfig.sh rename to frameworks/innerkitsimpl/pulseaudio/ohos_paconfig.sh diff --git a/pulseaudio/src/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/BUILD.gn similarity index 95% rename from pulseaudio/src/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/BUILD.gn index 71c492c355..da8fac3376 100644 --- a/pulseaudio/src/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/BUILD.gn @@ -14,8 +14,8 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" -libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/libsnd" config("pulsecommon_config") { visibility = [ ":*" ] @@ -127,7 +127,7 @@ ohos_shared_library("pulsecommon") { part_name = "multimedia_audio_standard" } ohos_prebuilt_etc("pa_daemon_config") { - source = "//foundation/multimedia/audio_standard/pulseaudio/conf/daemon.conf" + source = "$pulseaudio_build_path/conf/daemon.conf" subsystem_name = "multimedia" module_install_dir = "etc/pulse" @@ -135,14 +135,14 @@ ohos_prebuilt_etc("pa_daemon_config") { } ohos_prebuilt_etc("pa_default_config") { - source = "//foundation/multimedia/audio_standard/pulseaudio/conf/default.pa" + source = "$pulseaudio_build_path/conf/default.pa" subsystem_name = "multimedia" module_install_dir = "etc/pulse" part_name = "multimedia_audio_standard" } ohos_prebuilt_etc("pa_client_config") { - source = "//foundation/multimedia/audio_standard/pulseaudio/conf/client.conf" + source = "$pulseaudio_build_path/conf/client.conf" subsystem_name = "multimedia" module_install_dir = "etc/pulse" part_name = "multimedia_audio_standard" diff --git a/pulseaudio/src/daemon/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/daemon/BUILD.gn similarity index 97% rename from pulseaudio/src/daemon/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/daemon/BUILD.gn index e72361f3ce..89868e9edb 100644 --- a/pulseaudio/src/daemon/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/daemon/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" pulseaudio_dir = "//third_party/pulseaudio" config("daemon_config") { diff --git a/pulseaudio/src/daemon/ohos_daemon-conf.c b/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_daemon-conf.c similarity index 100% rename from pulseaudio/src/daemon/ohos_daemon-conf.c rename to frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_daemon-conf.c diff --git a/pulseaudio/src/daemon/ohos_pa_main.c b/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c similarity index 100% rename from pulseaudio/src/daemon/ohos_pa_main.c rename to frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c diff --git a/pulseaudio/src/modules/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/modules/BUILD.gn similarity index 99% rename from pulseaudio/src/modules/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/modules/BUILD.gn index e02fe30630..f85914bd38 100644 --- a/pulseaudio/src/modules/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/modules/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" group("modules") { deps = [ diff --git a/pulseaudio/src/modules/hdi/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/BUILD.gn similarity index 98% rename from pulseaudio/src/modules/hdi/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/BUILD.gn index 5de40efcd3..83fcf98202 100644 --- a/pulseaudio/src/modules/hdi/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" config("hdi_config") { visibility = [ ":*" ] diff --git a/pulseaudio/src/modules/hdi/hdi_sink.c b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/hdi_sink.c similarity index 100% rename from pulseaudio/src/modules/hdi/hdi_sink.c rename to frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/hdi_sink.c diff --git a/pulseaudio/src/modules/hdi/hdi_source.c b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/hdi_source.c similarity index 100% rename from pulseaudio/src/modules/hdi/hdi_source.c rename to frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/hdi_source.c diff --git a/pulseaudio/src/modules/hdi/module_hdi_sink.c b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/module_hdi_sink.c similarity index 100% rename from pulseaudio/src/modules/hdi/module_hdi_sink.c rename to frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/module_hdi_sink.c diff --git a/pulseaudio/src/modules/hdi/module_hdi_source.c b/frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/module_hdi_source.c similarity index 100% rename from pulseaudio/src/modules/hdi/module_hdi_source.c rename to frameworks/innerkitsimpl/pulseaudio/src/modules/hdi/module_hdi_source.c diff --git a/pulseaudio/src/pulse/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/pulse/BUILD.gn similarity index 98% rename from pulseaudio/src/pulse/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/pulse/BUILD.gn index 08c1f4ca6b..797695996b 100644 --- a/pulseaudio/src/pulse/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/pulse/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" config("pulse_config") { visibility = [ ":*" ] diff --git a/pulseaudio/src/pulse/ohos_glib-mainloop.c b/frameworks/innerkitsimpl/pulseaudio/src/pulse/ohos_glib-mainloop.c similarity index 100% rename from pulseaudio/src/pulse/ohos_glib-mainloop.c rename to frameworks/innerkitsimpl/pulseaudio/src/pulse/ohos_glib-mainloop.c diff --git a/pulseaudio/src/pulse/ohos_pa_volume.c b/frameworks/innerkitsimpl/pulseaudio/src/pulse/ohos_pa_volume.c similarity index 100% rename from pulseaudio/src/pulse/ohos_pa_volume.c rename to frameworks/innerkitsimpl/pulseaudio/src/pulse/ohos_pa_volume.c diff --git a/pulseaudio/src/pulsecore/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/pulsecore/BUILD.gn similarity index 98% rename from pulseaudio/src/pulsecore/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/pulsecore/BUILD.gn index 2a29c259c3..80737bb00d 100644 --- a/pulseaudio/src/pulsecore/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/pulsecore/BUILD.gn @@ -14,8 +14,8 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" -libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/libsnd" config("pulsecore_config") { visibility = [ ":*" ] diff --git a/pulseaudio/src/pulsecore/ltdl-stub.c b/frameworks/innerkitsimpl/pulseaudio/src/pulsecore/ltdl-stub.c similarity index 100% rename from pulseaudio/src/pulsecore/ltdl-stub.c rename to frameworks/innerkitsimpl/pulseaudio/src/pulsecore/ltdl-stub.c diff --git a/pulseaudio/src/utils/BUILD.gn b/frameworks/innerkitsimpl/pulseaudio/src/utils/BUILD.gn similarity index 96% rename from pulseaudio/src/utils/BUILD.gn rename to frameworks/innerkitsimpl/pulseaudio/src/utils/BUILD.gn index 7722a9e593..39a40462bb 100644 --- a/pulseaudio/src/utils/BUILD.gn +++ b/frameworks/innerkitsimpl/pulseaudio/src/utils/BUILD.gn @@ -14,8 +14,8 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" -libsndfile_build_path = "//foundation/multimedia/audio_standard/libsnd" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" +libsndfile_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/libsnd" config("pulseutils_config") { visibility = [ ":*" ] diff --git a/interfaces/innerkits/native/audiomanager/BUILD.gn b/interfaces/innerkits/native/audiomanager/BUILD.gn index 9eb2044ff8..7e065663fd 100644 --- a/interfaces/innerkits/native/audiomanager/BUILD.gn +++ b/interfaces/innerkits/native/audiomanager/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") pulseaudio_dir = "//third_party/pulseaudio" -pulseaudio_build_path = "//foundation/multimedia/audio_standard/pulseaudio" +pulseaudio_build_path = "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio" group("audio_client_test_packages") { deps = [ @@ -69,7 +69,7 @@ ohos_shared_library("audio_client") { deps = [ "//utils/native/base:utils", - "//foundation/multimedia/audio_standard/pulseaudio/src/pulse:pulse", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio/src/pulse:pulse", "//third_party/bounds_checking_function:libsec_static", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiopolicy:audio_policy_client", ] diff --git a/ohos.build b/ohos.build index 92ca3e932e..7c5667c56b 100644 --- a/ohos.build +++ b/ohos.build @@ -11,7 +11,7 @@ "//foundation/multimedia/audio_standard/sa_profile:audio_service_sa_profile", "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio", "//foundation/multimedia/audio_standard/interfaces/kits/js/audio_manager:audio_js", - "//foundation/multimedia/audio_standard/pulseaudio:pulseaudio_packages", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio:pulseaudio_packages", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client_test_packages", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorecorder:audio_recorder_test_packages", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer:audio_renderer_test", diff --git a/services/BUILD.gn b/services/BUILD.gn index 77d53bec19..259fc18f65 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -55,7 +55,7 @@ ohos_shared_library("audio_service") { deps = [ "//utils/native/base:utils", "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", - "//foundation/multimedia/audio_standard/pulseaudio/src/daemon:pulseaudio", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio/src/daemon:pulseaudio", "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/audiocapturer:audio_capturer_source", ] @@ -113,7 +113,7 @@ config("audio_policy_public_config") { "//third_party/libxml2/include", "//third_party/pulseaudio/src", "//third_party/pulseaudio/confgure/src", - "//foundation/multimedia/audio_standard/pulseaudio/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio/include", "//utils/system/safwk/native/include", "//utils/native/base/include", "//third_party/bounds_checking_function/include", @@ -145,7 +145,7 @@ ohos_shared_library("audio_policy_service") { deps = [ "//utils/native/base:utils", - "//foundation/multimedia/audio_standard/pulseaudio/src/pulse:pulse", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/pulseaudio/src/pulse:pulse", "//third_party/libxml2:xml2", "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", "//foundation/distributeddatamgr/distributeddatamgr/services/distributeddataservice/adapter:distributeddata_adapter", -- Gitee From a8bc9e945c18fce40869ff295ea53c394578aa8d Mon Sep 17 00:00:00 2001 From: sulav Date: Mon, 26 Jul 2021 08:40:34 +0530 Subject: [PATCH 22/32] gtest cases added for audio policy Signed-off-by: sulav --- frameworks/innerkitsimpl/test/BUILD.gn | 3 +- .../1.0/include/audio_policy_test.h | 58 +++ .../audiopolicy/1.0/src/audio_policy_test.cpp | 493 ++++++++++++++++++ .../test/moduletest/audiopolicy/BUILD.gn | 42 ++ 4 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/include/audio_policy_test.h create mode 100644 frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp create mode 100644 frameworks/innerkitsimpl/test/moduletest/audiopolicy/BUILD.gn diff --git a/frameworks/innerkitsimpl/test/BUILD.gn b/frameworks/innerkitsimpl/test/BUILD.gn index 4743d8a688..5fa4016c5a 100644 --- a/frameworks/innerkitsimpl/test/BUILD.gn +++ b/frameworks/innerkitsimpl/test/BUILD.gn @@ -16,6 +16,7 @@ group("audio_test") { deps = [ "moduletest/renderer_test:moduletest", - "moduletest/recorder_test:audio_recorder_module_test" + "moduletest/recorder_test:audio_recorder_module_test", + "moduletest/audiopolicy:audio_policy_module_test" ] } diff --git a/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/include/audio_policy_test.h b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/include/audio_policy_test.h new file mode 100644 index 0000000000..472f942660 --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/include/audio_policy_test.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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 + +namespace OHOS { +namespace AudioStandard { +namespace V1_0 { +using namespace std; +using namespace testing; + +struct PolicyParam { + float volume; + AudioStreamType streamType; + AudioRingerMode ringerMode; + AudioStandard::DeviceType deviceType; + AudioStandard::AudioDeviceDescriptor::DeviceFlag deviceFlag; + AudioStandard::AudioDeviceDescriptor::DeviceRole deviceRole; + bool active; + bool mute; + string key; + string value; +}; + +class AudioPolicyTest : public TestWithParam { +public: + AudioPolicyTest() {} + + virtual ~AudioPolicyTest() {} + + // SetUpTestCase: Called before all test cases + static void SetUpTestCase(void); + // TearDownTestCase: Called after all test case + static void TearDownTestCase(void); + // SetUp: Called before each test cases + void SetUp(void) override; + // TearDown: Called after each test cases + void TearDown(void) override; +}; +} +} +} diff --git a/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp new file mode 100644 index 0000000000..2bf1c97aec --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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_policy_test.h" +#include "audio_system_manager.h" + +using namespace std; +using namespace OHOS::AudioStandard; +using namespace testing::ext; + +namespace OHOS { +namespace AudioStandard { +namespace V1_0 { +void AudioPolicyTest::SetUpTestCase(void) +{ + ASSERT_NE(nullptr, AudioSystemManager::GetInstance()); +} + +void AudioPolicyTest::TearDownTestCase(void) {} + +void AudioPolicyTest::SetUp(void) {} + +void AudioPolicyTest::TearDown(void) {} + +namespace { +const PolicyParam VOLUME_PARAMS[] = { + { + .streamType = STREAM_MUSIC, + .volume = 0.5 + }, + { + .streamType = STREAM_RING, + .volume = 0.5 + } +}; + +const PolicyParam MUTE_PARAMS[] = { + { + .streamType = STREAM_MUSIC, + .mute = true + }, + { + .streamType = STREAM_MUSIC, + .mute = false + } +}; + +const PolicyParam STREAM_PARAMS[] = { + { + .streamType = STREAM_MUSIC, + .active = true + }, + { + .streamType = STREAM_RING, + .active = false + } +}; + +const PolicyParam DEVICE_PARAMS[] = { + { + .deviceType = SPEAKER, + .active = true + }, + { + .deviceType = MIC, + .active = true + }, + { + .deviceType = BLUETOOTH_A2DP, + .active = true + }, + { + .deviceType = BLUETOOTH_A2DP, + .active = false + }, + { + .deviceType = BLUETOOTH_SCO, + .active = true + }, + { + .deviceType = BLUETOOTH_SCO, + .active = false + }, + { + .deviceType = MIC, + .active = true + }, + { + .deviceType = BLUETOOTH_SCO, + .active = true + }, + { + .deviceType = SPEAKER, + .active = true + }, + { + .deviceType = BLUETOOTH_A2DP, + .active = true + }, +}; + +const PolicyParam RINGER_MODE_PARAMS[] = { + { + .ringerMode = RINGER_MODE_NORMAL + }, + { + .ringerMode = RINGER_MODE_SILENT + }, + { + .ringerMode = RINGER_MODE_VIBRATE + }, +}; + +const PolicyParam MIC_MUTE_PARAMS[] = { + { + .mute = true + }, + { + .mute = false + } +}; + +const PolicyParam VOLUME_RANGE_PARAMS[] = { + { + .streamType = STREAM_MUSIC + }, + { + .streamType = STREAM_RING + } +}; + +const PolicyParam AUDIO_PARAMS[] = { + { + .key = "sampling_rate", + .value = "8000" + }, + { + .key = "sampling_rate", + .value = "44100" + }, + { + .key = "sampling_rate", + .value = "96000" + } +}; + +const PolicyParam DEVICES_PARAMS[] = { + { + .deviceFlag = AudioDeviceDescriptor::DeviceFlag::INPUT_DEVICES_FLAG, + .deviceType = MIC, + .deviceRole = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE + }, + { + .deviceFlag = AudioDeviceDescriptor::DeviceFlag::OUTPUT_DEVICES_FLAG, + .deviceType = SPEAKER, + .deviceRole = AudioDeviceDescriptor::DeviceRole::OUTPUT_DEVICE + } +}; +} // namespace + +/* + * Set Volume + * + */ +class AudioPolicySetVolumeTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicySetVolumeTest, SetVolume, TestSize.Level1) +{ + PolicyParam params = GetParam(); + + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + float volume = params.volume; + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetVolume(volumeType, volume)); +} + +INSTANTIATE_TEST_CASE_P( + SetVolume, + AudioPolicySetVolumeTest, + ValuesIn(VOLUME_PARAMS)); + +/* + * Get Volume + * + */ + +class AudioPolicyGetVolumeTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyGetVolumeTest, GetVolume, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + float volume = params.volume; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetVolume(volumeType, volume)); + EXPECT_EQ(volume, AudioSystemManager::GetInstance()->GetVolume(volumeType)); +} + +INSTANTIATE_TEST_CASE_P( + GetVolume, + AudioPolicyGetVolumeTest, + ValuesIn(VOLUME_PARAMS)); + +/* + * Set Mute + * + */ +class AudioPolicySetMuteTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicySetMuteTest, SetMute, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + bool mute = params.mute; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetMute(volumeType, mute)); +} + + +INSTANTIATE_TEST_CASE_P( + SetMute, + AudioPolicySetMuteTest, + ValuesIn(MUTE_PARAMS)); + +/* + * Is Mute + * + */ +class AudioPolicyGetMuteTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyGetMuteTest, IsStreamMute, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + bool mute = params.mute; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetMute(volumeType, mute)); + EXPECT_EQ(mute, AudioSystemManager::GetInstance()->IsStreamMute(volumeType)); +} + +INSTANTIATE_TEST_CASE_P( + IsStreamMute, + AudioPolicyGetMuteTest, + ValuesIn(MUTE_PARAMS)); + +/* + * Is Stream Active + * + */ +class AudioPolicyIsStreamActiveTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyIsStreamActiveTest, IsStreamActive, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + + // review this code + EXPECT_EQ(params.active, AudioSystemManager::GetInstance()->IsStreamActive(volumeType)); +} + +INSTANTIATE_TEST_CASE_P( + IsStreamActive, + AudioPolicyIsStreamActiveTest, + ValuesIn(STREAM_PARAMS)); + +/* + * Set Device Active + * + */ +class AudioPolicySetDeviceActiveTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicySetDeviceActiveTest, SetDeviceActive, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioDeviceDescriptor::DeviceType deviceType = static_cast(params.deviceType); + bool active = params.active; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetDeviceActive(deviceType, active)); +} + +INSTANTIATE_TEST_CASE_P( + SetDeviceActive, + AudioPolicySetDeviceActiveTest, + ValuesIn(DEVICE_PARAMS)); + +/* + * Is Device Active + * + */ + +class AudioPolicyIsDeviceActiveTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyIsDeviceActiveTest, IsDeviceActive, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioDeviceDescriptor::DeviceType deviceType = static_cast(params.deviceType); + bool active = params.active; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetDeviceActive(deviceType, active)); + EXPECT_EQ(active, AudioSystemManager::GetInstance()->IsDeviceActive(deviceType)); +} + + +INSTANTIATE_TEST_CASE_P( + IsDeviceActive, + AudioPolicyIsDeviceActiveTest, + ValuesIn(DEVICE_PARAMS)); + +/* + * Set Ringer Mode + * + */ +class AudioPolicySetRingerModeTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicySetRingerModeTest, SetRingerMode, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioRingerMode ringerMode = params.ringerMode; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetRingerMode(ringerMode)); +} + + +INSTANTIATE_TEST_CASE_P( + SetRingerMode, + AudioPolicySetRingerModeTest, + ValuesIn(RINGER_MODE_PARAMS)); + +/* + * Get Ringer Mode + * + */ + +class AudioPolicyGetRingerModeTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyGetRingerModeTest, GetRingerMode, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioRingerMode ringerMode = params.ringerMode; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetRingerMode(ringerMode)); + EXPECT_EQ(ringerMode, AudioSystemManager::GetInstance()->GetRingerMode()); +} + +INSTANTIATE_TEST_CASE_P( + GetRingerMode, + AudioPolicyGetRingerModeTest, + ValuesIn(RINGER_MODE_PARAMS)); + + +/* + * Set microphone mute + * + */ +class AudioPolicySetMicrophoneMuteTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicySetMicrophoneMuteTest, SetMicrophoneMute, TestSize.Level1) +{ + PolicyParam params = GetParam(); + bool mute = params.mute; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetMicrophoneMute(mute)); +} + +INSTANTIATE_TEST_CASE_P( + SetMicrophoneMute, + AudioPolicySetMicrophoneMuteTest, + ValuesIn(MIC_MUTE_PARAMS)); + +/* + * Is Microphone Mute + * + */ +class AudioPolicyGetMicrophoneMuteTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyGetMicrophoneMuteTest, IsMicrophoneMute, TestSize.Level1) +{ + PolicyParam params = GetParam(); + bool mute = params.mute; + + EXPECT_EQ(MEDIA_OK, AudioSystemManager::GetInstance()->SetMicrophoneMute(mute)); + EXPECT_EQ(mute, AudioSystemManager::GetInstance()->IsMicrophoneMute()); +} + +INSTANTIATE_TEST_CASE_P( + IsMicrophoneMute, + AudioPolicyGetMicrophoneMuteTest, + ValuesIn(MIC_MUTE_PARAMS)); + +/* + * Check volume range + * + */ +class AudioPolicyVolumeRangeTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyVolumeRangeTest, GetMaxVolume, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + EXPECT_EQ(1.0, AudioSystemManager::GetInstance()->GetMaxVolume(volumeType)); +} + +HWTEST_P(AudioPolicyVolumeRangeTest, GetMinVolume, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::AudioVolumeType volumeType + = static_cast(params.streamType); + EXPECT_EQ(0, AudioSystemManager::GetInstance()->GetMinVolume(volumeType)); +} + +INSTANTIATE_TEST_CASE_P( + GetMaxVolume, + AudioPolicyVolumeRangeTest, + ValuesIn(VOLUME_RANGE_PARAMS)); + +INSTANTIATE_TEST_CASE_P( + GetMinVolume, + AudioPolicyVolumeRangeTest, + ValuesIn(VOLUME_RANGE_PARAMS)); + +/* + * Check volume range + * + */ +class AudioPolicyAudioParameterTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyAudioParameterTest, SetAudioParameter, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::GetInstance()->SetAudioParameter(params.key, params.value); + EXPECT_EQ(params.value, AudioSystemManager::GetInstance()->GetAudioParameter(params.key)); +} + +INSTANTIATE_TEST_CASE_P( + SetAudioParameter, + AudioPolicyAudioParameterTest, + ValuesIn(AUDIO_PARAMS)); + +HWTEST_P(AudioPolicyAudioParameterTest, GetAudioParameter, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioSystemManager::GetInstance()->SetAudioParameter(params.key, params.value); + EXPECT_EQ(params.value, AudioSystemManager::GetInstance()->GetAudioParameter(params.key)); +} + +INSTANTIATE_TEST_CASE_P( + GetAudioParameter, + AudioPolicyAudioParameterTest, + ValuesIn(AUDIO_PARAMS)); + +/* + * Check volume range + * + */ +class AudioPolicyGetDevicesTest : public AudioPolicyTest {}; + +HWTEST_P(AudioPolicyGetDevicesTest, GetDevices, TestSize.Level1) +{ + PolicyParam params = GetParam(); + AudioDeviceDescriptor::DeviceFlag deviceFlag = static_cast(params.deviceFlag); + AudioDeviceDescriptor::DeviceType deviceType = static_cast(params.deviceType); + AudioDeviceDescriptor::DeviceRole deviceRole = static_cast(params.deviceRole); + vector> audioDeviceDescriptors + = AudioSystemManager::GetInstance()->GetDevices(deviceFlag); + sptr audioDeviceDescriptor = audioDeviceDescriptors[0]; + EXPECT_EQ(deviceType, audioDeviceDescriptor->deviceType_); + EXPECT_EQ(deviceRole, audioDeviceDescriptor->deviceRole_); +} + +INSTANTIATE_TEST_CASE_P( + GetDevices, + AudioPolicyGetDevicesTest, + ValuesIn(DEVICES_PARAMS)); +} +} +} diff --git a/frameworks/innerkitsimpl/test/moduletest/audiopolicy/BUILD.gn b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/BUILD.gn new file mode 100644 index 0000000000..f1f218de0f --- /dev/null +++ b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +module_output_path = "audio_standard/audio_policy" + +group("moduletest") { + testonly = true + + deps = [ + ":audio_policy_module_test", + ] +} + +ohos_moduletest("audio_policy_module_test") { + module_out_path = module_output_path + include_dirs = [ + "./1.0/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] + + sources = [ + "1.0/src/audio_policy_test.cpp", + ] + + deps = [ + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiomanager:audio_client", + "//utils/native/base:utils", + ] +} -- Gitee From 372e25a78c946636ef088223f212de2b03425024 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Mon, 26 Jul 2021 14:12:40 +0530 Subject: [PATCH 23/32] Update audio_standard README.md en Signed-off-by: Vaidegi B --- README.md | 134 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 80fd4977b5..067cb37a08 100755 --- a/README.md +++ b/README.md @@ -1,22 +1,23 @@ # Audio -- [Introduction](#section119mcpsimp) - - [Basic Concepts](#section122mcpsimp) - -- [Directory Structure](#section179mcpsimp) -- [Usage Guidelines](#section112738505318) -- [Repositories Involved](#section340mcpsimp) - -## Introduction - -The **audio\_standard** repository supports the development of audio services. You can use this module to manage audio volume. + - [Introduction](#introduction) + - [Basic Concepts](#basic-concepts) + - [Directory Structure](#directory-structure) + - [Usage Guidelines](#usage-guidelines) + - [Audio Playback](#audio-playback) + - [Audio Recording](#audio-recording) + - [Audio Management](#audio-management) + - [Repositories Involved](#repositories-involved) + +## Introduction +The **audio\_standard** repository is used to implement audio-related features, including audio playback, recording and volume and device management. **Figure 1** Position in the subsystem architecture ![](figures/en-us_image_0000001152315135.png) -### Basic Concepts +### Basic Concepts - **Sampling** @@ -38,58 +39,113 @@ Audio data is in stream form. For the convenience of audio algorithm processing Pulse code modulation \(PCM\) is a method used to digitally represent sampled analog signals. It converts continuous-time analog signals into discrete-time digital signal samples. -## Directory Structure +## Directory Structure The structure of the repository directory is as follows: ``` /foundation/multimedia/audio_standard # Audio code ├── frameworks # Framework code -│ ├── innerkitsimpl # Internal interfaces implementation -│ └── kitsimpl # External interfaces implementation +│ ├── innerkitsimpl # Internal Native API Implementation +│ └── kitsimpl # External JS API Implementation ├── interfaces # Interfaces code -│ ├── innerkits # Internal interfaces -│ └── kits # External interfaces +│ ├── innerkits # Internal Native APIs +│ └── kits # External JS APIs +├── libsnd # Libsndfile build configuration +├── pulseaudio # Pulseaudio build configuration and pulseaudio-hdi modules ├── sa_profile # Service configuration profile ├── services # Service code ├── LICENSE # License file └── ohos.build # Build file ``` -## Usage Guidelines - -1. Obtain an **AudioManager** instance. +## Usage Guidelines +### Audio Playback +You can use APIs provided in this repository to convert audio data into audible analog signals, play the audio signals using output devices, and manage playback tasks. The following steps describe how to use **AudioRenderer** to develop the audio playback function: +1. Use **Create** API with required stream type to get **AudioRenderer** instance. + ``` + AudioStreamType streamType = STREAM_MUSIC; // example stream type + std::unique_ptr audioRenderer = AudioRenderer::Create(streamType); + ``` +2. (Optional) Static APIs **GetSupportedFormats**(), **GetSupportedChannels**(), **GetSupportedEncodingTypes**(), **GetSupportedSamplingRates**() can be used to get the supported values of the params. +3. To Prepare the device, call **SetParams** on the instance. + ``` + AudioRendererParams rendererParams; + rendererParams.sampleFormat = SAMPLE_S16LE; + rendererParams.sampleRate = SAMPLE_RATE_44100; + rendererParams.channelCount = STEREO; + rendererParams.encodingType = ENCODING_PCM; + audioRenderer->SetParams(rendererParams); ``` - const audioManager = audio.getAudioManager(); +4. (Optional) use audioRenderer->**GetParams**(rendererParams); to validate SetParams +5. Call **audioRenderer->Start()** function on the AudioRenderer instance to start the playback task. +6. Get the buffer size can be written, using **GetBufferSize**. Read the audio data to be played and transfer it into the bytes stream. Call the **Write** function repeatedly to write data untill all the data in the buffer is written. + ``` + audioRenderer->GetBufferSize(bufferLen); + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); // example shown reads audio data from a file + while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { + bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten); + if (bytesWritten < 0) + break; + } ``` +7. (Optional) Call audioRenderer->**Drain()** to drain the plackback stream. + +8. Call audioRenderer->**Stop()** function to Stop rendering. +9. After the playback task is complete, call the audioRenderer->**Release**() function on the AudioRenderer instance to release the resources. + +Provided the basic playback flow here. Please refer **audio_renderer.h** and **audio_info.h** for more useful APIs. -2. Obtain the audio stream volume. +### Audio Recording +You can use the APIs provided in this repository for your application to record voices using input devices, convert the voices into audio data, and manage recording tasks. The following steps describe how to use AudioReorder to develop the audio recording function: + +1. Use **Create** API with required stream type to get **AudioRecorder** instance. ``` - audioManager.getVolume(audio.AudioVolumeType.MEDIA, (err, value) => { - if (err) { - console.error(`failed to get volume ${err.message}`); - return; - } - console.log(`Media getVolume successful callback`); - }); + AudioStreamType streamType = STREAM_MUSIC; + std::unique_ptr audioRecorder = AudioRecorder::Create(streamType); ``` +2. (Optional) Static APIs **GetSupportedFormats**(), **GetSupportedChannels**(), **GetSupportedEncodingTypes**(), **GetSupportedSamplingRates()** can be used to get the supported values of the params. +3. To Prepare the device, call **SetParams** on the instance. + ``` + AudioRecorderParams recorderParams; + recorderParams.sampleFormat = SAMPLE_S16LE; + recorderParams.sampleRate = SAMPLE_RATE_44100; + recorderParams.channelCount = STEREO; + recorderParams.encodingType = ENCODING_PCM; -3. Set the audio stream volume. - + audioRecorder->SetParams(recorderParams); ``` - audioManager.setVolume(audio.AudioVolumeType.MEDIA, 30, (err)=>{ - if (err) { - console.error(`failed to set volume ${err.message}`); - return; - } - console.log(`Media setVolume successful callback`); - }) +4. (Optional) use audioRecorder->**GetParams**(recorderParams) to validate SetParams() +5. Call audioRenderer->**Start**() function on the AudioRecorder instance to start the recording task. +6. Get the buffer size can be read, using GetBufferSize. Read the recorded audio data and converts it to a byte stream. Call the read function repeatedly to read data. ``` + audioRecorder->GetBufferSize(bufferLen) + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlocking); // set isBlocking = true/false for blocking/non-blocking read + while (numBuffersToRecord) { + bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); + if (bytesRead < 0) { + break; + } else if (bytesRead > 0) { + fwrite(buffer, size, bytesRead, recFile); // example shows writes the recored data into a file + numBuffersToRecord--; + } + } + ``` +7. (Optional) Call audioRecorder->**Flush**() to flush the record buffer of this stream. +8. Call the audioRecorder->**Stop**() function on the AudioRecorder instance to stop the recording. +9. After the recording task is complete, call the audioRecorder->**Release**() function on the AudioRecorder instance to release resources. + + +### Audio Management +JS apps can use the APIs provided by auido manager to control the volume and the device.\ +Please refer the following for JS usage of audio volume and device management: + https://gitee.com/openharmony/docs/blob/master/en/application-dev/js-reference/audio-management.md -## Repositories Involved -multimedia\_audio\_standard +## Repositories Involved +[multimedia\_audio\_standard](https://gitee.com/openharmony/multimedia_audio_standard)\ +[multimedia\_media\_standard](https://gitee.com/openharmony/multimedia_media_standard) -- Gitee From 058fc172febf5a69027bf7dafcc9ed6f6b716659 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Mon, 26 Jul 2021 18:00:45 +0530 Subject: [PATCH 24/32] Update audio_standard Readme.md en with latest APIs Signed-off-by: Vaidegi B --- README.md | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) mode change 100755 => 100644 README.md diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 067cb37a08..6530020343 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [Repositories Involved](#repositories-involved) ## Introduction -The **audio\_standard** repository is used to implement audio-related features, including audio playback, recording and volume and device management. +The **audio\_standard** repository is used to implement audio-related features, including audio playback, recording, volume management and device management. **Figure 1** Position in the subsystem architecture @@ -46,13 +46,12 @@ The structure of the repository directory is as follows: ``` /foundation/multimedia/audio_standard # Audio code ├── frameworks # Framework code -│ ├── innerkitsimpl # Internal Native API Implementation +│ ├── innerkitsimpl # Internal Native API Implementation. +| | Pulseaudio and libsnd file build configuration.pulseaudio-hdi modules │ └── kitsimpl # External JS API Implementation -├── interfaces # Interfaces code +├── interfaces # Interfaces │ ├── innerkits # Internal Native APIs │ └── kits # External JS APIs -├── libsnd # Libsndfile build configuration -├── pulseaudio # Pulseaudio build configuration and pulseaudio-hdi modules ├── sa_profile # Service configuration profile ├── services # Service code ├── LICENSE # License file @@ -63,10 +62,10 @@ The structure of the repository directory is as follows: ### Audio Playback You can use APIs provided in this repository to convert audio data into audible analog signals, play the audio signals using output devices, and manage playback tasks. The following steps describe how to use **AudioRenderer** to develop the audio playback function: 1. Use **Create** API with required stream type to get **AudioRenderer** instance. - ``` - AudioStreamType streamType = STREAM_MUSIC; // example stream type - std::unique_ptr audioRenderer = AudioRenderer::Create(streamType); - ``` + ``` + AudioStreamType streamType = STREAM_MUSIC; // example stream type + std::unique_ptr audioRenderer = AudioRenderer::Create(streamType); + ``` 2. (Optional) Static APIs **GetSupportedFormats**(), **GetSupportedChannels**(), **GetSupportedEncodingTypes**(), **GetSupportedSamplingRates**() can be used to get the supported values of the params. 3. To Prepare the device, call **SetParams** on the instance. ``` @@ -80,22 +79,25 @@ You can use APIs provided in this repository to convert audio data into audible ``` 4. (Optional) use audioRenderer->**GetParams**(rendererParams); to validate SetParams 5. Call **audioRenderer->Start()** function on the AudioRenderer instance to start the playback task. -6. Get the buffer size can be written, using **GetBufferSize**. Read the audio data to be played and transfer it into the bytes stream. Call the **Write** function repeatedly to write data untill all the data in the buffer is written. - ``` - audioRenderer->GetBufferSize(bufferLen); - bytesToWrite = fread(buffer, 1, bufferLen, wavFile); // example shown reads audio data from a file +6. Get the buffer length to be written, using **GetBufferSize** API . + ``` + audioRenderer->GetBufferSize(bufferLen); + ``` +7. Read the audio data to be played from the source(example audio file) and transfer it into the bytes stream. Call the **Write** function repeatedly to write the render data. + ``` + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten); if (bytesWritten < 0) break; } ``` -7. (Optional) Call audioRenderer->**Drain()** to drain the plackback stream. +8. Call audioRenderer->**Drain**() to drain the playback stream. -8. Call audioRenderer->**Stop()** function to Stop rendering. -9. After the playback task is complete, call the audioRenderer->**Release**() function on the AudioRenderer instance to release the resources. +9. Call audioRenderer->**Stop()** function to Stop rendering. +10. After the playback task is complete, call the audioRenderer->**Release**() function on the AudioRenderer instance to release the resources. -Provided the basic playback flow here. Please refer **audio_renderer.h** and **audio_info.h** for more useful APIs. +Provided the basic playback usecase above. Please refer [**audio_renderer.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. ### Audio Recording @@ -104,7 +106,7 @@ You can use the APIs provided in this repository for your application to record 1. Use **Create** API with required stream type to get **AudioRecorder** instance. ``` AudioStreamType streamType = STREAM_MUSIC; - std::unique_ptr audioRecorder = AudioRecorder::Create(streamType); + std::unique_ptr audioRecorder = AudioRecorder::Create(streamType); ``` 2. (Optional) Static APIs **GetSupportedFormats**(), **GetSupportedChannels**(), **GetSupportedEncodingTypes**(), **GetSupportedSamplingRates()** can be used to get the supported values of the params. 3. To Prepare the device, call **SetParams** on the instance. @@ -119,9 +121,12 @@ You can use the APIs provided in this repository for your application to record ``` 4. (Optional) use audioRecorder->**GetParams**(recorderParams) to validate SetParams() 5. Call audioRenderer->**Start**() function on the AudioRecorder instance to start the recording task. -6. Get the buffer size can be read, using GetBufferSize. Read the recorded audio data and converts it to a byte stream. Call the read function repeatedly to read data. +6. Get the buffer length to be read, using **GetBufferSize** API. + ``` + audioRecorder->GetBufferSize(bufferLen); + ``` +7. Read the recorded audio data and convert it to a byte stream. Call the read function repeatedly to read data untill you want to stop recording ``` - audioRecorder->GetBufferSize(bufferLen) bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlocking); // set isBlocking = true/false for blocking/non-blocking read while (numBuffersToRecord) { bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlockingRead); @@ -133,14 +138,15 @@ You can use the APIs provided in this repository for your application to record } } ``` -7. (Optional) Call audioRecorder->**Flush**() to flush the record buffer of this stream. -8. Call the audioRecorder->**Stop**() function on the AudioRecorder instance to stop the recording. -9. After the recording task is complete, call the audioRecorder->**Release**() function on the AudioRecorder instance to release resources. +8. (Optional) Call audioRecorder->**Flush**() to flush the record buffer of this stream. +9. Call the audioRecorder->**Stop**() function on the AudioRecorder instance to stop the recording. +10. After the recording task is complete, call the audioRecorder->**Release**() function on the AudioRecorder instance to release resources. +Provided the basic recording usecase above. Please refer [**audio_recorder.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. ### Audio Management -JS apps can use the APIs provided by auido manager to control the volume and the device.\ +JS apps can use the APIs provided by audio manager to control the volume and the device.\ Please refer the following for JS usage of audio volume and device management: https://gitee.com/openharmony/docs/blob/master/en/application-dev/js-reference/audio-management.md -- Gitee From d688a6385acc2088768120ccc9654b25e1d17a58 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Mon, 26 Jul 2021 19:43:49 +0530 Subject: [PATCH 25/32] Remove currently unsupported APIs Signed-off-by: Vaidegi B --- .../audio_manager/@ohos.multimedia.audio.d.ts | 932 +----------------- 1 file changed, 1 insertion(+), 931 deletions(-) diff --git a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts index 38c2edc5ee..724a1ad6d0 100644 --- a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts +++ b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts @@ -29,24 +29,6 @@ declare namespace audio { * @devices */ function getAudioManager(): AudioManager; - /** - * Obtains an SoundPlayer instance. - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - function createSoundPlayer(): SoundPlayer; - /** - * Obtains an ToneDescriptor instance. - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - function createToneDescriptor(tone: ToneType): ToneDescriptor; - /** - * Obtains an SoundEffectBuilder instance. - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - function getSoundEffectBuilder(): SoundEffectBuilder; /** * Enumerates audio stream types. @@ -148,122 +130,7 @@ declare namespace audio { */ RINGER_MODE_VIBRATE = 2, } - /** - * 呼叫状态枚举. - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum CallState { - /** - * 空闲状态 - */ - IDLE = 0, - /** - * 打电话状态 - */ - IN_CALL = 1, - /** - * 处于voip状态 - */ - IN_VOIP = 2, - /** - * 铃声状态 - */ - RINGTONE = 3, - } - /** - * 音频编码方式枚举. - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum AudioEncodingFormat { - /** - * 默认 - */ - ENCODING_DEFAULT = 0, - /** - * 无效 - */ - ENCODING_INVALID = 1, - /** - * mp3 - */ - ENCODING_MP3 = 2, - /** - * pcm16bit - */ - ENCODING_PCM_16BIT = 3, - /** - * pcm8bit - */ - ENCODING_PCM_8BIT = 4, - /** - * pcmfloat - */ - ENCODING_PCM_FLOAT = 5, - } - /** - * 音频内容枚举. - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum ContentType { - /** - * 电影 - */ - CONTENT_TYPE_MOVIE = 0, - /** - * 音乐 - */ - CONTENT_TYPE_MUSIC = 1, - /** - * 可视化 - */ - CONTENT_TYPE_SONIFICATION = 2, - /** - * 演讲 - */ - CONTENT_TYPE_SPEECH = 3, - /** - * 未知 - */ - CONTENT_TYPE_UNKNOWN = 4, - } - enum InterruptType { - /** - * 静音 - */ - INTERRUPT_HINT_DUCK = 0, - /** - * 空 - */ - INTERRUPT_HINT_NONE = 1, - /** - * 暂停 - */ - INTERRUPT_HINT_PAUSE = 2, - /** - * 重新开始 - */ - INTERRUPT_HINT_RESUME = 3, - /** - * 停止 - */ - INTERRUPT_HINT_STOP = 4, - /** - * 不静音 - */ - INTERRUPT_HINT_UNDUCK = 5, - /** - * 开始 - */ - INTERRUPT_TYPE_BEGIN = 6, - /** - * 结束 - */ - INTERRUPT_TYPE_END = 7, - } /** * Manages audio volume and audio device information. * @devices @@ -354,30 +221,6 @@ declare namespace audio { * @devices */ setRingerMode(mode: AudioRingMode): Promise; - /** - * 获取主输出帧数,回调方式返回帧数。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getMasterOutputFrameCount(callback: AsyncCallback): void; - /** - * 获取主输出帧数,promise方式返回帧数。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getMasterOutputFrameCount(): Promise; - /** - * 获取主输出采样率,回调方式返回采样率。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getMasterOutputSampleRate(callback: AsyncCallback): void; - /** - * 获取主输出采样率,promise方式返回采样率。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getMasterOutputSampleRate(): Promise; /** * 判断流是否静音,回调方式返回。 * @sysCap SystemCapability.Multimedia.Audio @@ -414,42 +257,18 @@ declare namespace audio { * @devices */ isMicrophoneMute(): Promise; - /** - * 判断主设备是否静音,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - isMasterMute(callback: AsyncCallback): void; //不倾向与实现 - /** - * 判断主设备是否静音,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - isMasterMute(): Promise; //不倾向与实现 /** * 设置流静音,回调方式返回。 * @sysCap SystemCapability.Multimedia.Audio * @devices */ - setStreamMute(volumeType: AudioVolumeType, mute: boolean, callback: AsyncCallback) : void; + setStreamMute(volumeType: AudioVolumeType, mute: boolean, callback: AsyncCallback) : void; /** * 设置流静音,promise方式返回。 * @sysCap SystemCapability.Multimedia.Audio * @devices */ setStreamMute(volumeType: AudioVolumeType, mute: boolean): Promise; - /** - * 设置主设备静音,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - setMasterMute(mute: boolean, callback: AsyncCallback): void; //不倾向与实现 - /** - * 设置主设备静音,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - setMasterMute(mute: boolean): Promise; //不倾向与实现 /** * 设置麦克风是否静音,回调方式返回。 * @sysCap SystemCapability.Multimedia.Audio @@ -486,30 +305,6 @@ declare namespace audio { * @devices */ setDeviceActive(deviceType: DeviceType, active: boolean): Promise; - /** - * 连接蓝牙设备,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - connectBluetoothSco(callback: AsyncCallback): void; - /** - * 连接蓝牙设备,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - connectBluetoothSco(): Promise; - /** - * 断开蓝牙设备,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - disconnectBluetoothSco(callback: AsyncCallback): void; - /** - * 断开蓝牙设备,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - disconnectBluetoothSco(): Promise; /** * 获取音频参数,回调方式返回。 * @sysCap SystemCapability.Multimedia.Audio @@ -534,60 +329,6 @@ declare namespace audio { * @devices */ setAudioParameter(key: string, value: string): Promise; - /** - * 获取打电话状态,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getCallState(callback: AsyncCallback): void; - /** - * 获取打电话状态,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - getCallState(): Promise; - /** - * 设置打电话状态,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - setCallState(callState: CallState, callback: AsyncCallback): void; - /** - * 设置打电话状态,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - setCallState(callState: CallState): Promise; - /** - * 激活音频中断。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - activateAudioInterrupt(interrupt: AudioInterrupt): void; - /** - * 不激活音频中断。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - deactivateAudioInterrupt(interrupt: AudioInterrupt): void; - /** - * 监听音频中断。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'interrupt', callback: Callback): void; - /** - * 监听错误消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'error', callback: ErrorCallback): void; - /** - * 监听设备变化。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'deviceChange', callback: Callback): void; } /** @@ -596,51 +337,6 @@ declare namespace audio { * @sysCap SystemCapability.Multimedia.Audio */ interface AudioDeviceDescriptor { - /** - * id - * @devices - */ - id: number; - /** - * 名字 - * @devices - */ - name: string; - /** - * 地址 - * @devices - */ - address: string; - /** - * 采样率 - * @devices - */ - sampleRate: Array; - /** - * 通道数 - * @devices - */ - channelCounts: Array>; - /** - * 通道的mask序列 - * @devices - */ - channelIndexMasks: Array; - /** - * 通道的mask - * @devices - */ - channelMasks: Array; - /** - * 哈希值 - * @devices - */ - hashCode: number; - /** - * 编码方式 - * @devices - */ - encodeFormat: Array; /** * Audio device role * @devices @@ -652,63 +348,6 @@ declare namespace audio { */ readonly deviceType: DeviceType; } - /** - * 音频通道的类型 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum ChannelMask { - /** - * mono - */ - CHANNEL_IN_MONO = 0, - /** - * stereo - */ - CHANNEL_IN_STEREO = 1, - /** - * 无效 - */ - CHANNEL_INVALID = 2, - } - /** - * 音频中断。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface AudioInterrupt { - /** - * 音频流类型 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - streamType: AudioVolumeType; - /** - * 音频内容 - * @devices - */ - contentType: ContentType; - /** - * 暂停时是否静音 - * @devices - */ - pauseWhenDucked: boolean; - /** - * 中断类型 - * @devices - */ - streamFlag: InterruptType; - /** - * 音频通道的mask - * @devices - */ - chanelMask: ChannelMask; - /** - * 音频编码方式 - * @devices - */ - encodingFormat: AudioEncodingFormat; - } /** * A queue of AudioDeviceDescriptor, which is read-only. @@ -716,575 +355,6 @@ declare namespace audio { * @sysCap SystemCapability.Multimedia.Audio */ type AudioDeviceDescriptors = Array>; - /** - * 短音类型。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum SoundType { - /** - * 点击 - */ - KEY_CLICK = 0, - /** - * 删除 - */ - KEYPRESS_DELETE = 1, - /** - * 无效 - */ - KEYPRESS_INVALID = 2, - /** - * 返回 - */ - KEYPRESS_RETURN = 3, - /** - * 空格键 - */ - KEYPRESS_SPACEBAR = 4, - /** - * 标准 - */ - KEYPRESS_STANDARD = 5, - /** - * 下 - */ - NAVIGATION_DOWN = 6, - /** - * 左 - */ - NAVIGATION_LEFT = 7, - /** - * 右 - */ - NAVIGATION_RIGHT = 8, - /** - * 上 - */ - NAVIGATION_UP = 9, - } - /** - * 短音播放器。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface SoundPlayer { - /** - * 读取短音,返回id,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSound(path: string, callback: AsyncCallback): void; - /** - * 读取短音,返回id,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSound(path: string): Promise; - /** - * 通过tone读取短音,返回id,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSoundByTone(tone: ToneType, durationMs: number, callback: AsyncCallback): void; - /** - * 通过tone读取短音,返回id,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSoundByTone(tone: ToneType, durationMs: number): Promise; - /** - * 通过流类型读取短音,返回id,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSoundByStream(audioStream: AudioVolumeType, volume: number, callback: AsyncCallback); - /** - * 通过流类型读取短音,返回id,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - loadSoundByStream(audioStream: AudioVolumeType, volume: number): Promise; - /** - * 删除短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - unloadSound(soundId: number); - /** - * 播放短音,回调方式返回id。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - play(soundId: number, options: SoundOptions, callback: AsyncCallback): void; - /** - * 播放短音,回调方式返回id。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - play(soundId: number, callback: AsyncCallback): void; - /** - * 播放短音,promise方式返回id。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - play(soundId: number, options?: SoundOptions): Promise; - /** - * 暂停短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - pause(taskId: number): void; - /** - * 暂停所有短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - pauseAll(): void; - /** - * 重新开始短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - resume(taskId: number): void; - /** - * 重新开始所有短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - resumeAll(): void; - /** - * 停止短音。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - stop(taskId: number): void; - /** - * 设置参数。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - setOptions(taskId: number, options: SoundOptions): void; - /** - * 释放。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - release(): void; - /** - * 监听暂停消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'pause', callback: Callback): void; - /** - * 监听暂停所有消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'pauseAll', callback: Callback): void; - /** - * 监听重新开始消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'resume', callback: Callback): void; - /** - * 监听重新开始所有的消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'resumeAll', callback: Callback): void; - /** - * 监听暂停的消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'stop', callback: Callback): void; - /** - * 监听参数变化的消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'optionsChange', callback: Callback): void; - /** - * 监听完成的消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'complete', callback: Callback): void; - /** - * 监听错误消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'error', callback: ErrorCallback): void; - /** - * 监听释放的消息。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'release', callback: Callback): void; - } - /** - * 短音参数。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface SoundOptions { - /** - * 循环次数 - * @devices - */ - loopNumber: number; - /** - * 速率 - * @devices - */ - speed: number; - /** - * 音量 - * @devices - */ - volumes: SoundVolumes; - /** - * 优先级 - * @devices - */ - priority: number; - } - /** - * 短音音量 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface SoundVolumes { - /** - * 左声道 - * @devices - */ - left: number; - /** - * 右声道 - * @devices - */ - right: number; - } - /** - * tone类型 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum ToneType { - /** - * DTMF_0 - */ - DTMF_0 = 0, - /** - * DTMF_1 - */ - DTMF_1 = 1, - /** - * DTMF_2 - */ - DTMF_2 = 2, - /** - * DTMF_3 - */ - DTMF_3 = 3, - /** - * DTMF_4 - */ - DTMF_4 = 4, - /** - * DTMF_5 - */ - DTMF_5 = 5, - /** - * DTMF_6 - */ - DTMF_6 = 6, - /** - * DTMF_7 - */ - DTMF_7 = 7, - /** - * DTMF_8 - */ - DTMF_8 = 8, - /** - * DTMF_9 - */ - DTMF_9 = 9, - /** - * DTMF_A - */ - DTMF_A = 10, - /** - * DTMF_B - */ - DTMF_B = 11, - /** - * DTMF_C - */ - DTMF_C = 12, - /** - * DTMF_D - */ - DTMF_D = 13, - /** - * DTMF_P - */ - DTMF_P = 14, - /** - * DTMF_S - */ - DTMF_S = 15, - /** - * PROP_PROMPT - */ - PROP_PROMPT = 16, - /** - * SUP_CALL_WAITING - */ - SUP_CALL_WAITING = 17, - } - /** - * tone描述 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface ToneDescriptor { - /** - * tone类型 - * @devices - */ - toneType: ToneType; - /** - * 高频 - * @devices - */ - highFrequency: number; - /** - * 低频 - * @devices - */ - lowFrequency: number; - } - /** - * 声音特效模式。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum SoundEffectMode { - /** - * 辅助 - */ - SOUND_EFFECT_MODE_AUXILIARY = 0, - /** - * 插入 - */ - SOUND_EFFECT_MODE_INSERT = 1, - /** - * 待加工 - */ - SOUND_EFFECT_MODE_PRE_PROCESSING = 2, - } - /** - * 声音特效类型。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum SoundEffectType { - /** - * AE - */ - SOUND_EFFECT_TYPE_AE = 0, - /** - * EC - */ - SOUND_EFFECT_TYPE_EC = 1, - /** - * GC - */ - SOUND_EFFECT_TYPE_GC = 2, - /** - * 无效 - */ - SOUND_EFFECT_TYPE_INVALID = 3, - /** - * NS - */ - SOUND_EFFECT_TYPE_NS = 4, - } - /** - * 声音特效衍生类型。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - enum SoundEffectDerivative { - /** - * GAIN_CONTRAL_EFFECT - */ - GAIN_CONTRAL_EFFECT = 0, - /** - * ECHO_CANCELER_EFFECT - */ - ECHO_CANCELER_EFFECT = 1, - /** - * NOISE_SUPPRESSOR_EFFECT - */ - NOISE_SUPPRESSOR_EFFECT = 2, - } - /** - * 声音特效创建器。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface SoundEffectBuilder { - /** - * 获取可创建的声音特效,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - acquireEffects(callback: AsyncCallback>): void; - /** - * 获取可创建的声音特效,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - acquireEffects(): Promise>; - /** - * 创建声音特效,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - create(options: EffectOptions, callback: AsyncCallback): void; - /** - * 创建声音特效,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - create(options: EffectOptions): Promise; - } - /** - * 声音特效。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface SoundEffect { - /** - * 特效音模式 - * @devices - */ - mode: SoundEffectMode; - /** - * 名字 - * @devices - */ - name: string; - /** - * 类型 - * @devices - */ - type: SoundEffectType; - /** - * 衍生类型 - * @devices - */ - deriveType: SoundEffectDerivative; - /** - * uid - * @devices - */ - uid: string; - /** - * 激活 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - active(): void; - /** - * 停止 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - deactive(): void; - /** - * 释放 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - release(): void; - /** - * 监听激活的消息 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'active', callback: Callback): void; - /** - * 监听停止的消息 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'deactive', callback: Callback): void; - /** - * 监听释放的消息 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'release', callback: Callback): void; - /** - * 监听错误消息 - * @sysCap SystemCapability.Multimedia.Audio - * @devices - */ - on(type: 'error', callback: ErrorCallback): void; - } - /** - * 声音特效信息。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface EffectInfo { - /** - * 衍生类型 - * @devices - */ - deriveType: SoundEffectDerivative; - /** - * 是否可获取 - * @devices - */ - isAvailable: boolean; - } - /** - * 声音特效选项。 - * @devices - * @sysCap SystemCapability.Multimedia.Audio - */ - interface EffectOptions { - /** - * 衍生类型 - * @devices - */ - deriveType: SoundEffectDerivative - /** - * 音频播放器 - * @devices - */ - audioPlayer?: AudioPlayer; - /** - * 视频播放器 - * @devices - */ - videoPlayer?: VideoPlayer; - /** - * 包名 - * @devices - */ - pkgName: string; - } } export default audio; \ No newline at end of file -- Gitee From f9dd04853679d8a9794803e64cc2f4b2e4c6f175 Mon Sep 17 00:00:00 2001 From: sulav Date: Tue, 27 Jul 2021 19:59:05 +0530 Subject: [PATCH 26/32] Fix ISO declaration order for musl build Signed-off-by: sulav --- .../audiopolicy/1.0/src/audio_policy_test.cpp | 12 ++++++------ services/etc/pulseaudio.cfg | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp index 2bf1c97aec..f2d5fb8efa 100644 --- a/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp +++ b/frameworks/innerkitsimpl/test/moduletest/audiopolicy/1.0/src/audio_policy_test.cpp @@ -37,12 +37,12 @@ void AudioPolicyTest::TearDown(void) {} namespace { const PolicyParam VOLUME_PARAMS[] = { { - .streamType = STREAM_MUSIC, - .volume = 0.5 + .volume = 0.5, + .streamType = STREAM_MUSIC }, { - .streamType = STREAM_RING, - .volume = 0.5 + .volume = 0.5, + .streamType = STREAM_RING } }; @@ -158,13 +158,13 @@ const PolicyParam AUDIO_PARAMS[] = { const PolicyParam DEVICES_PARAMS[] = { { - .deviceFlag = AudioDeviceDescriptor::DeviceFlag::INPUT_DEVICES_FLAG, .deviceType = MIC, + .deviceFlag = AudioDeviceDescriptor::DeviceFlag::INPUT_DEVICES_FLAG, .deviceRole = AudioDeviceDescriptor::DeviceRole::INPUT_DEVICE }, { - .deviceFlag = AudioDeviceDescriptor::DeviceFlag::OUTPUT_DEVICES_FLAG, .deviceType = SPEAKER, + .deviceFlag = AudioDeviceDescriptor::DeviceFlag::OUTPUT_DEVICES_FLAG, .deviceRole = AudioDeviceDescriptor::DeviceRole::OUTPUT_DEVICE } }; diff --git a/services/etc/pulseaudio.cfg b/services/etc/pulseaudio.cfg index 6f8a01137a..d444809b53 100644 --- a/services/etc/pulseaudio.cfg +++ b/services/etc/pulseaudio.cfg @@ -5,8 +5,8 @@ "mkdir /data/local/.pulse_dir", "chmod 755 /data/local/.pulse_dir", "chown system shell /data/local/.pulse_dir", - "export PULSE_STATE_PATH \"/data/local/.pulse_dir\"", - "export PULSE_RUNTIME_PATH \"/data/local/.pulse_dir\"", + "export PULSE_STATE_PATH /data/local/.pulse_dir", + "export PULSE_RUNTIME_PATH /data/local/.pulse_dir", "start pulseaudio", "exec /system/bin/sleep 4", "trigger audio_policy_start" -- Gitee From 30914d9119240ee2df85025c2a6c8204572e31a6 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Tue, 27 Jul 2021 19:28:11 +0530 Subject: [PATCH 27/32] Update JS APIs as per new requirement Signed-off-by: Vaidegi B --- README.md | 18 +- .../audio_manager/src/audio_manager_napi.cpp | 63 +++++- .../audio_manager/@ohos.multimedia.audio.d.ts | 198 +++++++++--------- .../include/audio_manager_napi.h | 10 +- 4 files changed, 170 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index 6530020343..660d5e8b01 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Sampling is a process to obtain discrete-time signals by extracting samples from - **Sampling rate** -Sampling rate is the number of samples extracted from a continuous signal per second to form a discrete signal. It is measured in Hz. Generally, human hearing range is from 20 Hz to 20 kHz. Common audio sampling rates include 8 kHz, 11.025 kHz, 22.05 kHz, 16 kHz, 37.8 kHz, 44.1 kHz, 48 kHz, 96 kHz, and 192 kHz. +Sampling rate is the number of samples extracted from a continuous signal per second to form a discrete signal. It is measured in Hz. Generally, human hearing range is from 20 Hz to 20 kHz. Common audio sampling rates include 8 kHz, 11.025 kHz, 22.05 kHz, 16 kHz, 37.8 kHz, 44.1 kHz, 48 kHz, and 96 kHz. - **Channel** @@ -47,7 +47,7 @@ The structure of the repository directory is as follows: /foundation/multimedia/audio_standard # Audio code ├── frameworks # Framework code │ ├── innerkitsimpl # Internal Native API Implementation. -| | Pulseaudio and libsnd file build configuration.pulseaudio-hdi modules +| | Pulseaudio, libsndfile build configuration and pulseaudio-hdi modules │ └── kitsimpl # External JS API Implementation ├── interfaces # Interfaces │ ├── innerkits # Internal Native APIs @@ -77,15 +77,15 @@ You can use APIs provided in this repository to convert audio data into audible audioRenderer->SetParams(rendererParams); ``` -4. (Optional) use audioRenderer->**GetParams**(rendererParams); to validate SetParams +4. (Optional) use audioRenderer->**GetParams**(rendererParams) to validate SetParams 5. Call **audioRenderer->Start()** function on the AudioRenderer instance to start the playback task. 6. Get the buffer length to be written, using **GetBufferSize** API . ``` audioRenderer->GetBufferSize(bufferLen); ``` -7. Read the audio data to be played from the source(example audio file) and transfer it into the bytes stream. Call the **Write** function repeatedly to write the render data. +7. Read the audio data to be played from the source(for example, an audio file) and transfer it into the bytes stream. Call the **Write** function repeatedly to write the render data. ``` - bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { bytesWritten += audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten); if (bytesWritten < 0) @@ -97,7 +97,7 @@ You can use APIs provided in this repository to convert audio data into audible 9. Call audioRenderer->**Stop()** function to Stop rendering. 10. After the playback task is complete, call the audioRenderer->**Release**() function on the AudioRenderer instance to release the resources. -Provided the basic playback usecase above. Please refer [**audio_renderer.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. +Provided the basic playback usecase above. Please refer [**audio_renderer.h**](https://gitee.com/openharmony/multimedia_audio_standard/blob/master/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/blob/master/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. ### Audio Recording @@ -142,14 +142,12 @@ You can use the APIs provided in this repository for your application to record 9. Call the audioRecorder->**Stop**() function on the AudioRecorder instance to stop the recording. 10. After the recording task is complete, call the audioRecorder->**Release**() function on the AudioRecorder instance to release resources. -Provided the basic recording usecase above. Please refer [**audio_recorder.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. +Provided the basic recording usecase above. Please refer [**audio_recorder.h**](https://gitee.com/openharmony/multimedia_audio_standard/blob/master/interfaces/innerkits/native/audiorecorder/include/audio_recorder.h) and [**audio_info.h**](https://gitee.com/openharmony/multimedia_audio_standard/blob/master/interfaces/innerkits/native/audiocommon/include/audio_info.h) for more APIs. ### Audio Management JS apps can use the APIs provided by audio manager to control the volume and the device.\ -Please refer the following for JS usage of audio volume and device management: - https://gitee.com/openharmony/docs/blob/master/en/application-dev/js-reference/audio-management.md - +Please refer [**audio-management.md**](https://gitee.com/openharmony/docs/blob/master/en/application-dev/js-reference/audio-management.md) for JS usage of audio volume and device management. ## Repositories Involved diff --git a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp index d6563962b3..4f3f833f8d 100644 --- a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp @@ -92,12 +92,12 @@ static AudioSystemManager::AudioVolumeType GetNativeAudioVolumeType(int32_t volu AudioSystemManager::AudioVolumeType result = AudioSystemManager::STREAM_MUSIC; switch (volumeType) { - case AudioManagerNapi::MEDIA: - result = AudioSystemManager::STREAM_MUSIC; - break; case AudioManagerNapi::RINGTONE: result = AudioSystemManager::STREAM_RING; break; + case AudioManagerNapi::MEDIA: + result = AudioSystemManager::STREAM_MUSIC; + break; default: result = AudioSystemManager::STREAM_MUSIC; HiLog::Error(LABEL, "Unknown volume type, Set it to default MEDIA!"); @@ -160,6 +160,53 @@ static AudioDeviceDescriptor::DeviceFlag GetNativeDeviceFlag(int32_t deviceFlag) return result; } + +static AudioRingerMode GetNativeAudioRingerMode(int32_t ringMode) +{ + AudioRingerMode result = RINGER_MODE_NORMAL; + + switch (ringMode) { + case AudioManagerNapi::RINGER_MODE_SILENT: + result = RINGER_MODE_SILENT; + break; + case AudioManagerNapi::RINGER_MODE_VIBRATE: + result = RINGER_MODE_VIBRATE; + break; + case AudioManagerNapi::RINGER_MODE_NORMAL: + result = RINGER_MODE_NORMAL; + break; + default: + result = RINGER_MODE_NORMAL; + HiLog::Error(LABEL, "Unknown ringer mode requested by JS, Set it to default RINGER_MODE_NORMAL!"); + break; + } + + return result; +} + +static AudioManagerNapi::AudioRingMode GetJsAudioRingMode(int32_t ringerMode) +{ + AudioManagerNapi::AudioRingMode result = AudioManagerNapi::RINGER_MODE_NORMAL; + + switch (ringerMode) { + case RINGER_MODE_SILENT: + result = AudioManagerNapi::RINGER_MODE_SILENT; + break; + case RINGER_MODE_VIBRATE: + result = AudioManagerNapi::RINGER_MODE_VIBRATE; + break; + case RINGER_MODE_NORMAL: + result = AudioManagerNapi::RINGER_MODE_NORMAL; + break; + default: + result = AudioManagerNapi::RINGER_MODE_NORMAL; + HiLog::Error(LABEL, "Unknown ringer mode returned from native, Set it to default RINGER_MODE_NORMAL!"); + break; + } + + return result; +} + napi_status AudioManagerNapi::AddNamedProperty(napi_env env, napi_value object, const string name, int32_t enumValue) { napi_status status; @@ -409,9 +456,9 @@ napi_value AudioManagerNapi::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("getMaxVolume", GetMaxVolume), DECLARE_NAPI_FUNCTION("getMinVolume", GetMinVolume), DECLARE_NAPI_FUNCTION("getDevices", GetDevices), - DECLARE_NAPI_FUNCTION("setStreamMute", SetStreamMute), - DECLARE_NAPI_FUNCTION("isStreamMute", IsStreamMute), - DECLARE_NAPI_FUNCTION("isStreamActive", IsStreamActive), + DECLARE_NAPI_FUNCTION("mute", SetStreamMute), + DECLARE_NAPI_FUNCTION("isMute", IsStreamMute), + DECLARE_NAPI_FUNCTION("isActive", IsStreamActive), DECLARE_NAPI_FUNCTION("setRingerMode", SetRingerMode), DECLARE_NAPI_FUNCTION("getRingerMode", GetRingerMode), DECLARE_NAPI_FUNCTION("setDeviceActive", SetDeviceActive), @@ -800,7 +847,7 @@ napi_value AudioManagerNapi::SetRingerMode(napi_env env, napi_callback_info info [](napi_env env, void* data) { auto context = static_cast(data); context->status = - context->objectInfo->audioMngr_->SetRingerMode(static_cast(context->ringMode)); + context->objectInfo->audioMngr_->SetRingerMode(GetNativeAudioRingerMode(context->ringMode)); }, SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { @@ -855,7 +902,7 @@ napi_value AudioManagerNapi::GetRingerMode(napi_env env, napi_callback_info info env, nullptr, resource, [](napi_env env, void* data) { auto context = static_cast(data); - context->ringMode = context->objectInfo->audioMngr_->GetRingerMode(); + context->ringMode = GetJsAudioRingMode(context->objectInfo->audioMngr_->GetRingerMode()); context->intValue = context->ringMode; context->status = 0; }, diff --git a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts index 724a1ad6d0..4ed98a3abc 100644 --- a/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts +++ b/interfaces/kits/js/audio_manager/@ohos.multimedia.audio.d.ts @@ -13,7 +13,7 @@ * limitations under the License. */ import {ErrorCallback, AsyncCallback, Callback} from './basic'; -import {VideoPlayer, AudioPlayer} from '@ohos.Multimedia.media' +import {VideoPlayer, AudioPlayer} from './@ohos.multimedia.media' /** * @name audio * @since 6 @@ -25,8 +25,8 @@ declare namespace audio { /** * Obtains an AudioManager instance. - * @sysCap SystemCapability.Multimedia.Audio * @devices + * @sysCap SystemCapability.Multimedia.Audio */ function getAudioManager(): AudioManager; @@ -36,14 +36,14 @@ declare namespace audio { * @sysCap SystemCapability.Multimedia.Audio */ enum AudioVolumeType { - /** - * Audio streams for media purpose - */ - MEDIA = 1, - /** + /** * Audio streams for ring tones */ RINGTONE = 2, + /** + * Audio streams for media purpose + */ + MEDIA = 3, } /** @@ -112,23 +112,23 @@ declare namespace audio { MIC = 5, } /** - * 音频铃声枚举. + * Enumerates Audio Ringer modes * @devices * @sysCap SystemCapability.Multimedia.Audio */ enum AudioRingMode { /** - * 正常铃声模式 + * Silent mode */ - RINGER_MODE_NORMAL = 0, + RINGER_MODE_SILENT = 0, /** - * 静音铃声模式 + * Vibration mode */ - RINGER_MODE_SILENT = 1, - /** - * 振动铃声模式 + RINGER_MODE_VIBRATE, + /** + * Normal mode */ - RINGER_MODE_VIBRATE = 2, + RINGER_MODE_NORMAL, } /** @@ -142,193 +142,193 @@ declare namespace audio { * @devices * @sysCap SystemCapability.Multimedia.Audio */ - setVolume(audioType: AudioVolumeType, volume: number,callback: AsyncCallback): void; + setVolume(volumeType: AudioVolumeType, volume: number, callback: AsyncCallback): void; /** * Sets volume for a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - setVolume(audioType: AudioVolumeType, volume: number): Promise; + setVolume(volumeType: AudioVolumeType, volume: number): Promise; /** * Obtains volume of a stream. This method uses an asynchronous callback to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getVolume(audioType: AudioVolumeType, callback: AsyncCallback): void; + getVolume(volumeType: AudioVolumeType, callback: AsyncCallback): void; /** * Obtains the volume of a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getVolume(audioType: AudioVolumeType): Promise; + getVolume(volumeType: AudioVolumeType): Promise; /** * Obtains the minimum volume allowed for a stream. This method uses an asynchronous callback to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getMinVolume(audioType: AudioVolumeType, callback: AsyncCallback): void + getMinVolume(volumeType: AudioVolumeType, callback: AsyncCallback): void; /** * Obtains the minimum volume allowed for a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getMinVolume(audioType: AudioVolumeType): Promise; + getMinVolume(volumeType: AudioVolumeType): Promise; /** * Obtains the maximum volume allowed for a stream. This method uses an asynchronous callback to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getMaxVolume(audioType: AudioVolumeType, callback: AsyncCallback): void + getMaxVolume(volumeType: AudioVolumeType, callback: AsyncCallback): void; /** * Obtains the maximum volume allowed for a stream. This method uses a promise to return the execution result. * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getMaxVolume(audioType: AudioVolumeType): Promise; + getMaxVolume(volumeType: AudioVolumeType): Promise; /** - * Obtains the audio devices of a specified flag. This method uses an asynchronous callback to return the execution result. - * @devices + * Sets the stream to mute. This method uses an asynchronous callback to return the execution result. * @sysCap SystemCapability.Multimedia.Audio + * @devices */ - getDevices(deviceFlag: DeviceFlag, callback: AsyncCallback): void + mute(volumeType: AudioVolumeType, mute: boolean, callback: AsyncCallback): void; /** - * Obtains the audio devices with a specified flag. This method uses a promise to return the execution result. - * @devices + * Sets the stream to mute. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio */ - getDevices(deviceFlag: DeviceFlag): Promise; - /** - * 回调方式获取铃声模式。 + mute(volumeType: AudioVolumeType, mute: boolean): Promise; + /** + * Checks whether the stream is muted. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - getRingerMode(callback: AsyncCallback): void; + isMute(volumeType: AudioVolumeType, callback: AsyncCallback): void; /** - * promise方式获取铃声模式。 + * Checks whether the stream is muted. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - getRingerMode(): Promise; + isMute(volumeType: AudioVolumeType): Promise; /** - * 设置铃声模式,回调方式返回是否成功。 + * Checks whether the stream is active. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setRingerMode(mode: AudioRingMode, callback: AsyncCallback): void; + isActive(volumeType: AudioVolumeType, callback: AsyncCallback): void; /** - * 设置铃声模式,promise方式返回是否成功。 + * Checks whether the stream is active. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setRingerMode(mode: AudioRingMode): Promise; - /** - * 判断流是否静音,回调方式返回。 + isActive(volumeType: AudioVolumeType): Promise; + /** + * Mute/Unmutes the microphone. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isStreamMute(volumeType: AudioVolumeType, callback: AsyncCallback): void; + setMicrophoneMute(mute: boolean, callback: AsyncCallback): void; /** - * 判断流是否静音,promise方式返回。 + * Mute/Unmutes the microphone. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isStreamMute(volumeType: AudioVolumeType): Promise; + setMicrophoneMute(mute: boolean): Promise; /** - * 判断流是否激活,回调方式返回。 + * Checks whether the microphone is muted. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isStreamActive(volumeType: AudioVolumeType, callback: AsyncCallback): void; + isMicrophoneMute(callback: AsyncCallback): void; /** - * 判断流是否激活,promise方式返回。 + * Checks whether the microphone is muted. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isStreamActive(volumeType: AudioVolumeType): Promise; - /** - * 判断麦克风是否静音,回调方式返回。 + isMicrophoneMute(): Promise; + /** + * Sets the ringer mode. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isMicrophoneMute(callback: AsyncCallback): void; + setRingerMode(mode: AudioRingMode, callback: AsyncCallback): void; /** - * 判断麦克风是否静音,promise方式返回。 + * Sets the ringer mode. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isMicrophoneMute(): Promise; - /** - * 设置流静音,回调方式返回。 + setRingerMode(mode: AudioRingMode): Promise; + /** + * Gets the ringer mode. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setStreamMute(volumeType: AudioVolumeType, mute: boolean, callback: AsyncCallback) : void; + getRingerMode(callback: AsyncCallback): void; /** - * 设置流静音,promise方式返回。 + * Gets the ringer mode. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setStreamMute(volumeType: AudioVolumeType, mute: boolean): Promise; - /** - * 设置麦克风是否静音,回调方式返回。 + getRingerMode(): Promise; + /** + * Sets the audio parameter. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setMicrophoneMute(isMute: boolean, callback: AsyncCallback): void; + setAudioParameter(key: string, value: string, callback: AsyncCallback): void; /** - * 设置麦克风是否静音,promise方式返回。 + * Sets the audio parameter. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - setMicrophoneMute(isMute: boolean): Promise; - /** - * 设备是否激活,回调方式返回。 + setAudioParameter(key: string, value: string): Promise; + /** + * Gets the audio parameter. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isDeviceActive(deviceType: DeviceType, callback: AsyncCallback): void; + getAudioParameter(key: string, callback: AsyncCallback): void; /** - * 设备是否激活,promise方式返回。 + * Gets the audio parameter. This method uses a promise to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - isDeviceActive(deviceType: DeviceType): Promise; + getAudioParameter(key: string): Promise; /** - * 设置设备激活,回调方式返回。 - * @sysCap SystemCapability.Multimedia.Audio + * Obtains the audio devices of a specified flag. This method uses an asynchronous callback to return the execution result. * @devices + * @sysCap SystemCapability.Multimedia.Audio */ - setDeviceActive(deviceType: DeviceType, active: boolean, callback: AsyncCallback): void; + getDevices(deviceFlag: DeviceFlag, callback: AsyncCallback): void; /** - * 设置设备激活,promise方式返回。 - * @sysCap SystemCapability.Multimedia.Audio + * Obtains the audio devices with a specified flag. This method uses a promise to return the execution result. * @devices + * @sysCap SystemCapability.Multimedia.Audio */ - setDeviceActive(deviceType: DeviceType, active: boolean): Promise; - /** - * 获取音频参数,回调方式返回。 + getDevices(deviceFlag: DeviceFlag): Promise; + /** + * Activates the device. This method uses an asynchronous callback to return the execution result. + * @devices * @sysCap SystemCapability.Multimedia.Audio - * @devices */ - getAudioParameter(key: string, callback: AsyncCallback): void; + setDeviceActive(deviceType: DeviceType, active: boolean, callback: AsyncCallback): void; /** - * 获取音频参数,promise方式返回。 + * Activates the device. This method uses a promise to return the execution result. * @sysCap SystemCapability.Multimedia.Audio * @devices */ - getAudioParameter(key: string): Promise; + setDeviceActive(deviceType: DeviceType, active: boolean): Promise; /** - * 设置音频参数,回调方式返回。 + * Checks whether the device is active. This method uses an asynchronous callback to return the execution result. * @sysCap SystemCapability.Multimedia.Audio * @devices */ - setAudioParameter(key: string, value: string, callback: AsyncCallback): void; + isDeviceActive(deviceType: DeviceType, callback: AsyncCallback): void; /** - * 设置音频参数,回调方式返回。 + * Checks whether the device is active. This method uses a promise to return the execution result. * @sysCap SystemCapability.Multimedia.Audio * @devices */ - setAudioParameter(key: string, value: string): Promise; + isDeviceActive(deviceType: DeviceType): Promise; } /** diff --git a/interfaces/kits/js/audio_manager/include/audio_manager_napi.h b/interfaces/kits/js/audio_manager/include/audio_manager_napi.h index 9976ea3f98..416e59bbe2 100644 --- a/interfaces/kits/js/audio_manager/include/audio_manager_napi.h +++ b/interfaces/kits/js/audio_manager/include/audio_manager_napi.h @@ -32,8 +32,8 @@ public: ~AudioManagerNapi(); enum AudioVolumeType { - MEDIA = 1, - RINGTONE = 2 + RINGTONE = 2, + MEDIA = 3 }; enum DeviceFlag { @@ -42,6 +42,12 @@ public: ALL_DEVICES_FLAG = 3 }; + enum AudioRingMode { + RINGER_MODE_SILENT = 0, + RINGER_MODE_VIBRATE, + RINGER_MODE_NORMAL + }; + static napi_value Init(napi_env env, napi_value exports); private: -- Gitee From ca50372c081a851217b694132df554e39ef55655 Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Wed, 28 Jul 2021 01:10:31 +0530 Subject: [PATCH 28/32] Handle JS Enum object for updated enums Signed-off-by: Vaidegi B --- .../audio_manager/src/audio_manager_napi.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp index 4f3f833f8d..f7c95f6c53 100644 --- a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp @@ -229,14 +229,14 @@ napi_value AudioManagerNapi::CreateAudioVolumeTypeObject(napi_env env) status = napi_create_object(env, &result); if (status == napi_ok) { - for (int i = AudioManagerNapi::MEDIA; i <= AudioManagerNapi::RINGTONE; i++) { + for (int i = AudioManagerNapi::RINGTONE; i <= AudioManagerNapi::MEDIA; i++) { switch (i) { - case AudioManagerNapi::MEDIA: - propName = "MEDIA"; - break; case AudioManagerNapi::RINGTONE: propName = "RINGTONE"; break; + case AudioManagerNapi::MEDIA: + propName = "MEDIA"; + break; default: HiLog::Error(LABEL, "Invalid prop!"); continue; @@ -408,17 +408,17 @@ napi_value AudioManagerNapi::CreateAudioRingModeObject(napi_env env) status = napi_create_object(env, &result); if (status == napi_ok) { - for (int i = RINGER_MODE_NORMAL; i <= RINGER_MODE_VIBRATE; i++) { + for (int i = AudioManagerNapi::RINGER_MODE_SILENT; i <= AudioManagerNapi::RINGER_MODE_NORMAL; i++) { switch (i) { - case RINGER_MODE_NORMAL: - propName = "RINGER_MODE_NORMAL"; - break; - case RINGER_MODE_SILENT: + case AudioManagerNapi::RINGER_MODE_SILENT: propName = "RINGER_MODE_SILENT"; break; - case RINGER_MODE_VIBRATE: + case AudioManagerNapi::RINGER_MODE_VIBRATE: propName = "RINGER_MODE_VIBRATE"; break; + case AudioManagerNapi::RINGER_MODE_NORMAL: + propName = "RINGER_MODE_NORMAL"; + break; default: HiLog::Error(LABEL, "Invalid prop!"); continue; -- Gitee From 2782c0d14356481d57e6f1fbd124cf68f854a473 Mon Sep 17 00:00:00 2001 From: Ashish Sawakar Date: Wed, 28 Jul 2021 17:25:08 +0530 Subject: [PATCH 29/32] Change volume APIs volume level in integer range 0-15 for JS Change-Id: Idbe501c1325b4ddfbac457f43c39c564a7f7944b Signed-off-by: Ashish Sawakar --- .../include/audio_system_manager.h | 13 +++++--- services/include/audio_manager_base.h | 4 +-- services/include/client/audio_manager_proxy.h | 4 +-- services/include/server/audio_server.h | 8 ++--- services/src/client/audio_manager_proxy.cpp | 8 ++--- services/src/client/audio_system_manager.cpp | 31 ++++++++++++++----- services/src/server/audio_manager_stub.cpp | 8 ++--- services/src/server/audio_server.cpp | 4 +-- 8 files changed, 51 insertions(+), 29 deletions(-) diff --git a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h index cde085460a..d2a2fd1f2f 100644 --- a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h +++ b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h @@ -144,10 +144,10 @@ enum AudioVolumeType { STREAM_ACCESSIBILITY = 10 }; static AudioSystemManager* GetInstance(); - int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) const; - float GetVolume(AudioSystemManager::AudioVolumeType volumeType) const; - float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const; - float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const; + int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, int32_t volume) const; + int32_t GetVolume(AudioSystemManager::AudioVolumeType volumeType) const; + int32_t GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const; + int32_t GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const; int32_t SetMute(AudioSystemManager::AudioVolumeType volumeType, bool mute) const; bool IsStreamMute(AudioSystemManager::AudioVolumeType volumeType) const; int32_t SetMicrophoneMute(bool isMute) const; @@ -164,6 +164,11 @@ private: AudioSystemManager(); virtual ~AudioSystemManager(); void init(); + float MapVolumeToHDI(int32_t volume) const; + int32_t MapVolumeFromHDI(float volume) const; + static constexpr int32_t MAX_VOLUME_LEVEL = 15; + static constexpr int32_t MIN_VOLUME_LEVEL = 0; + static constexpr int32_t CONST_FACTOR = 100; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/include/audio_manager_base.h b/services/include/audio_manager_base.h index 2927bae0d9..6ff4f1027d 100644 --- a/services/include/audio_manager_base.h +++ b/services/include/audio_manager_base.h @@ -31,14 +31,14 @@ public: * * @return Returns the max volume. */ - virtual float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; + virtual int32_t GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; /** * Obtains min volume. * * @return Returns the min volume. */ - virtual float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; + virtual int32_t GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) = 0; /** * Sets Microphone Mute status. diff --git a/services/include/client/audio_manager_proxy.h b/services/include/client/audio_manager_proxy.h index 3b82f08d82..ac19fc4322 100644 --- a/services/include/client/audio_manager_proxy.h +++ b/services/include/client/audio_manager_proxy.h @@ -26,8 +26,8 @@ class AudioManagerProxy : public IRemoteProxy { public: explicit AudioManagerProxy(const sptr &impl); virtual ~AudioManagerProxy() = default; - float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; - float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; int32_t SetMicrophoneMute(bool isMute) override; bool IsMicrophoneMute() override; std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) override; diff --git a/services/include/server/audio_server.h b/services/include/server/audio_server.h index 2909574a07..b9407f66d5 100644 --- a/services/include/server/audio_server.h +++ b/services/include/server/audio_server.h @@ -35,8 +35,8 @@ public: void OnDump() override; void OnStart() override; void OnStop() override; - float GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; - float GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) override; + int32_t GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) override; int32_t SetMicrophoneMute(bool isMute) override; bool IsMicrophoneMute() override; std::vector> GetDevices(AudioDeviceDescriptor::DeviceFlag deviceFlag) override; @@ -44,8 +44,8 @@ public: void SetAudioParameter(const std::string key, const std::string value) override; const std::string GetAudioParameter(const std::string key) override; private: - static constexpr float MAX_VOLUME = 1.0; - static constexpr float MIN_VOLUME = 0; + static constexpr int32_t MAX_VOLUME = 15; + static constexpr int32_t MIN_VOLUME = 0; static std::unordered_map AudioStreamVolumeMap; std::vector> audioDeviceDescriptor_; static std::map audioParameters; diff --git a/services/src/client/audio_manager_proxy.cpp b/services/src/client/audio_manager_proxy.cpp index 81627e9450..56ea189463 100644 --- a/services/src/client/audio_manager_proxy.cpp +++ b/services/src/client/audio_manager_proxy.cpp @@ -24,7 +24,7 @@ AudioManagerProxy::AudioManagerProxy(const sptr &impl) { } -float AudioManagerProxy::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) +int32_t AudioManagerProxy::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) { MessageParcel data; MessageParcel reply; @@ -35,11 +35,11 @@ float AudioManagerProxy::GetMaxVolume(AudioSystemManager::AudioVolumeType volume MEDIA_ERR_LOG("Get max volume failed, error: %d", error); return error; } - float volume = reply.ReadFloat(); + int32_t volume = reply.ReadInt32(); return volume; } -float AudioManagerProxy::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) +int32_t AudioManagerProxy::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) { MessageParcel data; MessageParcel reply; @@ -52,7 +52,7 @@ float AudioManagerProxy::GetMinVolume(AudioSystemManager::AudioVolumeType volume return error; } - float volume = reply.ReadFloat(); + float volume = reply.ReadInt32(); return volume; } diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp index ffe8bfd4d7..b2ee6c388d 100644 --- a/services/src/client/audio_system_manager.cpp +++ b/services/src/client/audio_system_manager.cpp @@ -137,10 +137,10 @@ void AudioSystemManager::SetAudioParameter(const std::string key, const std::str g_sProxy->SetAudioParameter(key, value); } -int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volumeType, float volume) const +int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volumeType, int32_t volume) const { /* Validate and return INVALID_PARAMS error */ - if ((volume < 0) || (volume > 1)) { + if ((volume < MIN_VOLUME_LEVEL) || (volume > MAX_VOLUME_LEVEL)) { MEDIA_ERR_LOG("Invalid Volume Input!"); return ERR_INVALID_PARAM; } @@ -156,10 +156,11 @@ int32_t AudioSystemManager::SetVolume(AudioSystemManager::AudioVolumeType volume /* Call Audio Policy SetStreamVolume */ AudioStreamType StreamVolType = (AudioStreamType)volumeType; - return AudioPolicyManager::GetInstance().SetStreamVolume(StreamVolType, volume); + float volumeToHdi = MapVolumeToHDI(volume); + return AudioPolicyManager::GetInstance().SetStreamVolume(StreamVolType, volumeToHdi); } -float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeType) const +int32_t AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeType) const { switch (volumeType) { case STREAM_MUSIC: @@ -172,15 +173,31 @@ float AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volumeTy /* Call Audio Policy SetStreamMute */ AudioStreamType StreamVolType = (AudioStreamType)volumeType; - return AudioPolicyManager::GetInstance().GetStreamVolume(StreamVolType); + float volumeFromHdi = AudioPolicyManager::GetInstance().GetStreamVolume(StreamVolType); + + return MapVolumeFromHDI(volumeFromHdi); +} + +float AudioSystemManager::MapVolumeToHDI(int32_t volume) const +{ + float value = (float)volume / MAX_VOLUME_LEVEL; + float roundValue = (int)(value * CONST_FACTOR); + + return (float)roundValue / CONST_FACTOR; +} + +int32_t AudioSystemManager::MapVolumeFromHDI(float volume) const +{ + float value = (float)volume * MAX_VOLUME_LEVEL; + return nearbyint(value); } -float AudioSystemManager::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const +int32_t AudioSystemManager::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const { return g_sProxy->GetMaxVolume(volumeType); } -float AudioSystemManager::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const +int32_t AudioSystemManager::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) const { return g_sProxy->GetMinVolume(volumeType); } diff --git a/services/src/server/audio_manager_stub.cpp b/services/src/server/audio_manager_stub.cpp index f8a7853f83..8236b896f2 100644 --- a/services/src/server/audio_manager_stub.cpp +++ b/services/src/server/audio_manager_stub.cpp @@ -36,8 +36,8 @@ int AudioManagerStub::OnRemoteRequest( AudioSystemManager::AudioVolumeType volumeStreamConfig = static_cast(volumeType); MEDIA_DEBUG_LOG("GET_MAX_VOLUME volumeType= %{public}d", volumeStreamConfig); - float ret = GetMaxVolume(volumeStreamConfig); - reply.WriteFloat(ret); + int32_t ret = GetMaxVolume(volumeStreamConfig); + reply.WriteInt32(ret); return MEDIA_OK; } case GET_MIN_VOLUME: { @@ -47,8 +47,8 @@ int AudioManagerStub::OnRemoteRequest( AudioSystemManager::AudioVolumeType volumeStreamConfig = static_cast(volumeType); MEDIA_DEBUG_LOG("GET_MIN_VOLUME volumeType= %{public}d", volumeStreamConfig); - float ret = GetMinVolume(volumeStreamConfig); - reply.WriteFloat(ret); + int32_t ret = GetMinVolume(volumeStreamConfig); + reply.WriteInt32(ret); return MEDIA_OK; } case GET_DEVICES: { diff --git a/services/src/server/audio_server.cpp b/services/src/server/audio_server.cpp index 7c92f2bc45..872bc9c001 100644 --- a/services/src/server/audio_server.cpp +++ b/services/src/server/audio_server.cpp @@ -98,13 +98,13 @@ const std::string AudioServer::GetAudioParameter(const std::string key) } } -float AudioServer::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) +int32_t AudioServer::GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) { MEDIA_DEBUG_LOG("GetMaxVolume server"); return MAX_VOLUME; } -float AudioServer::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) +int32_t AudioServer::GetMinVolume(AudioSystemManager::AudioVolumeType volumeType) { MEDIA_DEBUG_LOG("GetMinVolume server"); return MIN_VOLUME; -- Gitee From 55d88973044babac9900b477f8ee423e8d1199bc Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Wed, 28 Jul 2021 18:07:07 +0530 Subject: [PATCH 30/32] Napi:Support volume level in integer range 0-15 for JS Signed-off-by: Vaidegi B --- .../audio_manager/src/audio_manager_napi.cpp | 94 ++++++++----------- 1 file changed, 39 insertions(+), 55 deletions(-) diff --git a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp index f7c95f6c53..0b6b959524 100644 --- a/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp +++ b/frameworks/kitsimpl/audio_manager/src/audio_manager_napi.cpp @@ -34,7 +34,7 @@ napi_ref AudioManagerNapi::audioRingModeRef_ = nullptr; size_t argc = num; \ napi_value argv[num] = {0}; \ napi_value thisVar = nullptr; \ - void* data; \ + void *data; \ napi_get_cb_info(env, info, &argc, argv, &thisVar, &data) struct AudioManagerAsyncContext { @@ -43,6 +43,7 @@ struct AudioManagerAsyncContext { napi_deferred deferred; napi_ref callbackRef = nullptr; int32_t volType; + int32_t volLevel; int32_t deviceType; int32_t ringMode; int32_t deviceFlag; @@ -51,11 +52,9 @@ struct AudioManagerAsyncContext { bool isMute; bool isActive; bool isTrue; - double volLevel; - double doubleValue; string key; string valueStr; - AudioManagerNapi* objectInfo; + AudioManagerNapi *objectInfo; vector> deviceDescriptors; }; @@ -571,7 +570,7 @@ static string GetStringArgument(napi_env env, napi_value value) status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength); if (status == napi_ok && bufLength > 0) { - buffer = (char *) malloc((bufLength + 1) * sizeof(char)); + buffer = (char *)malloc((bufLength + 1) * sizeof(char)); if (buffer != nullptr) { status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength); if (status == napi_ok) { @@ -617,7 +616,7 @@ static void CommonCallbackRoutine(napi_env env, AudioManagerAsyncContext* &async delete asyncContext; } -static void SetFunctionAsyncCallbackComplete(napi_env env, napi_status status, void* data) +static void SetFunctionAsyncCallbackComplete(napi_env env, napi_status status, void *data) { auto asyncContext = static_cast(data); napi_value valueParam = nullptr; @@ -632,7 +631,7 @@ static void SetFunctionAsyncCallbackComplete(napi_env env, napi_status status, v } } -static void IsTrueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +static void IsTrueAsyncCallbackComplete(napi_env env, napi_status status, void *data) { auto asyncContext = static_cast(data); napi_value valueParam = nullptr; @@ -647,22 +646,7 @@ static void IsTrueAsyncCallbackComplete(napi_env env, napi_status status, void* } } -static void GetDoubleValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) -{ - auto asyncContext = static_cast(data); - napi_value valueParam = nullptr; - - if (asyncContext != nullptr) { - if (!asyncContext->status) { - napi_create_double(env, asyncContext->doubleValue, &valueParam); - } - CommonCallbackRoutine(env, asyncContext, valueParam); - } else { - HiLog::Error(LABEL, "ERROR: AudioManagerAsyncContext* is Null!"); - } -} - -static void GetStringValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +static void GetStringValueAsyncCallbackComplete(napi_env env, napi_status status, void *data) { auto asyncContext = static_cast(data); napi_value valueParam = nullptr; @@ -677,7 +661,7 @@ static void GetStringValueAsyncCallbackComplete(napi_env env, napi_status status } } -static void GetIntValueAsyncCallbackComplete(napi_env env, napi_status status, void* data) +static void GetIntValueAsyncCallbackComplete(napi_env env, napi_status status, void *data) { auto asyncContext = static_cast(data); napi_value valueParam = nullptr; @@ -730,7 +714,7 @@ napi_value AudioManagerNapi::SetMicrophoneMute(napi_env env, napi_callback_info status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->status = context->objectInfo->audioMngr_->SetMicrophoneMute(context->isMute); }, @@ -785,7 +769,7 @@ napi_value AudioManagerNapi::IsMicrophoneMute(napi_env env, napi_callback_info i status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->isMute = context->objectInfo->audioMngr_->IsMicrophoneMute(); context->isTrue = context->isMute; @@ -844,7 +828,7 @@ napi_value AudioManagerNapi::SetRingerMode(napi_env env, napi_callback_info info status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->status = context->objectInfo->audioMngr_->SetRingerMode(GetNativeAudioRingerMode(context->ringMode)); @@ -900,7 +884,7 @@ napi_value AudioManagerNapi::GetRingerMode(napi_env env, napi_callback_info info status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->ringMode = GetJsAudioRingMode(context->objectInfo->audioMngr_->GetRingerMode()); context->intValue = context->ringMode; @@ -962,7 +946,7 @@ napi_value AudioManagerNapi::SetStreamMute(napi_env env, napi_callback_info info status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->status = context->objectInfo->audioMngr_->SetMute(GetNativeAudioVolumeType(context->volType), context->isMute); @@ -1021,7 +1005,7 @@ napi_value AudioManagerNapi::IsStreamMute(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->isMute = context->objectInfo->audioMngr_->IsStreamMute(GetNativeAudioVolumeType(context->volType)); @@ -1082,7 +1066,7 @@ napi_value AudioManagerNapi::IsStreamActive(napi_env env, napi_callback_info inf status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->isActive = context->objectInfo->audioMngr_->IsStreamActive(GetNativeAudioVolumeType(context->volType)); @@ -1145,7 +1129,7 @@ napi_value AudioManagerNapi::SetDeviceActive(napi_env env, napi_callback_info in status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->status = context->objectInfo->audioMngr_->SetDeviceActive( GetNativeDeviceType(context->deviceType), context->isActive); @@ -1204,7 +1188,7 @@ napi_value AudioManagerNapi::IsDeviceActive(napi_env env, napi_callback_info inf status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->isActive = context->objectInfo->audioMngr_->IsDeviceActive(GetNativeDeviceType(context->deviceType)); @@ -1267,7 +1251,7 @@ napi_value AudioManagerNapi::SetAudioParameter(napi_env env, napi_callback_info status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->objectInfo->audioMngr_->SetAudioParameter(context->key, context->valueStr); context->status = 0; @@ -1325,7 +1309,7 @@ napi_value AudioManagerNapi::GetAudioParameter(napi_env env, napi_callback_info napi_create_string_utf8(env, "GetAudioParameter", NAPI_AUTO_LENGTH, &resource); status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->valueStr = context->objectInfo->audioMngr_->GetAudioParameter(context->key); context->status = 0; @@ -1366,7 +1350,7 @@ napi_value AudioManagerNapi::SetVolume(napi_env env, napi_callback_info info) if (i == PARAM0 && valueType == napi_number) { napi_get_value_int32(env, argv[i], &asyncContext->volType); } else if (i == PARAM1 && valueType == napi_number) { - napi_get_value_double(env, argv[i], &asyncContext->volLevel); + napi_get_value_int32(env, argv[i], &asyncContext->volLevel); } else if (i == PARAM2 && valueType == napi_function) { napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef); break; @@ -1386,10 +1370,10 @@ napi_value AudioManagerNapi::SetVolume(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->status = context->objectInfo->audioMngr_->SetVolume(GetNativeAudioVolumeType(context->volType), - static_cast(context->volLevel)); + context->volLevel); }, SetFunctionAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { @@ -1445,14 +1429,14 @@ napi_value AudioManagerNapi::GetVolume(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); - context->volLevel = static_cast(context->objectInfo->audioMngr_->GetVolume( - GetNativeAudioVolumeType(context->volType))); - context->doubleValue = context->volLevel; + context->volLevel = context->objectInfo->audioMngr_->GetVolume( + GetNativeAudioVolumeType(context->volType)); + context->intValue = context->volLevel; context->status = 0; }, - GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + GetIntValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { result = nullptr; } else { @@ -1506,14 +1490,14 @@ napi_value AudioManagerNapi::GetMaxVolume(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); - context->volLevel = static_cast(context->objectInfo->audioMngr_->GetMaxVolume( - GetNativeAudioVolumeType(context->volType))); - context->doubleValue = context->volLevel; + context->volLevel = context->objectInfo->audioMngr_->GetMaxVolume( + GetNativeAudioVolumeType(context->volType)); + context->intValue = context->volLevel; context->status = 0; }, - GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + GetIntValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { result = nullptr; } else { @@ -1567,14 +1551,14 @@ napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); - context->volLevel = static_cast(context->objectInfo->audioMngr_->GetMinVolume( - GetNativeAudioVolumeType(context->volType))); - context->doubleValue = context->volLevel; + context->volLevel = context->objectInfo->audioMngr_->GetMinVolume( + GetNativeAudioVolumeType(context->volType)); + context->intValue = context->volLevel; context->status = 0; }, - GetDoubleValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); + GetIntValueAsyncCallbackComplete, static_cast(asyncContext.get()), &asyncContext->work); if (status != napi_ok) { result = nullptr; } else { @@ -1590,7 +1574,7 @@ napi_value AudioManagerNapi::GetMinVolume(napi_env env, napi_callback_info info) return result; } -static void GetDevicesAsyncCallbackComplete(napi_env env, napi_status status, void* data) +static void GetDevicesAsyncCallbackComplete(napi_env env, napi_status status, void *data) { auto asyncContext = static_cast(data); napi_value result[ARGS_TWO] = {0}; @@ -1659,7 +1643,7 @@ napi_value AudioManagerNapi::GetDevices(napi_env env, napi_callback_info info) status = napi_create_async_work( env, nullptr, resource, - [](napi_env env, void* data) { + [](napi_env env, void *data) { auto context = static_cast(data); context->deviceDescriptors = context->objectInfo->audioMngr_->GetDevices(GetNativeDeviceFlag(context->deviceFlag)); -- Gitee From fa30d1b2bc35ce8d6c7b4065b90d69c356d18da0 Mon Sep 17 00:00:00 2001 From: Anurup M Date: Thu, 29 Jul 2021 23:46:48 +0530 Subject: [PATCH 31/32] run audio service as system user Signed-off-by: Anurup M --- frameworks/innerkitsimpl/pulseaudio/conf/client.conf | 2 +- frameworks/innerkitsimpl/pulseaudio/conf/default.pa | 2 +- .../pulseaudio/src/daemon/ohos_pa_main.c | 9 ++++++--- services/etc/audio_policy.rc | 2 ++ services/etc/pulseaudio.rc | 12 +++++++----- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/frameworks/innerkitsimpl/pulseaudio/conf/client.conf b/frameworks/innerkitsimpl/pulseaudio/conf/client.conf index 9e40ae269b..685ea37e73 100644 --- a/frameworks/innerkitsimpl/pulseaudio/conf/client.conf +++ b/frameworks/innerkitsimpl/pulseaudio/conf/client.conf @@ -16,5 +16,5 @@ ## Configuration file for PulseAudio clients. See pulse-client.conf(5) for ## more information. Default values are commented out. Use either ; or # for ## commenting. -cookie-file = /data/local/.pulse_dir/cookie +cookie-file = /data/data/.pulse_dir/cookie diff --git a/frameworks/innerkitsimpl/pulseaudio/conf/default.pa b/frameworks/innerkitsimpl/pulseaudio/conf/default.pa index 1f08228fb4..96cd76a0be 100644 --- a/frameworks/innerkitsimpl/pulseaudio/conf/default.pa +++ b/frameworks/innerkitsimpl/pulseaudio/conf/default.pa @@ -22,7 +22,7 @@ # Load mandatory modules load-module libmodule-cli-protocol-unix.z.so -load-module libmodule-native-protocol-unix.z.so auth-cookie=/data/local/.pulse_dir/cookie +load-module libmodule-native-protocol-unix.z.so auth-cookie=/data/data/.pulse_dir/cookie ### Load audio drivers statically ### (it's probably better to not load these drivers manually, but instead diff --git a/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c b/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c index 34525aac6f..51ed63e489 100644 --- a/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c +++ b/frameworks/innerkitsimpl/pulseaudio/src/daemon/ohos_pa_main.c @@ -918,16 +918,18 @@ int ohos_pa_main(int argc, char *argv[]) { pa_set_env_and_record("PULSE_INTERNAL", "1"); pa_assert_se(chdir("/") == 0); +#ifdef HAVE_NO_OHOS umask(0077); - +#endif #ifdef HAVE_SYS_RESOURCE_H set_all_rlimits(conf); #endif pa_rtclock_hrtimer_enable(); +#ifdef HAVE_NO_OHOS if (conf->high_priority) pa_raise_priority(conf->nice_level); - +#endif if (conf->system_instance) if (change_user() < 0) goto finish; @@ -1005,10 +1007,11 @@ int ohos_pa_main(int argc, char *argv[]) { pa_log_info("Running in system mode: %s", pa_yes_no(pa_in_system_mode())); +#ifdef HAVE_NO_OHOS if (pa_in_system_mode()) pa_log_warn(_("OK, so you are running PA in system mode. Please make sure that you actually do want to do that.\n" "Please read http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/ for an explanation why system mode is usually a bad idea.")); - +#endif if (conf->use_pid_file) { int z; pa_pid_file_remove(); diff --git a/services/etc/audio_policy.rc b/services/etc/audio_policy.rc index 9e9f3f594a..5238a5a441 100644 --- a/services/etc/audio_policy.rc +++ b/services/etc/audio_policy.rc @@ -14,6 +14,8 @@ service audio_policy /system/bin/sa_main /system/profile/audio_policy.xml class z_core seclabel u:r:audiodistributedservice:s0 + user system + group system shell disabled on audio_policy_start diff --git a/services/etc/pulseaudio.rc b/services/etc/pulseaudio.rc index cec5b2a6d8..257bd5b8dd 100644 --- a/services/etc/pulseaudio.rc +++ b/services/etc/pulseaudio.rc @@ -14,14 +14,16 @@ service pulseaudio /system/bin/sa_main /system/profile/pulseaudio.xml class z_core seclabel u:r:audiodistributedservice:s0 + user system + group system shell disabled on post-fs-data - mkdir /data/local/.pulse_dir - chmod 755 /data/local/.pulse_dir - chown system shell /data/local/.pulse_dir - export PULSE_STATE_PATH "/data/local/.pulse_dir" - export PULSE_RUNTIME_PATH "/data/local/.pulse_dir" + mkdir /data/data/.pulse_dir + chmod 777 /data/data/.pulse_dir + chown system system /data/data/.pulse_dir + export PULSE_STATE_PATH "/data/data/.pulse_dir" + export PULSE_RUNTIME_PATH "/data/data/.pulse_dir" start pulseaudio exec /system/bin/sleep 4 trigger audio_policy_start -- Gitee From 9ec57d2cae8a011d9edfab6fdb3e6f102e1666f8 Mon Sep 17 00:00:00 2001 From: Ashish Sawakar Date: Tue, 3 Aug 2021 16:46:35 +0530 Subject: [PATCH 32/32] [Fix] audio recording in non blocking scenario Signed-off-by: Ashish Sawakar --- services/src/client/audio_service_client.cpp | 2 +- services/test/audio_recorder_test.cpp | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index cc63a15612..0276be3d05 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -889,7 +889,7 @@ int32_t AudioServiceClient::ReadStream(StreamBuffer &stream, bool isBlocking) pa_threaded_mainloop_wait(mainLoop); else { pa_threaded_mainloop_unlock(mainLoop); - return 0; + return readSize; } } else if (!internalReadBuffer) { retVal = pa_stream_drop(paStream); diff --git a/services/test/audio_recorder_test.cpp b/services/test/audio_recorder_test.cpp index e7640fe605..9c355b3fd4 100644 --- a/services/test/audio_recorder_test.cpp +++ b/services/test/audio_recorder_test.cpp @@ -109,11 +109,22 @@ public: size_t size = 1; size_t numBuffersToRecord = 1024; - int32_t bytesRead = 0; + int32_t len = 0; while (numBuffersToRecord) { - bytesRead = audioRecorder->Read(*buffer, bufferLen, isBlocking); + size_t bytesRead = 0; + while (bytesRead < bufferLen) { + len = audioRecorder->Read(*(buffer + bytesRead), bufferLen - bytesRead, isBlocking); + if (len >= 0) { + bytesRead += len; + } else { + bytesRead = -1; + MEDIA_INFO_LOG("Bytes read failed"); + break; + } + } MEDIA_INFO_LOG("Bytes read: %{public}d", bytesRead); if (bytesRead < 0) { + MEDIA_INFO_LOG("Bytes read less than 0"); break; } if (bytesRead > 0) { -- Gitee