From 21d318cb7a2937e83f885654746467855b0798ba Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 22 Jan 2020 20:37:24 +0900 Subject: [PATCH] Add audio-in set/get volume Change-Id: I281840bb01528f2903430fcd036a3c4812aec68c --- include/CAudioInfo.h | 3 ++ include/CAudioInput.h | 5 ++++ include/CPulseAudioClient.h | 6 +++- include/audio_io.h | 42 ++++++++++++++++++++++++++ include/cpp_audio_io.h | 3 +- src/audio_io.c | 10 +++++++ src/cpp/CAudioInput.cpp | 36 ++++++++++++++++++++++- src/cpp/CPulseAudioClient.cpp | 34 ++++++++++++++++++++++ src/cpp/cpp_audio_io.cpp | 55 ++++++++++++++++++++++++++++++++++- 9 files changed, 190 insertions(+), 4 deletions(-) diff --git a/include/CAudioInfo.h b/include/CAudioInfo.h index a74b7e4..6f89ccc 100644 --- a/include/CAudioInfo.h +++ b/include/CAudioInfo.h @@ -114,6 +114,9 @@ namespace tizen_media_audio { static constexpr unsigned int MIN_SYSTEM_SAMPLERATE = 8000; static constexpr unsigned int MAX_SYSTEM_SAMPLERATE = 192000; + static constexpr double MIN_RECORD_VOLUME = 0.0; + static constexpr double MAX_RECORD_VOLUME = 2.0; + /* Constructors */ CAudioInfo(); CAudioInfo(unsigned int sampleRate, EChannel channel, ESampleType sampleType, EAudioType audioType, int audioIndex); diff --git a/include/CAudioInput.h b/include/CAudioInput.h index a27bf18..d36608a 100644 --- a/include/CAudioInput.h +++ b/include/CAudioInput.h @@ -58,6 +58,9 @@ namespace tizen_media_audio { int peek(const void** buffer, size_t* length); int drop(); + void setVolume(double volume); + double getVolume(); + private: /* Private Methods */ void __setInit(bool flag) noexcept; @@ -66,6 +69,8 @@ namespace tizen_media_audio { bool __mIsUsedSyncRead; bool __mIsInit; + + double __mVolume; }; diff --git a/include/CPulseAudioClient.h b/include/CPulseAudioClient.h index 4eb774f..01e33fb 100644 --- a/include/CPulseAudioClient.h +++ b/include/CPulseAudioClient.h @@ -74,6 +74,8 @@ namespace tizen_media_audio { pa_usec_t getLatency(); pa_usec_t getFinalLatency(); + void applyRecordVolume(double volume); + private: /* Members */ EStreamDirection __mDirection; @@ -100,7 +102,7 @@ namespace tizen_media_audio { /* Private Method */ - /* Private Calblack Method */ + /* Private Callback Method */ static void __contextStateChangeCb(pa_context* c, void* user_data); static void __streamStateChangeCb(pa_stream* s, void* user_data); static void __streamCaptureCb(pa_stream* s, size_t length, void* user_data); @@ -112,6 +114,8 @@ namespace tizen_media_audio { static void __successStreamCb(pa_stream* s, int success, void* user_data); static void __successDrainCb(pa_stream* s, int success, void* user_data); static void __successDrainCbInThread(pa_stream* s, int success, void* user_data); + static void __successVolumeCb(pa_context* c, int success, void* user_data); + }; diff --git a/include/audio_io.h b/include/audio_io.h index 53e8b0e..421b0d5 100644 --- a/include/audio_io.h +++ b/include/audio_io.h @@ -556,6 +556,48 @@ int audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb ca */ int audio_in_unset_state_changed_cb(audio_in_h input); +/** + * @brief Gets the volume of the audio input data stream. + * + * @since_tizen 6.0 + * + * @remarks The default @a volume of the audio input stream is 1.0. + * + * @param[in] input The handle to the audio input + * @param[out] volume The current volume value of the audio input stream + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * + * @see audio_in_set_volume() + */ +int audio_in_get_volume(audio_in_h input, double *volume); + +/** + * @brief Sets the volume of the audio input data stream. + * + * @since_tizen 6.0 + * + * @remarks The default @a volume of the audio input stream is 1.0. + * If the @a volume is less than 1.0, the loudness of recorded data will be decreased. + * If the @a volume is greater than 1.0, the loudness of recorded data will be increased, + * which can be useful when the loudness of original recorded data is too low in certain environments. + * Note that the volume can be clipped if the @a volume is greater than 1.0 and the loudness of original recorded data is high enough. + * + * @param[in] input The handle to the audio input + * @param[in] volume The volume value to be set (0.0 <= volume <= 2.0) + * @return @c 0 on success, + * otherwise a negative error value + * @retval #AUDIO_IO_ERROR_NONE Successful + * @retval #AUDIO_IO_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #AUDIO_IO_ERROR_NOT_SUPPORTED Not supported + * + * @see audio_in_get_volume() + */ +int audio_in_set_volume(audio_in_h input, double volume); + /** * @} */ diff --git a/include/cpp_audio_io.h b/include/cpp_audio_io.h index 9b9e92d..2164d2f 100644 --- a/include/cpp_audio_io.h +++ b/include/cpp_audio_io.h @@ -45,7 +45,8 @@ int cpp_audio_in_peek(audio_in_h input, const void **buffer, unsigned int *lengt int cpp_audio_in_drop(audio_in_h input); int cpp_audio_in_set_state_changed_cb(audio_in_h input, audio_in_state_changed_cb callback, void* user_data); int cpp_audio_in_unset_state_changed_cb(audio_in_h input); - +int cpp_audio_in_get_volume(audio_in_h input, double *volume); +int cpp_audio_in_set_volume(audio_in_h input, double volume); int cpp_audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output); int cpp_audio_out_destroy(audio_out_h output); diff --git a/src/audio_io.c b/src/audio_io.c index af5ebb3..f25068b 100644 --- a/src/audio_io.c +++ b/src/audio_io.c @@ -118,6 +118,16 @@ int audio_in_unset_state_changed_cb(audio_in_h input) return cpp_audio_in_unset_state_changed_cb(input); } +int audio_in_get_volume(audio_in_h input, double *volume) +{ + return cpp_audio_in_get_volume(input, volume); +} + +int audio_in_set_volume(audio_in_h input, double volume) +{ + return cpp_audio_in_set_volume(input, volume); +} + /* Audio Out */ int audio_out_create_new(int sample_rate, audio_channel_e channel, audio_sample_type_e type, audio_out_h *output) { diff --git a/src/cpp/CAudioInput.cpp b/src/cpp/CAudioInput.cpp index 8b6633f..69cbd67 100644 --- a/src/cpp/CAudioInput.cpp +++ b/src/cpp/CAudioInput.cpp @@ -33,7 +33,8 @@ using namespace tizen_media_audio; CAudioInput::CAudioInput(CAudioInfo& info) : CAudioIO(info), __mIsUsedSyncRead(true), - __mIsInit(false) { + __mIsInit(false), + __mVolume(1.0) { mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN; } @@ -103,6 +104,7 @@ void CAudioInput::finalize() { CAudioIO::finalize(); __setInit(false); + __mVolume = 1.0; } void CAudioInput::prepare() { @@ -135,6 +137,7 @@ void CAudioInput::prepare() { internalLock(); mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_RECORD, spec, this); mpPulseAudioClient->initialize(); + mpPulseAudioClient->applyRecordVolume(__mVolume); #ifndef DISABLE_MOBILE_BACK_COMP /* Uncork stream which is created with CORKED flag */ mpPulseAudioClient->cork(false); @@ -317,3 +320,34 @@ int CAudioInput::drop() { return mpPulseAudioClient->drop(); } + +void CAudioInput::setVolume(double volume) { + if (!__IsInit()) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Not initialized"); //LCOV_EXCL_LINE + + AUDIO_IO_LOGE("%d, %p", __IsInit(), mpPulseAudioClient); + try { + if (__IsReady()) { + if (mpPulseAudioClient->isInThread()) { + mpPulseAudioClient->applyRecordVolume(volume); + } else { + internalLock(); + mpPulseAudioClient->applyRecordVolume(volume); + internalUnlock(); + } + } + } catch (const CAudioError& e) { + if (!mpPulseAudioClient->isInThread()) + internalUnlock(); + throw; + } + + __mVolume = volume; +} + +double CAudioInput::getVolume() { + if (!__IsInit()) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Not initialized"); //LCOV_EXCL_LINE + + return __mVolume; +} \ No newline at end of file diff --git a/src/cpp/CPulseAudioClient.cpp b/src/cpp/CPulseAudioClient.cpp index 2b598d7..ed65bf1 100644 --- a/src/cpp/CPulseAudioClient.cpp +++ b/src/cpp/CPulseAudioClient.cpp @@ -282,6 +282,10 @@ void CPulseAudioClient::__successDrainCb(pa_stream* s, int success, void* user_d pa_threaded_mainloop_signal(pClient->__mpMainloop, 0); } +void CPulseAudioClient::__successVolumeCb(pa_context *c, int success, void *user_data) { + AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data); +} + void CPulseAudioClient::initialize() { if (__mIsInit) return; @@ -1006,3 +1010,33 @@ pa_usec_t CPulseAudioClient::getFinalLatency() { return ret; } //LCOV_EXCL_STOP + +void CPulseAudioClient::applyRecordVolume(double volume) { + if (!__mIsInit) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CPulseAudioClient"); + + checkRunningState(); + + if (__mDirection != EStreamDirection::STREAM_DIRECTION_RECORD) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "The Playback client can't use this function"); //LCOV_EXCL_LINE + + try { + if (!isInThread()) + pa_threaded_mainloop_lock(__mpMainloop); + + pa_cvolume cv = { 0, }; + pa_volume_t v = PA_VOLUME_NORM * volume; + + pa_cvolume_set(&cv, __mSpec.getChannelMap().channels, v); + + pa_operation_unref(pa_context_set_source_output_volume(__mpContext, + pa_stream_get_index(__mpStream), &cv, __successVolumeCb, NULL)); + + if (!isInThread()) + pa_threaded_mainloop_unlock(__mpMainloop); + } catch (const CAudioError& e) { + if (!isInThread()) + pa_threaded_mainloop_unlock(__mpMainloop); + throw; + } +} \ No newline at end of file diff --git a/src/cpp/cpp_audio_io.cpp b/src/cpp/cpp_audio_io.cpp index 7161e53..223eed7 100644 --- a/src/cpp/cpp_audio_io.cpp +++ b/src/cpp/cpp_audio_io.cpp @@ -767,7 +767,7 @@ int cpp_audio_in_unset_state_changed_cb(audio_in_h input) { try { if (!handle) THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, - "Parameters are NULL output:%p", input); + "Parameters are NULL input:%p", input); assert(handle->audioIoHandle); AUDIO_IO_LOGD("[%p]", handle); @@ -787,6 +787,59 @@ int cpp_audio_in_unset_state_changed_cb(audio_in_h input) { return AUDIO_IO_ERROR_NONE; } +int cpp_audio_in_get_volume(audio_in_h input, double *volume) { + auto handle = static_cast(input); + + try { + if (!handle || !volume) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, + "Parameters are NULL input:%p, volume:%p", input, volume); + assert(handle->audioIoHandle); + AUDIO_IO_LOGD("[%p]", handle); + + auto input_handle = dynamic_cast(handle->audioIoHandle); + if (input_handle == nullptr) + return __convert_audio_io_error(CAudioError::EError::ERROR_INVALID_HANDLE); + + *volume = input_handle->getVolume(); + } catch (const CAudioError& e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return __convert_audio_io_error(e.getError()); + } + + AUDIO_IO_LOGD("[%p] done", handle); + + return AUDIO_IO_ERROR_NONE; +} + +int cpp_audio_in_set_volume(audio_in_h input, double volume) { + auto handle = static_cast(input); + + try { + if (!handle) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, + "Parameters are NULL input:%p", input); + + if (volume < CAudioInfo::MIN_RECORD_VOLUME || volume > CAudioInfo::MAX_RECORD_VOLUME) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Invalid volume: %f", volume); + + assert(handle->audioIoHandle); + AUDIO_IO_LOGD("[%p]", handle); + + auto input_handle = dynamic_cast(handle->audioIoHandle); + if (input_handle == nullptr) + return __convert_audio_io_error(CAudioError::EError::ERROR_INVALID_HANDLE); + + input_handle->setVolume(volume); + } catch (const CAudioError& e) { + AUDIO_IO_LOGE("%s", e.getErrorMsg()); + return __convert_audio_io_error(e.getError()); + } + + AUDIO_IO_LOGD("[%p] done", handle); + + return AUDIO_IO_ERROR_NONE; +} /** * Audio Out -- 2.34.1