From d9b5d9dd7ba4e90a8cbaf86e5fe9c2a93816fae9 Mon Sep 17 00:00:00 2001 From: liyuhang Date: Sun, 7 Jul 2024 07:47:00 +0000 Subject: [PATCH 1/2] VoIP support mono Signed-off-by: liyuhang Change-Id: I9cd0afc36501a673413ece2f921c300c2fa83830 --- .../native/audioutils/include/audio_utils.h | 6 + .../native/audioutils/src/audio_utils.cpp | 32 ++++++ .../client/src/audio_process_in_client.cpp | 36 +++--- .../common/include/i_audio_process_stream.h | 2 + .../server/include/audio_endpoint.h | 2 +- .../server/include/audio_process_in_server.h | 4 +- .../server/include/audio_service.h | 4 +- .../server/src/audio_endpoint.cpp | 108 ++++++++++++++++-- .../server/src/audio_process_in_server.cpp | 29 ++++- .../server/src/audio_service.cpp | 14 ++- 10 files changed, 199 insertions(+), 38 deletions(-) diff --git a/frameworks/native/audioutils/include/audio_utils.h b/frameworks/native/audioutils/include/audio_utils.h index 9102f5745b..921ed1ea00 100644 --- a/frameworks/native/audioutils/include/audio_utils.h +++ b/frameworks/native/audioutils/include/audio_utils.h @@ -367,6 +367,12 @@ private: size_t extraStrLen_ = 0; }; +class FormatConverter { +public: + static int32_t S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc); + static int32_t S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc); +}; + template int32_t GetKeyFromValue(const std::unordered_map &map, const V &value) { diff --git a/frameworks/native/audioutils/src/audio_utils.cpp b/frameworks/native/audioutils/src/audio_utils.cpp index a7819d8b91..901a8c470b 100644 --- a/frameworks/native/audioutils/src/audio_utils.cpp +++ b/frameworks/native/audioutils/src/audio_utils.cpp @@ -964,6 +964,38 @@ void LatencyMonitor::ShowBluetoothTimestamp() rendererMockTime_.c_str(), sinkDetectedTime_.c_str()); } +int32_t FormatConverter::S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc) +{ + size_t half = 2; // mono(1) -> stereo(2) + if (srcDesc.bufLength != dstDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { + return -1; + } + int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); + int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); + size_t count = srcDesc.bufLength / half; + for (size_t idx = 0; idx < count; idx++) { + *(dstPtr++) = *stcPtr; + *(dstPtr++) = *stcPtr++; + } + return 0; +} + +int32_t FormatConverter::S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc) +{ + size_t half = 2; // stereo(2) -> mono(1) + if (dstDesc.bufLength != srcDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { + return -1; + } + int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); + int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); + size_t count = srcDesc.bufLength / half; + for (size_t idx = 0; idx < count; idx++) { + *(dstPtr++) = (*stcPtr + *(stcPtr + 1)) / 2; // To obtain mono channel, add left to right, then divide by 2 + stcPtr += 2; // ptr++ on mono is equivalent to ptr+=2 on stereo + } + return 0; +} + const std::string AudioInfoDumpUtils::GetStreamName(AudioStreamType streamType) { std::string name; diff --git a/services/audio_service/client/src/audio_process_in_client.cpp b/services/audio_service/client/src/audio_process_in_client.cpp index 2dd44f0dc7..2878a54ae2 100644 --- a/services/audio_service/client/src/audio_process_in_client.cpp +++ b/services/audio_service/client/src/audio_process_in_client.cpp @@ -52,7 +52,7 @@ class ProcessCbImpl; class AudioProcessInClientInner : public AudioProcessInClient, public std::enable_shared_from_this { public: - explicit AudioProcessInClientInner(const sptr &ipcProxy); + AudioProcessInClientInner(const sptr &ipcProxy, bool isVoipMmap); ~AudioProcessInClientInner(); int32_t SaveDataCallback(const std::shared_ptr &dataCallback) override; @@ -178,6 +178,7 @@ private: sptr processProxy_ = nullptr; std::shared_ptr audioBuffer_ = nullptr; uint32_t sessionId_ = 0; + bool isVoipMmap_ = false; uint32_t totalSizeInFrame_ = 0; uint32_t spanSizeInFrame_ = 0; @@ -247,7 +248,8 @@ int32_t ProcessCbImpl::OnEndpointChange(int32_t status) std::mutex g_audioServerProxyMutex; sptr gAudioServerProxy = nullptr; -AudioProcessInClientInner::AudioProcessInClientInner(const sptr &ipcProxy) : processProxy_(ipcProxy) +AudioProcessInClientInner::AudioProcessInClientInner(const sptr &ipcProxy, + bool isVoipMmap) : processProxy_(ipcProxy), isVoipMmap_(isVoipMmap) { processProxy_->GetSessionId(sessionId_); AUDIO_INFO_LOG("Construct with sessionId: %{public}d", sessionId_); @@ -300,15 +302,19 @@ std::shared_ptr AudioProcessInClient::Create(const AudioPr sptr gasp = AudioProcessInClientInner::GetAudioServerProxy(); CHECK_AND_RETURN_RET_LOG(gasp != nullptr, nullptr, "Create failed, can not get service."); AudioProcessConfig resetConfig = config; + bool isVoipMmap = false; if (config.rendererInfo.streamUsage != STREAM_USAGE_VOICE_COMMUNICATION && config.capturerInfo.sourceType != SOURCE_TYPE_VOICE_COMMUNICATION) { resetConfig.streamInfo = AudioProcessInClientInner::g_targetStreamInfo; + } else { + isVoipMmap = true; } sptr ipcProxy = gasp->CreateAudioProcess(resetConfig); CHECK_AND_RETURN_RET_LOG(ipcProxy != nullptr, nullptr, "Create failed with null ipcProxy."); sptr iProcessProxy = iface_cast(ipcProxy); CHECK_AND_RETURN_RET_LOG(iProcessProxy != nullptr, nullptr, "Create failed when iface_cast."); - std::shared_ptr process = std::make_shared(iProcessProxy); + std::shared_ptr process = + std::make_shared(iProcessProxy, isVoipMmap); if (!process->Init(config)) { AUDIO_ERR_LOG("Init failed!"); process = nullptr; @@ -505,12 +511,12 @@ bool AudioProcessInClientInner::InitAudioBuffer() spanSizeInByte_ = spanSizeInFrame_ * byteSizePerFrame_; spanSizeInMs_ = spanSizeInFrame_ * MILLISECOND_PER_SECOND / processConfig_.streamInfo.samplingRate; - if (processConfig_.audioMode == AUDIO_MODE_PLAYBACK && clientByteSizePerFrame_ != 0) { - clientSpanSizeInByte_ = spanSizeInFrame_ * clientByteSizePerFrame_; + clientSpanSizeInByte_ = spanSizeInFrame_ * clientByteSizePerFrame_; + if (processConfig_.audioMode == AUDIO_MODE_PLAYBACK) { if (clientSpanSizeInFrame_ != spanSizeInFrame_) { clientSpanSizeInFrame_ = spanSizeInFrame_; } - } else { + } else if (!isVoipMmap_) { clientSpanSizeInByte_ = spanSizeInByte_; } @@ -568,13 +574,12 @@ bool AudioProcessInClientInner::Init(const AudioProcessConfig &config) { AUDIO_INFO_LOG("Call Init."); processConfig_ = config; - if (config.streamInfo.format != g_targetStreamInfo.format || - config.streamInfo.channels != g_targetStreamInfo.channels) { + if (!isVoipMmap_ && (config.streamInfo.format != g_targetStreamInfo.format || + config.streamInfo.channels != g_targetStreamInfo.channels)) { needConvert_ = true; } - if (config.audioMode == AUDIO_MODE_PLAYBACK) { - clientByteSizePerFrame_ = GetFormatSize(config.streamInfo); - } + clientByteSizePerFrame_ = GetFormatSize(config.streamInfo); + AUDIO_DEBUG_LOG("Using clientByteSizePerFrame_:%{public}zu", clientByteSizePerFrame_); bool isBufferInited = InitAudioBuffer(); CHECK_AND_RETURN_RET_LOG(isBufferInited, isBufferInited, "%{public}s init audio buffer fail.", __func__); @@ -676,9 +681,12 @@ int32_t AudioProcessInClientInner::GetBufferDesc(BufferDesc &bufDesc) const bool AudioProcessInClient::CheckIfSupport(const AudioProcessConfig &config) { - if (config.rendererInfo.streamUsage != STREAM_USAGE_VOICE_COMMUNICATION && - config.capturerInfo.sourceType != SOURCE_TYPE_VOICE_COMMUNICATION && - config.streamInfo.samplingRate != SAMPLE_RATE_48000) { + if (config.rendererInfo.streamUsage == STREAM_USAGE_VOICE_COMMUNICATION || + config.capturerInfo.sourceType == SOURCE_TYPE_VOICE_COMMUNICATION) { + return true; + } + + if (config.streamInfo.samplingRate != SAMPLE_RATE_48000) { return false; } 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 c5ce1e8af4..add3b0be35 100644 --- a/services/audio_service/common/include/i_audio_process_stream.h +++ b/services/audio_service/common/include/i_audio_process_stream.h @@ -40,6 +40,8 @@ public: virtual AppInfo GetAppInfo() = 0; + virtual BufferDesc &GetConvertedBuffer() = 0; + virtual ~IAudioProcessStream() = default; }; } // namespace AudioStandard diff --git a/services/audio_service/server/include/audio_endpoint.h b/services/audio_service/server/include/audio_endpoint.h index 53114f4bc8..4b369de3f1 100644 --- a/services/audio_service/server/include/audio_endpoint.h +++ b/services/audio_service/server/include/audio_endpoint.h @@ -62,7 +62,7 @@ public: }; static std::shared_ptr CreateEndpoint(EndpointType type, uint64_t id, - AudioStreamType streamType, const DeviceInfo &deviceInfo); + const AudioProcessConfig &clientConfig, const DeviceInfo &deviceInfo); static std::string GenerateEndpointKey(DeviceInfo &deviceInfo, int32_t endpointFlag); virtual std::string GetEndpointName() = 0; 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 ae145b3bef..31ee4bf025 100644 --- a/services/audio_service/server/include/audio_process_in_server.h +++ b/services/audio_service/server/include/audio_process_in_server.h @@ -77,7 +77,7 @@ public: void Dump(std::string &dumpString); int32_t ConfigProcessBuffer(uint32_t &totalSizeInframe, uint32_t &spanSizeInframe, - const std::shared_ptr &endpoint = nullptr); + DeviceStreamInfo &serverStreamInfo, const std::shared_ptr &endpoint = nullptr); int32_t AddProcessStatusListener(std::shared_ptr listener); int32_t RemoveProcessStatusListener(std::shared_ptr listener); @@ -87,6 +87,7 @@ public: bool GetInnerCapState() override; AppInfo GetAppInfo() override final; + BufferDesc &GetConvertedBuffer() override; public: const AudioProcessConfig processConfig_; @@ -112,6 +113,7 @@ private: std::shared_ptr processBuffer_ = nullptr; std::mutex listenerListLock_; std::vector> listenerList_; + BufferDesc convertedBuffer_ = {}; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/audio_service/server/include/audio_service.h b/services/audio_service/server/include/audio_service.h index c8f12e89b3..fc8e7a9f10 100644 --- a/services/audio_service/server/include/audio_service.h +++ b/services/audio_service/server/include/audio_service.h @@ -54,8 +54,8 @@ public: int32_t OnProcessRelease(IAudioProcessStream *process) override; DeviceInfo GetDeviceInfoForProcess(const AudioProcessConfig &config); - std::shared_ptr GetAudioEndpointForDevice(DeviceInfo &deviceInfo, AudioStreamType streamType, - bool isVoipStream); + std::shared_ptr GetAudioEndpointForDevice(DeviceInfo &deviceInfo, + const AudioProcessConfig &clientConfig, bool isVoipStream); int32_t NotifyStreamVolumeChanged(AudioStreamType streamType, float volume); int32_t LinkProcessToEndpoint(sptr process, std::shared_ptr endpoint); diff --git a/services/audio_service/server/src/audio_endpoint.cpp b/services/audio_service/server/src/audio_endpoint.cpp index bc5c817425..4ad9253c2f 100644 --- a/services/audio_service/server/src/audio_endpoint.cpp +++ b/services/audio_service/server/src/audio_endpoint.cpp @@ -92,7 +92,7 @@ private: class AudioEndpointInner : public AudioEndpoint { public: - explicit AudioEndpointInner(EndpointType type, uint64_t id); + AudioEndpointInner(EndpointType type, uint64_t id, const AudioProcessConfig &clientConfig); ~AudioEndpointInner(); bool Config(const DeviceInfo &deviceInfo) override; @@ -165,6 +165,11 @@ private: void RecordReSyncPosition(); void InitAudiobuffer(bool resetReadWritePos); void ProcessData(const std::vector &srcDataList, const AudioStreamData &dstData); + void ProcessSingleData(const AudioStreamData &srcData, const AudioStreamData &dstData); + void HandleZeroVolumeCheckEvent(); + void HandleRendererDataParams(const AudioStreamData &srcData, const AudioStreamData &dstData); + int32_t HandleCapturerDataParams(const BufferDesc &writeBuf, const BufferDesc &readBuf, + const BufferDesc &convertedBuffer); void ZeroVolumeCheck(const int32_t vol); int64_t GetPredictNextReadTime(uint64_t posInFrame); int64_t GetPredictNextWriteTime(uint64_t posInFrame); @@ -188,7 +193,8 @@ private: std::string GetStatusStr(EndpointStatus status); - int32_t WriteToSpecialProcBuf(const std::shared_ptr &procBuf, const BufferDesc &readBuf); + int32_t WriteToSpecialProcBuf(const std::shared_ptr &procBuf, const BufferDesc &readBuf, + const BufferDesc &convertedBuffer); void WriteToProcessBuffers(const BufferDesc &readBuf); int32_t ReadFromEndpoint(uint64_t curReadPos); bool KeepWorkloopRunning(); @@ -243,6 +249,7 @@ private: std::mutex listLock_; std::vector processList_; std::vector> processBufferList_; + AudioProcessConfig clientConfig_; std::atomic isInited_ = false; @@ -325,14 +332,14 @@ std::string AudioEndpoint::GenerateEndpointKey(DeviceInfo &deviceInfo, int32_t e } std::shared_ptr AudioEndpoint::CreateEndpoint(EndpointType type, uint64_t id, - AudioStreamType streamType, const DeviceInfo &deviceInfo) + const AudioProcessConfig &clientConfig, const DeviceInfo &deviceInfo) { std::shared_ptr audioEndpoint = nullptr; if (type == EndpointType::TYPE_INDEPENDENT && deviceInfo.deviceRole != INPUT_DEVICE && deviceInfo.networkId == LOCAL_NETWORK_ID) { - audioEndpoint = std::make_shared(type, id, streamType); + audioEndpoint = std::make_shared(type, id, clientConfig.streamType); } else { - audioEndpoint = std::make_shared(type, id); + audioEndpoint = std::make_shared(type, id, clientConfig); } CHECK_AND_RETURN_RET_LOG(audioEndpoint != nullptr, nullptr, "Create AudioEndpoint failed."); @@ -343,7 +350,8 @@ std::shared_ptr AudioEndpoint::CreateEndpoint(EndpointType type, return audioEndpoint; } -AudioEndpointInner::AudioEndpointInner(EndpointType type, uint64_t id) : endpointType_(type), id_(id) +AudioEndpointInner::AudioEndpointInner(EndpointType type, uint64_t id, + const AudioProcessConfig &clientConfig) : endpointType_(type), id_(id), clientConfig_(clientConfig) { AUDIO_INFO_LOG("AudioEndpoint type:%{public}d", endpointType_); } @@ -1313,6 +1321,11 @@ void AudioEndpointInner::ProcessData(const std::vector &srcData offset++; *dstPtr++ = sum > INT16_MAX ? INT16_MAX : (sum < INT16_MIN ? INT16_MIN : sum); } + HandleZeroVolumeCheckEvent(); +} + +void AudioEndpointInner::HandleZeroVolumeCheckEvent() +{ if (!zeroVolumeStopDevice_ && (ClockTime::GetCurNano() >= delayStopTimeForZeroVolume_)) { if (isStarted_) { if (fastSink_ != nullptr && fastSink_->Stop() == SUCCESS) { @@ -1327,6 +1340,49 @@ void AudioEndpointInner::ProcessData(const std::vector &srcData } } + +void AudioEndpointInner::HandleRendererDataParams(const AudioStreamData &srcData, const AudioStreamData &dstData) +{ + if (srcData.streamInfo.encoding != dstData.streamInfo.encoding) { + AUDIO_ERR_LOG("Different encoding formats"); + return; + } + if (srcData.streamInfo.format == SAMPLE_S16LE && srcData.streamInfo.channels == STEREO) { + return ProcessSingleData(srcData, dstData); + } + if (srcData.streamInfo.format == SAMPLE_S16LE && srcData.streamInfo.channels == MONO) { + CHECK_AND_RETURN_LOG(processList_.size() > 0 && processList_[0] != nullptr, "No avaliable process"); + BufferDesc &convertedBuffer = processList_[0]->GetConvertedBuffer(); + int32_t ret = FormatConverter::S16MonoToS16Stereo(srcData.bufferDesc, convertedBuffer); + CHECK_AND_RETURN_LOG(ret == SUCCESS, "Convert channel from mono to stereo failed"); + AudioStreamData dataAfterProcess = srcData; + dataAfterProcess.bufferDesc = convertedBuffer; + ProcessSingleData(dataAfterProcess, dstData); + ret = memset_s(static_cast(convertedBuffer.buffer), sizeof(convertedBuffer.buffer), 0, + sizeof(convertedBuffer.buffer)); + CHECK_AND_RETURN_LOG(ret == EOK, "memset converted buffer to 0 failed"); + } +} + +void AudioEndpointInner::ProcessSingleData(const AudioStreamData &srcData, const AudioStreamData &dstData) +{ + CHECK_AND_RETURN_LOG(dstData.streamInfo.format == SAMPLE_S16LE && dstData.streamInfo.channels == STEREO, + "ProcessData failed, streamInfo are not support"); + + size_t dataLength = dstData.bufferDesc.dataLength; + dataLength /= 2; // SAMPLE_S16LE--> 2 byte + int16_t *dstPtr = reinterpret_cast(dstData.bufferDesc.buffer); + for (size_t offset = 0; dataLength > 0; dataLength--) { + int32_t vol = srcData.volumeStart; // change to modify volume of each channel + int16_t *srcPtr = reinterpret_cast(srcData.bufferDesc.buffer) + offset; + int32_t sum = (*srcPtr * static_cast(vol)) >> VOLUME_SHIFT_NUMBER; // 1/65536 + ZeroVolumeCheck(vol); + offset++; + *dstPtr++ = sum > INT16_MAX ? INT16_MAX : (sum < INT16_MIN ? INT16_MIN : sum); + } + HandleZeroVolumeCheckEvent(); +} + void AudioEndpointInner::ZeroVolumeCheck(const int32_t vol) { if (std::abs(vol - 0) <= std::numeric_limits::epsilon()) { @@ -1411,7 +1467,11 @@ bool AudioEndpointInner::ProcessToEndpointDataHandle(uint64_t curWritePos) memset_s(dstStreamData.bufferDesc.buffer, dstStreamData.bufferDesc.bufLength, 0, dstStreamData.bufferDesc.bufLength); } else { - ProcessData(audioDataList, dstStreamData); + if (endpointType_ == TYPE_VOIP_MMAP && audioDataList.size() == 1) { + HandleRendererDataParams(audioDataList[0], dstStreamData); + } else { + ProcessData(audioDataList, dstStreamData); + } } if (isInnerCapEnabled_) { @@ -1680,7 +1740,7 @@ bool AudioEndpointInner::KeepWorkloopRunning() } int32_t AudioEndpointInner::WriteToSpecialProcBuf(const std::shared_ptr &procBuf, - const BufferDesc &readBuf) + const BufferDesc &readBuf, const BufferDesc &convertedBuffer) { CHECK_AND_RETURN_RET_LOG(procBuf != nullptr, ERR_INVALID_HANDLE, "process buffer is null."); uint64_t curWritePos = procBuf->GetCurWriteFrame(); @@ -1704,8 +1764,13 @@ int32_t AudioEndpointInner::WriteToSpecialProcBuf(const std::shared_ptrGetWriteBuffer(curWritePos, writeBuf); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "get write buffer fail, ret %{public}d.", ret); - ret = memcpy_s(static_cast(writeBuf.buffer), writeBuf.bufLength, - static_cast(readBuf.buffer), readBuf.bufLength); + if (endpointType_ == TYPE_VOIP_MMAP) { + ret = HandleCapturerDataParams(writeBuf, readBuf, convertedBuffer); + } else { + ret = memcpy_s(static_cast(writeBuf.buffer), writeBuf.bufLength, + static_cast(readBuf.buffer), readBuf.bufLength); + } + CHECK_AND_RETURN_RET_LOG(ret == EOK, ERR_WRITE_FAILED, "memcpy data to process buffer fail, " "curWritePos %{public}" PRIu64", ret %{public}d.", curWritePos, ret); @@ -1721,6 +1786,27 @@ int32_t AudioEndpointInner::WriteToSpecialProcBuf(const std::shared_ptr(writeBuf.buffer), writeBuf.bufLength, + static_cast(readBuf.buffer), readBuf.bufLength); + } + if (clientConfig_.streamInfo.format == SAMPLE_S16LE && clientConfig_.streamInfo.channels == MONO) { + int32_t ret = FormatConverter::S16StereoToS16Mono(readBuf, convertedBuffer); + CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_WRITE_FAILED, "Convert channel from stereo to mono failed"); + ret = memcpy_s(static_cast(writeBuf.buffer), writeBuf.bufLength, + static_cast(convertedBuffer.buffer), convertedBuffer.bufLength); + CHECK_AND_RETURN_RET_LOG(ret == EOK, ERR_WRITE_FAILED, "memcpy_s failed"); + ret = memset_s(static_cast(convertedBuffer.buffer), sizeof(convertedBuffer.buffer), 0, + sizeof(convertedBuffer.buffer)); + CHECK_AND_RETURN_RET_LOG(ret == EOK, ERR_WRITE_FAILED, "memset converted buffer to 0 failed"); + return EOK; + } + return ERR_NOT_SUPPORTED; +} + void AudioEndpointInner::WriteToProcessBuffers(const BufferDesc &readBuf) { CheckRecordSignal(readBuf.buffer, readBuf.bufLength); @@ -1735,7 +1821,7 @@ void AudioEndpointInner::WriteToProcessBuffers(const BufferDesc &readBuf) continue; } - int32_t ret = WriteToSpecialProcBuf(processBufferList_[i], readBuf); + int32_t ret = WriteToSpecialProcBuf(processBufferList_[i], readBuf, processList_[i]->GetConvertedBuffer()); CHECK_AND_CONTINUE_LOG(ret == SUCCESS, "endpoint write to process buffer %{public}zu fail, ret %{public}d.", i, ret); AUDIO_DEBUG_LOG("endpoint process buffer %{public}zu write success.", i); 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 866939f347..b5e7ca12f0 100644 --- a/services/audio_service/server/src/audio_process_in_server.cpp +++ b/services/audio_service/server/src/audio_process_in_server.cpp @@ -47,6 +47,9 @@ AudioProcessInServer::AudioProcessInServer(const AudioProcessConfig &processConf AudioProcessInServer::~AudioProcessInServer() { AUDIO_INFO_LOG("~AudioProcessInServer()"); + if (convertedBuffer_.buffer != nullptr) { + delete []convertedBuffer_.buffer; + } } int32_t AudioProcessInServer::GetSessionId(uint32_t &sessionId) @@ -231,6 +234,11 @@ AppInfo AudioProcessInServer::GetAppInfo() return processConfig_.appInfo; } +BufferDesc &AudioProcessInServer::GetConvertedBuffer() +{ + return convertedBuffer_; +} + int AudioProcessInServer::Dump(int fd, const std::vector &args) { return SUCCESS; @@ -314,7 +322,7 @@ int32_t AudioProcessInServer::InitBufferStatus() } int32_t AudioProcessInServer::ConfigProcessBuffer(uint32_t &totalSizeInframe, - uint32_t &spanSizeInframe, const std::shared_ptr &buffer) + uint32_t &spanSizeInframe, DeviceStreamInfo &serverStreamInfo, const std::shared_ptr &buffer) { if (processBuffer_ != nullptr) { AUDIO_INFO_LOG("ConfigProcessBuffer: process buffer already configed!"); @@ -323,12 +331,27 @@ int32_t AudioProcessInServer::ConfigProcessBuffer(uint32_t &totalSizeInframe, // check CHECK_AND_RETURN_RET_LOG(totalSizeInframe != 0 && spanSizeInframe != 0 && totalSizeInframe % spanSizeInframe == 0, ERR_INVALID_PARAM, "ConfigProcessBuffer failed: ERR_INVALID_PARAM"); - totalSizeInframe_ = totalSizeInframe; - spanSizeInframe_ = spanSizeInframe; + CHECK_AND_RETURN_RET_LOG(serverStreamInfo.samplingRate.size() > 0 && serverStreamInfo.channels.size() > 0, + ERR_INVALID_PARAM, "Invalid stream info in server"); + uint32_t spanTime = spanSizeInframe * AUDIO_MS_PER_SECOND / *serverStreamInfo.samplingRate.rbegin(); + spanSizeInframe_ = spanTime * processConfig_.streamInfo.samplingRate / AUDIO_MS_PER_SECOND; + totalSizeInframe_ = totalSizeInframe / spanSizeInframe * spanSizeInframe_; uint32_t channel = processConfig_.streamInfo.channels; uint32_t formatbyte = PcmFormatToBits(processConfig_.streamInfo.format); byteSizePerFrame_ = channel * formatbyte; + if (*serverStreamInfo.channels.rbegin() != processConfig_.streamInfo.channels) { + size_t spanSizeInByte = 0; + if (processConfig_.audioMode == AUDIO_MODE_PLAYBACK) { + uint32_t serverByteSize = *serverStreamInfo.channels.rbegin() * PcmFormatToBits(serverStreamInfo.format); + spanSizeInByte = static_cast(spanSizeInframe * serverByteSize); + } else { + spanSizeInByte = static_cast(spanSizeInframe_ * byteSizePerFrame_); + } + convertedBuffer_.buffer = new uint8_t[spanSizeInByte]; + convertedBuffer_.bufLength = spanSizeInByte; + convertedBuffer_.dataLength = spanSizeInByte; + } if (buffer == nullptr) { // create OHAudioBuffer in server. diff --git a/services/audio_service/server/src/audio_service.cpp b/services/audio_service/server/src/audio_service.cpp index cf24a42719..d69fb1baa6 100644 --- a/services/audio_service/server/src/audio_service.cpp +++ b/services/audio_service/server/src/audio_service.cpp @@ -403,20 +403,22 @@ sptr AudioService::GetAudioProcess(const AudioProcessConfi AUDIO_INFO_LOG("GetAudioProcess dump %{public}s", ProcessConfig::DumpProcessConfig(config).c_str()); DeviceInfo deviceInfo = GetDeviceInfoForProcess(config); std::lock_guard lock(processListMutex_); - std::shared_ptr audioEndpoint = GetAudioEndpointForDevice(deviceInfo, config.streamType, + std::shared_ptr audioEndpoint = GetAudioEndpointForDevice(deviceInfo, config, IsEndpointTypeVoip(config, deviceInfo)); CHECK_AND_RETURN_RET_LOG(audioEndpoint != nullptr, nullptr, "no endpoint found for the process"); uint32_t totalSizeInframe = 0; uint32_t spanSizeInframe = 0; audioEndpoint->GetPreferBufferInfo(totalSizeInframe, spanSizeInframe); + CHECK_AND_RETURN_RET_LOG(*deviceInfo.audioStreamInfo.samplingRate.rbegin() > 0, nullptr, + "Sample rate in server is invalid."); sptr process = AudioProcessInServer::Create(config, this); CHECK_AND_RETURN_RET_LOG(process != nullptr, nullptr, "AudioProcessInServer create failed."); std::shared_ptr buffer = audioEndpoint->GetEndpointType() == AudioEndpoint::TYPE_INDEPENDENT ? audioEndpoint->GetBuffer() : nullptr; - int32_t ret = process->ConfigProcessBuffer(totalSizeInframe, spanSizeInframe, buffer); + int32_t ret = process->ConfigProcessBuffer(totalSizeInframe, spanSizeInframe, deviceInfo.audioStreamInfo, buffer); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, nullptr, "ConfigProcessBuffer failed"); ret = LinkProcessToEndpoint(process, audioEndpoint); @@ -446,7 +448,7 @@ void AudioService::ResetAudioEndpoint() } DeviceInfo deviceInfo = GetDeviceInfoForProcess(config); - std::shared_ptr audioEndpoint = GetAudioEndpointForDevice(deviceInfo, config.streamType, + std::shared_ptr audioEndpoint = GetAudioEndpointForDevice(deviceInfo, config, IsEndpointTypeVoip(config, deviceInfo)); CHECK_AND_RETURN_LOG(audioEndpoint != nullptr, "Get new endpoint failed"); @@ -585,7 +587,7 @@ DeviceInfo AudioService::GetDeviceInfoForProcess(const AudioProcessConfig &confi } std::shared_ptr AudioService::GetAudioEndpointForDevice(DeviceInfo &deviceInfo, - AudioStreamType streamType, bool isVoipStream) + const AudioProcessConfig &clientConfig, bool isVoipStream) { int32_t endpointSeparateFlag = -1; GetSysPara("persist.multimedia.audioflag.fast.disableseparate", endpointSeparateFlag); @@ -602,7 +604,7 @@ std::shared_ptr AudioService::GetAudioEndpointForDevice(DeviceInf return endpointList_[deviceKey]; } else { std::shared_ptr endpoint = AudioEndpoint::CreateEndpoint(isVoipStream ? - AudioEndpoint::TYPE_VOIP_MMAP : AudioEndpoint::TYPE_MMAP, endpointFlag, streamType, deviceInfo); + AudioEndpoint::TYPE_VOIP_MMAP : AudioEndpoint::TYPE_MMAP, endpointFlag, clientConfig, deviceInfo); CHECK_AND_RETURN_RET_LOG(endpoint != nullptr, nullptr, "Create mmap AudioEndpoint failed."); endpointList_[deviceKey] = endpoint; return endpoint; @@ -611,7 +613,7 @@ std::shared_ptr AudioService::GetAudioEndpointForDevice(DeviceInf // Create Independent stream. std::string deviceKey = deviceInfo.networkId + std::to_string(deviceInfo.deviceId) + "_" + std::to_string(g_id); std::shared_ptr endpoint = AudioEndpoint::CreateEndpoint(AudioEndpoint::TYPE_INDEPENDENT, - g_id, streamType, deviceInfo); + g_id, clientConfig, deviceInfo); CHECK_AND_RETURN_RET_LOG(endpoint != nullptr, nullptr, "Create independent AudioEndpoint failed."); g_id++; endpointList_[deviceKey] = endpoint; -- Gitee From c788c8c06bc6e0479577089d4e163547f82b84fe Mon Sep 17 00:00:00 2001 From: liyuhang Date: Fri, 12 Jul 2024 06:22:58 +0000 Subject: [PATCH 2/2] Move format convert, from utils to common Signed-off-by: liyuhang Change-Id: I8a0dd1c37bf302c9243c139158b27789a2c95857 --- .../native/audioutils/include/audio_utils.h | 6 --- .../native/audioutils/src/audio_utils.cpp | 32 ----------- services/audio_service/BUILD.gn | 1 + .../common/include/format_converter.h | 31 +++++++++++ .../common/src/format_converter.cpp | 53 +++++++++++++++++++ .../server/src/audio_endpoint.cpp | 1 + .../server/src/audio_process_in_server.cpp | 2 +- 7 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 services/audio_service/common/include/format_converter.h create mode 100644 services/audio_service/common/src/format_converter.cpp diff --git a/frameworks/native/audioutils/include/audio_utils.h b/frameworks/native/audioutils/include/audio_utils.h index 921ed1ea00..9102f5745b 100644 --- a/frameworks/native/audioutils/include/audio_utils.h +++ b/frameworks/native/audioutils/include/audio_utils.h @@ -367,12 +367,6 @@ private: size_t extraStrLen_ = 0; }; -class FormatConverter { -public: - static int32_t S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc); - static int32_t S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc); -}; - template int32_t GetKeyFromValue(const std::unordered_map &map, const V &value) { diff --git a/frameworks/native/audioutils/src/audio_utils.cpp b/frameworks/native/audioutils/src/audio_utils.cpp index 901a8c470b..a7819d8b91 100644 --- a/frameworks/native/audioutils/src/audio_utils.cpp +++ b/frameworks/native/audioutils/src/audio_utils.cpp @@ -964,38 +964,6 @@ void LatencyMonitor::ShowBluetoothTimestamp() rendererMockTime_.c_str(), sinkDetectedTime_.c_str()); } -int32_t FormatConverter::S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc) -{ - size_t half = 2; // mono(1) -> stereo(2) - if (srcDesc.bufLength != dstDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { - return -1; - } - int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); - int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); - size_t count = srcDesc.bufLength / half; - for (size_t idx = 0; idx < count; idx++) { - *(dstPtr++) = *stcPtr; - *(dstPtr++) = *stcPtr++; - } - return 0; -} - -int32_t FormatConverter::S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc) -{ - size_t half = 2; // stereo(2) -> mono(1) - if (dstDesc.bufLength != srcDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { - return -1; - } - int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); - int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); - size_t count = srcDesc.bufLength / half; - for (size_t idx = 0; idx < count; idx++) { - *(dstPtr++) = (*stcPtr + *(stcPtr + 1)) / 2; // To obtain mono channel, add left to right, then divide by 2 - stcPtr += 2; // ptr++ on mono is equivalent to ptr+=2 on stereo - } - return 0; -} - const std::string AudioInfoDumpUtils::GetStreamName(AudioStreamType streamType) { std::string name; diff --git a/services/audio_service/BUILD.gn b/services/audio_service/BUILD.gn index f2c0ab6053..78b89706d7 100644 --- a/services/audio_service/BUILD.gn +++ b/services/audio_service/BUILD.gn @@ -47,6 +47,7 @@ ohos_shared_library("audio_common") { "common/src/audio_resample.cpp", "common/src/audio_ring_cache.cpp", "common/src/audio_thread_task.cpp", + "common/src/format_converter.cpp", "common/src/futex_tool.cpp", "common/src/linear_pos_time_model.cpp", "common/src/oh_audio_buffer.cpp", diff --git a/services/audio_service/common/include/format_converter.h b/services/audio_service/common/include/format_converter.h new file mode 100644 index 0000000000..30346fd612 --- /dev/null +++ b/services/audio_service/common/include/format_converter.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FORMAT_CONVERTER_H +#define FORMAT_CONVERTER_H + +#include "stdint.h" +#include "audio_info.h" + +namespace OHOS { +namespace AudioStandard { +class FormatConverter { +public: + static int32_t S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc); + static int32_t S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc); +}; +} // namespace AudioStandard +} // namespace OHOS +#endif // FORMAT_CONVERTER_H diff --git a/services/audio_service/common/src/format_converter.cpp b/services/audio_service/common/src/format_converter.cpp new file mode 100644 index 0000000000..0f64dcab01 --- /dev/null +++ b/services/audio_service/common/src/format_converter.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "format_converter.h" +#include + +namespace OHOS { +namespace AudioStandard { +int32_t FormatConverter::S16MonoToS16Stereo(const BufferDesc &srcDesc, const BufferDesc &dstDesc) +{ + size_t half = 2; // mono(1) -> stereo(2) + if (srcDesc.bufLength != dstDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { + return -1; + } + int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); + int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); + size_t count = srcDesc.bufLength / half; + for (size_t idx = 0; idx < count; idx++) { + *(dstPtr++) = *stcPtr; + *(dstPtr++) = *stcPtr++; + } + return 0; +} + +int32_t FormatConverter::S16StereoToS16Mono(const BufferDesc &srcDesc, const BufferDesc &dstDesc) +{ + size_t half = 2; // stereo(2) -> mono(1) + if (dstDesc.bufLength != srcDesc.bufLength / half || srcDesc.buffer == nullptr || dstDesc.buffer == nullptr) { + return -1; + } + int16_t *stcPtr = reinterpret_cast(srcDesc.buffer); + int16_t *dstPtr = reinterpret_cast(dstDesc.buffer); + size_t count = srcDesc.bufLength / half; + for (size_t idx = 0; idx < count; idx++) { + *(dstPtr++) = (*stcPtr + *(stcPtr + 1)) / 2; // To obtain mono channel, add left to right, then divide by 2 + stcPtr += 2; // ptr++ on mono is equivalent to ptr+=2 on stereo + } + return 0; +} +} // namespace AudioStandard +} // namespace OHOS diff --git a/services/audio_service/server/src/audio_endpoint.cpp b/services/audio_service/server/src/audio_endpoint.cpp index 4ad9253c2f..3d915ab314 100644 --- a/services/audio_service/server/src/audio_endpoint.cpp +++ b/services/audio_service/server/src/audio_endpoint.cpp @@ -33,6 +33,7 @@ #include "bluetooth_renderer_sink.h" #include "fast_audio_renderer_sink.h" #include "fast_audio_capturer_source.h" +#include "format_converter.h" #include "i_audio_capturer_source.h" #include "i_stream_manager.h" #include "linear_pos_time_model.h" 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 b5e7ca12f0..e4aca79248 100644 --- a/services/audio_service/server/src/audio_process_in_server.cpp +++ b/services/audio_service/server/src/audio_process_in_server.cpp @@ -48,7 +48,7 @@ AudioProcessInServer::~AudioProcessInServer() { AUDIO_INFO_LOG("~AudioProcessInServer()"); if (convertedBuffer_.buffer != nullptr) { - delete []convertedBuffer_.buffer; + delete [] convertedBuffer_.buffer; } } -- Gitee