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 "system_sound_log.h"
26 #include "media_errors.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 std::string NON_SYNC_HAPTICS_PATH = "resource/media/haptics/standard/non-synchronized/";
43
SystemTonePlayerImpl(const shared_ptr<Context> & context,SystemSoundManagerImpl & systemSoundMgr,SystemToneType systemToneType)44 SystemTonePlayerImpl::SystemTonePlayerImpl(const shared_ptr<Context> &context,
45 SystemSoundManagerImpl &systemSoundMgr, SystemToneType systemToneType)
46 : context_(context),
47 systemSoundMgr_(systemSoundMgr),
48 systemToneType_(systemToneType)
49 {
50 audioHapticManager_ = AudioHapticManagerFactory::CreateAudioHapticManager();
51 CHECK_AND_RETURN_LOG(audioHapticManager_ != nullptr, "Failed to get audio haptic manager");
52
53 std::string systemToneUri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
54 InitPlayer(systemToneUri);
55 }
56
~SystemTonePlayerImpl()57 SystemTonePlayerImpl::~SystemTonePlayerImpl()
58 {
59 DeleteAllPlayer();
60 if (audioHapticManager_ != nullptr) {
61 audioHapticManager_->UnregisterSource(sourceId_);
62 audioHapticManager_ = nullptr;
63 }
64 }
65
GetDefaultNonSyncHapticsPath()66 std::string SystemTonePlayerImpl::GetDefaultNonSyncHapticsPath()
67 {
68 char buf[MAX_PATH_LEN];
69 char *path = GetOneCfgFile(NON_SYNC_HAPTICS_PATH.c_str(), buf, MAX_PATH_LEN);
70 if (path == nullptr || *path == '\0') {
71 MEDIA_LOGE("Failed to get default non-sync haptics path");
72 return "";
73 }
74 std::string filePath = path;
75 MEDIA_LOGI("Default non-sync haptics path [%{public}s]", filePath.c_str());
76 filePath = filePath + "Tick-tock.json";
77 return filePath;
78 }
79
InitPlayer(const std::string & audioUri)80 int32_t SystemTonePlayerImpl::InitPlayer(const std::string &audioUri)
81 {
82 MEDIA_LOGI("Enter InitPlayer() with audio uri %{public}s", audioUri.c_str());
83
84 if (sourceId_ != -1) {
85 (void)audioHapticManager_->UnregisterSource(sourceId_);
86 sourceId_ = -1;
87 }
88
89 if (audioUri == NO_SYSTEM_SOUND) {
90 defaultNonSyncHapticUri_ = GetDefaultNonSyncHapticsPath();
91 configuredUri_ = NO_SYSTEM_SOUND;
92 systemToneState_ = SystemToneState::STATE_NEW;
93 return MSERR_OK;
94 }
95
96 // Get the haptic file uri according to the audio file uri.
97 hapticUri_ = GetHapticUriForAudioUri(audioUri);
98 if (hapticUri_ == "") {
99 MEDIA_LOGW("haptic uri is empty. Play system tone without vibration");
100 isHapticUriEmpty_ = true;
101 }
102
103 sourceId_ = audioHapticManager_->RegisterSource(ChangeUri(audioUri), hapticUri_);
104 CHECK_AND_RETURN_RET_LOG(sourceId_ != -1, MSERR_OPEN_FILE_FAILED,
105 "Failed to register source for audio haptic manager");
106 (void)audioHapticManager_->SetAudioLatencyMode(sourceId_, AUDIO_LATENCY_MODE_NORMAL);
107 (void)audioHapticManager_->SetStreamUsage(sourceId_, AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION);
108
109 configuredUri_ = audioUri;
110 systemToneState_ = SystemToneState::STATE_NEW;
111 return MSERR_OK;
112 }
113
CreatePlayerWithOptions(const AudioHapticPlayerOptions & options)114 int32_t SystemTonePlayerImpl::CreatePlayerWithOptions(const AudioHapticPlayerOptions &options)
115 {
116 playerMap_[streamId_] = audioHapticManager_->CreatePlayer(sourceId_, options);
117 CHECK_AND_RETURN_RET_LOG(playerMap_[streamId_] != nullptr, MSERR_OPEN_FILE_FAILED,
118 "Failed to create system tone player instance");
119
120 callbackMap_[streamId_] = std::make_shared<SystemTonePlayerCallback>(streamId_, shared_from_this());
121 CHECK_AND_RETURN_RET_LOG(callbackMap_[streamId_] != nullptr, MSERR_OPEN_FILE_FAILED,
122 "Failed to create system tone player callback object");
123 (void)playerMap_[streamId_]->SetAudioHapticPlayerCallback(callbackMap_[streamId_]);
124
125 int32_t result = playerMap_[streamId_]->Prepare();
126 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result,
127 "Failed to prepare for system tone player: %{public}d", result);
128 return MSERR_OK;
129 }
130
UpdateStreamId()131 void SystemTonePlayerImpl::UpdateStreamId()
132 {
133 // Update streamId_ and ensure that streamId_ has no player.
134 streamId_++;
135 if (streamId_ > MAX_STREAM_ID) {
136 streamId_ = 1;
137 }
138 if (playerMap_.count(streamId_) > 0) {
139 DeletePlayer(streamId_);
140 }
141 }
142
GetOptionsFromRingerMode()143 SystemToneOptions SystemTonePlayerImpl::GetOptionsFromRingerMode()
144 {
145 SystemToneOptions options = {false, false};
146 AudioStandard::AudioRingerMode ringerMode = systemSoundMgr_.GetRingerMode();
147 MEDIA_LOGI("Current ringer mode is %{public}d", ringerMode);
148 if (ringerMode == AudioStandard::AudioRingerMode::RINGER_MODE_SILENT) {
149 options.muteAudio = true;
150 options.muteHaptics = true;
151 } else if (ringerMode == AudioStandard::AudioRingerMode::RINGER_MODE_VIBRATE) {
152 options.muteAudio = true;
153 }
154 return options;
155 }
156
GetHapticUriForAudioUri(const std::string & audioUri)157 std::string SystemTonePlayerImpl::GetHapticUriForAudioUri(const std::string &audioUri)
158 {
159 std::string hapticUri = "";
160 if (audioUri.length() > AUDIO_FORMAT_STR.length() &&
161 audioUri.rfind(AUDIO_FORMAT_STR) == audioUri.length() - AUDIO_FORMAT_STR.length()) {
162 // the end of audio uri is ".ogg"
163 hapticUri = audioUri;
164 hapticUri.replace(hapticUri.rfind(AUDIO_FORMAT_STR), AUDIO_FORMAT_STR.length(), HAPTIC_FORMAT_STR);
165 }
166
167 if (hapticUri == "" || !IsFileExisting(hapticUri)) {
168 MEDIA_LOGW("Failed to find the vibration json file for audioUri. Use the default json file.");
169 std::string defaultSystemToneUri = systemSoundMgr_.GetDefaultSystemToneUri(SYSTEM_TONE_TYPE_NOTIFICATION);
170 if (defaultSystemToneUri.length() > AUDIO_FORMAT_STR.length() &&
171 defaultSystemToneUri.rfind(AUDIO_FORMAT_STR) == defaultSystemToneUri.length() - AUDIO_FORMAT_STR.length()) {
172 // the end of default system tone uri is ".ogg"
173 hapticUri = defaultSystemToneUri;
174 hapticUri.replace(hapticUri.rfind(AUDIO_FORMAT_STR), AUDIO_FORMAT_STR.length(), HAPTIC_FORMAT_STR);
175 } else {
176 MEDIA_LOGW("The default system tone uri is invalid!");
177 }
178 }
179
180 return hapticUri;
181 }
182
IsFileExisting(const std::string & fileUri)183 bool SystemTonePlayerImpl::IsFileExisting(const std::string &fileUri)
184 {
185 struct stat buffer;
186 return (stat(fileUri.c_str(), &buffer) == 0);
187 }
188
CreateDataShareHelper(int32_t systemAbilityId)189 static shared_ptr<DataShare::DataShareHelper> CreateDataShareHelper(int32_t systemAbilityId)
190 {
191 auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
192 if (saManager == nullptr) {
193 return nullptr;
194 }
195 auto remoteObj = saManager->GetSystemAbility(systemAbilityId);
196 if (remoteObj == nullptr) {
197 return nullptr;
198 }
199 return DataShare::DataShareHelper::Creator(remoteObj, RINGTONE_URI);
200 }
201
ChangeUri(const std::string & uri)202 std::string SystemTonePlayerImpl::ChangeUri(const std::string &uri)
203 {
204 std::string systemtoneUri = uri;
205 size_t found = uri.find(RINGTONE_CUSTOMIZED_BASE_PATH);
206 if (found != std::string::npos) {
207 std::shared_ptr<DataShare::DataShareHelper> dataShareHelper =
208 CreateDataShareHelper(STORAGE_MANAGER_MANAGER_ID);
209 CHECK_AND_RETURN_RET_LOG(dataShareHelper != nullptr, uri, "Failed to create dataShareHelper.");
210 DataShare::DatashareBusinessError businessError;
211 DataShare::DataSharePredicates queryPredicates;
212 Uri ringtonePathUri(RINGTONE_PATH_URI);
213 vector<string> columns = {{RINGTONE_COLUMN_TONE_ID}, {RINGTONE_COLUMN_DATA}};
214 queryPredicates.EqualTo(RINGTONE_COLUMN_DATA, uri);
215 auto resultSet = dataShareHelper->Query(ringtonePathUri, queryPredicates, columns, &businessError);
216 auto results = make_unique<RingtoneFetchResult<RingtoneAsset>>(move(resultSet));
217 unique_ptr<RingtoneAsset> ringtoneAsset = results->GetFirstObject();
218 if (ringtoneAsset != nullptr) {
219 string uriStr = RINGTONE_PATH_URI + RINGTONE_SLASH_CHAR + to_string(ringtoneAsset->GetId());
220 Uri ofUri(uriStr);
221 int32_t fd = dataShareHelper->OpenFile(ofUri, "r");
222 if (fd > 0) {
223 systemtoneUri = FDHEAD + to_string(fd);
224 }
225 }
226 resultSet == nullptr ? : resultSet->Close();
227 dataShareHelper->Release();
228 }
229 MEDIA_LOGI("SystemTonePlayerImpl::ChangeUri systemtoneUri is %{public}s", systemtoneUri.c_str());
230 return systemtoneUri;
231 }
232
Prepare()233 int32_t SystemTonePlayerImpl::Prepare()
234 {
235 MEDIA_LOGI("Enter Prepare()");
236 std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
237 CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
238 "System tone player has been released!");
239
240 std::string systemToneUri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
241 if (!configuredUri_.empty() && configuredUri_ == systemToneUri) {
242 MEDIA_LOGI("The right system tone uri has been registered. Return directly.");
243 systemToneState_ = SystemToneState::STATE_PREPARED;
244 return MSERR_OK;
245 }
246
247 // reload audio haptic player for system tone.
248 int32_t result = InitPlayer(systemToneUri);
249 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result,
250 "Failed to init player for system tone player: %{public}d", result);
251 systemToneState_ = SystemToneState::STATE_PREPARED;
252 return result;
253 }
254
Start()255 int32_t SystemTonePlayerImpl::Start()
256 {
257 MEDIA_LOGI("Enter Start()");
258 SystemToneOptions systemToneOptions = {false, false};
259 return Start(systemToneOptions);
260 }
261
Start(const SystemToneOptions & systemToneOptions)262 int32_t SystemTonePlayerImpl::Start(const SystemToneOptions &systemToneOptions)
263 {
264 MEDIA_LOGI("Enter Start() with systemToneOptions: muteAudio %{public}d, muteHaptics %{public}d",
265 systemToneOptions.muteAudio, systemToneOptions.muteHaptics);
266 std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
267 CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
268 "System tone player has been released!");
269
270 int32_t result = MSERR_OK;
271 UpdateStreamId();
272 SystemToneOptions ringerModeOptions = GetOptionsFromRingerMode();
273 bool actualMuteAudio = ringerModeOptions.muteAudio || systemToneOptions.muteAudio ||
274 configuredUri_ == NO_SYSTEM_SOUND;
275 bool actualMuteHaptics = ringerModeOptions.muteHaptics || systemToneOptions.muteHaptics || isHapticUriEmpty_;
276 if (actualMuteAudio) {
277 // the audio of system tone player has been muted. Only start vibrator.
278 if (!actualMuteHaptics) {
279 std::string hapticUri = (configuredUri_ == NO_SYSTEM_SOUND) ?
280 defaultNonSyncHapticUri_ : hapticUri_;
281 SystemSoundVibrator::StartVibratorForSystemTone(hapticUri);
282 }
283 return streamId_;
284 }
285 result = CreatePlayerWithOptions({actualMuteAudio, actualMuteHaptics});
286 CHECK_AND_RETURN_RET_LOG((result == MSERR_OK && playerMap_[streamId_] != nullptr), -1,
287 "Failed to create audio haptic player: %{public}d", result);
288
289 result = playerMap_[streamId_]->Start();
290 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, -1,
291 "Failed to start audio haptic player: %{public}d", result);
292 return streamId_;
293 }
294
Stop(const int32_t & streamId)295 int32_t SystemTonePlayerImpl::Stop(const int32_t &streamId)
296 {
297 MEDIA_LOGI("Enter Stop() with streamId %{public}d", streamId);
298 std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
299 CHECK_AND_RETURN_RET_LOG(systemToneState_ != SystemToneState::STATE_RELEASED, MSERR_INVALID_STATE,
300 "System tone player has been released!");
301
302 if (playerMap_.count(streamId) == 0 || playerMap_[streamId] == nullptr) {
303 MEDIA_LOGW("The stream has been stopped or the id %{public}d is invalid.", streamId);
304 return MSERR_OK;
305 }
306
307 int32_t result = playerMap_[streamId]->Stop();
308 DeletePlayer(streamId);
309 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, MSERR_INVALID_OPERATION,
310 "Failed to stop audio haptic player: %{public}d", result);
311 return result;
312 }
313
Release()314 int32_t SystemTonePlayerImpl::Release()
315 {
316 MEDIA_LOGI("Enter Release()");
317 std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
318 if (systemToneState_ == SystemToneState::STATE_RELEASED) {
319 MEDIA_LOGW("System tone player has been released!");
320 return MSERR_OK;
321 }
322 DeleteAllPlayer();
323 if (audioHapticManager_ != nullptr) {
324 audioHapticManager_->UnregisterSource(sourceId_);
325 audioHapticManager_ = nullptr;
326 }
327 sourceId_ = -1;
328 streamId_ = 0;
329 configuredUri_ = "";
330
331 systemToneState_ = SystemToneState::STATE_RELEASED;
332 return MSERR_OK;
333 }
334
GetTitle() const335 std::string SystemTonePlayerImpl::GetTitle() const
336 {
337 MEDIA_LOGI("Enter GetTitle()");
338 std::string uri = systemSoundMgr_.GetSystemToneUri(context_, systemToneType_);
339 return uri.substr(uri.find_last_of("/") + 1);
340 }
341
DeletePlayer(const int32_t & streamId)342 void SystemTonePlayerImpl::DeletePlayer(const int32_t &streamId)
343 {
344 MEDIA_LOGI("DeletePlayer for streamId %{public}d", streamId);
345 if (playerMap_.count(streamId) > 0) {
346 if (playerMap_[streamId] != nullptr) {
347 playerMap_[streamId]->Release();
348 }
349 playerMap_.erase(streamId);
350 }
351 if (callbackMap_.count(streamId) > 0) {
352 callbackMap_.erase(streamId);
353 }
354 MEDIA_LOGI("DeletePlayer. playerMap_.size() %{public}zu callbackMap_.size() %{public}zu ",
355 playerMap_.size(), callbackMap_.size());
356 }
357
DeleteAllPlayer()358 void SystemTonePlayerImpl::DeleteAllPlayer()
359 {
360 MEDIA_LOGI("Delete all audio haptic player!");
361 for (auto iter = playerMap_.begin(); iter != playerMap_.end(); iter++) {
362 if (iter->second != nullptr) {
363 iter->second->Release();
364 }
365 }
366 playerMap_.clear();
367 callbackMap_.clear();
368 }
369
NotifyEndofStreamEvent(const int32_t & streamId)370 void SystemTonePlayerImpl::NotifyEndofStreamEvent(const int32_t &streamId)
371 {
372 std::lock_guard<std::mutex> lock(systemTonePlayerMutex_);
373 // onPlayFinished for a stream.
374 DeletePlayer(streamId);
375 }
376
NotifyInterruptEvent(const int32_t & streamId,const AudioStandard::InterruptEvent & interruptEvent)377 void SystemTonePlayerImpl::NotifyInterruptEvent(const int32_t &streamId,
378 const AudioStandard::InterruptEvent &interruptEvent)
379 {
380 MEDIA_LOGW("Interrupt event is not supported for system tone player!");
381 }
382
383 // Callback class symbols
SystemTonePlayerCallback(int32_t streamId,std::shared_ptr<SystemTonePlayerImpl> systemTonePlayerImpl)384 SystemTonePlayerCallback::SystemTonePlayerCallback(int32_t streamId,
385 std::shared_ptr<SystemTonePlayerImpl> systemTonePlayerImpl)
386 {
387 streamId_ = streamId;
388 systemTonePlayerImpl_ = systemTonePlayerImpl;
389 }
390
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)391 void SystemTonePlayerCallback::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
392 {
393 MEDIA_LOGI("OnInterrupt from audio haptic player: hintTye %{public}d", interruptEvent.hintType);
394 std::shared_ptr<SystemTonePlayerImpl> player = systemTonePlayerImpl_.lock();
395 if (player == nullptr) {
396 MEDIA_LOGE("The audio haptic player has been released.");
397 return;
398 }
399 player->NotifyInterruptEvent(streamId_, interruptEvent);
400 }
401
OnEndOfStream(void)402 void SystemTonePlayerCallback::OnEndOfStream(void)
403 {
404 MEDIA_LOGI("OnEndOfStream from audio haptic player. StreamId %{public}d", streamId_);
405 std::shared_ptr<SystemTonePlayerImpl> player = systemTonePlayerImpl_.lock();
406 if (player == nullptr) {
407 MEDIA_LOGE("The audio haptic player has been released.");
408 return;
409 }
410 player->NotifyEndofStreamEvent(streamId_);
411 }
412
OnError(int32_t errorCode)413 void SystemTonePlayerCallback::OnError(int32_t errorCode)
414 {
415 MEDIA_LOGI("OnError from audio haptic player. errorCode %{public}d", errorCode);
416 }
417 } // namesapce AudioStandard
418 } // namespace OHOS
419