diff --git a/frameworks/native/audioadapter/src/pulse_audio_service_adapter_impl.cpp b/frameworks/native/audioadapter/src/pulse_audio_service_adapter_impl.cpp index 6af9d39ba5459dfda12f184a1f46ed1f4e1a18f1..9cb6cb94d8c3b01da7e9ce492475dcd8f93334e7 100644 --- a/frameworks/native/audioadapter/src/pulse_audio_service_adapter_impl.cpp +++ b/frameworks/native/audioadapter/src/pulse_audio_service_adapter_impl.cpp @@ -725,6 +725,9 @@ void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, con CHECK_AND_RETURN_LOG(i->proplist != nullptr, "Invalid Proplist for sink input (%{public}d).", i->index); + std::string streamMode = pa_proplist_gets(i->proplist, "stream.mode"); + if (streamMode == DUP_STREAM) { return; } + const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); const char *streamVolume = pa_proplist_gets(i->proplist, "stream.volumeFactor"); const char *streamPowerVolume = pa_proplist_gets(i->proplist, "stream.powerVolumeFactor"); @@ -736,11 +739,8 @@ void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, con CHECK_AND_RETURN_LOG((streamtype != nullptr) && (streamVolume != nullptr) && (streamPowerVolume != nullptr) && (sessionCStr != nullptr), "Invalid Stream parameter info."); - std::stringstream sessionStr; - uint32_t sessionID; - sessionStr << sessionCStr; - sessionStr >> sessionID; - AUDIO_DEBUG_LOG("sessionID %{public}u", sessionID); + uint32_t sessionID = 0; + CastValue(sessionID, sessionCStr); sinkIndexSessionIDMap[i->index] = sessionID; @@ -760,8 +760,6 @@ void PulseAudioServiceAdapterImpl::PaGetSinkInputInfoVolumeCb(pa_context *c, con if (streamTypeID == userData->streamType || userData->isSubscribingCb) { pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, nullptr, nullptr)); } - AUDIO_DEBUG_LOG("volume %{public}f for stream uid %{public}d"\ - ", volumeFactor %{public}f, volumeDbCb %{public}f", vol, uid, volumeFactor, volumeDbCb); HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::AUDIO, "VOLUME_CHANGE", HiviewDFX::HiSysEvent::EventType::BEHAVIOR, "ISOUTPUT", 1, "STREAMID", sessionID, "APP_UID", uid, "APP_PID", pid, "STREAMTYPE", streamTypeID, "VOLUME", vol, @@ -832,6 +830,12 @@ void PulseAudioServiceAdapterImpl::PaGetAllSinkInputsCb(pa_context *c, const pa_ CHECK_AND_RETURN_LOG(i->proplist != nullptr, "Invalid Proplist for sink input (%{public}d).", i->index); + std::string streamMode = pa_proplist_gets(i->proplist, "stream.mode"); + if (streamMode == DUP_STREAM) { + AUDIO_INFO_LOG("Dup stream dismissed:%{public}u", i->index); + return; + } + AudioStreamType audioStreamType = STREAM_DEFAULT; const char *streamType = pa_proplist_gets(i->proplist, "stream.type"); if (streamType != nullptr) { diff --git a/frameworks/native/audiocapturer/include/audio_capturer_private.h b/frameworks/native/audiocapturer/include/audio_capturer_private.h index bdbe30f9a52237d581beb7f4c3dd653401224578..030e3375f400b2fe4fd32b3d3f290ece6266b730 100644 --- a/frameworks/native/audiocapturer/include/audio_capturer_private.h +++ b/frameworks/native/audiocapturer/include/audio_capturer_private.h @@ -32,6 +32,7 @@ class AudioCapturerPrivate : public AudioCapturer { public: int32_t GetFrameCount(uint32_t &frameCount) const override; int32_t SetParams(const AudioCapturerParams params) override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; int32_t SetCapturerCallback(const std::shared_ptr &callback) override; int32_t GetParams(AudioCapturerParams ¶ms) const override; int32_t GetCapturerInfo(AudioCapturerInfo &capturerInfo) const override; @@ -88,6 +89,7 @@ public: std::shared_ptr audioStream_; AudioCapturerInfo capturerInfo_ = {}; + AudioPlaybackCaptureConfig filterConfig_ = {{{}, FilterMode::INCLUDE, {}, FilterMode::INCLUDE}, false}; AudioStreamType audioStreamType_; std::string cachePath_; bool abortRestore_ = false; diff --git a/frameworks/native/audiocapturer/src/audio_capturer.cpp b/frameworks/native/audiocapturer/src/audio_capturer.cpp index 49553966ec574fcbf26f7c42ed5a99df9ccc37e6..c859d044cb3c9d3cd1dcbc63e4c0546b4203f584 100644 --- a/frameworks/native/audiocapturer/src/audio_capturer.cpp +++ b/frameworks/native/audiocapturer/src/audio_capturer.cpp @@ -116,12 +116,11 @@ std::unique_ptr AudioCapturer::Create(const AudioCapturerOptions capturer->cachePath_ = cachePath; } - if (capturer->InitPlaybackCapturer(sourceType, capturerOptions.playbackCaptureConfig) != SUCCESS) { - return nullptr; - } + // InitPlaybackCapturer will be replaced by UpdatePlaybackCaptureConfig. capturer->capturerInfo_.sourceType = sourceType; capturer->capturerInfo_.capturerFlags = capturerOptions.capturerInfo.capturerFlags; + capturer->filterConfig_ = capturerOptions.playbackCaptureConfig; if (capturer->SetParams(params) != SUCCESS) { capturer = nullptr; } @@ -133,6 +132,24 @@ std::unique_ptr AudioCapturer::Create(const AudioCapturerOptions return capturer; } +// This will be called in Create and after Create. +int32_t AudioCapturerPrivate::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + // UpdatePlaybackCaptureConfig will only work for InnerCap streams. + if (capturerInfo_.sourceType != SOURCE_TYPE_PLAYBACK_CAPTURE) { + AUDIO_WARNING_LOG("This is not a PLAYBACK_CAPTURE stream."); + return ERR_INVALID_OPERATION; + } + + if (config.filterOptions.usages.size() == 0 && config.filterOptions.pids.size() == 0) { + AUDIO_WARNING_LOG("Both usages and pids are empty!"); + } + + CHECK_AND_RETURN_RET_LOG(audioStream_ != nullptr, ERR_OPERATION_FAILED, "Failed with null audioStream_"); + + return audioStream_->UpdatePlaybackCaptureConfig(config); +} + AudioCapturerPrivate::AudioCapturerPrivate(AudioStreamType audioStreamType, const AppInfo &appInfo, bool createStream) { if (audioStreamType < STREAM_VOICE_CALL || audioStreamType > STREAM_ALL) { @@ -234,8 +251,11 @@ int32_t AudioCapturerPrivate::InitAudioStream(const AudioStreamParams &audioStre audioStream_->SetCapturerSource(capturerInfo_.sourceType); int32_t ret = audioStream_->SetAudioStreamInfo(audioStreamParams, capturerProxyObj_); - if (ret != SUCCESS) { - return ret; + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "SetAudioStreamInfo failed"); + // for inner-capturer + if (capturerInfo_.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE) { + ret = UpdatePlaybackCaptureConfig(filterConfig_); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "UpdatePlaybackCaptureConfig Failed"); } InitLatencyMeasurement(audioStreamParams); return ret; diff --git a/frameworks/native/audiostream/include/audio_stream.h b/frameworks/native/audiostream/include/audio_stream.h index bdb80ef2ef944075c18bf46b3b1650380c5d5490..fddbd3c7add134d8d630dfac8f5d365c342831f3 100644 --- a/frameworks/native/audiostream/include/audio_stream.h +++ b/frameworks/native/audiostream/include/audio_stream.h @@ -49,6 +49,7 @@ public: const std::shared_ptr &proxyObj) override; int32_t GetAudioStreamInfo(AudioStreamParams &info) override; int32_t GetAudioSessionID(uint32_t &sessionID) override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; State GetState() override; bool GetAudioTime(Timestamp ×tamp, Timestamp::Timestampbase base) override; bool GetAudioPosition(Timestamp ×tamp, Timestamp::Timestampbase base) override; diff --git a/frameworks/native/audiostream/include/fast_audio_stream.h b/frameworks/native/audiostream/include/fast_audio_stream.h index 3131d2dae8e987e6701f45b1f26466d4d4e0b15d..5562e573797f1fcd6255533d4d2ab63a62522886 100644 --- a/frameworks/native/audiostream/include/fast_audio_stream.h +++ b/frameworks/native/audiostream/include/fast_audio_stream.h @@ -65,6 +65,7 @@ public: void SetClientID(int32_t clientPid, int32_t clientUid, uint32_t appTokenId) override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; void SetRendererInfo(const AudioRendererInfo &rendererInfo) override; void SetCapturerInfo(const AudioCapturerInfo &capturerInfo) override; int32_t SetAudioStreamInfo(const AudioStreamParams info, diff --git a/frameworks/native/audiostream/include/i_audio_stream.h b/frameworks/native/audiostream/include/i_audio_stream.h index e8c9a401120d3587483677982b5ffbf104abc315..1c48226daed5eeba1449858039b2e3e4eb019371 100644 --- a/frameworks/native/audiostream/include/i_audio_stream.h +++ b/frameworks/native/audiostream/include/i_audio_stream.h @@ -112,6 +112,7 @@ public: static std::map, AudioStreamType> CreateStreamMap(); static const std::string GetEffectSceneName(const StreamUsage &streamUsage); + virtual int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) = 0; virtual void SetClientID(int32_t clientPid, int32_t clientUid, uint32_t appTokenId) = 0; virtual void SetRendererInfo(const AudioRendererInfo &rendererInfo) = 0; virtual void SetCapturerInfo(const AudioCapturerInfo &capturerInfo) = 0; diff --git a/frameworks/native/audioutils/include/audio_utils.h b/frameworks/native/audioutils/include/audio_utils.h index 08dadbe045aacc491b95029ec4a2ff0434ba44e1..9ddee832a5a87729da5f444438d9e45e39979c48 100644 --- a/frameworks/native/audioutils/include/audio_utils.h +++ b/frameworks/native/audioutils/include/audio_utils.h @@ -89,6 +89,7 @@ public: static bool VerifyIsSystemApp(); static bool VerifySelfPermission(); static bool VerifySystemPermission(); + static bool VerifyPermission(const std::string &permissionName, uint32_t tokenId); }; void AdjustStereoToMonoForPCM8Bit(int8_t *data, uint64_t len); diff --git a/frameworks/native/audioutils/src/audio_utils.cpp b/frameworks/native/audioutils/src/audio_utils.cpp index 4d470f0c651ceba05800531efd7c637aa1b267a0..351bda4e634ec4c7e87e45df5267ed1c9b310554 100644 --- a/frameworks/native/audioutils/src/audio_utils.cpp +++ b/frameworks/native/audioutils/src/audio_utils.cpp @@ -197,6 +197,15 @@ bool PermissionUtil::VerifySystemPermission() return false; } +bool PermissionUtil::VerifyPermission(const std::string &permissionName, uint32_t tokenId) +{ + int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, permissionName); + CHECK_AND_RETURN_RET_LOG(res == Security::AccessToken::PermissionState::PERMISSION_GRANTED, + false, "Permission denied [%{public}s]", permissionName.c_str()); + + return true; +} + void AdjustStereoToMonoForPCM8Bit(int8_t *data, uint64_t len) { // the number 2: stereo audio has 2 channels diff --git a/frameworks/native/playbackcapturer/include/playback_capturer_manager.h b/frameworks/native/playbackcapturer/include/playback_capturer_manager.h index 0ff6ab6fc7bd5d9061fdadb4295c56e66932f1fc..7d9121036ebb6c8043e9ef47b4eb92fb9577c4cd 100644 --- a/frameworks/native/playbackcapturer/include/playback_capturer_manager.h +++ b/frameworks/native/playbackcapturer/include/playback_capturer_manager.h @@ -21,13 +21,25 @@ #include #include #include +#include #include #include +#include "audio_info.h" #include "playback_capturer_adapter.h" namespace OHOS { namespace AudioStandard { +class ICapturerFilterListener { +public: + virtual ~ICapturerFilterListener() = default; + + // This will be called when a filter is first enabled or changed. + virtual int32_t OnCapturerFilterChange(uint32_t sessionId, const AudioPlaybackCaptureConfig &newConfig) = 0; + + // This will be called when a filter released. + virtual int32_t OnCapturerFilterRemove(uint32_t sessionId) = 0; +}; class PlaybackCapturerManager { public: @@ -41,10 +53,20 @@ public: bool IsCaptureSilently(); bool GetInnerCapturerState(); void SetInnerCapturerState(bool state); + + // add for new playback-capturer + std::vector GetDefaultUsages(); + bool RegisterCapturerFilterListener(ICapturerFilterListener *listener); + int32_t SetPlaybackCapturerFilterInfo(uint32_t sessionId, const AudioPlaybackCaptureConfig &config); + int32_t RemovePlaybackCapturerFilterInfo(uint32_t sessionId); private: + std::mutex setMutex_; std::unordered_set supportStreamUsageSet_; + std::vector defaultUsages_ = { STREAM_USAGE_MEDIA, STREAM_USAGE_MUSIC, STREAM_USAGE_MOVIE, + STREAM_USAGE_GAME, STREAM_USAGE_AUDIOBOOK }; bool isCaptureSilently_; bool isInnerCapturerRunning_ = false; + ICapturerFilterListener *listener_ = nullptr; }; } // namespace AudioStandard diff --git a/frameworks/native/playbackcapturer/src/playback_capturer_manager.cpp b/frameworks/native/playbackcapturer/src/playback_capturer_manager.cpp index d659e5387ec7aa957e89ae8fed34544e8d756326..4bfe10470af5017f88af98441132be01a46edea5 100644 --- a/frameworks/native/playbackcapturer/src/playback_capturer_manager.cpp +++ b/frameworks/native/playbackcapturer/src/playback_capturer_manager.cpp @@ -90,9 +90,10 @@ PlaybackCapturerManager* PlaybackCapturerManager::GetInstance() void PlaybackCapturerManager::SetSupportStreamUsage(std::vector usage) { + std::lock_guard lock(setMutex_); supportStreamUsageSet_.clear(); if (usage.empty()) { - AUDIO_DEBUG_LOG("Clear support streamUsage"); + AUDIO_INFO_LOG("Clear support streamUsage"); return; } for (size_t i = 0; i < usage.size(); i++) { @@ -102,6 +103,7 @@ void PlaybackCapturerManager::SetSupportStreamUsage(std::vector usage) bool PlaybackCapturerManager::IsStreamSupportInnerCapturer(int32_t streamUsage) { + std::lock_guard lock(setMutex_); if (supportStreamUsageSet_.empty()) { return streamUsage == STREAM_USAGE_MEDIA || streamUsage == STREAM_USAGE_MUSIC || streamUsage == STREAM_USAGE_MOVIE || streamUsage == STREAM_USAGE_GAME || @@ -134,5 +136,36 @@ bool PlaybackCapturerManager::GetInnerCapturerState() { return isInnerCapturerRunning_; } + +std::vector PlaybackCapturerManager::GetDefaultUsages() +{ + return defaultUsages_; +} + +bool PlaybackCapturerManager::RegisterCapturerFilterListener(ICapturerFilterListener *listener) +{ + if (listener == nullptr || listener_ != nullptr) { + AUDIO_ERR_LOG("Register fail: listener is %{public}s", (listener == nullptr ? "null." : "already set.")); + return false; + } + AUDIO_INFO_LOG("Register success"); + listener_ = listener; + return true; +} + +int32_t PlaybackCapturerManager::SetPlaybackCapturerFilterInfo(uint32_t sessionId, + const AudioPlaybackCaptureConfig &config) +{ + CHECK_AND_RETURN_RET_LOG(listener_ != nullptr, ERR_ILLEGAL_STATE, "listener is null!"); + + return listener_->OnCapturerFilterChange(sessionId, config); +} + +int32_t PlaybackCapturerManager::RemovePlaybackCapturerFilterInfo(uint32_t sessionId) +{ + CHECK_AND_RETURN_RET_LOG(listener_ != nullptr, ERR_ILLEGAL_STATE, "listener is null!"); + + return listener_->OnCapturerFilterRemove(sessionId); +} } // namespace OHOS } // namespace AudioStandard \ No newline at end of file diff --git a/frameworks/native/pulseaudio/modules/capturer/module_inner_capturer_sink.c b/frameworks/native/pulseaudio/modules/capturer/module_inner_capturer_sink.c index 71f31bdef972c10503118cea05e36012882590e4..553885bd352a6d62898a36c0e8689296697e72ae 100644 --- a/frameworks/native/pulseaudio/modules/capturer/module_inner_capturer_sink.c +++ b/frameworks/native/pulseaudio/modules/capturer/module_inner_capturer_sink.c @@ -86,7 +86,7 @@ static const char * const VALID_MODARGS[] = { "rate", "channels", "channel_map", - "buffer_size" + "buffer_size", "formats", NULL }; @@ -370,8 +370,7 @@ int pa__init(pa_module *m) pa_assert(m); ma = pa_modargs_new(m->argument, VALID_MODARGS); - CHECK_AND_RETURN_RET_LOG(ma != NULL, InitFailed(m, ma), - "Failed to parse module arguments."); + CHECK_AND_RETURN_RET_LOG(ma != NULL, InitFailed(m, ma), "Failed to parse module arguments:%{public}s", m->argument); m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; diff --git a/frameworks/native/pulseaudio/modules/hdi/hdi_sink.c b/frameworks/native/pulseaudio/modules/hdi/hdi_sink.c index 78ee1c46008d29476cd6a8c47280a76c5541f602..7944838472fd82ade7aff5bfd23089da3ce589d9 100644 --- a/frameworks/native/pulseaudio/modules/hdi/hdi_sink.c +++ b/frameworks/native/pulseaudio/modules/hdi/hdi_sink.c @@ -91,6 +91,7 @@ const char *DEVICE_CLASS_REMOTE = "remote"; const char *DEVICE_CLASS_OFFLOAD = "offload"; const char *DEVICE_CLASS_MULTICHANNEL = "multichannel"; const char *SINK_NAME_REMOTE_CAST_INNER_CAPTURER = "RemoteCastInnerCapturer"; +const char *DUP_STEAM_NAME = "DupStream"; // should be same with DUP_STEAM in audio_info.h const int32_t WAIT_CLOSE_PA_OR_EFFECT_TIME = 4; // secs static bool g_isVolumeChange = true; @@ -3449,6 +3450,11 @@ static pa_hook_result_t SinkInputStateChangedCb(pa_core *core, pa_sink_input *i, static pa_hook_result_t SinkInputPutCb(pa_core *core, pa_sink_input *i, struct Userdata *u) { pa_sink_input_assert_ref(i); + const char *streamMode = pa_proplist_gets(i->proplist, "stream.mode"); + if (streamMode != NULL && !strcmp(streamMode, DUP_STEAM_NAME)) { + AUDIO_INFO_LOG("Dup stream is dismissed:%{public}u", i->index); + return PA_HOOK_OK; + } i->state_change = PaInputStateChangeCb; i->volume_changed = PaInputVolumeChangeCb; return PA_HOOK_OK; diff --git a/frameworks/native/pulseaudio/modules/hdi/module_hdi_sink.c b/frameworks/native/pulseaudio/modules/hdi/module_hdi_sink.c index 6629bee078b51fceb6f64e6c21ca90faff1c71ba..0e841a3da542d624a4a611a16abdbda27d904f27 100644 --- a/frameworks/native/pulseaudio/modules/hdi/module_hdi_sink.c +++ b/frameworks/native/pulseaudio/modules/hdi/module_hdi_sink.c @@ -144,29 +144,6 @@ static pa_hook_result_t SinkInputUnlinkCb(pa_core *c, pa_sink_input *si, void *u return PA_HOOK_OK; } -static pa_hook_result_t SourceOutputStateChangedCb(pa_core *c, pa_source_output *so, void *u) -{ - pa_assert(c); - pa_assert(so); - - int innerCapturerFlag = 0; - const char *flag = pa_proplist_gets(so->proplist, "stream.isInnerCapturer"); - if (flag != NULL) { - pa_atoi(flag, &innerCapturerFlag); - } - - if (innerCapturerFlag == 1) { - if (so->state == PA_SOURCE_OUTPUT_RUNNING) { - SetInnerCapturerState(true); - so->destination_source = so->source; - } else { - SetInnerCapturerState(false); - } - } - - return PA_HOOK_OK; -} - static pa_hook_result_t SinkInputStateChangedCb(pa_core *c, pa_sink_input *si, void *u) { pa_assert(c); @@ -239,8 +216,7 @@ int pa__init(pa_module *m) (pa_hook_cb_t)SinkInputNewCb, NULL); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t)SinkInputUnlinkCb, NULL); - pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_LATE, - (pa_hook_cb_t)SourceOutputStateChangedCb, NULL); + // SourceOutputStateChangedCb will be replaced by UpdatePlaybackCaptureConfig in CapturerInServer pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t)SinkInputStateChangedCb, NULL); pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], PA_HOOK_LATE, diff --git a/interfaces/inner_api/native/audiocapturer/include/audio_capturer.h b/interfaces/inner_api/native/audiocapturer/include/audio_capturer.h index c2240e6f0c53e339e9c0db09241179f380488cd0..a7719a2480ec708a101d1235970502e3ef35c397 100644 --- a/interfaces/inner_api/native/audiocapturer/include/audio_capturer.h +++ b/interfaces/inner_api/native/audiocapturer/include/audio_capturer.h @@ -215,6 +215,17 @@ public: */ virtual int32_t SetParams(const AudioCapturerParams params) = 0; + /** + * @brief Update AudioPlaybackCaptureConfig, only for Inner-Cap records. + * + * @param config Indicates information about audio capture parameters to set. For details, see + * {@link CaptureFilterOptions}. + * @return Returns {@link SUCCESS} if the setting is successful; returns an error code defined + * in {@link audio_errors.h} otherwise. + * @since 12 + */ + virtual int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) = 0; + /** * @brief Registers the capturer callback listener. * (1)If old SetParams(const AudioCapturerParams params) API, diff --git a/interfaces/inner_api/native/audiocommon/include/audio_info.h b/interfaces/inner_api/native/audiocommon/include/audio_info.h index 815d2e5ab47cfa9c7fb243550bd54e241b0480dc..5a553037ced7c336c7bd78a3823c6866bd24080d 100644 --- a/interfaces/inner_api/native/audiocommon/include/audio_info.h +++ b/interfaces/inner_api/native/audiocommon/include/audio_info.h @@ -76,8 +76,12 @@ constexpr std::string_view WAKEUP_NAMES[WAKEUP_LIMIT] = { constexpr std::string_view VOICE_CALL_REC_NAME = "Voice_call_rec"; const std::string INNER_CAPTURER_SOURCE = "Speaker.monitor"; +const std::string INNER_CAPTURER_SINK = "InnerCapturerSink"; +const std::string NEW_INNER_CAPTURER_SOURCE = "InnerCapturerSink.monitor"; const std::string REMOTE_CAST_INNER_CAPTURER_SINK_NAME = "RemoteCastInnerCapturer"; const std::string MONITOR_SOURCE_SUFFIX = ".monitor"; +const std::string DUP_STREAM = "DupStream"; +const std::string NORMAL_STREAM = "NormalStream"; #ifdef FEATURE_DTMF_TONE // Maximun number of sine waves in a tone segment @@ -450,13 +454,27 @@ enum AudioDeviceUsage : int32_t { D_ALL_DEVICES = 15, }; +enum FilterMode : uint32_t { + INCLUDE = 0, + EXCLUDE, + MAX_FILTER_MODE +}; + +// 1.If the size of usages or pids is 0, FilterMode will not work. +// 2.Filters will only works with FileterMode INCLUDE or EXCLUDE while the vector size is not zero. +// 3.If usages and pids are both not empty, the result is the intersection of the two Filter. +// 4.If usages.size() == 0, defalut usages will be filtered with FilterMode::INCLUDE. +// 5.Default usages are MEDIA MUSIC MOVIE GAME and BOOK. struct CaptureFilterOptions { std::vector usages; + FilterMode usageFilterMode {FilterMode::INCLUDE}; + std::vector pids; + FilterMode pidFilterMode {FilterMode::INCLUDE}; }; struct AudioPlaybackCaptureConfig { CaptureFilterOptions filterOptions; - bool silentCapture {false}; + bool silentCapture {false}; // To be deprecated since 12 }; struct AudioCapturerOptions { @@ -611,6 +629,16 @@ enum AudioMode { AUDIO_MODE_RECORD }; +// LEGACY_INNER_CAP: Called from hap build with api < 12, work normally. +// LEGACY_MUTE_CAP: Called from hap build with api >= 12, will cap mute data. +// MODERN_INNER_CAP: Called from SA with inner-cap right, work with filter. +enum InnerCapMode : uint32_t { + LEGACY_INNER_CAP = 0, + LEGACY_MUTE_CAP, + MODERN_INNER_CAP, + INVALID_CAP_MODE +}; + struct AudioProcessConfig { AppInfo appInfo; @@ -632,7 +660,7 @@ struct AudioProcessConfig { AudioPrivacyType privacyType; - // Waiting for review: add isWakeupCapturer isInnerCapturer + InnerCapMode innerCapMode {InnerCapMode::INVALID_CAP_MODE}; }; struct Volume { diff --git a/interfaces/inner_api/native/audiocommon/include/audio_stream_info.h b/interfaces/inner_api/native/audiocommon/include/audio_stream_info.h index 58d0fdc69f16f6941b1dd15631ce20bd16354af6..fd3a8b4c272423a0e307e12e0bd9e654c44db244 100644 --- a/interfaces/inner_api/native/audiocommon/include/audio_stream_info.h +++ b/interfaces/inner_api/native/audiocommon/include/audio_stream_info.h @@ -581,6 +581,7 @@ struct AudioStreamData { BufferDesc bufferDesc; int32_t volumeStart; int32_t volumeEnd; + bool isInnerCaped = false; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_policy/etc/audio_config.para b/services/audio_policy/etc/audio_config.para index b96c5026e60e21ed629656935e9616b21d24f759..35c8955f0d668b3f466b07fafff9db75ed175268 100644 --- a/services/audio_policy/etc/audio_config.para +++ b/services/audio_policy/etc/audio_config.para @@ -11,7 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. persist.multimedia.audio.ringtonevolume = 7 -persist.multimedia.audio.mmap.enable = 1 const.multimedia.audio.fixedvolume = false const.multimedia.audio.volumestep = 1 persist.vendor.media.offload.enable = true diff --git a/services/audio_policy/etc/audio_config.para.dac b/services/audio_policy/etc/audio_config.para.dac index 773652b48319bc2e4ea8d7da2673281a6bc4f1ae..523b616163e865c5c04d11bb6f19bc717583bab8 100644 --- a/services/audio_policy/etc/audio_config.para.dac +++ b/services/audio_policy/etc/audio_config.para.dac @@ -12,7 +12,6 @@ # limitations under the License. persist.multimedia.audio.ringtonevolume = audio:audio:660 -persist.multimedia.audio.mmap.enable = audio:audio:660 persist.multimedia.audioflag.forceipc.renderer = audio:audio:664 persist.multimedia.audioflag.ipc.capturer = audio:audio:664 const.multimedia.audio.fixedvolume = audio:audio:660 diff --git a/services/audio_policy/server/include/service/audio_policy_service.h b/services/audio_policy/server/include/service/audio_policy_service.h index 1732e20f8d54c72353252e8ffb8c7cdd81376806..93cf81b14ac563a0e1deb3406ca05e5800d5a95e 100644 --- a/services/audio_policy/server/include/service/audio_policy_service.h +++ b/services/audio_policy/server/include/service/audio_policy_service.h @@ -227,6 +227,8 @@ public: void OnAudioBalanceChanged(float audioBalance); + void LoadModernInnerCapSink(); + void LoadEffectLibrary(); int32_t SetAudioSessionCallback(AudioSessionCallback *callback); diff --git a/services/audio_policy/server/src/service/audio_policy_service.cpp b/services/audio_policy/server/src/service/audio_policy_service.cpp index 88d0bc8eab804396cc7e04beab58412c73fe3b20..05cc0de4f7f40e23fcb072338f61811351936e58 100644 --- a/services/audio_policy/server/src/service/audio_policy_service.cpp +++ b/services/audio_policy/server/src/service/audio_policy_service.cpp @@ -46,7 +46,7 @@ namespace OHOS { namespace AudioStandard { using namespace std; -static const std::string INNER_CAPTURER_SINK_NAME = "InnerCapturer"; +static const std::string INNER_CAPTURER_SINK_LEGACY = "InnerCapturer"; static const std::string RECEIVER_SINK_NAME = "Receiver"; static const std::string SINK_NAME_FOR_CAPTURE_SUFFIX = "_CAP"; @@ -3506,6 +3506,8 @@ void AudioPolicyService::OnServiceConnected(AudioServiceIndex serviceIndex) } audioEffectManager_.SetMasterSinkAvailable(); } + // load inner-cap-sink + LoadModernInnerCapSink(); RegisterBluetoothListener(); } @@ -3601,7 +3603,7 @@ void AudioPolicyService::LoadSinksForCapturer() { AUDIO_INFO_LOG("Start"); AudioStreamInfo streamInfo; - LoadInnerCapturerSink(INNER_CAPTURER_SINK_NAME, streamInfo); + LoadInnerCapturerSink(INNER_CAPTURER_SINK_LEGACY, streamInfo); LoadReceiverSink(); const sptr gsp = GetAudioServerProxy(); CHECK_AND_RETURN_LOG(gsp != nullptr, "error for g_adProxy null"); @@ -3649,12 +3651,12 @@ void AudioPolicyService::LoadLoopback() std::string moduleName; AUDIO_INFO_LOG("Start"); std::lock_guard ioHandleLock(ioHandlesMutex_); - CHECK_AND_RETURN_LOG(IOHandles_.count(INNER_CAPTURER_SINK_NAME) == 1u, + CHECK_AND_RETURN_LOG(IOHandles_.count(INNER_CAPTURER_SINK_LEGACY) == 1u, "failed for InnerCapturer not loaded"); LoopbackModuleInfo moduleInfo = {}; moduleInfo.lib = "libmodule-loopback.z.so"; - moduleInfo.sink = INNER_CAPTURER_SINK_NAME; + moduleInfo.sink = INNER_CAPTURER_SINK_LEGACY; for (auto sceneType = AUDIO_SUPPORTED_SCENE_TYPES.begin(); sceneType != AUDIO_SUPPORTED_SCENE_TYPES.end(); ++sceneType) { @@ -3683,14 +3685,29 @@ void AudioPolicyService::UnloadLoopback() for (auto sceneType = AUDIO_SUPPORTED_SCENE_TYPES.begin(); sceneType != AUDIO_SUPPORTED_SCENE_TYPES.end(); ++sceneType) { - module = sceneType->second + SINK_NAME_FOR_CAPTURE_SUFFIX + MONITOR_SOURCE_SUFFIX + INNER_CAPTURER_SINK_NAME; + module = sceneType->second + SINK_NAME_FOR_CAPTURE_SUFFIX + MONITOR_SOURCE_SUFFIX + INNER_CAPTURER_SINK_LEGACY; ClosePortAndEraseIOHandle(module); } - module = RECEIVER_SINK_NAME + MONITOR_SOURCE_SUFFIX + INNER_CAPTURER_SINK_NAME; + module = RECEIVER_SINK_NAME + MONITOR_SOURCE_SUFFIX + INNER_CAPTURER_SINK_LEGACY; ClosePortAndEraseIOHandle(module); } +void AudioPolicyService::LoadModernInnerCapSink() +{ + AUDIO_INFO_LOG("Start"); + AudioModuleInfo moduleInfo = {}; + moduleInfo.lib = "libmodule-inner-capturer-sink.z.so"; + moduleInfo.name = INNER_CAPTURER_SINK; + + moduleInfo.format = "s16le"; + moduleInfo.channels = "2"; // 2 channel + moduleInfo.rate = "48000"; + moduleInfo.bufferSize = "3840"; // 20ms + + OpenPortAndInsertIOHandle(moduleInfo.name, moduleInfo); +} + void AudioPolicyService::LoadEffectLibrary() { // IPC -> audioservice load library diff --git a/services/audio_policy/server/src/service/manager/audio_adapter_manager.cpp b/services/audio_policy/server/src/service/manager/audio_adapter_manager.cpp index ded2c2775925b1aa558580bb32e320f55c7ae412..1496fe4f04a1a2fa273ac2f35972d8d7bda885a4 100644 --- a/services/audio_policy/server/src/service/manager/audio_adapter_manager.cpp +++ b/services/audio_policy/server/src/service/manager/audio_adapter_manager.cpp @@ -666,6 +666,85 @@ int32_t AudioAdapterManager::CloseAudioPort(AudioIOHandle ioHandle) return audioServiceAdapter_->CloseAudioPort(ioHandle); } +void UpdateSinkArgs(const AudioModuleInfo &audioModuleInfo, std::string &args) +{ + if (!audioModuleInfo.name.empty()) { + args.append(" sink_name="); + args.append(audioModuleInfo.name); + } + + if (!audioModuleInfo.adapterName.empty()) { + args.append(" adapter_name="); + args.append(audioModuleInfo.adapterName); + } + + if (!audioModuleInfo.className.empty()) { + args.append(" device_class="); + args.append(audioModuleInfo.className); + } + + if (!audioModuleInfo.fileName.empty()) { + args.append(" file_path="); + args.append(audioModuleInfo.fileName); + } + if (!audioModuleInfo.sinkLatency.empty()) { + args.append(" sink_latency="); + args.append(audioModuleInfo.sinkLatency); + } + + if (!audioModuleInfo.networkId.empty()) { + args.append(" network_id="); + args.append(audioModuleInfo.networkId); + } else { + args.append(" network_id=LocalDevice"); + } + + if (!audioModuleInfo.deviceType.empty()) { + args.append(" device_type="); + args.append(audioModuleInfo.deviceType); + } +} + +void UpdateSourceArgs(const AudioModuleInfo &audioModuleInfo, std::string &args) +{ + if (!audioModuleInfo.name.empty()) { + args.append(" source_name="); + args.append(audioModuleInfo.name); + } + + if (!audioModuleInfo.adapterName.empty()) { + args.append(" adapter_name="); + args.append(audioModuleInfo.adapterName); + } + + if (!audioModuleInfo.className.empty()) { + args.append(" device_class="); + args.append(audioModuleInfo.className); + } + + if (!audioModuleInfo.fileName.empty()) { + args.append(" file_path="); + args.append(audioModuleInfo.fileName); + } + + if (!audioModuleInfo.networkId.empty()) { + args.append(" network_id="); + args.append(audioModuleInfo.networkId); + } else { + args.append(" network_id=LocalDevice"); + } + + if (!audioModuleInfo.deviceType.empty()) { + args.append(" device_type="); + args.append(audioModuleInfo.deviceType); + } + + if (!audioModuleInfo.sourceType.empty()) { + args.append(" source_type="); + args.append(audioModuleInfo.sourceType); + } +} + void UpdateCommonArgs(const AudioModuleInfo &audioModuleInfo, std::string &args) { if (!audioModuleInfo.rate.empty()) { @@ -732,82 +811,14 @@ std::string AudioAdapterManager::GetModuleArgs(const AudioModuleInfo &audioModul if (audioModuleInfo.lib == HDI_SINK) { UpdateCommonArgs(audioModuleInfo, args); - if (!audioModuleInfo.name.empty()) { - args.append(" sink_name="); - args.append(audioModuleInfo.name); - } - - if (!audioModuleInfo.adapterName.empty()) { - args.append(" adapter_name="); - args.append(audioModuleInfo.adapterName); - } - - if (!audioModuleInfo.className.empty()) { - args.append(" device_class="); - args.append(audioModuleInfo.className); - } - - if (!audioModuleInfo.fileName.empty()) { - args.append(" file_path="); - args.append(audioModuleInfo.fileName); - } - if (!audioModuleInfo.sinkLatency.empty()) { - args.append(" sink_latency="); - args.append(audioModuleInfo.sinkLatency); - } + UpdateSinkArgs(audioModuleInfo, args); if (testModeOn_) { args.append(" test_mode_on="); args.append("1"); } - if (!audioModuleInfo.networkId.empty()) { - args.append(" network_id="); - args.append(audioModuleInfo.networkId); - } else { - args.append(" network_id=LocalDevice"); - } - - if (!audioModuleInfo.deviceType.empty()) { - args.append(" device_type="); - args.append(audioModuleInfo.deviceType); - } } else if (audioModuleInfo.lib == HDI_SOURCE) { UpdateCommonArgs(audioModuleInfo, args); - if (!audioModuleInfo.name.empty()) { - args.append(" source_name="); - args.append(audioModuleInfo.name); - } - - if (!audioModuleInfo.adapterName.empty()) { - args.append(" adapter_name="); - args.append(audioModuleInfo.adapterName); - } - - if (!audioModuleInfo.className.empty()) { - args.append(" device_class="); - args.append(audioModuleInfo.className); - } - - if (!audioModuleInfo.fileName.empty()) { - args.append(" file_path="); - args.append(audioModuleInfo.fileName); - } - - if (!audioModuleInfo.networkId.empty()) { - args.append(" network_id="); - args.append(audioModuleInfo.networkId); - } else { - args.append(" network_id=LocalDevice"); - } - - if (!audioModuleInfo.deviceType.empty()) { - args.append(" device_type="); - args.append(audioModuleInfo.deviceType); - } - - if (!audioModuleInfo.sourceType.empty()) { - args.append(" source_type="); - args.append(audioModuleInfo.sourceType); - } + UpdateSourceArgs(audioModuleInfo, args); } else if (audioModuleInfo.lib == PIPE_SINK) { if (!audioModuleInfo.fileName.empty()) { args = "file="; @@ -835,6 +846,7 @@ std::string AudioAdapterManager::GetModuleArgs(const AudioModuleInfo &audioModul args.append(audioModuleInfo.sceneName); } } else if (audioModuleInfo.lib == INNER_CAPTURER_SINK || audioModuleInfo.lib == RECEIVER_SINK) { + UpdateCommonArgs(audioModuleInfo, args); if (!audioModuleInfo.name.empty()) { args.append(" sink_name="); args.append(audioModuleInfo.name); diff --git a/services/audio_service/BUILD.gn b/services/audio_service/BUILD.gn index f5b8447d9b07d748346cb7a6facccb47be04cdb9..cd979aa35c39f751fa07beafbceba24b87851865 100644 --- a/services/audio_service/BUILD.gn +++ b/services/audio_service/BUILD.gn @@ -305,6 +305,7 @@ ohos_shared_library("audio_process_service") { "../../frameworks/native/hdiadapter/sink:renderer_sink_adapter", "../../frameworks/native/hdiadapter/source:fast_audio_capturer_source", "../../frameworks/native/hdiadapter/source:remote_fast_audio_capturer_source", + "../../frameworks/native/playbackcapturer:playback_capturer", ] public_deps = [ "//third_party/bounds_checking_function:libsec_static" ] @@ -376,6 +377,8 @@ ohos_shared_library("audio_service") { external_deps = [ "access_token:libaccesstoken_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", "c_utils:utils", "drivers_interface_audio:effect_idl_headers", "drivers_interface_audio:libeffect_proxy_1.0", diff --git a/services/audio_service/client/include/ipc_stream_proxy.h b/services/audio_service/client/include/ipc_stream_proxy.h index 0459e8519537ea348853349257cfff28436d0568..7eeb6065009720626d5770c89576f28658d3c155 100644 --- a/services/audio_service/client/include/ipc_stream_proxy.h +++ b/services/audio_service/client/include/ipc_stream_proxy.h @@ -47,6 +47,8 @@ public: int32_t Drain() override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; + int32_t GetAudioTime(uint64_t &framePos, uint64_t ×tamp) override; int32_t GetAudioPosition(uint64_t &framePos, uint64_t ×tamp) override; diff --git a/services/audio_service/client/src/audio_stream.cpp b/services/audio_service/client/src/audio_stream.cpp index 2c581040181b9c4c8b8f3e932c837e762582cbab..059f1abeb8f4ca136b35d7f427212995363410c7 100644 --- a/services/audio_service/client/src/audio_stream.cpp +++ b/services/audio_service/client/src/audio_stream.cpp @@ -171,6 +171,12 @@ void AudioStream::SetCapturerInfo(const AudioCapturerInfo &capturerInfo) capturerInfo_ = capturerInfo; } +int32_t AudioStream::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + AUDIO_ERR_LOG("Unsupported operation!"); + return ERR_NOT_SUPPORTED; +} + State AudioStream::GetState() { return state_; diff --git a/services/audio_service/client/src/capturer_in_client.cpp b/services/audio_service/client/src/capturer_in_client.cpp index a6e36e8336bc17a2293c24b10d3c0570bb4de530..dcc919562d820b5e34871dcae4a7863607d912a1 100644 --- a/services/audio_service/client/src/capturer_in_client.cpp +++ b/services/audio_service/client/src/capturer_in_client.cpp @@ -44,6 +44,7 @@ #include "audio_server_death_recipient.h" #include "audio_stream_tracker.h" #include "audio_system_manager.h" +#include "audio_process_config.h" #include "ipc_stream_listener_impl.h" #include "ipc_stream_listener_stub.h" #include "callback_handler.h" @@ -74,6 +75,7 @@ public: void SetClientID(int32_t clientPid, int32_t clientUid, uint32_t appTokenId) override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; void SetRendererInfo(const AudioRendererInfo &rendererInfo) override; void SetCapturerInfo(const AudioCapturerInfo &capturerInfo) override; int32_t GetAudioStreamInfo(AudioStreamParams &info) override; @@ -248,6 +250,7 @@ private: size_t cbBufferSize_ = 0; SafeBlockQueue cbBufferQueue_; // only one cbBuffer_ + AudioPlaybackCaptureConfig filterConfig_ = {{{}, FilterMode::INCLUDE, {}, FilterMode::INCLUDE}, false}; bool isInnerCapturer_ = false; bool isWakeupCapturer_ = false; @@ -383,6 +386,17 @@ void CapturerInClientInner::SetClientID(int32_t clientPid, int32_t clientUid, ui return; } +int32_t CapturerInClientInner::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + AUDIO_INFO_LOG("client set %{public}s", ProcessConfig::DumpInnerCapConfig(config).c_str()); + CHECK_AND_RETURN_RET_LOG(ipcStream_ != nullptr, ERR_ILLEGAL_STATE, "IpcStream is already nullptr"); + int32_t ret = ipcStream_->UpdatePlaybackCaptureConfig(config); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "failed: %{public}d", ret); + + filterConfig_ = config; + return SUCCESS; +} + void CapturerInClientInner::SetRendererInfo(const AudioRendererInfo &rendererInfo) { AUDIO_WARNING_LOG("SetRendererInfo is not supported"); @@ -1503,6 +1517,7 @@ int32_t CapturerInClientInner::Write(uint8_t *buffer, size_t bufferSize) int32_t CapturerInClientInner::HandleCapturerRead(size_t &readSize, size_t &userSize, uint8_t &buffer, bool isBlockingRead) { + Trace trace("CapturerInClientInner::HandleCapturerRead " + std::to_string(userSize)); while (readSize < userSize) { AUDIO_DEBUG_LOG("readSize %{public}zu < userSize %{public}zu", readSize, userSize); OptResult result = ringCache_->GetReadableSize(); diff --git a/services/audio_service/client/src/fast_audio_stream.cpp b/services/audio_service/client/src/fast_audio_stream.cpp index a7b72b309c96c0096d8ba5c4f68c277c0190d37d..2b5f063637d4229b19a7033727a934830ae7acaf 100644 --- a/services/audio_service/client/src/fast_audio_stream.cpp +++ b/services/audio_service/client/src/fast_audio_stream.cpp @@ -56,6 +56,12 @@ void FastAudioStream::SetClientID(int32_t clientPid, int32_t clientUid, uint32_t appTokenId_ = appTokenId; } +int32_t FastAudioStream::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + AUDIO_ERR_LOG("Unsupported operation!"); + return ERR_NOT_SUPPORTED; +} + void FastAudioStream::SetRendererInfo(const AudioRendererInfo &rendererInfo) { rendererInfo_ = rendererInfo; diff --git a/services/audio_service/client/src/ipc_stream_proxy.cpp b/services/audio_service/client/src/ipc_stream_proxy.cpp index 707e93d9cee7af8f3370254b30902e445044b7a8..a3324d1d7a3bc1eb50f38ce0c3104f4b8913edc0 100644 --- a/services/audio_service/client/src/ipc_stream_proxy.cpp +++ b/services/audio_service/client/src/ipc_stream_proxy.cpp @@ -18,6 +18,7 @@ #include "ipc_stream_proxy.h" #include "audio_log.h" #include "audio_errors.h" +#include "audio_process_config.h" namespace OHOS { namespace AudioStandard { @@ -181,6 +182,22 @@ int32_t IpcStreamProxy::Drain() return reply.ReadInt32(); } +int32_t IpcStreamProxy::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + CHECK_AND_RETURN_RET_LOG(data.WriteInterfaceToken(GetDescriptor()), ERROR, "Write descriptor failed!"); + + int32_t ret = ProcessConfig::WriteInnerCapConfigToParcel(config, data); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Write config failed"); + + ret = Remote()->SendRequest(IpcStreamMsg::ON_UPDATA_PLAYBACK_CAPTURER_CONFIG, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AUDIO_OK, ret, "Failed, ipc error: %{public}d", ret); + return reply.ReadInt32(); +} + int32_t IpcStreamProxy::GetAudioTime(uint64_t &framePos, uint64_t ×tamp) { MessageParcel data; diff --git a/services/audio_service/client/src/renderer_in_client.cpp b/services/audio_service/client/src/renderer_in_client.cpp index d8ee0ea59e77ac0c93f9be7b08f3a50848c5620b..09e5bcaa73c7d52d9ba229cfc0b46baadab69148 100644 --- a/services/audio_service/client/src/renderer_in_client.cpp +++ b/services/audio_service/client/src/renderer_in_client.cpp @@ -130,6 +130,7 @@ public: // IAudioStream void SetClientID(int32_t clientPid, int32_t clientUid, uint32_t appTokenId) override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; void SetRendererInfo(const AudioRendererInfo &rendererInfo) override; void SetCapturerInfo(const AudioCapturerInfo &capturerInfo) override; int32_t SetAudioStreamInfo(const AudioStreamParams info, @@ -519,6 +520,12 @@ void RendererInClientInner::SetClientID(int32_t clientPid, int32_t clientUid, ui appTokenId_ = appTokenId; } +int32_t RendererInClientInner::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + AUDIO_ERR_LOG("Unsupported operation!"); + return ERR_NOT_SUPPORTED; +} + void RendererInClientInner::SetRendererInfo(const AudioRendererInfo &rendererInfo) { rendererInfo_ = rendererInfo; diff --git a/services/audio_service/common/include/audio_process_config.h b/services/audio_service/common/include/audio_process_config.h index a2c3c33cd01ac11e44748215bb3694c4ba6b6c6c..872eb357fa221af06aa71e658817e2999407df13 100644 --- a/services/audio_service/common/include/audio_process_config.h +++ b/services/audio_service/common/include/audio_process_config.h @@ -26,6 +26,12 @@ namespace OHOS { namespace AudioStandard { class ProcessConfig { public: + static int32_t WriteInnerCapConfigToParcel(const AudioPlaybackCaptureConfig &config, MessageParcel &parcel); + + static int32_t ReadInnerCapConfigFromParcel(AudioPlaybackCaptureConfig &config, MessageParcel &parcel); + + static std::string DumpInnerCapConfig(const AudioPlaybackCaptureConfig &config); + static int32_t WriteConfigToParcel(const AudioProcessConfig &config, MessageParcel &parcel); static int32_t ReadConfigFromParcel(AudioProcessConfig &config, MessageParcel &parcel); diff --git a/services/audio_service/common/include/i_audio_process_stream.h b/services/audio_service/common/include/i_audio_process_stream.h index c506b339b0ec247e7911f11bae5e41fa5cf0816f..df5381447bed26c728c96320a2fdaf40778a4c43 100644 --- a/services/audio_service/common/include/i_audio_process_stream.h +++ b/services/audio_service/common/include/i_audio_process_stream.h @@ -34,6 +34,10 @@ public: virtual AudioStreamType GetAudioStreamType() = 0; + virtual void SetInnerCapState(bool isInnerCapped) = 0; + + virtual bool GetInnerCapState() = 0; + virtual ~IAudioProcessStream() = default; }; } // namespace AudioStandard diff --git a/services/audio_service/common/include/ipc_stream.h b/services/audio_service/common/include/ipc_stream.h index 06b1694af04590778afc76fd27a2e3f71f38092e..56478be753eb5280dc1b94bf05d76b9b602b2d73 100644 --- a/services/audio_service/common/include/ipc_stream.h +++ b/services/audio_service/common/include/ipc_stream.h @@ -54,6 +54,8 @@ public: virtual int32_t Drain() = 0; + virtual int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) = 0; + virtual int32_t GetAudioTime(uint64_t &framePos, uint64_t ×tamp) = 0; virtual int32_t GetAudioPosition(uint64_t &framePos, uint64_t ×tamp) = 0; @@ -99,6 +101,7 @@ public: ON_RELEASE, ON_FLUSH, ON_DRAIN, + ON_UPDATA_PLAYBACK_CAPTURER_CONFIG, OH_GET_AUDIO_TIME, OH_GET_AUDIO_POSITION, ON_GET_LATENCY, diff --git a/services/audio_service/common/src/audio_process_config.cpp b/services/audio_service/common/src/audio_process_config.cpp index 7928c7a44fc9b787f34edc1ddf6321c1efeb2268..ce6843570248da9ac26a5e1fdefb6c9aa7501c04 100644 --- a/services/audio_service/common/src/audio_process_config.cpp +++ b/services/audio_service/common/src/audio_process_config.cpp @@ -17,6 +17,7 @@ #include "audio_process_config.h" +#include #include #include "audio_errors.h" @@ -24,6 +25,170 @@ namespace OHOS { namespace AudioStandard { +namespace { +static const uint32_t MAX_VALID_USAGE_SIZE = 30; // 128 for pids +static const uint32_t MAX_VALID_PIDS_SIZE = 128; // 128 for pids +static std::map USAGE_TO_STRING_MAP = { + {STREAM_USAGE_INVALID, "INVALID"}, + {STREAM_USAGE_UNKNOWN, "UNKNOWN"}, + {STREAM_USAGE_MEDIA, "MEDIA"}, + {STREAM_USAGE_MUSIC, "MUSIC"}, + {STREAM_USAGE_VOICE_COMMUNICATION, "VOICE_COMMUNICATION"}, + {STREAM_USAGE_VOICE_ASSISTANT, "VOICE_ASSISTANT"}, + {STREAM_USAGE_ALARM, "ALARM"}, + {STREAM_USAGE_VOICE_MESSAGE, "VOICE_MESSAGE"}, + {STREAM_USAGE_NOTIFICATION_RINGTONE, "NOTIFICATION_RINGTONE"}, + {STREAM_USAGE_RINGTONE, "RINGTONE"}, + {STREAM_USAGE_NOTIFICATION, "NOTIFICATION"}, + {STREAM_USAGE_ACCESSIBILITY, "ACCESSIBILITY"}, + {STREAM_USAGE_SYSTEM, "SYSTEM"}, + {STREAM_USAGE_MOVIE, "MOVIE"}, + {STREAM_USAGE_GAME, "GAME"}, + {STREAM_USAGE_AUDIOBOOK, "AUDIOBOOK"}, + {STREAM_USAGE_NAVIGATION, "NAVIGATION"}, + {STREAM_USAGE_DTMF, "DTMF"}, + {STREAM_USAGE_ENFORCED_TONE, "ENFORCED_TONE"}, + {STREAM_USAGE_ULTRASONIC, "ULTRASONIC"}, + {STREAM_USAGE_VIDEO_COMMUNICATION, "VIDEO_COMMUNICATION"}, + {STREAM_USAGE_RANGING, "RANGING"}, + {STREAM_USAGE_VOICE_MODEM_COMMUNICATION, "VOICE_MODEM_COMMUNICATION"} +}; +} + +int32_t ProcessConfig::WriteInnerCapConfigToParcel(const AudioPlaybackCaptureConfig &config, MessageParcel &parcel) +{ + // filterOptions.usages + size_t usageSize = config.filterOptions.usages.size(); + CHECK_AND_RETURN_RET_LOG(usageSize < MAX_VALID_USAGE_SIZE, ERR_INVALID_PARAM, "usageSize is too large"); + parcel.WriteUint32(usageSize); + for (size_t i = 0; i < usageSize; i++) { + parcel.WriteInt32(static_cast(config.filterOptions.usages[i])); + } + + // filterOptions.usageFilterMode + parcel.WriteUint32(config.filterOptions.usageFilterMode); + + // filterOptions.pids + size_t pidSize = config.filterOptions.pids.size(); + CHECK_AND_RETURN_RET_LOG(pidSize <= MAX_VALID_PIDS_SIZE, ERR_INVALID_PARAM, "pidSize is too large"); + parcel.WriteUint32(pidSize); + for (size_t i = 0; i < pidSize; i++) { + parcel.WriteUint32(config.filterOptions.pids[i]); + } + + // filterOptions.pidFilterMode + parcel.WriteUint32(config.filterOptions.pidFilterMode); + + // silentCapture + parcel.WriteBool(config.silentCapture); + return SUCCESS; +} + +int32_t ProcessConfig::ReadInnerCapConfigFromParcel(AudioPlaybackCaptureConfig &config, MessageParcel &parcel) +{ + // filterOptions.usages + uint32_t usageSize = parcel.ReadUint32(); + if (usageSize > MAX_VALID_USAGE_SIZE) { + AUDIO_ERR_LOG("Invalid param, usageSize is too large: %{public}u", usageSize); + return ERR_INVALID_PARAM; + } + std::vector usages = {}; + for (uint32_t i = 0; i < usageSize; i++) { + int32_t tmpUsage = parcel.ReadInt32(); + if (std::find(AUDIO_SUPPORTED_STREAM_USAGES.begin(), AUDIO_SUPPORTED_STREAM_USAGES.end(), tmpUsage) == + AUDIO_SUPPORTED_STREAM_USAGES.end()) { + AUDIO_ERR_LOG("Invalid param, usage: %{public}d", tmpUsage); + return ERR_INVALID_PARAM; + } + usages.push_back(static_cast(tmpUsage)); + } + config.filterOptions.usages = usages; + + // filterOptions.usageFilterMode + uint32_t tempMode = parcel.ReadUint32(); + if (tempMode >= FilterMode::MAX_FILTER_MODE) { + AUDIO_ERR_LOG("Invalid param, usageFilterMode : %{public}u", tempMode); + return ERR_INVALID_PARAM; + } + config.filterOptions.usageFilterMode = static_cast(tempMode); + + // filterOptions.pids + uint32_t pidSize = parcel.ReadUint32(); + if (pidSize > MAX_VALID_PIDS_SIZE) { + AUDIO_ERR_LOG("Invalid param, pidSize is too large: %{public}u", pidSize); + return ERR_INVALID_PARAM; + } + std::vector pids = {}; + for (uint32_t i = 0; i < pidSize; i++) { + int32_t tmpPid = parcel.ReadInt32(); + if (tmpPid <= 0) { + AUDIO_ERR_LOG("Invalid param, pid: %{public}d", tmpPid); + return ERR_INVALID_PARAM; + } + pids.push_back(tmpPid); + } + config.filterOptions.pids = pids; + + // filterOptions.pidFilterMode + tempMode = parcel.ReadUint32(); + if (tempMode >= FilterMode::MAX_FILTER_MODE) { + AUDIO_ERR_LOG("Invalid param, pidFilterMode : %{public}u", tempMode); + return ERR_INVALID_PARAM; + } + config.filterOptions.pidFilterMode = static_cast(tempMode); + + // silentCapture + config.silentCapture = parcel.ReadBool(); + + return SUCCESS; +} + +// INCLUDE 3 usages { 1 2 4 } && EXCLUDE 1 pids { 1234 } +std::string ProcessConfig::DumpInnerCapConfig(const AudioPlaybackCaptureConfig &config) +{ + std::stringstream temp; + + // filterOptions + switch (config.filterOptions.usageFilterMode) { + case FilterMode::INCLUDE: + temp << "INCLUDE"; + break; + case FilterMode::EXCLUDE: + temp << "EXCLUDE"; + break; + default: + temp << "INVALID"; + break; + } + temp << " " << config.filterOptions.usages.size() << " usages { "; + for (size_t i = 0; i < config.filterOptions.usages.size(); i++) { + StreamUsage usage = config.filterOptions.usages[i]; + temp << USAGE_TO_STRING_MAP[usage] << " "; + } + temp << "} && "; + + // INCLUDE 3 pids { 1 2 4 } + switch (config.filterOptions.pidFilterMode) { + case FilterMode::INCLUDE: + temp << "INCLUDE"; + break; + case FilterMode::EXCLUDE: + temp << "EXCLUDE"; + break; + default: + temp << "INVALID"; + break; + } + temp << " " << config.filterOptions.pids.size() << " pids { "; + for (size_t i = 0; i < config.filterOptions.pids.size(); i++) { + temp << config.filterOptions.pids[i] << " "; + } + temp << "}"; + // silentCapture will not be dumped. + + return temp.str(); +} + int32_t ProcessConfig::WriteConfigToParcel(const AudioProcessConfig &config, MessageParcel &parcel) { // AppInfo diff --git a/services/audio_service/server/include/audio_endpoint.h b/services/audio_service/server/include/audio_endpoint.h index 6cdebafa354be58f284f599a6917b137f602e0ca..c2c9a875467a99df91547905f9a94462a3488838 100644 --- a/services/audio_service/server/include/audio_endpoint.h +++ b/services/audio_service/server/include/audio_endpoint.h @@ -74,6 +74,10 @@ public: virtual void Release() = 0; + virtual bool ShouldInnerCap() = 0; + virtual int32_t EnableFastInnerCap() = 0; + virtual int32_t DisableFastInnerCap() = 0; + virtual int32_t LinkProcessStream(IAudioProcessStream *processStream) = 0; virtual int32_t UnlinkProcessStream(IAudioProcessStream *processStream) = 0; @@ -117,6 +121,11 @@ public: return endpointType_; } + // for inner-cap + bool ShouldInnerCap() override; + int32_t EnableFastInnerCap() override; + int32_t DisableFastInnerCap() override; + int32_t SetVolume(AudioStreamType streamType, float volume) override; int32_t ResolveBuffer(std::shared_ptr &buffer) override; diff --git a/services/audio_service/server/include/audio_process_in_server.h b/services/audio_service/server/include/audio_process_in_server.h index dd24181c14051bfb35bad1316296f8ea17d9ac60..94da6e37410faf74d397eed51f89ec374641d45a 100644 --- a/services/audio_service/server/include/audio_process_in_server.h +++ b/services/audio_service/server/include/audio_process_in_server.h @@ -82,12 +82,18 @@ public: int32_t AddProcessStatusListener(std::shared_ptr listener); int32_t RemoveProcessStatusListener(std::shared_ptr listener); + // for inner-cap + void SetInnerCapState(bool isInnerCapped) override; + bool GetInnerCapState() override; +public: + const AudioProcessConfig processConfig_; + private: AudioProcessInServer(const AudioProcessConfig &processConfig, ProcessReleaseCallback *releaseCallback); int32_t InitBufferStatus(); private: - AudioProcessConfig processConfig_; + bool isInnerCapped_ = false; ProcessReleaseCallback *releaseCallback_ = nullptr; uint32_t sessionId_ = 0; diff --git a/services/audio_service/server/include/audio_server.h b/services/audio_service/server/include/audio_server.h index 49759a98c2e6e5cd7156cba4b08844924f075c21..d47d7b16abcbe95d405d4b38c5fd35e1a6e748ba 100644 --- a/services/audio_service/server/include/audio_server.h +++ b/services/audio_service/server/include/audio_server.h @@ -140,11 +140,14 @@ private: bool VerifyClientPermission(const std::string &permissionName, Security::AccessToken::AccessTokenID tokenId = Security::AccessToken::INVALID_TOKENID); bool PermissionChecker(const AudioProcessConfig &config); - bool CheckPlaybackPermission(Security::AccessToken::AccessTokenID tokenId, const StreamUsage streamUsage); - bool CheckRecorderPermission(Security::AccessToken::AccessTokenID tokenId, const SourceType sourceType, - int32_t appUid); + bool CheckPlaybackPermission(const AudioProcessConfig &config); + bool CheckRecorderPermission(const AudioProcessConfig &config); bool CheckVoiceCallRecorderPermission(Security::AccessToken::AccessTokenID tokenId); + void ResetRecordConfig(int32_t callerUid, AudioProcessConfig &config); + AudioProcessConfig ResetProcessConfig(const AudioProcessConfig &config); + int32_t GetHapBuildApiVersion(int32_t callerUid); + void AudioServerDied(pid_t pid); void RegisterPolicyServerDeathRecipient(); void RegisterAudioCapturerSourceCallback(); @@ -171,7 +174,6 @@ private: std::mutex setWakeupCloseCallbackMutex_; std::mutex audioParameterMutex_; std::mutex audioSceneMutex_; - bool isGetProcessEnabled_ = false; std::unique_ptr audioEffectServer_; }; } // namespace AudioStandard diff --git a/services/audio_service/server/include/audio_service.h b/services/audio_service/server/include/audio_service.h index e5ef14b11ed7c4898d03ee7a67945dafdfaa1313..7deb340ac3ff7064d8851b906b984c411e7a4015 100644 --- a/services/audio_service/server/include/audio_service.h +++ b/services/audio_service/server/include/audio_service.h @@ -26,14 +26,27 @@ #include "audio_process_in_server.h" #include "audio_endpoint.h" #include "ipc_stream_in_server.h" +#include "playback_capturer_manager.h" namespace OHOS { namespace AudioStandard { -class AudioService : public ProcessReleaseCallback { +namespace { +enum InnerCapFilterPolicy : uint32_t { + POLICY_INVALID = 0, + POLICY_USAGES_ONLY, + POLICY_USAGES_AND_PIDS +}; +} // anonymous namespace + +class AudioService : public ProcessReleaseCallback, public ICapturerFilterListener { public: static AudioService *GetInstance(); ~AudioService(); + // override for ICapturerFilterListener + int32_t OnCapturerFilterChange(uint32_t sessionId, const AudioPlaybackCaptureConfig &newConfig) override; + int32_t OnCapturerFilterRemove(uint32_t sessionId) override; + sptr GetIpcStream(const AudioProcessConfig &config, int32_t &ret); sptr GetAudioProcess(const AudioProcessConfig &config); @@ -49,10 +62,22 @@ public: void Dump(std::stringstream &dumpString); float GetMaxAmplitude(bool isOutputDevice); + void RemoveRenderer(uint32_t sessionId); + private: AudioService(); void DelayCallReleaseEndpoint(std::string endpointName, int32_t delayInMs); + void InsertRenderer(uint32_t sessionId, std::shared_ptr renderer); + // for inner-capturer + void CheckInnerCapForRenderer(uint32_t sessionId, std::shared_ptr renderer); + void CheckInnerCapForProcess(sptr process, std::shared_ptr endpoint); + void FilterAllFastProcess(); + InnerCapFilterPolicy GetInnerCapFilterPolicy(); + bool ShouldBeInnerCap(const AudioProcessConfig &rendererConfig); + int32_t OnInitInnerCapList(); // for first InnerCap filter take effect. + int32_t OnUpdateInnerCapList(); // for some InnerCap filter has already take effect. + private: std::mutex processListMutex_; std::vector, std::shared_ptr>> linkedPairedList_; @@ -61,6 +86,15 @@ private: std::condition_variable releaseEndpointCV_; std::set releasingEndpointSet_; std::map> endpointList_; + + // for inner-capturer + PlaybackCapturerManager *innerCapturerMgr_ = nullptr; + uint32_t workingInnerCapId_ = 0; // invalid sessionId + AudioPlaybackCaptureConfig workingConfig_; + + std::mutex rendererMapMutex_; + std::vector> filteredRendererMap_ = {}; + std::map> allRendererMap_ = {}; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_service/server/include/capturer_in_server.h b/services/audio_service/server/include/capturer_in_server.h index f4ad301f37a3026ac3880865da05a769dec0ac0a..4da529e4cae32e8fec418d82de41135921a05edb 100644 --- a/services/audio_service/server/include/capturer_in_server.h +++ b/services/audio_service/server/include/capturer_in_server.h @@ -24,11 +24,6 @@ namespace OHOS { namespace AudioStandard { -class CapturerListener { -public: - virtual void OnReadEvent() = 0; - virtual void ReceivedBuffer() = 0; -}; class CapturerInServer : public IStatusCallback, public IReadCallback, public std::enable_shared_from_this { public: @@ -49,7 +44,6 @@ public: int32_t GetLatency(uint64_t &latency); int32_t Init(); - void RegisterTestCallback(const std::weak_ptr &callback); int32_t ConfigServerBuffer(); int32_t InitBufferStatus(); @@ -58,6 +52,10 @@ public: void ReadData(size_t length); int32_t DrainAudioBuffer(); + // for inner-cap. + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config); + int32_t UpdatePlaybackCaptureConfigInLegacy(const AudioPlaybackCaptureConfig &config); + private: int32_t InitCacheBuffer(size_t targetSize); @@ -68,8 +66,8 @@ private: IOperation operation_ = OPERATION_INVALID; IStatus status_ = I_STATUS_IDLE; + AudioPlaybackCaptureConfig filterConfig_; std::weak_ptr streamListener_; - std::weak_ptr testCallback_; AudioProcessConfig processConfig_; size_t totalSizeInFrame_ = 0; size_t spanSizeInFrame_ = 0; @@ -85,6 +83,7 @@ private: uint32_t overFlowLogFlag_ = 0; std::unique_ptr ringCache_ = nullptr; size_t cacheSizeInBytes_ = 0; + std::unique_ptr dischargeBuffer_ = nullptr; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_service/server/include/i_stream_manager.h b/services/audio_service/server/include/i_stream_manager.h index 92aa25f76d9e64026e7fe4303ae3e76091978bc6..af4a74763cf25df292bbf324764d5ac071a3066e 100644 --- a/services/audio_service/server/include/i_stream_manager.h +++ b/services/audio_service/server/include/i_stream_manager.h @@ -22,7 +22,8 @@ namespace OHOS { namespace AudioStandard { enum ManagerType : int32_t { - PLAYBACK = 0, + PLAYBACK = 0, + DUP_PLAYBACK, RECORDER, }; @@ -32,6 +33,7 @@ public: static IStreamManager &GetPlaybackManager(); static IStreamManager &GetRecorderManager(); + static IStreamManager &GetDupPlaybackManager(); virtual int32_t CreateRender(AudioProcessConfig processConfig, std::shared_ptr &stream) = 0; virtual int32_t ReleaseRender(uint32_t streamIndex_) = 0; diff --git a/services/audio_service/server/include/ipc_stream_in_server.h b/services/audio_service/server/include/ipc_stream_in_server.h index 4cd2f9e7ee844aecbe3a535d60cb9924eeb6671c..0e3ebbc5943a56ff2620f90d78cd54eddd779bc1 100644 --- a/services/audio_service/server/include/ipc_stream_in_server.h +++ b/services/audio_service/server/include/ipc_stream_in_server.h @@ -69,6 +69,8 @@ public: int32_t Drain() override; + int32_t UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) override; + int32_t GetAudioTime(uint64_t &framePos, uint64_t ×tamp) override; int32_t GetAudioPosition(uint64_t &framePos, uint64_t ×tamp) override; @@ -102,6 +104,8 @@ public: int32_t UpdateSpatializationState(bool spatializationEnabled, bool headTrackingEnabled) override; // renderer only + // for inner-capturer + std::shared_ptr GetRenderer(); private: int32_t ConfigRenderer(); int32_t ConfigCapturer(); diff --git a/services/audio_service/server/include/ipc_stream_stub.h b/services/audio_service/server/include/ipc_stream_stub.h index fd2ee871aa429abbc561ad10fc17591cbfa9cbda..6dbe102c330cba511a815ae06ab838a2eb945d80 100644 --- a/services/audio_service/server/include/ipc_stream_stub.h +++ b/services/audio_service/server/include/ipc_stream_stub.h @@ -39,6 +39,7 @@ private: int32_t HandleRelease(MessageParcel &data, MessageParcel &reply); int32_t HandleFlush(MessageParcel &data, MessageParcel &reply); int32_t HandleDrain(MessageParcel &data, MessageParcel &reply); + int32_t HandleUpdatePlaybackCaptureConfig(MessageParcel &data, MessageParcel &reply); int32_t HandleGetAudioTime(MessageParcel &data, MessageParcel &reply); int32_t HandleGetAudioPosition(MessageParcel &data, MessageParcel &reply); int32_t HandleGetLatency(MessageParcel &data, MessageParcel &reply); @@ -71,6 +72,7 @@ private: &IpcStreamStub::HandleRelease, &IpcStreamStub::HandleFlush, &IpcStreamStub::HandleDrain, + &IpcStreamStub::HandleUpdatePlaybackCaptureConfig, &IpcStreamStub::HandleGetAudioTime, &IpcStreamStub::HandleGetAudioPosition, &IpcStreamStub::HandleGetLatency, diff --git a/services/audio_service/server/include/renderer_in_server.h b/services/audio_service/server/include/renderer_in_server.h index b3e026efe094fa3320d345d6c78135dffbbbdbb9..eb56ccd35140022a000b2453e1e515b008d8ceb3 100644 --- a/services/audio_service/server/include/renderer_in_server.h +++ b/services/audio_service/server/include/renderer_in_server.h @@ -23,6 +23,16 @@ namespace OHOS { namespace AudioStandard { +class StreamCallbacks : public IStatusCallback, public IWriteCallback { +public: + explicit StreamCallbacks(uint32_t streamIndex); + virtual ~StreamCallbacks() = default; + void OnStatusUpdate(IOperation operation) override; + int32_t OnWriteData(size_t length) override; +private: + uint32_t streamIndex_ = 0; +}; + class RendererInServer : public IStatusCallback, public IWriteCallback, public std::enable_shared_from_this { public: @@ -69,6 +79,12 @@ public: int32_t DrainAudioBuffer(); int32_t GetInfo(); + // for inner-cap + int32_t EnableInnerCap(); + int32_t DisableInnerCap(); + int32_t InitDupStream(); +public: + const AudioProcessConfig processConfig_; private: void OnStatusUpdateSub(IOperation operation); std::mutex statusLock_; @@ -78,8 +94,14 @@ private: IOperation operation_ = OPERATION_INVALID; IStatus status_ = I_STATUS_IDLE; + // for inner-cap + std::mutex dupMutex_; + std::atomic isInnerCapEnabled_ = false; + uint32_t dupStreamIndex_ = 0; + std::shared_ptr dupStreamCallback_ = nullptr; + std::shared_ptr dupStream_ = nullptr; + std::weak_ptr streamListener_; - AudioProcessConfig processConfig_; size_t totalSizeInFrame_ = 0; size_t spanSizeInFrame_ = 0; size_t spanSizeInByte_ = 0; diff --git a/services/audio_service/server/src/audio_endpoint.cpp b/services/audio_service/server/src/audio_endpoint.cpp index 83d976cfba4b31abdafd77ad8adceca7bcfbb46c..cbdd21dac873ab252a69925e5f99c9965efac9e9 100644 --- a/services/audio_service/server/src/audio_endpoint.cpp +++ b/services/audio_service/server/src/audio_endpoint.cpp @@ -33,6 +33,7 @@ #include "fast_audio_renderer_sink.h" #include "fast_audio_capturer_source.h" #include "i_audio_capturer_source.h" +#include "i_stream_manager.h" #include "linear_pos_time_model.h" #include "policy_handler.h" #include "remote_fast_audio_renderer_sink.h" @@ -74,6 +75,16 @@ static enum HdiAdapterFormat ConvertToHdiAdapterFormat(AudioSampleFormat format) return adapterFormat; } +class MockCallbacks : public IStatusCallback, public IWriteCallback { +public: + explicit MockCallbacks(uint32_t streamIndex); + virtual ~MockCallbacks() = default; + void OnStatusUpdate(IOperation operation) override; + int32_t OnWriteData(size_t length) override; +private: + uint32_t streamIndex_ = 0; +}; + class AudioEndpointInner : public AudioEndpoint { public: explicit AudioEndpointInner(EndpointType type, uint64_t id); @@ -120,6 +131,13 @@ public: return dstAudioBuffer_; } + // for inner-cap + bool ShouldInnerCap() override; + int32_t EnableFastInnerCap() override; + int32_t DisableFastInnerCap() override; + + int32_t InitDupStream(); + EndpointStatus GetStatus() override; void Release() override; @@ -132,6 +150,8 @@ public: float GetMaxAmplitude() override; private: + AudioProcessConfig GetInnerCapConfig(); + void MixToDupStream(const std::vector &srcDataList); bool ConfigInputPoint(const DeviceInfo &deviceInfo); int32_t PrepareDeviceBuffer(const DeviceInfo &deviceInfo); int32_t GetAdapterBufferInfo(const DeviceInfo &deviceInfo); @@ -200,6 +220,16 @@ private: std::atomic isInited_ = false; + // for inner-cap + std::mutex dupMutex_; + std::atomic isInnerCapEnabled_ = false; + uint32_t dupStreamIndex_ = 0; + std::shared_ptr dupStreamCallback_ = nullptr; + std::shared_ptr dupStream_ = nullptr; + size_t dupBufferSize_ = 0; + std::unique_ptr dupBuffer_ = nullptr; + FILE *dumpC2SDup_ = nullptr; // client to server inner-cap dump file + IMmapAudioRendererSink *fastSink_ = nullptr; IMmapAudioCapturerSource *fastSource_ = nullptr; @@ -314,6 +344,128 @@ int32_t AudioEndpointInner::ResolveBuffer(std::shared_ptr &buffer return SUCCESS; } +MockCallbacks::MockCallbacks(uint32_t streamIndex) : streamIndex_(streamIndex) +{ + AUDIO_INFO_LOG("DupStream %{public}u create MockCallbacks", streamIndex_); +} + +void MockCallbacks::OnStatusUpdate(IOperation operation) +{ + AUDIO_INFO_LOG("DupStream %{public}u recv operation: %{public}d", streamIndex_, operation); +} + +int32_t MockCallbacks::OnWriteData(size_t length) +{ + Trace trace("DupStream::OnWriteData length " + std::to_string(length)); + return SUCCESS; +} + +bool AudioEndpointInner::ShouldInnerCap() +{ + bool shouldBecapped = false; + std::lock_guard lock(listLock_); + for (uint32_t i = 0; i < processList_.size(); i++) { + if (processList_[i]->GetInnerCapState()) { + shouldBecapped = true; + break; + } + } + AUDIO_INFO_LOG("find endpoint inner-cap state: %{public}s", shouldBecapped ? "true" : "false"); + return shouldBecapped; +} + +AudioProcessConfig AudioEndpointInner::GetInnerCapConfig() +{ + AudioProcessConfig processConfig; + + processConfig.appInfo.appPid = getpid(); + processConfig.appInfo.appUid = getuid(); + + processConfig.streamInfo = dstStreamInfo_; + + processConfig.audioMode = AUDIO_MODE_PLAYBACK; + + // processConfig.rendererInfo ? + + processConfig.streamType = STREAM_MUSIC; + + return processConfig; +} + +int32_t AudioEndpointInner::InitDupStream() +{ + std::lock_guard lock(dupMutex_); + CHECK_AND_RETURN_RET_LOG(isInnerCapEnabled_ == false, SUCCESS, "already enabled"); + + AudioProcessConfig processConfig = GetInnerCapConfig(); + int32_t ret = IStreamManager::GetDupPlaybackManager().CreateRender(processConfig, dupStream_); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS && dupStream_ != nullptr, ERR_OPERATION_FAILED, "Failed: %{public}d", ret); + dupStreamIndex_ = dupStream_->GetStreamIndex(); + + dupStreamCallback_ = std::make_shared(dupStreamIndex_); + dupStream_->RegisterStatusCallback(dupStreamCallback_); + dupStream_->RegisterWriteCallback(dupStreamCallback_); + + // eg: /data/local/tmp/LocalDevice6_0_48000_2_1_c2s_dup.pcm + AudioStreamInfo tempInfo = processConfig.streamInfo; + std::string dupDumpName = GetEndpointName() + "_" + std::to_string(tempInfo.samplingRate) + "_" + + std::to_string(tempInfo.channels) + "_" + std::to_string(tempInfo.format) + "_c2s_dup.pcm"; + DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, dupDumpName, &dumpC2SDup_); + + AUDIO_INFO_LOG("Dup Renderer %{public}d with Endpoint status: %{public}s", dupStreamIndex_, + GetStatusStr(endpointStatus_).c_str()); + + // buffer init + dupBufferSize_ = dstSpanSizeInframe_ * dstByteSizePerFrame_; // each + CHECK_AND_RETURN_RET_LOG(dupBufferSize_ < dstAudioBuffer_->GetDataSize(), ERR_OPERATION_FAILED, "Init buffer fail"); + dupBuffer_ = std::make_unique(dupBufferSize_); + ret = memset_s(reinterpret_cast(dupBuffer_.get()), dupBufferSize_, 0, dupBufferSize_); + if (ret != EOK) { + AUDIO_WARNING_LOG("memset buffer fail, ret %{public}d", ret); + } + + if (endpointStatus_ == RUNNING || (endpointStatus_ == IDEL && isDeviceRunningInIdel_)) { + AUDIO_INFO_LOG("Endpoint %{public}d is already running, let's start the dup stream", deviceInfo_.deviceId); + dupStream_->Start(); + } + // mark enabled last + isInnerCapEnabled_ = true; + return SUCCESS; +} + +int32_t AudioEndpointInner::EnableFastInnerCap() +{ + if (isInnerCapEnabled_) { + AUDIO_INFO_LOG("InnerCap is already enabled"); + return SUCCESS; + } + + CHECK_AND_RETURN_RET_LOG(deviceInfo_.deviceRole == OUTPUT_DEVICE, ERR_INVALID_OPERATION, "Not output device!"); + int32_t ret = InitDupStream(); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "Init dup stream failed"); + return SUCCESS; +} + +int32_t AudioEndpointInner::DisableFastInnerCap() +{ + if (deviceInfo_.deviceRole != OUTPUT_DEVICE) { + return SUCCESS; + } + std::lock_guard lock(dupMutex_); + if (!isInnerCapEnabled_) { + AUDIO_INFO_LOG("InnerCap is already disabled."); + return SUCCESS; + } + isInnerCapEnabled_ = false; + AUDIO_INFO_LOG("Disable dup renderer %{public}d with Endpoint status: %{public}s", dupStreamIndex_, + GetStatusStr(endpointStatus_).c_str()); + + IStreamManager::GetDupPlaybackManager().ReleaseRender(dupStreamIndex_); + dupStream_ = nullptr; + + return SUCCESS; +} + AudioEndpoint::EndpointStatus AudioEndpointInner::GetStatus() { AUDIO_INFO_LOG("AudioEndpoint get status:%{public}s", GetStatusStr(endpointStatus_).c_str()); @@ -361,6 +513,11 @@ void AudioEndpointInner::Release() AUDIO_INFO_LOG("Set device buffer null"); dstAudioBuffer_ = nullptr; } + + if (deviceInfo_.deviceRole == OUTPUT_DEVICE && isInnerCapEnabled_) { + DisableFastInnerCap(); + } + DumpFileUtil::CloseDumpFile(&dumpDcp_); DumpFileUtil::CloseDumpFile(&dumpHdi_); } @@ -691,6 +848,14 @@ bool AudioEndpointInner::StartDevice() } } + if (isInnerCapEnabled_) { + Trace trace("AudioEndpointInner::StartDupStream"); + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Start(); + } + } + if (isStarted_ == false) { endpointStatus_ = IDEL; workThreadCV_.notify_all(); @@ -719,6 +884,14 @@ bool AudioEndpointInner::DelayStopDevice() } } + if (isInnerCapEnabled_) { + Trace trace("AudioEndpointInner::StopDupStreamInDelay"); + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Stop(); + } + } + if (deviceInfo_.deviceRole == INPUT_DEVICE) { CHECK_AND_RETURN_RET_LOG(fastSource_ != nullptr && fastSource_->Stop() == SUCCESS, false, "Source stop failed."); @@ -743,6 +916,15 @@ bool AudioEndpointInner::StopDevice() dstAudioBuffer_->GetDataSize()); AUDIO_INFO_LOG("StopDevice clear buffer ret:%{public}d", ret); } + + if (isInnerCapEnabled_) { + Trace trace("AudioEndpointInner::StopDupStream"); + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Stop(); + } + } + if (deviceInfo_.deviceRole == INPUT_DEVICE) { CHECK_AND_RETURN_RET_LOG(fastSource_ != nullptr && fastSource_->Stop() == SUCCESS, false, "Source stop failed."); @@ -979,6 +1161,42 @@ bool AudioEndpointInner::CheckAllBufferReady(int64_t checkTime, uint64_t curWrit return isAllReady; } +void AudioEndpointInner::MixToDupStream(const std::vector &srcDataList) +{ + Trace trace("AudioEndpointInner::MixToDupStream"); + std::lock_guard lock(dupMutex_); + CHECK_AND_RETURN_LOG(dupBuffer_ != nullptr, "Buffer is not ready"); + + for (size_t i = 0; i < srcDataList.size(); i++) { + if (!srcDataList[i].isInnerCaped) { + continue; + } + size_t dataLength = dupBufferSize_; + dataLength /= 2; // SAMPLE_S16LE--> 2 byte + int16_t *dstPtr = reinterpret_cast(dupBuffer_.get()); + + for (size_t offset = 0; dataLength > 0; dataLength--) { + int32_t sum = *dstPtr; + sum += *(reinterpret_cast(srcDataList[i].bufferDesc.buffer) + offset); + *dstPtr = sum > INT16_MAX ? INT16_MAX : (sum < INT16_MIN ? INT16_MIN : sum); + dstPtr++; + offset++; + } + } + BufferDesc temp; + temp.buffer = dupBuffer_.get(); + temp.bufLength = dupBufferSize_; + temp.dataLength = dupBufferSize_; + + int32_t ret = dupStream_->EnqueueBuffer(temp); + CHECK_AND_RETURN_LOG(ret == SUCCESS, "EnqueueBuffer failed:%{public}d", ret); + + ret = memset_s(reinterpret_cast(dupBuffer_.get()), dupBufferSize_, 0, dupBufferSize_); + if (ret != EOK) { + AUDIO_WARNING_LOG("memset buffer fail, ret %{public}d", ret); + } +} + void AudioEndpointInner::ProcessData(const std::vector &srcDataList, const AudioStreamData &dstData) { size_t srcListSize = srcDataList.size(); @@ -1044,6 +1262,7 @@ void AudioEndpointInner::GetAllReadyProcessData(std::vector &au } streamData.volumeEnd = curReadSpan->volumeEnd; streamData.streamInfo = processList_[i]->GetStreamInfo(); + streamData.isInnerCaped = processList_[i]->GetInnerCapState(); SpanStatus targetStatus = SpanStatus::SPAN_WRITE_DONE; if (curReadSpan->spanStatus.compare_exchange_strong(targetStatus, SpanStatus::SPAN_READING)) { processBufferList_[i]->GetReadbuffer(curRead, streamData.bufferDesc); // check return? @@ -1084,6 +1303,10 @@ bool AudioEndpointInner::ProcessToEndpointDataHandle(uint64_t curWritePos) ProcessData(audioDataList, dstStreamData); } + if (isInnerCapEnabled_) { + MixToDupStream(audioDataList); + } + DumpFileUtil::WriteDumpFile(dumpHdi_, static_cast(dstStreamData.bufferDesc.buffer), dstStreamData.bufferDesc.bufLength); diff --git a/services/audio_service/server/src/audio_endpoint_separate.cpp b/services/audio_service/server/src/audio_endpoint_separate.cpp index 11fe81c24e3bcdaa22690b0d6d8fbc5bc628af57..b9a7dbed71386386b0c3fea6f7f61ed3e715f7d2 100644 --- a/services/audio_service/server/src/audio_endpoint_separate.cpp +++ b/services/audio_service/server/src/audio_endpoint_separate.cpp @@ -81,6 +81,24 @@ std::string AudioEndpointSeparate::GetEndpointName() return deviceInfo_.networkId + std::to_string(deviceInfo_.deviceId) + "_" + std::to_string(id_); } +bool AudioEndpointSeparate::ShouldInnerCap() +{ + AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported"); + return false; +} + +int32_t AudioEndpointSeparate::EnableFastInnerCap() +{ + AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported"); + return ERR_INVALID_OPERATION; +} + +int32_t AudioEndpointSeparate::DisableFastInnerCap() +{ + AUDIO_WARNING_LOG("AudioEndpointSeparate is not supported"); + return ERR_INVALID_OPERATION; +} + int32_t AudioEndpointSeparate::SetVolume(AudioStreamType streamType, float volume) { if (streamType_ == streamType) { diff --git a/services/audio_service/server/src/audio_process_in_server.cpp b/services/audio_service/server/src/audio_process_in_server.cpp index fb35864326a1a7932ee2c27ff8ea45e1d9810552..8be29f45889a5eba892df3336636904cd42dcfe7 100644 --- a/services/audio_service/server/src/audio_process_in_server.cpp +++ b/services/audio_service/server/src/audio_process_in_server.cpp @@ -181,6 +181,17 @@ int32_t AudioProcessInServer::RegisterProcessCb(sptr object) return SUCCESS; } +void AudioProcessInServer::SetInnerCapState(bool isInnerCapped) +{ + AUDIO_INFO_LOG("process[%{public}u] innercapped: %{public}s", sessionId_, isInnerCapped ? "true" : "false"); + isInnerCapped_ = isInnerCapped; +} + +bool AudioProcessInServer::GetInnerCapState() +{ + return isInnerCapped_; +} + int AudioProcessInServer::Dump(int fd, const std::vector &args) { return SUCCESS; diff --git a/services/audio_service/server/src/audio_server.cpp b/services/audio_service/server/src/audio_server.cpp index 5f8a286b6d03895bbf500429d35a8668006cbcfa..9c5fb644856e2c2fc4e8b0f514449684712f25ae 100644 --- a/services/audio_service/server/src/audio_server.cpp +++ b/services/audio_service/server/src/audio_server.cpp @@ -25,6 +25,8 @@ #include #include +#include "bundle_mgr_interface.h" +#include "bundle_mgr_proxy.h" #include "iservice_registry.h" #include "system_ability_definition.h" #include "hisysevent.h" @@ -70,6 +72,8 @@ static const std::vector STREAMS_NEED_VERIFY_SYSTEM_PERMISSION = { STREAM_USAGE_ULTRASONIC, STREAM_USAGE_VOICE_MODEM_COMMUNICATION }; +static const int32_t MODERN_INNER_API_VERSION = 12; +const int32_t API_VERSION_REMAINDER = 1000; static constexpr int32_t VM_MANAGER_UID = 5010; static const std::set RECORD_CHECK_FORWARD_LIST = { VM_MANAGER_UID @@ -897,17 +901,65 @@ int32_t AudioServer::RegiestPolicyProvider(const sptr &object) return SUCCESS; } -sptr AudioServer::CreateAudioProcess(const AudioProcessConfig &config) +int32_t AudioServer::GetHapBuildApiVersion(int32_t callerUid) { - bool ret = IsParamEnabled("persist.multimedia.audio.mmap.enable", isGetProcessEnabled_); - CHECK_AND_RETURN_RET_LOG(ret, nullptr, "CreateAudioProcess is not enabled!"); + std::string bundleName {""}; + AppExecFwk::BundleInfo bundleInfo; + auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + CHECK_AND_RETURN_RET_LOG(saManager != nullptr, 0, "failed: saManager is nullptr"); + + sptr remoteObject = saManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + CHECK_AND_RETURN_RET_LOG(remoteObject != nullptr, 0, "failed: remoteObject is nullptr"); + + sptr bundleMgrProxy = OHOS::iface_cast(remoteObject); + CHECK_AND_RETURN_RET_LOG(bundleMgrProxy != nullptr, 0, "failed: bundleMgrProxy is nullptr"); + + bundleMgrProxy->GetNameForUid(callerUid, bundleName); + bundleMgrProxy->GetBundleInfoV9(bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT | + AppExecFwk::BundleFlag::GET_BUNDLE_WITH_ABILITIES | + AppExecFwk::BundleFlag::GET_BUNDLE_WITH_REQUESTED_PERMISSION | + AppExecFwk::BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO | + AppExecFwk::BundleFlag::GET_BUNDLE_WITH_HASH_VALUE, + bundleInfo, + AppExecFwk::Constants::ALL_USERID); + int32_t hapApiVersion = bundleInfo.applicationInfo.apiTargetVersion % API_VERSION_REMAINDER; + AUDIO_INFO_LOG("callerUid %{public}d, version %{public}d", callerUid, hapApiVersion); + return hapApiVersion; +} + +void AudioServer::ResetRecordConfig(int32_t callerUid, AudioProcessConfig &config) +{ + if (config.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE) { + config.isInnerCapturer = true; + config.innerCapMode = LEGACY_INNER_CAP; + if (callerUid == MEDIA_SERVICE_UID) { + config.innerCapMode = MODERN_INNER_CAP; + } else if (GetHapBuildApiVersion(callerUid) >= MODERN_INNER_API_VERSION) { // not media, check build api-version + config.innerCapMode = LEGACY_MUTE_CAP; + } + } else { + config.isInnerCapturer = false; + } +#ifdef AUDIO_BUILD_VARIANT_ROOT + if (callerUid == ROOT_UID) { + config.innerCapMode = MODERN_INNER_CAP; + } +#endif + if (config.capturerInfo.sourceType == SourceType::SOURCE_TYPE_WAKEUP) { + config.isWakeupCapturer = true; + } else { + config.isWakeupCapturer = false; + } +} + +AudioProcessConfig AudioServer::ResetProcessConfig(const AudioProcessConfig &config) +{ + AudioProcessConfig resetConfig(config); - // client pid uid check. int32_t callerUid = IPCSkeleton::GetCallingUid(); int32_t callerPid = IPCSkeleton::GetCallingPid(); - AUDIO_DEBUG_LOG("Create process for uid:%{public}d pid:%{public}d", callerUid, callerPid); - AudioProcessConfig resetConfig(config); + // client pid uid check. if (callerUid == MEDIA_SERVICE_UID) { AUDIO_INFO_LOG("Create process for media service."); } else if (RECORD_CHECK_FORWARD_LIST.count(callerUid)) { @@ -921,6 +973,15 @@ sptr AudioServer::CreateAudioProcess(const AudioProcessConfig &co resetConfig.appInfo.appTokenId = IPCSkeleton::GetCallingTokenID(); } + if (resetConfig.audioMode == AUDIO_MODE_RECORD) { + ResetRecordConfig(callerUid, resetConfig); + } + return resetConfig; +} + +sptr AudioServer::CreateAudioProcess(const AudioProcessConfig &config) +{ + AudioProcessConfig resetConfig = ResetProcessConfig(config); CHECK_AND_RETURN_RET_LOG(PermissionChecker(resetConfig), nullptr, "Create audio process failed, no permission"); if ((resetConfig.audioMode == AUDIO_MODE_PLAYBACK && resetConfig.rendererInfo.rendererFlags == 0) || @@ -1108,15 +1169,21 @@ bool AudioServer::VerifyClientPermission(const std::string &permissionName, bool AudioServer::PermissionChecker(const AudioProcessConfig &config) { if (config.audioMode == AUDIO_MODE_PLAYBACK) { - return CheckPlaybackPermission(config.appInfo.appTokenId, config.rendererInfo.streamUsage); - } else { - return CheckRecorderPermission(config.appInfo.appTokenId, config.capturerInfo.sourceType, - config.appInfo.appUid); + return CheckPlaybackPermission(config); + } + + if (config.audioMode == AUDIO_MODE_RECORD) { + return CheckRecorderPermission(config); } + + AUDIO_ERR_LOG("Check failed invalid mode."); + return false; } -bool AudioServer::CheckPlaybackPermission(Security::AccessToken::AccessTokenID tokenId, const StreamUsage streamUsage) +bool AudioServer::CheckPlaybackPermission(const AudioProcessConfig &config) { + StreamUsage streamUsage = config.rendererInfo.streamUsage; + bool needVerifyPermission = false; for (const auto& item : STREAMS_NEED_VERIFY_SYSTEM_PERMISSION) { if (streamUsage == item) { @@ -1132,9 +1199,11 @@ bool AudioServer::CheckPlaybackPermission(Security::AccessToken::AccessTokenID t return true; } -bool AudioServer::CheckRecorderPermission(Security::AccessToken::AccessTokenID tokenId, const SourceType sourceType, - int32_t appUid) +bool AudioServer::CheckRecorderPermission(const AudioProcessConfig &config) { + Security::AccessToken::AccessTokenID tokenId = config.appInfo.appTokenId; + SourceType sourceType = config.capturerInfo.sourceType; + int32_t appUid = config.appInfo.appUid; #ifdef AUDIO_BUILD_VARIANT_ROOT if (appUid == ROOT_UID) { return true; diff --git a/services/audio_service/server/src/audio_service.cpp b/services/audio_service/server/src/audio_service.cpp index e4ca1e2a87670d9cdcf034b63e46194877594319..748b4264e8cfc0f8f209da5ac7fdae867092ad4d 100644 --- a/services/audio_service/server/src/audio_service.cpp +++ b/services/audio_service/server/src/audio_service.cpp @@ -21,6 +21,7 @@ #include "audio_errors.h" #include "audio_log.h" +#include "audio_utils.h" #include "remote_audio_renderer_sink.h" #include "policy_handler.h" #include "ipc_stream_in_server.h" @@ -89,14 +90,238 @@ int32_t AudioService::OnProcessRelease(IAudioProcessStream *process) sptr AudioService::GetIpcStream(const AudioProcessConfig &config, int32_t &ret) { + if (innerCapturerMgr_ == nullptr) { + innerCapturerMgr_ = PlaybackCapturerManager::GetInstance(); // As mgr is a singleton, lock is needless here. + innerCapturerMgr_->RegisterCapturerFilterListener(this); + } + // in plan: GetDeviceInfoForProcess(config) and stream limit check + // in plan: call GetProcessDeviceInfo to load inner-cap-sink sptr ipcStreamInServer = IpcStreamInServer::Create(config, ret); + // in plan: Put playback into list, check if EnableInnerCap is need. + if (ipcStreamInServer != nullptr && config.audioMode == AUDIO_MODE_PLAYBACK) { + uint32_t sessionId = 0; + std::shared_ptr renderer = ipcStreamInServer->GetRenderer(); + if (renderer != nullptr && renderer->GetSessionId(sessionId) == SUCCESS) { + InsertRenderer(sessionId, renderer); // for all renderers + CheckInnerCapForRenderer(sessionId, renderer); + } + } + return ipcStreamInServer; } +void AudioService::InsertRenderer(uint32_t sessionId, std::shared_ptr renderer) +{ + std::unique_lock lock(rendererMapMutex_); + AUDIO_INFO_LOG("Insert renderer:%{public}u into map", sessionId); + allRendererMap_[sessionId] = renderer; +} + +void AudioService::RemoveRenderer(uint32_t sessionId) +{ + std::unique_lock lock(rendererMapMutex_); + AUDIO_INFO_LOG("Renderer:%{public}u will be removed.", sessionId); + if (!allRendererMap_.count(sessionId)) { + AUDIO_WARNING_LOG("Renderer in not in map!"); + return; + } + allRendererMap_.erase(sessionId); +} + +void AudioService::CheckInnerCapForRenderer(uint32_t sessionId, std::shared_ptr renderer) +{ + CHECK_AND_RETURN_LOG(renderer != nullptr, "renderer is null."); + + std::unique_lock lock(rendererMapMutex_); + + // inner-cap not working + if (workingInnerCapId_ == 0) { + return; + } + // in plan: check if meet with the workingConfig_ + if (ShouldBeInnerCap(renderer->processConfig_)) { + filteredRendererMap_.push_back(renderer); + renderer->EnableInnerCap(); // for debug + } +} + +InnerCapFilterPolicy AudioService::GetInnerCapFilterPolicy() +{ + auto usagesSize = workingConfig_.filterOptions.usages.size(); + auto pidsSize = workingConfig_.filterOptions.pids.size(); + if (usagesSize == 0 && pidsSize == 0) { + AUDIO_ERR_LOG("error, invalid usages and pids"); + return POLICY_INVALID; + } + if (usagesSize > 0 && pidsSize == 0) { + AUDIO_INFO_LOG("usages only"); + return POLICY_USAGES_ONLY; + } + return POLICY_USAGES_AND_PIDS; +} + +template +bool isFilterMatched(const std::vector ¶ms, T param, FilterMode mode) +{ + bool isFound = std::count(params.begin(), params.end(), param) != 0; + return (mode == FilterMode::INCLUDE && isFound) || (mode == FilterMode::EXCLUDE && !isFound); +} + +bool AudioService::ShouldBeInnerCap(const AudioProcessConfig &rendererConfig) +{ + bool canBeCaptured = rendererConfig.privacyType == AudioPrivacyType::PRIVACY_TYPE_PUBLIC; + if (!canBeCaptured) { + AUDIO_WARNING_LOG("%{public}d privacy is not public!", rendererConfig.appInfo.appPid); + return false; + } + InnerCapFilterPolicy filterPolicy = GetInnerCapFilterPolicy(); + bool res = false; + switch (filterPolicy) { + case POLICY_INVALID: + return false; + case POLICY_USAGES_ONLY: + res = isFilterMatched(workingConfig_.filterOptions.usages, + rendererConfig.rendererInfo.streamUsage, workingConfig_.filterOptions.usageFilterMode); + break; + case POLICY_USAGES_AND_PIDS: + res = isFilterMatched(workingConfig_.filterOptions.usages, rendererConfig.rendererInfo.streamUsage, + workingConfig_.filterOptions.usageFilterMode) && + isFilterMatched(workingConfig_.filterOptions.pids, rendererConfig.appInfo.appPid, + workingConfig_.filterOptions.pidFilterMode); + break; + default: + break; + } + + AUDIO_INFO_LOG("pid:%{public}d usage:%{public}d result:%{public}s", rendererConfig.appInfo.appPid, + rendererConfig.rendererInfo.streamUsage, res ? "true" : "false"); + return res; +} + +void AudioService::FilterAllFastProcess() +{ + std::unique_lock lock(processListMutex_); + if (linkedPairedList_.size() == 0) { + return; + } + for (auto paired : linkedPairedList_) { + AudioProcessConfig temp = paired.first->processConfig_; + if (temp.audioMode == AUDIO_MODE_PLAYBACK && ShouldBeInnerCap(temp)) { + paired.first->SetInnerCapState(true); + paired.second->EnableFastInnerCap(); + } else { + paired.first->SetInnerCapState(false); + } + } + + for (auto pair : endpointList_) { + if (pair.second->GetDeviceRole() == OUTPUT_DEVICE && !pair.second->ShouldInnerCap()) { + pair.second->DisableFastInnerCap(); + } + } +} + +int32_t AudioService::OnInitInnerCapList() +{ + AUDIO_INFO_LOG("workingInnerCapId_ is %{public}d", workingInnerCapId_); + FilterAllFastProcess(); + std::unique_lock lock(rendererMapMutex_); + for (auto it = allRendererMap_.begin(); it != allRendererMap_.end(); it++) { + std::shared_ptr renderer = it->second.lock(); + if (renderer == nullptr) { + AUDIO_WARNING_LOG("Renderer is already released!"); + continue; + } + if (ShouldBeInnerCap(renderer->processConfig_)) { + renderer->EnableInnerCap(); + filteredRendererMap_.push_back(renderer); + } + } + return SUCCESS; +} + +int32_t AudioService::OnUpdateInnerCapList() +{ + AUDIO_INFO_LOG("workingInnerCapId_ is %{public}d", workingInnerCapId_); + + std::unique_lock lock(rendererMapMutex_); + for (size_t i = 0; i < filteredRendererMap_.size(); i++) { + std::shared_ptr renderer = filteredRendererMap_[i].lock(); + if (renderer == nullptr) { + AUDIO_WARNING_LOG("Renderer is already released!"); + continue; + } + if (!ShouldBeInnerCap(renderer->processConfig_)) { + renderer->DisableInnerCap(); + } + } + filteredRendererMap_.clear(); + lock.unlock(); + // EnableInnerCap will be called twice as it's already in filteredRendererMap_. + return OnInitInnerCapList(); +} + +// Only one session is working at the same time. +int32_t AudioService::OnCapturerFilterChange(uint32_t sessionId, const AudioPlaybackCaptureConfig &newConfig) +{ + Trace trace("AudioService::OnCapturerFilterChange"); + // in plan: + // step 1: if sessionId is not added before, add the sessionId and enbale the filter in allRendererMap_ + // step 2: if sessionId is already in using, this means the config is changed. Check the filtered renderer before, + // call disable inner-cap for those not meet with the new config, than filter all allRendererMap_. + if (workingInnerCapId_ == 0) { + workingInnerCapId_ = sessionId; + workingConfig_ = newConfig; + return OnInitInnerCapList(); + } + + if (workingInnerCapId_ == sessionId) { + workingConfig_ = newConfig; + return OnUpdateInnerCapList(); + } + + AUDIO_WARNING_LOG("%{public}u is working, comming %{public}u will not work!", workingInnerCapId_, sessionId); + return ERR_OPERATION_FAILED; +} + +int32_t AudioService::OnCapturerFilterRemove(uint32_t sessionId) +{ + if (workingInnerCapId_ != sessionId) { + AUDIO_WARNING_LOG("%{public}u is working, remove %{public}u will not work!", workingInnerCapId_, sessionId); + return SUCCESS; + } + workingInnerCapId_ = 0; + workingConfig_ = {}; + + std::unique_lock lockEndpoint(processListMutex_); + for (auto pair : endpointList_) { + if (pair.second->GetDeviceRole() == OUTPUT_DEVICE) { + pair.second->DisableFastInnerCap(); + } + } + lockEndpoint.unlock(); + + std::lock_guard lock(rendererMapMutex_); + for (size_t i = 0; i < filteredRendererMap_.size(); i++) { + std::shared_ptr renderer = filteredRendererMap_[i].lock(); + if (renderer == nullptr) { + AUDIO_WARNING_LOG("Find renderer is already released!"); + continue; + } + renderer->DisableInnerCap(); + } + AUDIO_INFO_LOG("Filter removed, clear %{public}zu filtered renderer.", filteredRendererMap_.size()); + + filteredRendererMap_.clear(); + + return SUCCESS; +} + sptr AudioService::GetAudioProcess(const AudioProcessConfig &config) { + Trace trace("AudioService::GetAudioProcess for " + std::to_string(config.appInfo.appPid)); AUDIO_INFO_LOG("GetAudioProcess dump %{public}s", ProcessConfig::DumpProcessConfig(config).c_str()); DeviceInfo deviceInfo = GetDeviceInfoForProcess(config); std::shared_ptr audioEndpoint = GetAudioEndpointForDevice(deviceInfo, config.streamType); @@ -119,9 +344,26 @@ sptr AudioService::GetAudioProcess(const AudioProcessConfi CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, nullptr, "LinkProcessToEndpoint failed"); linkedPairedList_.push_back(std::make_pair(process, audioEndpoint)); + CheckInnerCapForProcess(process, audioEndpoint); return process; } +void AudioService::CheckInnerCapForProcess(sptr process, std::shared_ptr endpoint) +{ + Trace trace("AudioService::CheckInnerCapForProcess:" + std::to_string(process->processConfig_.appInfo.appPid)); + // inner-cap not working + if (workingInnerCapId_ == 0) { + return; + } + + if (ShouldBeInnerCap(process->processConfig_)) { + process->SetInnerCapState(true); + endpoint->EnableFastInnerCap(); + } else { + process->SetInnerCapState(false); + } +} + int32_t AudioService::NotifyStreamVolumeChanged(AudioStreamType streamType, float volume) { int32_t ret = SUCCESS; @@ -262,6 +504,9 @@ std::shared_ptr AudioService::GetAudioEndpointForDevice(DeviceInf void AudioService::Dump(std::stringstream &dumpStringStream) { AUDIO_INFO_LOG("AudioService dump begin"); + if (workingInnerCapId_ != 0) { + dumpStringStream << "InnerCap filter:" << ProcessConfig::DumpInnerCapConfig(workingConfig_) << std::endl; + } // dump process for (auto paired : linkedPairedList_) { paired.first->Dump(dumpStringStream); diff --git a/services/audio_service/server/src/capturer_in_server.cpp b/services/audio_service/server/src/capturer_in_server.cpp index e206dd3a834dbdfc4dcd50eaae638be49f1b020f..dfd9ecc43a3ecf2bb7f45e4108d7031d7d416616 100644 --- a/services/audio_service/server/src/capturer_in_server.cpp +++ b/services/audio_service/server/src/capturer_in_server.cpp @@ -21,7 +21,9 @@ #include "audio_errors.h" #include "audio_utils.h" #include "audio_log.h" +#include "audio_process_config.h" #include "i_stream_manager.h" +#include "playback_capturer_manager.h" namespace OHOS { namespace AudioStandard { @@ -185,11 +187,8 @@ void CapturerInServer::ReadData(size_t length) std::shared_ptr stateListener = streamListener_.lock(); CHECK_AND_RETURN_LOG(stateListener != nullptr, "IStreamListener is nullptr"); - uint64_t currentReadFrame = audioServerBuffer_->GetCurReadFrame(); uint64_t currentWriteFrame = audioServerBuffer_->GetCurWriteFrame(); - AUDIO_DEBUG_LOG("Current write frame: %{public}" PRIu64 ", read frame: %{public}" PRIu64 "," - "avaliable frame:%{public}d, spanSizeInFrame:%{public}zu", currentWriteFrame, currentReadFrame, - audioServerBuffer_->GetAvailableDataFrames(), spanSizeInFrame_); + if (audioServerBuffer_->GetAvailableDataFrames() <= static_cast(spanSizeInFrame_)) { if (overFlowLogFlag_ == 0) { AUDIO_INFO_LOG("OverFlow!!!"); @@ -199,7 +198,7 @@ void CapturerInServer::ReadData(size_t length) overFlowLogFlag_++; BufferDesc dstBuffer = stream_->DequeueBuffer(length); stream_->EnqueueBuffer(dstBuffer); - stateListener->OnOperationHandled(UPDATE_STREAM, currentReadFrame); + stateListener->OnOperationHandled(UPDATE_STREAM, currentWriteFrame); return; } @@ -213,26 +212,31 @@ void CapturerInServer::ReadData(size_t length) stream_->EnqueueBuffer(srcBuffer); return; } - { - BufferDesc dstBuffer = {nullptr, 0, 0}; - uint64_t curWritePos = audioServerBuffer_->GetCurWriteFrame(); - if (audioServerBuffer_->GetWriteBuffer(curWritePos, dstBuffer) < 0) { - return; - } - ringCache_->Dequeue({dstBuffer.buffer, dstBuffer.bufLength}); - uint64_t nextWriteFrame = currentWriteFrame + spanSizeInFrame_; - AUDIO_DEBUG_LOG("Read data, current write frame: %{public}" PRIu64 ", next write frame: %{public}" PRIu64 "", - currentWriteFrame, nextWriteFrame); - audioServerBuffer_->SetCurWriteFrame(nextWriteFrame); - audioServerBuffer_->SetHandleInfo(currentWriteFrame, ClockTime::GetCurNano()); + BufferDesc dstBuffer = {nullptr, 0, 0}; + uint64_t curWritePos = audioServerBuffer_->GetCurWriteFrame(); + if (audioServerBuffer_->GetWriteBuffer(curWritePos, dstBuffer) < 0) { + return; } + if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE && processConfig_.innerCapMode == + LEGACY_MUTE_CAP) { + dstBuffer.buffer = dischargeBuffer_.get(); // discharge valid data. + } + ringCache_->Dequeue({dstBuffer.buffer, dstBuffer.bufLength}); + + uint64_t nextWriteFrame = currentWriteFrame + spanSizeInFrame_; + AUDIO_DEBUG_LOG("Read data, current write frame: %{public}" PRIu64 ", next write frame: %{public}" PRIu64 "", + currentWriteFrame, nextWriteFrame); + audioServerBuffer_->SetCurWriteFrame(nextWriteFrame); + audioServerBuffer_->SetHandleInfo(currentWriteFrame, ClockTime::GetCurNano()); + stream_->EnqueueBuffer(srcBuffer); - stateListener->OnOperationHandled(UPDATE_STREAM, currentReadFrame); + stateListener->OnOperationHandled(UPDATE_STREAM, currentWriteFrame); } int32_t CapturerInServer::OnReadData(size_t length) { + Trace trace("CapturerInServer::OnReadData:" + std::to_string(length)); ReadData(length); return SUCCESS; } @@ -360,6 +364,68 @@ int32_t CapturerInServer::Release() return ret; } status_ = I_STATUS_RELEASED; + if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE) { + AUDIO_INFO_LOG("Disable inner capturer for %{public}u", streamIndex_); + if (processConfig_.innerCapMode == MODERN_INNER_CAP) { + PlaybackCapturerManager::GetInstance()->RemovePlaybackCapturerFilterInfo(streamIndex_); + } else { + PlaybackCapturerManager::GetInstance()->SetInnerCapturerState(false); + } + } + return SUCCESS; +} + +int32_t CapturerInServer::UpdatePlaybackCaptureConfigInLegacy(const AudioPlaybackCaptureConfig &config) +{ + Trace trace("UpdatePlaybackCaptureConfigInLegacy"); + // Legacy mode, only usage filter works. + AUDIO_INFO_LOG("Update config in legacy mode with %{public}zu usage", config.filterOptions.usages.size()); + + std::vector usage; + for (size_t i = 0; i < config.filterOptions.usages.size(); i++) { + usage.push_back(config.filterOptions.usages[i]); + } + + PlaybackCapturerManager::GetInstance()->SetSupportStreamUsage(usage); + PlaybackCapturerManager::GetInstance()->SetInnerCapturerState(true); + return SUCCESS; +} + +int32_t CapturerInServer::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + Trace trace("UpdatePlaybackCaptureConfig:" + ProcessConfig::DumpInnerCapConfig(config)); + CHECK_AND_RETURN_RET_LOG(processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE, + ERR_INVALID_OPERATION, "This not a inner-cap source!"); + + AUDIO_INFO_LOG("Client using config: %{public}s", ProcessConfig::DumpInnerCapConfig(config).c_str()); + + for (auto &usg : config.filterOptions.usages) { + if (usg != STREAM_USAGE_VOICE_COMMUNICATION) { + continue; + } + + if (!PermissionUtil::VerifyPermission(CAPTURER_VOICE_DOWNLINK_PERMISSION, processConfig_.appInfo.appTokenId)) { + AUDIO_ERR_LOG("downlink capturer permission check failed"); + return ERR_PERMISSION_DENIED; + } + } + + filterConfig_ = config; + + if (filterConfig_.filterOptions.usages.size() == 0) { + std::vector defalutUsages = PlaybackCapturerManager::GetInstance()->GetDefaultUsages(); + for (size_t i = 0; i < defalutUsages.size(); i++) { + filterConfig_.filterOptions.usages.push_back(defalutUsages[i]); + } + AUDIO_INFO_LOG("Reset config to %{public}s", ProcessConfig::DumpInnerCapConfig(filterConfig_).c_str()); + } + + if (processConfig_.innerCapMode != MODERN_INNER_CAP) { + return UpdatePlaybackCaptureConfigInLegacy(filterConfig_); + } + + // in plan: add more check and print config + PlaybackCapturerManager::GetInstance()->SetPlaybackCapturerFilterInfo(streamIndex_, filterConfig_); return SUCCESS; } @@ -383,11 +449,6 @@ int32_t CapturerInServer::GetLatency(uint64_t &latency) return stream_->GetLatency(latency); } -void CapturerInServer::RegisterTestCallback(const std::weak_ptr &callback) -{ - testCallback_ = callback; -} - int32_t CapturerInServer::InitCacheBuffer(size_t targetSize) { CHECK_AND_RETURN_RET_LOG(spanSizeInBytes_ != 0, ERR_OPERATION_FAILED, "spanSizeInByte_ invalid"); @@ -405,6 +466,11 @@ int32_t CapturerInServer::InitCacheBuffer(size_t targetSize) } } + if (processConfig_.capturerInfo.sourceType == SOURCE_TYPE_PLAYBACK_CAPTURE && processConfig_.innerCapMode == + LEGACY_MUTE_CAP) { + dischargeBuffer_ = std::make_unique(cacheSizeInBytes_); + } + return SUCCESS; } } // namespace AudioStandard diff --git a/services/audio_service/server/src/i_stream_manager.cpp b/services/audio_service/server/src/i_stream_manager.cpp index 6d90739a614b51e1272dd764b2018494512de934..0e182accf14fabf4cf686645c5f51f9f6f8297b2 100644 --- a/services/audio_service/server/src/i_stream_manager.cpp +++ b/services/audio_service/server/src/i_stream_manager.cpp @@ -23,6 +23,12 @@ IStreamManager &IStreamManager::GetPlaybackManager() return adapterManager; } +IStreamManager &IStreamManager::GetDupPlaybackManager() +{ + static PaAdapterManager adapterManager(DUP_PLAYBACK); + return adapterManager; +} + IStreamManager &IStreamManager::GetRecorderManager() { static PaAdapterManager adapterManager(RECORDER); diff --git a/services/audio_service/server/src/ipc_stream_in_server.cpp b/services/audio_service/server/src/ipc_stream_in_server.cpp index 06af1ce7a9ac743c810a185879faae895f5c6dae..76a82ad41d1b2cd62dc78d8be75acd185c811685 100644 --- a/services/audio_service/server/src/ipc_stream_in_server.cpp +++ b/services/audio_service/server/src/ipc_stream_in_server.cpp @@ -89,6 +89,16 @@ int32_t IpcStreamInServer::Config() return ERR_OPERATION_FAILED; } +std::shared_ptr IpcStreamInServer::GetRenderer() +{ + if (mode_ != AUDIO_MODE_PLAYBACK || rendererInServer_ == nullptr) { + AUDIO_ERR_LOG("GetRenderer failed, mode is %{public}s", (mode_ != AUDIO_MODE_PLAYBACK ? " not playback" : + "playback, but renderer is null!")); + return nullptr; + } + return rendererInServer_; +} + int32_t IpcStreamInServer::ConfigRenderer() { rendererInServer_ = std::make_shared(config_, streamListenerHolder_); @@ -228,6 +238,15 @@ int32_t IpcStreamInServer::Drain() return ERR_OPERATION_FAILED; } +int32_t IpcStreamInServer::UpdatePlaybackCaptureConfig(const AudioPlaybackCaptureConfig &config) +{ + if (mode_ == AUDIO_MODE_RECORD && capturerInServer_ != nullptr) { + return capturerInServer_->UpdatePlaybackCaptureConfig(config); + } + AUDIO_ERR_LOG("Failed, invalid mode: %{public}d", static_cast(mode_)); + return ERR_OPERATION_FAILED; +} + int32_t IpcStreamInServer::GetAudioTime(uint64_t &framePos, uint64_t ×tamp) { if (mode_ == AUDIO_MODE_PLAYBACK && rendererInServer_ != nullptr) { diff --git a/services/audio_service/server/src/ipc_stream_stub.cpp b/services/audio_service/server/src/ipc_stream_stub.cpp index 6b717a9f545c69ed2893faddb07fd0df9402426e..6678e3a6ca09cbf964cf34b2125983540dded54f 100644 --- a/services/audio_service/server/src/ipc_stream_stub.cpp +++ b/services/audio_service/server/src/ipc_stream_stub.cpp @@ -18,6 +18,7 @@ #include "ipc_stream_stub.h" #include "audio_log.h" #include "audio_errors.h" +#include "audio_process_config.h" namespace OHOS { namespace AudioStandard { @@ -130,6 +131,17 @@ int32_t IpcStreamStub::HandleDrain(MessageParcel &data, MessageParcel &reply) return AUDIO_OK; } +int32_t IpcStreamStub::HandleUpdatePlaybackCaptureConfig(MessageParcel &data, MessageParcel &reply) +{ + AudioPlaybackCaptureConfig config; + int32_t ret = ProcessConfig::ReadInnerCapConfigFromParcel(config, data); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, AUDIO_ERR, "Read config failed"); + + reply.WriteInt32(UpdatePlaybackCaptureConfig(config)); + + return AUDIO_OK; +} + int32_t IpcStreamStub::HandleGetAudioTime(MessageParcel &data, MessageParcel &reply) { (void)data; diff --git a/services/audio_service/server/src/pa_adapter_manager.cpp b/services/audio_service/server/src/pa_adapter_manager.cpp index f51c2125909e11184e2e967a96ecc7f0834e08f5..9619f29b4b2984c8377c9ae504dd0ccde83f2de6 100644 --- a/services/audio_service/server/src/pa_adapter_manager.cpp +++ b/services/audio_service/server/src/pa_adapter_manager.cpp @@ -80,7 +80,7 @@ static bool IsEnhanceMode(SourceType sourceType) PaAdapterManager::PaAdapterManager(ManagerType type) { - AUDIO_DEBUG_LOG("Constructor PaAdapterManager"); + AUDIO_INFO_LOG("Constructor with type:%{public}d", type); mainLoop_ = nullptr; api_ = nullptr; context_ = nullptr; @@ -137,6 +137,7 @@ int32_t PaAdapterManager::ReleaseRender(uint32_t streamIndex) int32_t PaAdapterManager::CreateCapturer(AudioProcessConfig processConfig, std::shared_ptr &stream) { AUDIO_DEBUG_LOG("Create capturer start"); + CHECK_AND_RETURN_RET_LOG(managerType_ == RECORDER, ERROR, "Invalid managerType:%{public}d", managerType_); int32_t ret = InitPaContext(); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Failed to init pa context"); @@ -212,8 +213,12 @@ int32_t PaAdapterManager::InitPaContext() api_ = pa_threaded_mainloop_get_api(mainLoop_); if (managerType_ == PLAYBACK) { pa_threaded_mainloop_set_name(mainLoop_, "OS_RendererML"); - } else { + } else if (managerType_ == DUP_PLAYBACK) { + pa_threaded_mainloop_set_name(mainLoop_, "OS_DRendererML"); + } else if (managerType_ == RECORDER) { pa_threaded_mainloop_set_name(mainLoop_, "OS_CapturerML"); + } else { + AUDIO_ERR_LOG("Not supported managerType:%{public}d", managerType_); } if (api_ == nullptr) { pa_threaded_mainloop_free(mainLoop_); @@ -292,8 +297,14 @@ int32_t PaAdapterManager::GetDeviceNameForConnect(AudioProcessConfig processConf if (no < WAKEUP_LIMIT) { deviceName = WAKEUP_NAMES[no]; } - } else if (processConfig.isInnerCapturer) { - deviceName = INNER_CAPTURER_SOURCE; + } + if (processConfig.isInnerCapturer) { + if (processConfig.innerCapMode == MODERN_INNER_CAP) { + AUDIO_INFO_LOG("Create the modern inner-cap."); + deviceName = NEW_INNER_CAPTURER_SOURCE; + } else { + deviceName = INNER_CAPTURER_SOURCE; + } } else if (processConfig.capturerInfo.sourceType == SOURCE_TYPE_REMOTE_CAST) { deviceName = REMOTE_CAST_INNER_CAPTURER_SINK_NAME + MONITOR_SOURCE_SUFFIX; } @@ -421,9 +432,11 @@ int32_t PaAdapterManager::SetPaProplist(pa_proplist *propList, pa_channel_map &m pa_proplist_sets(propList, "stream.startTime", streamStartTime.c_str()); if (processConfig.audioMode == AUDIO_MODE_PLAYBACK) { + // mark dup stream for dismissing volume handle + pa_proplist_sets(propList, "stream.mode", managerType_ == DUP_PLAYBACK ? DUP_STREAM.c_str() : + NORMAL_STREAM.c_str()); pa_proplist_sets(propList, "stream.flush", "false"); - AudioPrivacyType privacyType = processConfig.privacyType; - pa_proplist_sets(propList, "stream.privacyType", std::to_string(privacyType).c_str()); + pa_proplist_sets(propList, "stream.privacyType", std::to_string(processConfig.privacyType).c_str()); pa_proplist_sets(propList, "stream.usage", std::to_string(processConfig.rendererInfo.streamUsage).c_str()); pa_proplist_sets(propList, "scene.type", processConfig.rendererInfo.sceneType.c_str()); pa_proplist_sets(propList, "spatialization.enabled", @@ -490,10 +503,11 @@ int32_t PaAdapterManager::ConnectStreamToPA(pa_stream *paStream, pa_sample_spec PaLockGuard lock(mainLoop_); int32_t XcollieFlag = 0; // flag 0 do nothing but the caller defined function - if (managerType_ == PLAYBACK) { + if (managerType_ == PLAYBACK || managerType_ == DUP_PLAYBACK) { int32_t rendererRet = ConnectRendererStreamToPA(paStream, sampleSpec); CHECK_AND_RETURN_RET_LOG(rendererRet == SUCCESS, rendererRet, "ConnectRendererStreamToPA failed"); - } else { + } + if (managerType_ == RECORDER) { XcollieFlag = 2; // flag 2 die when timeout, restart server int32_t capturerRet = ConnectCapturerStreamToPA(paStream, sampleSpec, deviceName); CHECK_AND_RETURN_RET_LOG(capturerRet == SUCCESS, capturerRet, "ConnectCapturerStreamToPA failed"); @@ -526,19 +540,27 @@ int32_t PaAdapterManager::ConnectRendererStreamToPA(pa_stream *paStream, pa_samp uint32_t maxlength = 4; // 4 is max buffer length of playback uint32_t prebuf = 1; // 1 is prebuf of playback - AUDIO_INFO_LOG("Create ipc playback stream tlength: %{public}u, maxlength: %{public}u", tlength, maxlength); + if (managerType_ == DUP_PLAYBACK) { + maxlength = 8; // 8 is double of normal + prebuf = 2; // 2 is double of normal, use more prebuf for dup stream + } + AUDIO_INFO_LOG("Create ipc playback stream tlength: %{public}u, maxlength: %{public}u prebuf: %{public}u", tlength, + maxlength, prebuf); pa_buffer_attr bufferAttr; bufferAttr.fragsize = static_cast(-1); bufferAttr.prebuf = pa_usec_to_bytes(BUF_LENGTH_IN_MSEC * PA_USEC_PER_MSEC * prebuf, &sampleSpec); bufferAttr.maxlength = pa_usec_to_bytes(BUF_LENGTH_IN_MSEC * PA_USEC_PER_MSEC * maxlength, &sampleSpec); bufferAttr.tlength = pa_usec_to_bytes(BUF_LENGTH_IN_MSEC * PA_USEC_PER_MSEC * tlength, &sampleSpec); bufferAttr.minreq = pa_usec_to_bytes(BUF_LENGTH_IN_MSEC * PA_USEC_PER_MSEC, &sampleSpec); - AUDIO_INFO_LOG("bufferAttr, maxLength: %{public}u, tlength: %{public}u, prebuf: %{public}u", - maxlength, tlength, prebuf); - int32_t result = pa_stream_connect_playback(paStream, nullptr, &bufferAttr, - (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_START_CORKED | - PA_STREAM_VARIABLE_RATE), nullptr, nullptr); + const char *sinkName = managerType_ == DUP_PLAYBACK ? INNER_CAPTURER_SINK.c_str() : nullptr; + int flags = PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_START_CORKED | + PA_STREAM_VARIABLE_RATE; + if (managerType_ == DUP_PLAYBACK) { + flags |= PA_STREAM_DONT_MOVE; // should not move dup streams + } + int32_t result = pa_stream_connect_playback(paStream, sinkName, &bufferAttr, static_cast(flags), + nullptr, nullptr); if (result < 0) { int32_t error = pa_context_errno(context_); AUDIO_ERR_LOG("connection to stream error: %{public}d", error); diff --git a/services/audio_service/server/src/pa_capturer_stream_impl.cpp b/services/audio_service/server/src/pa_capturer_stream_impl.cpp index de7b3771e97aa892c771d5dc7c64f196d84aa8e1..f0441c9a438c37dd21eccbe571ced4613c1ad77f 100644 --- a/services/audio_service/server/src/pa_capturer_stream_impl.cpp +++ b/services/audio_service/server/src/pa_capturer_stream_impl.cpp @@ -20,6 +20,7 @@ #include "pa_adapter_tools.h" #include "audio_errors.h" #include "audio_log.h" +#include "audio_utils.h" #include "policy_handler.h" namespace OHOS { @@ -333,8 +334,8 @@ int32_t PaCapturerStreamImpl::DropBuffer() void PaCapturerStreamImpl::PAStreamReadCb(pa_stream *stream, size_t length, void *userdata) { - AUDIO_DEBUG_LOG("PAStreamReadCb, length size: %{public}zu, pa_stream_readable_size: %{public}zu", - length, pa_stream_readable_size(stream)); + Trace trace("PaCapturerStreamImpl::PAStreamReadCb:length " + std::to_string(length) + " readable:" + + std::to_string(pa_stream_readable_size(stream))); if (!userdata) { AUDIO_ERR_LOG("PAStreamReadCb: userdata is null"); diff --git a/services/audio_service/server/src/renderer_in_server.cpp b/services/audio_service/server/src/renderer_in_server.cpp index 8d208cc13bea9f5a976e09e8d624de2e5ac9d956..9d4d1ecbbc759ab8b08a042cec32a23f14041329 100644 --- a/services/audio_service/server/src/renderer_in_server.cpp +++ b/services/audio_service/server/src/renderer_in_server.cpp @@ -21,6 +21,7 @@ #include "audio_errors.h" #include "audio_log.h" #include "audio_utils.h" +#include "audio_service.h" #include "i_stream_manager.h" namespace OHOS { @@ -32,8 +33,8 @@ namespace { } RendererInServer::RendererInServer(AudioProcessConfig processConfig, std::weak_ptr streamListener) + : processConfig_(processConfig) { - processConfig_ = processConfig; streamListener_ = streamListener; } @@ -247,6 +248,13 @@ int32_t RendererInServer::WriteData() DumpFileUtil::WriteDumpFile(dumpC2S_, static_cast(bufferDesc.buffer), bufferDesc.bufLength); uint64_t nextReadFrame = currentReadFrame + spanSizeInFrame_; audioServerBuffer_->SetCurReadFrame(nextReadFrame); + if (isInnerCapEnabled_) { + Trace traceDup("RendererInServer::WriteData DupSteam write"); + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->EnqueueBuffer(bufferDesc); // what if enqueue fail? + } + } memset_s(bufferDesc.buffer, bufferDesc.bufLength, 0, bufferDesc.bufLength); // clear is needed for reuse. } else { Trace trace3("RendererInServer::WriteData GetReadbuffer failed"); @@ -350,6 +358,13 @@ int32_t RendererInServer::Start() audioServerBuffer_->SetHandleInfo(currentReadFrame, tempTime); AUDIO_INFO_LOG("Server update position %{public}" PRIu64" time%{public} " PRId64".", currentReadFrame, tempTime); resetTime_ = true; + + if (isInnerCapEnabled_) { + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Start(); + } + } return SUCCESS; } @@ -363,6 +378,12 @@ int32_t RendererInServer::Pause() } status_ = I_STATUS_PAUSING; int ret = stream_->Pause(); + if (isInnerCapEnabled_) { + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Pause(); + } + } CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Pause stream failed, reason: %{public}d", ret); return SUCCESS; } @@ -401,6 +422,12 @@ int32_t RendererInServer::Flush() int ret = stream_->Flush(); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Flush stream failed, reason: %{public}d", ret); + if (isInnerCapEnabled_) { + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Flush(); + } + } return SUCCESS; } @@ -429,6 +456,12 @@ int32_t RendererInServer::Drain() DrainAudioBuffer(); int ret = stream_->Drain(); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Drain stream failed, reason: %{public}d", ret); + if (isInnerCapEnabled_) { + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Drain(); + } + } return SUCCESS; } @@ -444,12 +477,19 @@ int32_t RendererInServer::Stop() status_ = I_STATUS_STOPPING; } int ret = stream_->Stop(); + if (isInnerCapEnabled_) { + std::lock_guard lock(dupMutex_); + if (dupStream_ != nullptr) { + dupStream_->Stop(); + } + } CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "Stop stream failed, reason: %{public}d", ret); return SUCCESS; } int32_t RendererInServer::Release() { + AudioService::GetInstance()->RemoveRenderer(streamIndex_); { std::unique_lock lock(statusLock_); if (status_ == I_STATUS_RELEASED) { @@ -464,6 +504,11 @@ int32_t RendererInServer::Release() return ret; } status_ = I_STATUS_RELEASED; + + if (isInnerCapEnabled_) { + DisableInnerCap(); + } + return SUCCESS; } @@ -532,6 +577,72 @@ int32_t RendererInServer::GetPrivacyType(int32_t &privacyType) return stream_->GetPrivacyType(privacyType); } +int32_t RendererInServer::EnableInnerCap() +{ + // in plan + if (isInnerCapEnabled_) { + AUDIO_INFO_LOG("InnerCap is already enabled"); + return SUCCESS; + } + int32_t ret = InitDupStream(); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "Init dup stream failed"); + return SUCCESS; +} + +int32_t RendererInServer::DisableInnerCap() +{ + std::lock_guard lock(dupMutex_); + if (!isInnerCapEnabled_) { + AUDIO_WARNING_LOG("InnerCap is already disabled."); + return ERR_INVALID_OPERATION; + } + isInnerCapEnabled_ = false; + AUDIO_INFO_LOG("Disable dup renderer %{public}u with status: %{public}d", streamIndex_, status_); + // in plan: call stop? + IStreamManager::GetDupPlaybackManager().ReleaseRender(dupStreamIndex_); + dupStream_ = nullptr; + + return ERROR; +} + +int32_t RendererInServer::InitDupStream() +{ + std::lock_guard lock(dupMutex_); + int32_t ret = IStreamManager::GetDupPlaybackManager().CreateRender(processConfig_, dupStream_); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS && dupStream_ != nullptr, ERR_OPERATION_FAILED, "Failed: %{public}d", ret); + dupStreamIndex_ = dupStream_->GetStreamIndex(); + + dupStreamCallback_ = std::make_shared(dupStreamIndex_); + dupStream_->RegisterStatusCallback(dupStreamCallback_); + dupStream_->RegisterWriteCallback(dupStreamCallback_); + + AUDIO_INFO_LOG("Dup Renderer %{public}u with status: %{public}d", streamIndex_, status_); + + isInnerCapEnabled_ = true; + + if (status_ == I_STATUS_STARTED) { + AUDIO_INFO_LOG("Renderer %{public}u is already running, let's start the dup stream", streamIndex_); + dupStream_->Start(); + } + return SUCCESS; +} + +StreamCallbacks::StreamCallbacks(uint32_t streamIndex) : streamIndex_(streamIndex) +{ + AUDIO_INFO_LOG("DupStream %{public}u create StreamCallbacks", streamIndex_); +} + +void StreamCallbacks::OnStatusUpdate(IOperation operation) +{ + AUDIO_INFO_LOG("DupStream %{public}u recv operation: %{public}d", streamIndex_, operation); +} + +int32_t StreamCallbacks::OnWriteData(size_t length) +{ + Trace trace("DupStream::OnWriteData length " + std::to_string(length)); + return SUCCESS; +} + int32_t RendererInServer::SetOffloadMode(int32_t state, bool isAppBack) { return stream_->SetOffloadMode(state, isAppBack); diff --git a/services/audio_service/test/unittest/audio_service_common_unit_test.cpp b/services/audio_service/test/unittest/audio_service_common_unit_test.cpp index a63a5256818ac72cf61ecfe64f497bc5054beabb..098b7b802a44f2d36ee9277f14d778d88adbb8b3 100644 --- a/services/audio_service/test/unittest/audio_service_common_unit_test.cpp +++ b/services/audio_service/test/unittest/audio_service_common_unit_test.cpp @@ -17,6 +17,7 @@ #include "audio_log.h" #include "audio_info.h" #include "audio_ring_cache.h" +#include "audio_process_config.h" #include "linear_pos_time_model.h" #include "oh_audio_buffer.h" #include @@ -58,6 +59,19 @@ void AudioServiceCommonUnitTest::TearDown(void) // input testcase teardown step,teardown invoked after each testcases } +/** + * @tc.name : Test ProcessConfig API + * @tc.type : FUNC + * @tc.number: ProcessConfigTest_001 + * @tc.desc : Test ProcessConfig test. + */ +HWTEST(AudioServiceCommonUnitTest, ProcessConfigTest_001, TestSize.Level1) +{ + AudioPlaybackCaptureConfig config = {{{STREAM_USAGE_MUSIC}, FilterMode::INCLUDE, {0}, FilterMode::INCLUDE}, false}; + std::string dumpStr = ProcessConfig::DumpInnerCapConfig(config); + EXPECT_NE(dumpStr, ""); +} + /** * @tc.name : Test LinearPosTimeModel API * @tc.type : FUNC