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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] 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/14] =?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