diff --git a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h index 39cecf0fc068cedaf59afb1459dfd938779dcfc2..09497ecbc4323443d166c1eb3b2aa7af56a6c11e 100644 --- a/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h +++ b/frameworks/innerkitsimpl/audiorenderer/include/audio_renderer_private.h @@ -37,6 +37,8 @@ public: bool Flush() const override; bool Release() const override; int32_t GetBufferSize(size_t &bufferSize) const override; + int32_t SetVolume(float volume) const override; + float GetVolume() const override; std::unique_ptr audioRenderer; diff --git a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp index df37e8ca5352bc0455014b3b94c9787ef9786bc5..02deadf3983d0ea02258fa18a705535a46ba2f2f 100644 --- a/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp +++ b/frameworks/innerkitsimpl/audiorenderer/src/audio_renderer.cpp @@ -120,6 +120,16 @@ int32_t AudioRendererPrivate::GetBufferSize(size_t &bufferSize) const return audioRenderer->GetBufferSize(bufferSize); } +int32_t AudioRendererPrivate::SetVolume(float volume) const +{ + return audioRenderer->SetVolume(volume); +} + +float AudioRendererPrivate::GetVolume() const +{ + return audioRenderer->GetVolume(); +} + std::vector AudioRenderer::GetSupportedFormats() { return AUDIO_SUPPORTED_FORMATS; diff --git a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h index d2a2fd1f2f951b84568e38550b5b5c1bab91ee77..0a57e8956ebb65163e668732e26ab6bde2d0becd 100644 --- a/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h +++ b/interfaces/innerkits/native/audiomanager/include/audio_system_manager.h @@ -144,6 +144,8 @@ enum AudioVolumeType { STREAM_ACCESSIBILITY = 10 }; static AudioSystemManager* GetInstance(); + static float MapVolumeToHDI(int32_t volume); + static int32_t MapVolumeFromHDI(float volume); int32_t SetVolume(AudioSystemManager::AudioVolumeType volumeType, int32_t volume) const; int32_t GetVolume(AudioSystemManager::AudioVolumeType volumeType) const; int32_t GetMaxVolume(AudioSystemManager::AudioVolumeType volumeType) const; @@ -164,8 +166,6 @@ private: AudioSystemManager(); virtual ~AudioSystemManager(); void init(); - float MapVolumeToHDI(int32_t volume) const; - int32_t MapVolumeFromHDI(float volume) const; static constexpr int32_t MAX_VOLUME_LEVEL = 15; static constexpr int32_t MIN_VOLUME_LEVEL = 0; static constexpr int32_t CONST_FACTOR = 100; diff --git a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h index 649f795212d17e2412d98ebb5bd5bd862e0fc110..899d604e6eb644498c5cd63f3b68162480079c58 100644 --- a/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h +++ b/interfaces/innerkits/native/audiorenderer/include/audio_renderer.h @@ -194,6 +194,22 @@ public: */ virtual int32_t GetBufferSize(size_t &bufferSize) const = 0; + /** + * @brief Set the track volume + * + * @param volume The volume to be set for the current track. + * @return Returns {@link SUCCESS} if volume is successfully set; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + virtual int32_t SetVolume(float volume) const = 0; + + /** + * @brief Obtains the current track volume + * + * @return Returns current track volume + */ + virtual float GetVolume() const = 0; + /** * @brief Obtains the foramts supported by renderer. * diff --git a/interfaces/innerkits/native/audiostream/include/audio_stream.h b/interfaces/innerkits/native/audiostream/include/audio_stream.h index a84edc539a72c08555e956aa1ace1d66a392a110..0f97407bf8d6c44df1f2e7bed2f91f0913a70e57 100644 --- a/interfaces/innerkits/native/audiostream/include/audio_stream.h +++ b/interfaces/innerkits/native/audiostream/include/audio_stream.h @@ -62,6 +62,8 @@ public: int32_t GetBufferSize(size_t &bufferSize); int32_t GetFrameCount(uint32_t &frameCount); int32_t GetLatency(uint64_t &latency); + int32_t SetVolume(float volume); + float GetVolume(); std::vector GetSupportedFormats(); std::vector GetSupportedChannels(); diff --git a/services/include/client/audio_service_client.h b/services/include/client/audio_service_client.h index a51c7ab91d1e7184e0480ba07b8727e5c56beac8..20dda2af1201eda15a3e23db35e822fa8ba9cdb7 100644 --- a/services/include/client/audio_service_client.h +++ b/services/include/client/audio_service_client.h @@ -26,6 +26,8 @@ #include #include +#include "audio_system_manager.h" + namespace OHOS { namespace AudioStandard { enum ASClientType { @@ -266,6 +268,22 @@ public: */ void RegisterAudioCapturerCallbacks(const AudioCapturerCallbacks &cb); + /** + * @brief Set the track volume + * + * @param volume The volume to be set for the current track. + * @return Returns {@link SUCCESS} if volume is successfully set; returns an error code + * defined in {@link audio_errors.h} otherwise. + */ + int32_t SetStreamVolume(float volume); + + /** + * @brief Obtains the current track volume + * + * @return Returns current track volume + */ + float GetStreamVolume(); + private: pa_threaded_mainloop *mainLoop; pa_mainloop_api *api; @@ -284,6 +302,10 @@ private: bool isContextConnected; bool isStreamConnected; + float mVolumeFactor; + AudioStreamType mStreamType; + AudioSystemManager *mAudioSystemMgr; + // To be set while using audio stream // functionality for callbacks AudioRendererCallbacks* mAudioRendererCallbacks; @@ -329,6 +351,9 @@ private: static pa_sample_spec ConvertToPAAudioParams(AudioStreamParams audioParams); static AudioStreamParams ConvertFromPAAudioParams(pa_sample_spec paSampleSpec); + static constexpr float MAX_STREAM_VOLUME_LEVEL = 1.0f; + static constexpr float MIN_STREAM_VOLUME_LEVEL = 0.0f; + // Resets PA audio client and free up resources if any with this API void ResetPAAudioClient(); @@ -339,6 +364,8 @@ private: static void PAStreamRequestCb(pa_stream *stream, size_t length, void *userdata); static void PAStreamCmdSuccessCb(pa_stream *stream, int32_t success, void *userdata); static void PAStreamLatencyUpdateCb(pa_stream *stream, void *userdata); + + static void GetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp index a9d2616428c772903f9be7efe988bb0a2216a813..3d2b01cdede6f6a9583bd385935fe4779226d078 100644 --- a/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp +++ b/services/src/audio_policy/server/service/src/manager/pulseaudio_policy_manager.cpp @@ -786,15 +786,17 @@ void PulseAudioPolicyManager::GetSinkInputInfoVolumeCb(pa_context *c, const pa_s } const char *streamtype = pa_proplist_gets(i->proplist, "stream.type"); - if (streamtype == NULL) { + const char *streamVolume = pa_proplist_gets(i->proplist, "stream.volumeFactor"); + if ((streamtype == NULL) || (streamVolume == NULL)) { MEDIA_ERR_LOG("[PolicyManager] Invalid StreamType."); return; } std::string streamType(streamtype); + float volumeFactor = std::atof(streamVolume); AudioStreamType streamID = thiz->GetStreamIDByType(streamType); - float vol = thiz->mVolumeMap[streamID]; + float vol = thiz->mVolumeMap[streamID] * volumeFactor; if (thiz->mRingerMode != RINGER_MODE_NORMAL) { if (!streamType.compare("ring")) { diff --git a/services/src/client/audio_service_client.cpp b/services/src/client/audio_service_client.cpp index e0a1048ce5f8064025e0e38d1e43549cd345f395..283220a51f58b0f1f067b7fb192245512cf0886a 100644 --- a/services/src/client/audio_service_client.cpp +++ b/services/src/client/audio_service_client.cpp @@ -201,6 +201,10 @@ AudioServiceClient::AudioServiceClient() sourceOutputs.clear(); clientInfo.clear(); + mVolumeFactor = 1.0f; + mStreamType = STREAM_MUSIC; + mAudioSystemMgr = NULL; + mAudioRendererCallbacks = NULL; mAudioCapturerCallbacks = NULL; internalReadBuffer = NULL; @@ -311,6 +315,8 @@ int32_t AudioServiceClient::Initialize(ASClientType eClientType) return AUDIO_CLIENT_INIT_ERR; } + mAudioSystemMgr = AudioSystemManager::GetInstance(); + isContextConnected = true; pa_threaded_mainloop_lock(mainLoop); @@ -473,6 +479,7 @@ int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStr } pa_threaded_mainloop_lock(mainLoop); + mStreamType = audioType; const std::string streamName = GetStreamName(audioType); sampleSpec = ConvertToPAAudioParams(audioParams); @@ -485,6 +492,7 @@ int32_t AudioServiceClient::CreateStream(AudioStreamParams audioParams, AudioStr } pa_proplist_sets(propList, "stream.type", streamName.c_str()); + pa_proplist_sets(propList, "stream.volumeFactor", std::to_string(mVolumeFactor).c_str()); if (!(paStream = pa_stream_new_with_proplist(context, streamName.c_str(), &sampleSpec, NULL, propList))) { error = pa_context_errno(context); @@ -1082,5 +1090,101 @@ void AudioServiceClient::RegisterAudioCapturerCallbacks(const AudioCapturerCallb MEDIA_INFO_LOG("Registering audio record callbacks"); mAudioCapturerCallbacks = (AudioCapturerCallbacks *) &cb; } + +int32_t AudioServiceClient::SetStreamVolume(float volume) +{ + MEDIA_INFO_LOG("SetVolume volume: %{public}f", volume); + + if (context == NULL) { + MEDIA_ERR_LOG("context is null"); + return AUDIO_CLIENT_ERR; + } + + /* Validate and return INVALID_PARAMS error */ + if ((volume < MIN_STREAM_VOLUME_LEVEL) || (volume > MAX_STREAM_VOLUME_LEVEL)) { + MEDIA_ERR_LOG("Invalid Volume Input!"); + return AUDIO_CLIENT_INVALID_PARAMS_ERR; + } + + mVolumeFactor = volume; + pa_proplist *propList = pa_proplist_new(); + if (propList == NULL) { + MEDIA_ERR_LOG("pa_proplist_new failed"); + return AUDIO_CLIENT_ERR; + } + + pa_proplist_sets(propList, "stream.volumeFactor", std::to_string(mVolumeFactor).c_str()); + pa_operation *updatePropOperation = pa_stream_proplist_update(paStream, PA_UPDATE_REPLACE, propList, NULL, NULL); + while (pa_operation_get_state(updatePropOperation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + pa_proplist_free(propList); + pa_operation_unref(updatePropOperation); + + pa_threaded_mainloop_lock(mainLoop); + uint32_t idx = pa_stream_get_index(paStream); + pa_operation *operation = pa_context_get_sink_input_info(context, idx, AudioServiceClient::GetSinkInputInfoVolumeCb, + reinterpret_cast(this)); + if (operation == NULL) { + MEDIA_ERR_LOG("pa_context_get_sink_input_info_list returned null"); + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_ERR; + } + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { + pa_threaded_mainloop_wait(mainLoop); + } + + pa_operation_unref(operation); + pa_threaded_mainloop_unlock(mainLoop); + + return AUDIO_CLIENT_SUCCESS; +} + +float AudioServiceClient::GetStreamVolume() +{ + return mVolumeFactor; +} + +void AudioServiceClient::GetSinkInputInfoVolumeCb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) +{ + MEDIA_INFO_LOG("GetSinkInputInfoVolumeCb in"); + AudioServiceClient *thiz = reinterpret_cast(userdata); + + if (eol < 0) { + MEDIA_ERR_LOG("Failed to get sink input information: %s", pa_strerror(pa_context_errno(c))); + return; + } + + if (eol) { + pa_threaded_mainloop_signal(thiz->mainLoop, 0); + return; + } + + if (i->proplist == NULL) { + MEDIA_ERR_LOG("Invalid prop list for sink input (%{public}d).", i->index); + return; + } + + if (thiz->mAudioSystemMgr == NULL) { + MEDIA_ERR_LOG("System manager instance is null"); + return; + } + + pa_cvolume cv = i->volume; + int32_t systemVolumeInt + = thiz->mAudioSystemMgr->GetVolume(static_cast(thiz->mStreamType)); + float systemVolume = AudioSystemManager::MapVolumeToHDI(systemVolumeInt); + + float vol = systemVolume * thiz->mVolumeFactor; + int32_t volume = pa_sw_volume_from_linear(vol); + pa_cvolume_set(&cv, i->channel_map.channels, volume); + pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &cv, NULL, NULL)); + + MEDIA_INFO_LOG("Applied volume : %{public}f for stream : %{public}s, volumeInt%{public}d", + vol, i->name, volume); + + return; +} } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/client/audio_stream.cpp b/services/src/client/audio_stream.cpp index 8627146b5445c21a936e8b6be747d3cc6f243ded..0e1ef1f53d8393299ca2ebbcbb94344323b28c2c 100644 --- a/services/src/client/audio_stream.cpp +++ b/services/src/client/audio_stream.cpp @@ -374,5 +374,15 @@ bool AudioStream::ReleaseAudioStream() return true; } + +int32_t AudioStream::SetVolume(float volume) +{ + return SetStreamVolume(volume); +} + +float AudioStream::GetVolume() +{ + return GetStreamVolume(); +} } } diff --git a/services/src/client/audio_system_manager.cpp b/services/src/client/audio_system_manager.cpp index b2ee6c388db2790d1438966fc819a26467cd89dc..d63d8fe1da51d7888c56bf1dc4768fcd88d43bf8 100644 --- a/services/src/client/audio_system_manager.cpp +++ b/services/src/client/audio_system_manager.cpp @@ -178,7 +178,7 @@ int32_t AudioSystemManager::GetVolume(AudioSystemManager::AudioVolumeType volume return MapVolumeFromHDI(volumeFromHdi); } -float AudioSystemManager::MapVolumeToHDI(int32_t volume) const +float AudioSystemManager::MapVolumeToHDI(int32_t volume) { float value = (float)volume / MAX_VOLUME_LEVEL; float roundValue = (int)(value * CONST_FACTOR); @@ -186,7 +186,7 @@ float AudioSystemManager::MapVolumeToHDI(int32_t volume) const return (float)roundValue / CONST_FACTOR; } -int32_t AudioSystemManager::MapVolumeFromHDI(float volume) const +int32_t AudioSystemManager::MapVolumeFromHDI(float volume) { float value = (float)volume * MAX_VOLUME_LEVEL; return nearbyint(value); diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 9deecb7c9cb7cd36371bcfe92902b0ec073e23d4..95639db72922df86ab198f75579e487ece9d2ec2 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -30,6 +30,7 @@ namespace AudioTestConstants { constexpr int32_t PAUSE_BUFFER_POSITION = 1400000; constexpr int32_t PAUSE_RENDER_TIME_SECONDS = 1; constexpr int32_t STOP_RENDER_TIME_SECONDS = 1; + constexpr float TRACK_VOLUME = 0.2f; } class AudioRendererTest { @@ -83,6 +84,10 @@ public: } MEDIA_INFO_LOG("AudioRendererTest: Playback started"); + if (audioRenderer->SetVolume(AudioTestConstants::TRACK_VOLUME) == AudioTestConstants::SUCCESS) { + MEDIA_INFO_LOG("AudioRendererTest: volume set to: %{public}f", audioRenderer->GetVolume()); + } + MEDIA_INFO_LOG("AudioRendererTest: Get Audio parameters:"); AudioRendererParams paRendererParams; if (audioRenderer->GetParams(paRendererParams) == AudioTestConstants::SUCCESS) { @@ -144,6 +149,10 @@ public: pauseTested = true; sleep(AudioTestConstants::PAUSE_RENDER_TIME_SECONDS); MEDIA_INFO_LOG("Audio render resume"); + if (audioRenderer->SetVolume(1.0) == AudioTestConstants::SUCCESS) { + MEDIA_INFO_LOG("AudioRendererTest: after resume volume set to: %{public}f", + audioRenderer->GetVolume()); + } if (!audioRenderer->Flush()) { MEDIA_ERR_LOG("AudioRendererTest: flush failed"); break;