1 /*
2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "TonePlayerImpl"
17 #endif
18
19 #include <sys/time.h>
20 #include <utility>
21
22 #include <climits>
23 #include <cmath>
24 #include <cfloat>
25 #include "securec.h"
26 #include "audio_common_log.h"
27 #include "audio_policy_manager.h"
28 #include "tone_player_impl.h"
29 #include "audio_utils.h"
30 #include "audio_errors.h"
31 #include "parameter.h"
32 #ifdef AUDIO_TEL_CORE_SERVICE_ENABLE
33 #include "core_service_client.h"
34 #endif
35 #ifdef AUIDO_TEL_CELLULAR_DATA_ENABLE
36 #include "cellular_data_client.h"
37 #endif
38
39 namespace OHOS {
40 namespace AudioStandard {
41 namespace {
42 constexpr int32_t C20MS = 20;
43 constexpr int32_t C1000MS = 1000;
44 constexpr int32_t CDOUBLE = 2;
45 constexpr int32_t DIGITAMPLITUDE = 800;
46 constexpr int32_t AMPLITUDE = 8000;
47 constexpr int32_t BIT8 = 8;
48 constexpr int32_t SYSPARA_SIZE = 128;
49 const char DEBUG_COUNTRYCODE_NAME[] = "debug.toneplayer.country";
50 const char DEFAULT_STRING[] = "error";
51 const char DUMP_TONEPLAYER_FILENAME[] = "dump_toneplayer_audio.pcm";
52
53 static const std::vector<ToneType> TONE_TYPE_LIST = {
54 TONE_TYPE_DIAL_0,
55 TONE_TYPE_DIAL_1,
56 TONE_TYPE_DIAL_2,
57 TONE_TYPE_DIAL_3,
58 TONE_TYPE_DIAL_4,
59 TONE_TYPE_DIAL_5,
60 TONE_TYPE_DIAL_6,
61 TONE_TYPE_DIAL_7,
62 TONE_TYPE_DIAL_8,
63 TONE_TYPE_DIAL_9,
64 TONE_TYPE_DIAL_S,
65 TONE_TYPE_DIAL_P
66 };
67 }
68
TonePlayerImpl(const std::string cachePath,const AudioRendererInfo & rendereInfo)69 TonePlayerImpl::TonePlayerImpl(const std::string cachePath, const AudioRendererInfo &rendereInfo)
70 {
71 toneState_ = TONE_IDLE;
72 rendererOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
73 rendererOptions_.streamInfo.samplingRate = SAMPLE_RATE_48000;
74 rendererOptions_.streamInfo.format = SAMPLE_S16LE;
75 rendererOptions_.streamInfo.channels = MONO;
76
77 // contentType::CONTENT_TYPE_MUSIC;
78 rendererOptions_.rendererInfo.contentType = rendereInfo.contentType;
79
80 // streamUsage::STREAM_USAGE_MEDIA;
81 rendererOptions_.rendererInfo.streamUsage = rendereInfo.streamUsage;
82 rendererOptions_.rendererInfo.rendererFlags = AUDIO_FLAG_FORCED_NORMAL; // use AUDIO_FLAG_FORCED_NORMAL
83
84 rendererOptions_.strategy = { AudioConcurrencyMode::MIX_WITH_OTHERS };
85 supportedTones_ = AudioPolicyManager::GetInstance().GetSupportedTones(GetCountryCode());
86 toneInfo_ = NULL;
87 initialToneInfo_ = NULL;
88 samplingRate_ = rendererOptions_.streamInfo.samplingRate;
89 }
90
~TonePlayerImpl()91 TonePlayerImpl::~TonePlayerImpl()
92 {
93 AUDIO_INFO_LOG("TonePlayerImpl destructor");
94 if (audioRenderer_ != nullptr) {
95 audioRenderer_->Stop();
96 audioRenderer_->Release();
97 }
98 audioRenderer_ = nullptr;
99 }
100
Create(const AudioRendererInfo & rendererInfo)101 std::shared_ptr<TonePlayer> TonePlayer::Create(const AudioRendererInfo &rendererInfo)
102 {
103 if (!PermissionUtil::VerifySelfPermission()) {
104 AUDIO_ERR_LOG("Create: No system permission");
105 return nullptr;
106 }
107 return std::make_shared<TonePlayerImpl>("", rendererInfo);
108 }
109
Create(const std::string cachePath,const AudioRendererInfo & rendererInfo)110 std::shared_ptr<TonePlayer> TonePlayer::Create(const std::string cachePath, const AudioRendererInfo &rendererInfo)
111 {
112 bool checkPermission = PermissionUtil::VerifySelfPermission();
113 CHECK_AND_RETURN_RET_LOG(checkPermission, nullptr, "Create: No system permission");
114 return std::make_shared<TonePlayerImpl>(cachePath, rendererInfo);
115 }
116
OnInterrupt(const InterruptEvent & interruptEvent)117 void TonePlayerImpl::OnInterrupt(const InterruptEvent &interruptEvent)
118 {
119 AUDIO_INFO_LOG("ToneType %{public}d eventType: %{public}d", toneType_, interruptEvent.eventType);
120 return;
121 }
122
OnStateChange(const RendererState state,const StateChangeCmdType cmdType)123 void TonePlayerImpl::OnStateChange(const RendererState state, const StateChangeCmdType __attribute__((unused)) cmdType)
124 {
125 AUDIO_INFO_LOG("ToneType %{public}d OnStateChange state: %{public}d", toneType_, state);
126 }
127
OnWriteData(size_t length)128 void TonePlayerImpl::OnWriteData(size_t length)
129 {
130 std::lock_guard<std::mutex> lock(optMutex_);
131 if (toneState_ == TONE_RELEASED) {
132 AUDIO_WARNING_LOG("Tone %{public}d is already released", toneType_);
133 return;
134 }
135 BufferDesc bufDesc = {};
136 if (audioRenderer_ != nullptr) {
137 audioRenderer_->GetBufferDesc(bufDesc);
138 } else {
139 AUDIO_ERR_LOG("OnWriteData audioRenderer_ is null");
140 }
141 bufDesc.dataLength = 0;
142 if (bufDesc.bufLength == 0) {
143 AUDIO_WARNING_LOG(" bufDesc bufLength is 0");
144 return;
145 }
146
147 // Clear output buffer: WaveGenerator accumulates into audioBuffer buffer
148 memset_s(bufDesc.buffer, bufDesc.bufLength, 0, bufDesc.bufLength);
149 if (AudioToneSequenceGen(bufDesc) == false) {
150 AUDIO_WARNING_LOG("SequenceGen error");
151 bufDesc.dataLength = bufDesc.bufLength;
152 }
153 DumpFileUtil::WriteDumpFile(dumpFile_, static_cast<void *>(bufDesc.buffer), bufDesc.dataLength);
154 if (audioRenderer_ != nullptr) {
155 audioRenderer_->Enqueue(bufDesc);
156 } else {
157 AUDIO_ERR_LOG("AudioToneDataThreadFunc Enqueue audioRenderer_ is null");
158 }
159 }
160
LoadTone(ToneType toneType)161 bool TonePlayerImpl::LoadTone(ToneType toneType)
162 {
163 std::lock_guard<std::mutex> lock(optMutex_);
164 AUDIO_INFO_LOG("LoadTone type: %{public}d", toneType);
165 bool result = false;
166 bool checkPermission = PermissionUtil::VerifySelfPermission();
167 CHECK_AND_RETURN_RET_LOG(checkPermission, false, "LoadTone: No system permission");
168 if (toneType >= NUM_TONES) {
169 return result;
170 }
171 if (std::find(supportedTones_.begin(), supportedTones_.end(), (int32_t)toneType) == supportedTones_.end()) {
172 return result;
173 }
174 toneType_ = toneType;
175 amplitudeType_ = std::count(TONE_TYPE_LIST.begin(), TONE_TYPE_LIST.end(), toneType_) > 0 ?
176 DIGITAMPLITUDE : AMPLITUDE;
177 initialToneInfo_ = AudioPolicyManager::GetInstance().GetToneConfig(toneType, GetCountryCode());
178 if (initialToneInfo_->segmentCnt == 0) {
179 AUDIO_ERR_LOG("LoadTone failed, calling GetToneConfig returned invalid");
180 return result;
181 }
182 if (!isRendererInited_) {
183 isRendererInited_ = InitAudioRenderer();
184 CHECK_AND_RETURN_RET_LOG(isRendererInited_, false, "InitAudioRenderer failed");
185 }
186 result = InitToneWaveInfo();
187 CHECK_AND_RETURN_RET_LOG(result, false, "InitToneWaveInfo failed");
188 toneState_ = TONE_INIT;
189 DumpFileUtil::OpenDumpFile(DumpFileUtil::DUMP_CLIENT_PARA, DUMP_TONEPLAYER_FILENAME, &dumpFile_);
190 return result;
191 }
192
StartTone()193 bool TonePlayerImpl::StartTone()
194 {
195 std::lock_guard<std::mutex> lock(optMutex_);
196 AUDIO_INFO_LOG("STARTTONE ToneType %{public}d", toneType_);
197 CHECK_AND_RETURN_RET_LOG(toneState_ == TONE_INIT || toneState_ == TONE_STOPPED, false,
198 "Start audioRenderer_ is null");
199
200 if (!isRendererInited_ || audioRenderer_ == nullptr) {
201 AUDIO_ERR_LOG("Start audioRenderer_ is null");
202 return false;
203 }
204 bool result = audioRenderer_->Start();
205 CHECK_AND_RETURN_RET_LOG(result, result, "Start audioRenderer_ failed");
206 toneState_ = TONE_STARTING;
207 return result;
208 }
209
StopTone()210 bool TonePlayerImpl::StopTone()
211 {
212 std::lock_guard<std::mutex> lock(optMutex_);
213 AUDIO_INFO_LOG("STOPTONE ToneType %{public}d", toneType_);
214
215 if (!isRendererInited_ || audioRenderer_ == nullptr) {
216 AUDIO_ERR_LOG("Stop audioRenderer_ is null");
217 return false;
218 }
219 // in plan: mark state stopping, smooth volume in onwritedata
220 bool result = audioRenderer_->Stop();
221 CHECK_AND_RETURN_RET_LOG(result, result, "Stop audioRenderer_ failed");
222 toneState_ = TONE_STOPPING;
223 return result;
224 }
225
Release()226 bool TonePlayerImpl::Release()
227 {
228 std::unique_lock<std::mutex> lock(optMutex_);
229 toneState_ = TONE_RELEASED;
230 lock.unlock();
231 if (audioRenderer_ != nullptr) {
232 audioRenderer_->Stop();
233 audioRenderer_->Release();
234 audioRenderer_ = nullptr;
235 }
236 DumpFileUtil::CloseDumpFile(&dumpFile_);
237 return true;
238 }
239
GetCurrentSegmentUpdated()240 void TonePlayerImpl::GetCurrentSegmentUpdated()
241 {
242 if (toneInfo_->segments[currSegment_].loopCnt) {
243 if (loopCounter_ < toneInfo_->segments[currSegment_].loopCnt) {
244 currSegment_ = toneInfo_->segments[currSegment_].loopIndx;
245 ++loopCounter_;
246 } else {
247 // completed loop. go to next segment
248 loopCounter_ = 0;
249 currSegment_++;
250 }
251 } else {
252 // no looping required , go to next segment
253 currSegment_++;
254 }
255 AUDIO_INFO_LOG("GetCurrentSegmentUpdated loopCounter_: %{public}d, currSegment_: %{public}d",
256 loopCounter_, currSegment_);
257 }
258
CheckToneContinuity()259 bool TonePlayerImpl::CheckToneContinuity()
260 {
261 AUDIO_INFO_LOG("CheckToneContinuity Entry loopCounter_: %{public}d, currSegment_: %{public}d",
262 loopCounter_, currSegment_);
263 bool retVal = false;
264 GetCurrentSegmentUpdated();
265
266 // Handle loop if last segment reached
267 if (toneInfo_->segments[currSegment_].duration == 0) {
268 AUDIO_DEBUG_LOG("Last Seg: %{public}d", currSegment_);
269 if (currCount_ < toneInfo_->repeatCnt) {
270 currSegment_ = toneInfo_->repeatSegment;
271 ++currCount_;
272 retVal = true;
273 } else {
274 retVal = false;
275 }
276 } else {
277 retVal = true;
278 }
279 AUDIO_DEBUG_LOG("CheckToneContinuity End loopCounter_: %{public}d, currSegment_: %{public}d currCount_: %{public}d",
280 loopCounter_, currSegment_, currCount_);
281 return retVal;
282 }
283
ContinueToneplay(uint32_t reqSample,int8_t * audioBuffer)284 bool TonePlayerImpl::ContinueToneplay(uint32_t reqSample, int8_t *audioBuffer)
285 {
286 if (toneState_ != TONE_RUNNING) {
287 return false;
288 }
289 if (totalSample_ <= nextSegSample_) {
290 if (toneInfo_->segments[currSegment_].duration != 0) {
291 GetSamples(toneInfo_->segments[currSegment_].waveFreq, audioBuffer, reqSample);
292 }
293 return true;
294 }
295
296 if (CheckToneContinuity()) {
297 if (toneInfo_->segments[currSegment_].duration != 0) {
298 sampleCount_ = 0;
299 GetSamples(toneInfo_->segments[currSegment_].waveFreq, audioBuffer, reqSample);
300 }
301 }
302 nextSegSample_ += (toneInfo_->segments[currSegment_].duration * samplingRate_) / C1000MS;
303 AUDIO_INFO_LOG("ContinueToneplay nextSegSample_: %{public}d", nextSegSample_);
304 return true;
305 }
306
GetSamples(uint16_t * freqs,int8_t * buffer,uint32_t reqSamples)307 int32_t TonePlayerImpl::GetSamples(uint16_t *freqs, int8_t *buffer, uint32_t reqSamples)
308 {
309 uint32_t index;
310 uint8_t *data;
311 uint16_t freqVal;
312 float pi = 3.1428f;
313 for (uint32_t i = 0; i <= TONEINFO_MAX_WAVES; i++) {
314 if (freqs[i] == 0) {
315 break;
316 }
317 freqVal = freqs[i];
318 AUDIO_DEBUG_LOG("GetSamples Freq: %{public}d sampleCount_: %{public}d", freqVal, sampleCount_);
319 index = sampleCount_;
320 data = reinterpret_cast<uint8_t*>(buffer);
321 double factor = freqVal * 2 * pi / samplingRate_; // 2 is a parameter in the sine wave formula
322 for (uint32_t idx = 0; idx < reqSamples; idx++) {
323 int16_t sample = amplitudeType_ * sin(factor * index);
324 uint32_t result;
325 if (i == 0) {
326 result = (sample & 0xFF);
327 *data = result & 0xFF;
328 data++;
329 *data = ((sample & 0xFF00) >> BIT8);
330 data++;
331 } else {
332 result = *data + (static_cast<uint16_t>(sample) & 0xFF);
333 *data = result & 0xFF;
334 data++;
335 *data += (result >> BIT8) + ((sample & 0xFF00) >> BIT8);
336 data++;
337 }
338 index++;
339 }
340 }
341 sampleCount_ += reqSamples;
342 return 0;
343 }
344
Str16ToStr8(std::u16string str)345 std::string TonePlayerImpl::Str16ToStr8(std::u16string str)
346 {
347 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(DEFAULT_STRING);
348 std::string result = convert.to_bytes(str);
349 return result == DEFAULT_STRING ? "" : result;
350 }
351
GetCountryCode()352 std::string TonePlayerImpl::GetCountryCode()
353 {
354 char paramValue[SYSPARA_SIZE] = {0};
355 GetParameter(DEBUG_COUNTRYCODE_NAME, "", paramValue, SYSPARA_SIZE);
356 if (strcmp(paramValue, "")) {
357 AUDIO_DEBUG_LOG("GetParameter %{public}s", paramValue);
358 std::string countryCode(paramValue);
359 for (char &c : countryCode) {
360 c = std::tolower(c);
361 }
362 return countryCode;
363 }
364
365 std::string countryCodeStr8 = "";
366 #if defined(AUDIO_TEL_CORE_SERVICE_ENABLE) && defined(AUIDO_TEL_CELLULAR_DATA_ENABLE)
367 int32_t slotId = Telephony::CellularDataClient::GetInstance().GetDefaultCellularDataSlotId();
368 std::u16string countryCodeForNetwork;
369 DelayedRefSingleton<Telephony::CoreServiceClient>::GetInstance().GetIsoCountryCodeForNetwork(
370 slotId, countryCodeForNetwork);
371 countryCodeStr8 = Str16ToStr8(countryCodeForNetwork);
372 if (countryCodeStr8.empty()) {
373 std::u16string countryCodeForSim;
374 DelayedRefSingleton<Telephony::CoreServiceClient>::GetInstance().GetISOCountryCodeForSim(
375 slotId, countryCodeForSim);
376 countryCodeStr8 = Str16ToStr8(countryCodeForSim);
377 }
378 AUDIO_DEBUG_LOG("GetISOCountryCode %{public}s", paramValue);
379 #endif
380 for (char &c : countryCodeStr8) {
381 c = std::tolower(c);
382 }
383 return countryCodeStr8;
384 }
385
CheckToneStarted(uint32_t reqSample,int8_t * audioBuffer)386 bool TonePlayerImpl::CheckToneStarted(uint32_t reqSample, int8_t *audioBuffer)
387 {
388 if (toneState_ != TONE_STARTING) {
389 return false;
390 }
391 toneState_ = TONE_RUNNING;
392 if (toneInfo_->segments[currSegment_].duration != 0) {
393 sampleCount_ = 0;
394 GetSamples(toneInfo_->segments[currSegment_].waveFreq, audioBuffer, reqSample);
395 }
396 return true;
397 }
398
CheckToneStopped()399 bool TonePlayerImpl::CheckToneStopped()
400 {
401 if (toneState_ == TONE_STOPPED) {
402 return true;
403 }
404 if (toneInfo_->segments[currSegment_].duration == 0 || totalSample_ > maxSample_ || toneState_ == TONE_STOPPING) {
405 if (toneState_ == TONE_RUNNING) {
406 toneState_ = TONE_STOPPING;
407 AUDIO_DEBUG_LOG("Audicallback move playing to stoping");
408 }
409 return true;
410 }
411 return false;
412 }
413
AudioToneSequenceGen(BufferDesc & bufDesc)414 bool TonePlayerImpl::AudioToneSequenceGen(BufferDesc &bufDesc)
415 {
416 int8_t *audioBuffer = reinterpret_cast<int8_t *>(bufDesc.buffer);
417 uint32_t totalBufAvailable = bufDesc.bufLength / sizeof(int16_t);
418 bool retVal = true;
419 while (totalBufAvailable) {
420 uint32_t reqSamples = totalBufAvailable < processSize_ * CDOUBLE ? totalBufAvailable : processSize_;
421 AUDIO_DEBUG_LOG("AudioToneDataThreadFunc, lReqSmp: %{public}d totalBufAvailable: %{public}d",
422 reqSamples, totalBufAvailable);
423 // Update pcm frame count and end time (current time at the end of this process)
424 totalSample_ += reqSamples;
425 if (CheckToneStopped()) {
426 // in plan: do smooth works
427 AUDIO_PRERELEASE_LOGI("CheckToneStopped true toneType_ %{public}d", toneType_);
428 if (toneState_ == TONE_STOPPING) {
429 toneState_ = TONE_STOPPED;
430 totalBufAvailable = 0;
431 }
432 return false;
433 } else if (CheckToneStarted(reqSamples, audioBuffer)) {
434 bufDesc.dataLength += reqSamples * sizeof(int16_t);
435 } else {
436 if (ContinueToneplay(reqSamples, audioBuffer)) {
437 bufDesc.dataLength += reqSamples * sizeof(int16_t);
438 }
439 }
440 totalBufAvailable -= reqSamples;
441 audioBuffer += reqSamples * sizeof(int16_t);
442 }
443 return retVal;
444 }
445
InitToneWaveInfo()446 bool TonePlayerImpl::InitToneWaveInfo()
447 {
448 AUDIO_INFO_LOG("InitToneWaveInfo ToneType %{public}d", toneType_);
449 if (initialToneInfo_ == NULL) {
450 return false;
451 }
452 toneInfo_ = initialToneInfo_;
453 maxSample_ = TONEINFO_INF;
454
455 // Initialize tone sequencer
456 totalSample_ = 0;
457 currSegment_ = 0;
458 currCount_ = 0;
459 loopCounter_ = 0;
460 if (toneInfo_->segments[0].duration == TONEINFO_INF) {
461 nextSegSample_ = TONEINFO_INF;
462 } else {
463 nextSegSample_ = (toneInfo_->segments[0].duration * samplingRate_) / C1000MS;
464 }
465 AUDIO_INFO_LOG("Prepare wave, nextSegSample_: %{public}d", nextSegSample_);
466 return true;
467 }
468
469
InitAudioRenderer()470 bool TonePlayerImpl::InitAudioRenderer()
471 {
472 processSize_ = (rendererOptions_.streamInfo.samplingRate * C20MS) / C1000MS;
473 audioRenderer_ = AudioRenderer::CreateRenderer(rendererOptions_);
474 CHECK_AND_RETURN_RET_LOG(audioRenderer_ != nullptr, false,
475 "Renderer create failed");
476
477 if (rendererOptions_.rendererInfo.streamUsage == STREAM_USAGE_VOICE_MODEM_COMMUNICATION) {
478 audioRenderer_->EnableVoiceModemCommunicationStartStream(true);
479 }
480
481 size_t targetSize = 0;
482 int32_t ret = audioRenderer_->GetBufferSize(targetSize);
483
484 AUDIO_DEBUG_LOG("Playback renderer created");
485 int32_t setRenderMode = audioRenderer_->SetRenderMode(RENDER_MODE_CALLBACK);
486 CHECK_AND_RETURN_RET_LOG(!setRenderMode, false, "initAudioRenderer: SetRenderMode failed");
487 AUDIO_DEBUG_LOG("SetRenderMode Sucessful");
488
489 if (ret == 0 && targetSize != 0) {
490 size_t bufferDuration = 20; // 20 -> 20ms
491 audioRenderer_->SetBufferDuration(bufferDuration);
492 AUDIO_INFO_LOG("Init renderer with buffer %{public}zu, duration %{public}zu", targetSize, bufferDuration);
493 }
494
495 audioRenderer_->SetAudioEffectMode(EFFECT_NONE);
496
497 int32_t setRendererWrite = audioRenderer_->SetRendererWriteCallback(shared_from_this());
498 CHECK_AND_RETURN_RET_LOG(!setRendererWrite, false, "SetRendererWriteCallback failed");
499 AUDIO_DEBUG_LOG("SetRendererWriteCallback Sucessful");
500
501 int32_t setRendererCallback = audioRenderer_->SetRendererCallback(shared_from_this());
502 CHECK_AND_RETURN_RET_LOG(!setRendererCallback, false, "initAudioRenderer: SetRendererCallbackfailed");
503 AUDIO_DEBUG_LOG("SetRendererCallback Sucessful");
504 return true;
505 }
506 } // end namespace AudioStandard
507 } // end OHOS
508