1 /*
2  * Copyright (c) 2023 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 
16 #include "system_tone_player_impl.h"
17 
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <thread>
21 
22 #include "audio_info.h"
23 #include "config_policy_utils.h"
24 
25 #include "media_errors.h"
26 #include "system_sound_log.h"
27 #include "system_sound_vibrator.h"
28 
29 using namespace std;
30 using namespace OHOS::AbilityRuntime;
31 
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "SystemTonePlayer"};
34 }
35 
36 namespace OHOS {
37 namespace Media {
38 const std::string FDHEAD = "fd://";
39 const std::string AUDIO_FORMAT_STR = ".ogg";
40 const std::string HAPTIC_FORMAT_STR = ".json";
41 const int32_t MAX_STREAM_ID = 128;
42 const int32_t ERRCODE_OPERATION_NOT_ALLOWED = 5400102;
43 const int32_t ERRCODE_IOERROR = 5400103;
44 const int32_t ERRCODE_INVALID_PARAMS = 20700002;
45 const int32_t ERRCODE_UNSUPPORTED_OPERATION = 20700003;
46 const std::string GENTLE_HAPTIC_PATH = "/sys_prod/resource/media/haptics/gentle/synchronized/notifications";
47 const std::string RINGTONE_PATH = "/media/audio/";
48 const std::string STANDARD_HAPTICS_PATH = "/media/haptics/standard/synchronized/";
49 const std::string GENTLE_HAPTICS_PATH = "/media/haptics/gentle/synchronized/";
50 const std::string NON_SYNC_HAPTICS_PATH = "resource/media/haptics/standard/non-synchronized/";
51 
FormateHapticUri(const std::string & audioUri,ToneHapticsFeature feature)52 static std::string FormateHapticUri(const std::string &audioUri, ToneHapticsFeature feature)
53 {
54     std::string hapticUri = audioUri;
55     if (feature == ToneHapticsFeature::GENTLE) {
56         hapticUri.replace(0, hapticUri.rfind("/"), GENTLE_HAPTIC_PATH);
57     }
58     hapticUri.replace(hapticUri.rfind(AUDIO_FORMAT_STR), AUDIO_FORMAT_STR.length(), HAPTIC_FORMAT_STR);
59     return hapticUri;
60 }
61 
IsFileExisting(const std::string & fileUri)62 static bool IsFileExisting(const std::string &fileUri)
63 {
64     struct stat buffer;
65     return (stat(fileUri.c_str(), &buffer) == 0);
66 }
67 
FindHapticUriByAudioUri(const std::string & audioUri,ToneHapticsFeature feature,bool & isSupported)68 static std::string FindHapticUriByAudioUri(const std::string &audioUri, ToneHapticsFeature feature,
69     bool &isSupported)
70 {
71     std::string hapticUri = "";
72     if (audioUri.length() <= AUDIO_FORMAT_STR.length() ||
73         audioUri.rfind(AUDIO_FORMAT_STR) != audioUri.length() - AUDIO_FORMAT_STR.length()) {
74         MEDIA_LOGW("invalid audio uri: %{public}s", audioUri.c_str());
75         isSupported = false;
76         return hapticUri;
77     }
78     // the end of default system tone uri is ".ogg"
79     hapticUri = FormateHapticUri(audioUri, feature);
80     isSupported = !hapticUri.empty() && IsFileExisting(hapticUri);
81     return hapticUri;
82 }
83 
SystemTonePlayerImpl(const shared_ptr<Context> & context,SystemSoundManagerImpl & systemSoundMgr,SystemToneType systemToneType)84 SystemTonePlayerImpl::SystemTonePlayerImpl(const shared_ptr<Context> &context,
85     SystemSoundManagerImpl &systemSoundMgr, SystemToneType systemToneType)
86     : context_(context),
87       systemSoundMgr_(systemSoundMgr),
88       systemToneType_(systemToneType)
89 {
90     audioHapticManager_ = AudioHapticManagerFactory::CreateAudioHapticManager();
91     CHECK_AND_RETURN_LOG(audioHapticManager_ != nullptr, "Failed to get audio haptic manager");
92 
93     if (InitDataShareHelper()) {
94         std::string systemToneUri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
95         InitPlayer(systemToneUri);
96         ReleaseDataShareHelper();
97     }
98 }
99 
~SystemTonePlayerImpl()100 SystemTonePlayerImpl::~SystemTonePlayerImpl()
101 {
102     DeleteAllPlayer();
103     if (audioHapticManager_ != nullptr) {
104         ReleaseHapticsSourceIds();
105         audioHapticManager_ = nullptr;
106     }
107     ReleaseDataShareHelper();
108 }
109 
GetDefaultNonSyncHapticsPath()110 std::string SystemTonePlayerImpl::GetDefaultNonSyncHapticsPath()
111 {
112     char buf[MAX_PATH_LEN];
113     char *path = GetOneCfgFile(NON_SYNC_HAPTICS_PATH.c_str(), buf, MAX_PATH_LEN);
114     if (path == nullptr || *path == '\0') {
115         MEDIA_LOGE("Failed to get default non-sync haptics path");
116         return "";
117     }
118     std::string filePath = path;
119     MEDIA_LOGI("Default non-sync haptics path [%{public}s]", filePath.c_str());
120     filePath = filePath + "Tick-tock.json";
121     return filePath;
122 }
123 
IsSameHapticMaps(const std::map<ToneHapticsFeature,std::string> & hapticUriMap)124 bool SystemTonePlayerImpl::IsSameHapticMaps(const std::map<ToneHapticsFeature, std::string> &hapticUriMap)
125 {
126     if (hapticUriMap_.size() != hapticUriMap.size()) {
127         return false;
128     }
129     for (auto &[feature, hapticUri] : hapticUriMap) {
130         if (hapticUriMap_.find(feature) == hapticUriMap_.end()) {
131             return false;
132         }
133         if (hapticUriMap_[feature] != hapticUri) {
134             return false;
135         }
136     }
137     return true;
138 }
139 
InitPlayer(const std::string & audioUri)140 int32_t SystemTonePlayerImpl::InitPlayer(const std::string &audioUri)
141 {
142     MEDIA_LOGI("Enter InitPlayer() with audio uri %{public}s", audioUri.c_str());
143 
144     if (audioUri == NO_SYSTEM_SOUND) {
145         if (!configuredUri_.empty() && configuredUri_ == audioUri) {
146             MEDIA_LOGI("The right system tone uri has been registered. Return directly.");
147             systemToneState_ = SystemToneState::STATE_PREPARED;
148             return MSERR_OK;
149         }
150         defaultNonSyncHapticUri_ = GetDefaultNonSyncHapticsPath();
151         configuredUri_ = NO_SYSTEM_SOUND;
152         systemToneState_ = SystemToneState::STATE_NEW;
153         return MSERR_OK;
154     }
155 
156     std::map<ToneHapticsFeature, std::string> hapticUriMap;
157     GetCurrentHapticSettings(audioUri, hapticUriMap);
158 
159     if (configuredUri_ == audioUri && IsSameHapticMaps(hapticUriMap)) {
160         MEDIA_LOGI("The right system tone uri has been registered. Return directly.");
161         systemToneState_ = SystemToneState::STATE_PREPARED;
162         return MSERR_OK;
163     }
164 
165     configuredUri_ = audioUri;
166     hapticUriMap_.swap(hapticUriMap);
167 
168     ReleaseHapticsSourceIds();
169     // Get the haptic file uri according to the audio file uri.
170     InitHapticsSourceIds();
171 
172     systemToneState_ = SystemToneState::STATE_NEW;
173     return MSERR_OK;
174 }
175 
CreatePlayerWithOptions(const AudioHapticPlayerOptions & options)176 int32_t SystemTonePlayerImpl::CreatePlayerWithOptions(const AudioHapticPlayerOptions &options)
177 {
178     CHECK_AND_RETURN_RET_LOG(sourceIds_.find(hapticsFeature_) != sourceIds_.end(), MSERR_OPEN_FILE_FAILED,
179         "Failed to find suorce id");
180     CHECK_AND_RETURN_RET_LOG(audioHapticManager_ != nullptr, MSERR_OPEN_FILE_FAILED,
181         "AudioHapticManager_ is nullptr");
182     playerMap_[streamId_] = audioHapticManager_->CreatePlayer(sourceIds_[hapticsFeature_], options);
183     CHECK_AND_RETURN_RET_LOG(playerMap_[streamId_] != nullptr, MSERR_OPEN_FILE_FAILED,
184         "Failed to create system tone player instance");
185 
186     callbackMap_[streamId_] = std::make_shared<SystemTonePlayerCallback>(streamId_, shared_from_this());
187     CHECK_AND_RETURN_RET_LOG(callbackMap_[streamId_] != nullptr, MSERR_OPEN_FILE_FAILED,
188         "Failed to create system tone player callback object");
189     (void)playerMap_[streamId_]->SetAudioHapticPlayerCallback(callbackMap_[streamId_]);
190     playerMap_[streamId_]->SetHapticsMode(hapticsMode_);
191 
192     int32_t result = playerMap_[streamId_]->Prepare();
193     CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result,
194         "Failed to prepare for system tone player: %{public}d", result);
195     return MSERR_OK;
196 }
197 
UpdateStreamId()198 void SystemTonePlayerImpl::UpdateStreamId()
199 {
200     // Update streamId_ and ensure that streamId_ has no player.
201     streamId_++;
202     if (streamId_ > MAX_STREAM_ID) {
203         streamId_ = 1;
204     }
205     if (playerMap_.count(streamId_) > 0) {
206         DeletePlayer(streamId_);
207     }
208 }
209 
GetOptionsFromRingerMode()210 SystemToneOptions SystemTonePlayerImpl::GetOptionsFromRingerMode()
211 {
212     SystemToneOptions options = {false, false};
213     AudioStandard::AudioRingerMode ringerMode = systemSoundMgr_.GetRingerMode();
214     MEDIA_LOGI("Current ringer mode is %{public}d", ringerMode);
215     if (ringerMode == AudioStandard::AudioRingerMode::RINGER_MODE_SILENT) {
216         options.muteAudio = true;
217         options.muteHaptics = true;
218     } else if (ringerMode == AudioStandard::AudioRingerMode::RINGER_MODE_VIBRATE) {
219         options.muteAudio = true;
220     } else if (ringerMode == AudioStandard::AudioRingerMode::RINGER_MODE_NORMAL) {
221         bool hapticsSwitchStatus = systemSoundMgr_.CheckVibrateSwitchStatus();
222         options.muteHaptics = !hapticsSwitchStatus;
223     }
224     return options;
225 }
226 
GetNewHapticUriForAudioUri(const std::string & audioUri,const std::string & ringtonePath,const std::string & hapticsPath)227 std::string SystemTonePlayerImpl::GetNewHapticUriForAudioUri(const std::string &audioUri,
228     const std::string &ringtonePath, const std::string& hapticsPath)
229 {
230     string hapticUri = audioUri;
231     size_t pos = hapticUri.find(ringtonePath);
232     if (pos == string::npos) {
233         return "";
234     }
235     hapticUri.replace(pos, ringtonePath.size(), hapticsPath);
236     if (hapticUri.length() > AUDIO_FORMAT_STR.length() &&
237         hapticUri.rfind(AUDIO_FORMAT_STR) == hapticUri.length() - AUDIO_FORMAT_STR.length()) {
238         hapticUri.replace(hapticUri.rfind(AUDIO_FORMAT_STR), AUDIO_FORMAT_STR.length(), HAPTIC_FORMAT_STR);
239         if (IsFileExisting(hapticUri)) {
240             return hapticUri;
241         }
242     }
243     return "";
244 }
245 
GetNewHapticUriForAudioUri(const std::string & audioUri,std::map<ToneHapticsFeature,std::string> & hapticsUriMap)246 void SystemTonePlayerImpl::GetNewHapticUriForAudioUri(const std::string &audioUri,
247     std::map<ToneHapticsFeature, std::string> &hapticsUriMap)
248 {
249     supportedHapticsFeatures_.clear();
250     std::string currAudioUri = audioUri;
251     std::string hapticUri = GetNewHapticUriForAudioUri(audioUri, RINGTONE_PATH, STANDARD_HAPTICS_PATH);
252     if (hapticUri.empty()) {
253         currAudioUri = systemSoundMgr_.GetDefaultSystemToneUri(SYSTEM_TONE_TYPE_NOTIFICATION);
254         hapticUri = GetNewHapticUriForAudioUri(currAudioUri, RINGTONE_PATH, STANDARD_HAPTICS_PATH);
255         if (hapticUri.empty()) {
256             MEDIA_LOGW("Failed to find the default json file. Play system tone without vibration.");
257             isHapticUriEmpty_ = true;
258             return;
259         }
260     }
261     supportedHapticsFeatures_.push_back(ToneHapticsFeature::STANDARD);
262     hapticsUriMap[ToneHapticsFeature::STANDARD] = hapticUri;
263     MEDIA_LOGI("GetNewHapticUriForAudioUri: STANDARD hapticUri %{public}s ", hapticUri.c_str());
264     hapticUri = GetNewHapticUriForAudioUri(currAudioUri, RINGTONE_PATH, GENTLE_HAPTICS_PATH);
265     if (!hapticUri.empty()) {
266         supportedHapticsFeatures_.push_back(ToneHapticsFeature::GENTLE);
267         hapticsUriMap[ToneHapticsFeature::GENTLE] = hapticUri;
268         MEDIA_LOGI("GetNewHapticUriForAudioUri: GENTLE hapticUri %{public}s ", hapticUri.c_str());
269     }
270 }
271 
GetHapticUriForAudioUri(const std::string & audioUri,std::map<ToneHapticsFeature,std::string> & hapticsUriMap)272 void SystemTonePlayerImpl::GetHapticUriForAudioUri(const std::string &audioUri,
273     std::map<ToneHapticsFeature, std::string> &hapticsUriMap)
274 {
275     supportedHapticsFeatures_.clear();
276     bool isSupported = false;
277     std::string currAudioUri = audioUri;
278     std::string hapticUri = FindHapticUriByAudioUri(currAudioUri, ToneHapticsFeature::STANDARD, isSupported);
279     if (!isSupported) {
280         MEDIA_LOGW("Failed to find the vibration json file for audioUri. Use the default json file.");
281         currAudioUri = systemSoundMgr_.GetDefaultSystemToneUri(SYSTEM_TONE_TYPE_NOTIFICATION);
282         hapticUri = FindHapticUriByAudioUri(currAudioUri, ToneHapticsFeature::STANDARD, isSupported);
283         if (!isSupported) {
284             MEDIA_LOGW("Failed to find the default json file. Play system tone without vibration.");
285             isHapticUriEmpty_ = true;
286             return;
287         }
288     }
289     supportedHapticsFeatures_.push_back(ToneHapticsFeature::STANDARD);
290     hapticsUriMap[ToneHapticsFeature::STANDARD] = hapticUri;
291     MEDIA_LOGI("GetHapticUriForAudioUri: STANDARD hapticUri %{public}s ", hapticUri.c_str());
292     hapticUri = FindHapticUriByAudioUri(currAudioUri, ToneHapticsFeature::GENTLE, isSupported);
293     if (isSupported) {
294         supportedHapticsFeatures_.push_back(ToneHapticsFeature::GENTLE);
295         hapticsUriMap[ToneHapticsFeature::GENTLE] = hapticUri;
296         MEDIA_LOGI("GetHapticUriForAudioUri: GENTLE hapticUri %{public}s ", hapticUri.c_str());
297     }
298 }
299 
CreateDataShareHelper(int32_t systemAbilityId)300 static shared_ptr<DataShare::DataShareHelper> CreateDataShareHelper(int32_t systemAbilityId)
301 {
302     auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
303     if (saManager == nullptr) {
304         return nullptr;
305     }
306     auto remoteObj = saManager->GetSystemAbility(systemAbilityId);
307     if (remoteObj == nullptr) {
308         return nullptr;
309     }
310     return DataShare::DataShareHelper::Creator(remoteObj, RINGTONE_URI);
311 }
312 
InitDataShareHelper()313 bool SystemTonePlayerImpl::InitDataShareHelper()
314 {
315     MEDIA_LOGD("Enter InitDataShareHelper()");
316     ReleaseDataShareHelper();
317     dataShareHelper_ = CreateDataShareHelper(STORAGE_MANAGER_MANAGER_ID);
318     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, false, "Failed to create dataShareHelper.");
319     return true;
320 }
321 
ReleaseDataShareHelper()322 void SystemTonePlayerImpl::ReleaseDataShareHelper()
323 {
324     if (dataShareHelper_ != nullptr) {
325         MEDIA_LOGD("Enter ReleaseDataShareHelper()");
326         dataShareHelper_->Release();
327         dataShareHelper_ = nullptr;
328     }
329 }
330 
ChangeUri(const std::string & uri)331 std::string SystemTonePlayerImpl::ChangeUri(const std::string &uri)
332 {
333     std::string systemtoneUri = uri;
334     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, systemtoneUri, "Failed to init dataShareHelper_.");
335 
336     DataShare::DatashareBusinessError businessError;
337     DataShare::DataSharePredicates queryPredicates;
338     Uri ringtonePathUri(RINGTONE_PATH_URI);
339     vector<string> columns = {{RINGTONE_COLUMN_TONE_ID}, {RINGTONE_COLUMN_DATA}};
340     queryPredicates.EqualTo(RINGTONE_COLUMN_DATA, uri);
341     auto resultSet = dataShareHelper_->Query(ringtonePathUri, queryPredicates, columns, &businessError);
342     auto results = make_unique<RingtoneFetchResult<RingtoneAsset>>(move(resultSet));
343     unique_ptr<RingtoneAsset> ringtoneAsset = results->GetFirstObject();
344     if (ringtoneAsset != nullptr) {
345         string uriStr = RINGTONE_PATH_URI + RINGTONE_SLASH_CHAR + to_string(ringtoneAsset->GetId());
346         MEDIA_LOGD("ChangeUri::Open systemtoneUri is %{public}s", uriStr.c_str());
347         Uri ofUri(uriStr);
348         int32_t fd = dataShareHelper_->OpenFile(ofUri, "r");
349         if (fd > 0) {
350             systemtoneUri = FDHEAD + to_string(fd);
351         }
352     }
353 
354     resultSet == nullptr ? : resultSet->Close();
355     MEDIA_LOGI("SystemTonePlayerImpl::ChangeUri systemtoneUri is %{public}s", systemtoneUri.c_str());
356     return systemtoneUri;
357 }
358 
ChangeHapticsUri(const std::string & hapticsUri)359 std::string SystemTonePlayerImpl::ChangeHapticsUri(const std::string &hapticsUri)
360 {
361     std::string newHapticsUri = hapticsUri;
362     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, newHapticsUri, "Failed to init dataShareHelper_.");
363 
364     DataShare::DatashareBusinessError businessError;
365     DataShare::DataSharePredicates queryPredicates;
366     Uri hapticsPathUri(VIBRATE_PATH_URI);
367     vector<string> columns = {{VIBRATE_COLUMN_VIBRATE_ID}, {VIBRATE_COLUMN_DATA}};
368     queryPredicates.EqualTo(RINGTONE_COLUMN_DATA, hapticsUri);
369     auto resultSet = dataShareHelper_->Query(hapticsPathUri, queryPredicates, columns, &businessError);
370     auto results = make_unique<RingtoneFetchResult<VibrateAsset>>(move(resultSet));
371 
372     unique_ptr<VibrateAsset> vibrateAssetByUri = results->GetFirstObject();
373     if (vibrateAssetByUri != nullptr) {
374         string uriStr = VIBRATE_PATH_URI + RINGTONE_SLASH_CHAR + to_string(vibrateAssetByUri->GetId());
375         MEDIA_LOGD("ChangeHapticsUri::Open newHapticsUri is %{public}s", uriStr.c_str());
376         Uri ofUri(uriStr);
377         int32_t fd = dataShareHelper_->OpenFile(ofUri, "r");
378         if (fd > 0) {
379             newHapticsUri = FDHEAD + to_string(fd);
380         }
381     }
382 
383     resultSet == nullptr ? : resultSet->Close();
384     MEDIA_LOGI("SystemTonePlayerImpl::ChangeHapticsUri newHapticsUri is %{public}s", newHapticsUri.c_str());
385     return newHapticsUri;
386 }
387 
Prepare()388 int32_t SystemTonePlayerImpl::Prepare()
389 {
390     MEDIA_LOGI("Enter Prepare()");
391     std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
392     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
393         "System tone player has been released!");
394 
395     if (!InitDataShareHelper()) {
396         return ERRCODE_IOERROR;
397     }
398     std::string audioUri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
399     int32_t result = InitPlayer(audioUri);
400     ReleaseDataShareHelper();
401     CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result,
402         "Failed to init player for system tone player: %{public}d", result);
403     systemToneState_ = SystemToneState::STATE_PREPARED;
404     return result;
405 }
406 
Start()407 int32_t SystemTonePlayerImpl::Start()
408 {
409     MEDIA_LOGI("Enter Start()");
410     SystemToneOptions systemToneOptions = {false, false};
411     return Start(systemToneOptions);
412 }
413 
Start(const SystemToneOptions & systemToneOptions)414 int32_t SystemTonePlayerImpl::Start(const SystemToneOptions &systemToneOptions)
415 {
416     MEDIA_LOGI("Enter Start() with systemToneOptions: muteAudio %{public}d, muteHaptics %{public}d",
417         systemToneOptions.muteAudio, systemToneOptions.muteHaptics);
418     std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
419     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
420         "System tone player has been released!");
421 
422     int32_t result = MSERR_OK;
423     UpdateStreamId();
424     SystemToneOptions ringerModeOptions = GetOptionsFromRingerMode();
425     bool actualMuteAudio = ringerModeOptions.muteAudio || systemToneOptions.muteAudio ||
426         configuredUri_ == NO_SYSTEM_SOUND || std::abs(volume_) <= std::numeric_limits<float>::epsilon();
427     bool actualMuteHaptics = ringerModeOptions.muteHaptics || systemToneOptions.muteHaptics || isHapticUriEmpty_;
428     if (actualMuteAudio) {
429         // the audio of system tone player has been muted. Only start vibrator.
430         if (!actualMuteHaptics) {
431             std::string hapticUri = (configuredUri_ == NO_SYSTEM_SOUND) ?
432                 defaultNonSyncHapticUri_ : hapticUriMap_[hapticsFeature_];
433             SystemSoundVibrator::StartVibratorForSystemTone(hapticUri);
434         }
435         return streamId_;
436     }
437     result = CreatePlayerWithOptions({actualMuteAudio, actualMuteHaptics});
438     CHECK_AND_RETURN_RET_LOG((result == MSERR_OK && playerMap_[streamId_] != nullptr), -1,
439         "Failed to create audio haptic player: %{public}d", result);
440 
441     result = playerMap_[streamId_]->SetVolume(volume_);
442     result = playerMap_[streamId_]->Start();
443     CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, -1,
444         "Failed to start audio haptic player: %{public}d", result);
445     return streamId_;
446 }
447 
Stop(const int32_t & streamId)448 int32_t SystemTonePlayerImpl::Stop(const int32_t &streamId)
449 {
450     MEDIA_LOGI("Enter Stop() with streamId %{public}d", streamId);
451     std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
452     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
453         "System tone player has been released!");
454 
455     if (playerMap_.count(streamId) == 0 || playerMap_[streamId] == nullptr) {
456         MEDIA_LOGW("The stream has been stopped or the id %{public}d is invalid.", streamId);
457         return MSERR_OK;
458     }
459 
460     int32_t result = playerMap_[streamId]->Stop();
461     DeletePlayer(streamId);
462     CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, MSERR_INVALID_OPERATION,
463         "Failed to stop audio haptic player: %{public}d", result);
464     return result;
465 }
466 
Release()467 int32_t SystemTonePlayerImpl::Release()
468 {
469     MEDIA_LOGI("Enter Release()");
470     std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
471     if (systemToneState_ == SystemToneState::STATE_RELEASED) {
472         MEDIA_LOGW("System tone player has been released!");
473         return MSERR_OK;
474     }
475     DeleteAllPlayer();
476     streamId_ = 0;
477     configuredUri_ = "";
478 
479     if (audioHapticManager_ != nullptr) {
480         ReleaseHapticsSourceIds();
481         audioHapticManager_ = nullptr;
482     }
483     hapticsFeature_ = ToneHapticsFeature::STANDARD;
484     volume_ = SYS_TONE_PLAYER_MAX_VOLUME;
485     systemToneState_ = SystemToneState::STATE_RELEASED;
486     return MSERR_OK;
487 }
488 
GetTitle() const489 std::string SystemTonePlayerImpl::GetTitle() const
490 {
491     MEDIA_LOGI("Enter GetTitle()");
492     std::string uri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
493     return uri.substr(uri.find_last_of("/") + 1);
494 }
495 
DeletePlayer(const int32_t & streamId)496 void SystemTonePlayerImpl::DeletePlayer(const int32_t &streamId)
497 {
498     MEDIA_LOGI("DeletePlayer for streamId %{public}d", streamId);
499     if (playerMap_.count(streamId) > 0) {
500         if (playerMap_[streamId] != nullptr) {
501             playerMap_[streamId]->Release();
502         }
503         playerMap_.erase(streamId);
504     }
505     if (callbackMap_.count(streamId) > 0) {
506         callbackMap_.erase(streamId);
507     }
508     MEDIA_LOGI("DeletePlayer. playerMap_.size() %{public}zu  callbackMap_.size() %{public}zu ",
509         playerMap_.size(), callbackMap_.size());
510 }
511 
DeleteAllPlayer()512 void SystemTonePlayerImpl::DeleteAllPlayer()
513 {
514     MEDIA_LOGI("Delete all audio haptic player!");
515     for (auto iter = playerMap_.begin(); iter != playerMap_.end(); iter++) {
516         if (iter->second != nullptr) {
517             iter->second->Release();
518         }
519     }
520     playerMap_.clear();
521     callbackMap_.clear();
522 }
523 
NotifyEndofStreamEvent(const int32_t & streamId)524 void SystemTonePlayerImpl::NotifyEndofStreamEvent(const int32_t &streamId)
525 {
526     std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
527     // onPlayFinished for a stream.
528     DeletePlayer(streamId);
529 }
530 
NotifyInterruptEvent(const int32_t & streamId,const AudioStandard::InterruptEvent & interruptEvent)531 void SystemTonePlayerImpl::NotifyInterruptEvent(const int32_t &streamId,
532     const AudioStandard::InterruptEvent &interruptEvent)
533 {
534     MEDIA_LOGW("Interrupt event is not supported for system tone player!");
535 }
536 
537 // Callback class symbols
SystemTonePlayerCallback(int32_t streamId,std::shared_ptr<SystemTonePlayerImpl> systemTonePlayerImpl)538 SystemTonePlayerCallback::SystemTonePlayerCallback(int32_t streamId,
539     std::shared_ptr<SystemTonePlayerImpl> systemTonePlayerImpl)
540 {
541     streamId_ = streamId;
542     systemTonePlayerImpl_ = systemTonePlayerImpl;
543 }
544 
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)545 void SystemTonePlayerCallback::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
546 {
547     MEDIA_LOGI("OnInterrupt from audio haptic player: hintTye %{public}d", interruptEvent.hintType);
548     std::shared_ptr<SystemTonePlayerImpl> player = systemTonePlayerImpl_.lock();
549     if (player == nullptr) {
550         MEDIA_LOGE("The audio haptic player has been released.");
551         return;
552     }
553     player->NotifyInterruptEvent(streamId_, interruptEvent);
554 }
555 
OnEndOfStream(void)556 void SystemTonePlayerCallback::OnEndOfStream(void)
557 {
558     MEDIA_LOGI("OnEndOfStream from audio haptic player. StreamId %{public}d", streamId_);
559     std::shared_ptr<SystemTonePlayerImpl> player = systemTonePlayerImpl_.lock();
560     if (player == nullptr) {
561         MEDIA_LOGE("The audio haptic player has been released.");
562         return;
563     }
564     player->NotifyEndofStreamEvent(streamId_);
565 }
566 
OnError(int32_t errorCode)567 void SystemTonePlayerCallback::OnError(int32_t errorCode)
568 {
569     MEDIA_LOGI("OnError from audio haptic player. errorCode %{public}d", errorCode);
570 }
571 
IsValidVolume(float & scale)572 static bool IsValidVolume(float &scale)
573 {
574     static float eps = 1e-5;
575     static float maxVal = 1;
576     static float minVal = 0;
577     if (scale >= minVal || scale <= maxVal) {
578         return true;
579     }
580     if (scale > maxVal && abs(scale - maxVal) < eps) {
581         scale = maxVal;
582         return true;
583     }
584     if (scale < minVal && abs(scale - minVal) < eps) {
585         scale = minVal;
586         return true;
587     }
588     return false;
589 }
590 
SetAudioVolume(float volume)591 int32_t SystemTonePlayerImpl::SetAudioVolume(float volume)
592 {
593     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, ERRCODE_OPERATION_NOT_ALLOWED,
594         "System tone player has been released!");
595     CHECK_AND_RETURN_RET_LOG(IsValidVolume(volume), ERRCODE_INVALID_PARAMS,
596         "Invliad volume, the volume must be in the [0, 1] range");
597     volume_ = volume;
598     return MSERR_OK;
599 }
600 
GetAudioVolume(float & recvValue)601 int32_t SystemTonePlayerImpl::GetAudioVolume(float &recvValue)
602 {
603     recvValue = volume_;
604     return MSERR_OK;
605 }
606 
GetSupportHapticsFeatures(std::vector<ToneHapticsFeature> & recvFeatures)607 int32_t SystemTonePlayerImpl::GetSupportHapticsFeatures(std::vector<ToneHapticsFeature> &recvFeatures)
608 {
609     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, ERRCODE_UNSUPPORTED_OPERATION,
610         "System tone player has been released!");
611     recvFeatures = supportedHapticsFeatures_;
612     return MSERR_OK;
613 }
614 
SetHapticsFeature(ToneHapticsFeature feature)615 int32_t SystemTonePlayerImpl::SetHapticsFeature(ToneHapticsFeature feature)
616 {
617     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, ERRCODE_OPERATION_NOT_ALLOWED,
618         "System tone player has been released!");
619     CHECK_AND_RETURN_RET_LOG((feature == ToneHapticsFeature::STANDARD || feature == ToneHapticsFeature::GENTLE) &&
620         std::find(supportedHapticsFeatures_.begin(),
621         supportedHapticsFeatures_.end(), feature) != supportedHapticsFeatures_.end(),
622         ERRCODE_UNSUPPORTED_OPERATION, "Unsupport haptics features %{public}d", feature);
623     hapticsFeature_ = feature;
624     return MSERR_OK;
625 }
626 
GetHapticsFeature(ToneHapticsFeature & feature)627 int32_t SystemTonePlayerImpl::GetHapticsFeature(ToneHapticsFeature &feature)
628 {
629     CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, ERRCODE_UNSUPPORTED_OPERATION,
630         "System tone player has been released!");
631     feature = hapticsFeature_;
632     return MSERR_OK;
633 }
634 
ConvertToToneHapticsType(SystemToneType type)635 ToneHapticsType SystemTonePlayerImpl::ConvertToToneHapticsType(SystemToneType type)
636 {
637     switch (type) {
638         case SystemToneType::SYSTEM_TONE_TYPE_SIM_CARD_0:
639             return ToneHapticsType::TEXT_MESSAGE_SIM_CARD_0;
640         case SystemToneType::SYSTEM_TONE_TYPE_SIM_CARD_1:
641             return ToneHapticsType::TEXT_MESSAGE_SIM_CARD_1;
642         case SystemToneType::SYSTEM_TONE_TYPE_NOTIFICATION:
643             return ToneHapticsType::NOTIFICATION;
644         default:
645             return ToneHapticsType::NOTIFICATION;
646     }
647 }
648 
ConvertToHapticsMode(ToneHapticsMode toneHapticsMode)649 HapticsMode SystemTonePlayerImpl::ConvertToHapticsMode(ToneHapticsMode toneHapticsMode)
650 {
651     switch (toneHapticsMode) {
652         case ToneHapticsMode::NONE:
653             return HapticsMode::HAPTICS_MODE_NONE;
654         case ToneHapticsMode::SYNC:
655             return HapticsMode::HAPTICS_MODE_SYNC;
656         case ToneHapticsMode::NON_SYNC:
657             return HapticsMode::HAPTICS_MODE_NON_SYNC;
658         default:
659             return HapticsMode::HAPTICS_MODE_INVALID;
660     }
661 }
662 
GetNewHapticSettings(const std::string & audioUri,std::map<ToneHapticsFeature,std::string> & hapticsUris)663 void SystemTonePlayerImpl::GetNewHapticSettings(const std::string &audioUri,
664     std::map<ToneHapticsFeature, std::string> &hapticsUris)
665 {
666     supportedHapticsFeatures_.clear();
667     ToneHapticsSettings settings;
668     int32_t result = systemSoundMgr_.GetToneHapticsSettings(dataShareHelper_, audioUri,
669         ConvertToToneHapticsType(systemToneType_), settings);
670     if (result != 0) {
671         MEDIA_LOGW("GetNewHapticSettings: get haptic settings fail");
672         return;
673     }
674     hapticsMode_ = ConvertToHapticsMode(settings.mode);
675     supportedHapticsFeatures_.push_back(ToneHapticsFeature::STANDARD);
676     hapticsUris[ToneHapticsFeature::STANDARD] = settings.hapticsUri;
677     MEDIA_LOGI("GetHapticUriForAudioUri: STANDARD hapticUri %{public}s ", settings.hapticsUri.c_str());
678     std::string hapticUri = systemSoundMgr_.GetHapticsUriByStyle(dataShareHelper_, settings.hapticsUri,
679         HapticsStyle::HAPTICS_STYLE_GENTLE);
680     if (!hapticUri.empty()) {
681         supportedHapticsFeatures_.push_back(ToneHapticsFeature::GENTLE);
682         hapticsUris[ToneHapticsFeature::GENTLE] = hapticUri;
683         MEDIA_LOGI("GetHapticUriForAudioUri: GENTLE hapticUri %{public}s ", hapticUri.c_str());
684     }
685 }
686 
GetCurrentHapticSettings(const std::string & audioUri,std::map<ToneHapticsFeature,std::string> & hapticUriMap)687 void SystemTonePlayerImpl::GetCurrentHapticSettings(const std::string &audioUri,
688     std::map<ToneHapticsFeature, std::string> &hapticUriMap)
689 {
690     GetNewHapticSettings(audioUri, hapticUriMap);
691     if (hapticUriMap.empty()) {
692         hapticsMode_ = HapticsMode::HAPTICS_MODE_SYNC;
693         GetNewHapticUriForAudioUri(audioUri, hapticUriMap);
694         if (hapticUriMap.empty()) {
695             GetHapticUriForAudioUri(audioUri, hapticUriMap);
696         }
697     }
698 }
699 
RegisterSource(const std::string & audioUri,const std::string & hapticUri)700 int32_t SystemTonePlayerImpl::RegisterSource(const std::string &audioUri, const std::string &hapticUri)
701 {
702     string newAudioUri = ChangeUri(audioUri);
703     string newHapticUri = ChangeHapticsUri(hapticUri);
704 
705     int32_t sourceId = audioHapticManager_->RegisterSource(newAudioUri, newHapticUri);
706 
707     const std::string fdHead = "fd://";
708     if (newAudioUri.find(fdHead) != std::string::npos) {
709         int32_t fd = atoi(newAudioUri.substr(fdHead.size()).c_str());
710         if (fd > 0) {
711             close(fd);
712         }
713     }
714     if (newHapticUri.find(fdHead) != std::string::npos) {
715         int32_t fd = atoi(newHapticUri.substr(fdHead.size()).c_str());
716         if (fd > 0) {
717             close(fd);
718         }
719     }
720 
721     return sourceId;
722 }
723 
InitHapticsSourceIds()724 void SystemTonePlayerImpl::InitHapticsSourceIds()
725 {
726     if (audioHapticManager_ == nullptr) {
727         return;
728     }
729 
730     int32_t sourceId;
731     for (auto it = hapticUriMap_.begin(); it != hapticUriMap_.end(); ++it) {
732         MEDIA_LOGI("InitHapticsSourceIds%{public}d: ToneUri:%{public}s, hapticsUri:%{public}s, mode:%{public}d.",
733             it->first, configuredUri_.c_str(), it->second.c_str(), hapticsMode_);
734         sourceId = RegisterSource(configuredUri_, it->second);
735         CHECK_AND_CONTINUE_LOG(sourceId != -1, "Failed to register source for audio haptic manager");
736         (void)audioHapticManager_->SetAudioLatencyMode(sourceId, AUDIO_LATENCY_MODE_NORMAL);
737         (void)audioHapticManager_->SetStreamUsage(sourceId, AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION);
738         sourceIds_[it->first] = sourceId;
739     }
740 }
741 
ReleaseHapticsSourceIds()742 void SystemTonePlayerImpl::ReleaseHapticsSourceIds()
743 {
744     for (auto it = sourceIds_.begin(); it != sourceIds_.end(); ++it) {
745         if (it->second != -1) {
746             (void)audioHapticManager_->UnregisterSource(it->second);
747             it->second = -1;
748         }
749     }
750 }
751 } // namesapce AudioStandard
752 } // namespace OHOS
753