From: luozheng <1732036298@qq.com> Date: Tue, 9 Apr 2024 07:44:00 +0000 (+0800) Subject: 1.实现倒计时到期播放音乐功能 X-Git-Tag: release_V1.2.70_20241020_135402~1189^2~32 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=b75f08da0dc0049140288576e335333d02c4a87a;p=mirrors%2FFD230.git 1.实现倒计时到期播放音乐功能 2.遗留问题:在手表刚刚开机时倒计时播放铃声会出现线程创建失败导致铃声播放失败问题 --- diff --git a/code/sdk/application/wearable/fd230app/nativeui/countdown/include/CountDownModel.h b/code/sdk/application/wearable/fd230app/nativeui/countdown/include/CountDownModel.h index 147a40e80..935850e4b 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/countdown/include/CountDownModel.h +++ b/code/sdk/application/wearable/fd230app/nativeui/countdown/include/CountDownModel.h @@ -2,15 +2,67 @@ * @Author: luozheng 1732036298@qq.com * @Date: 2024-04-07 18:15:53 * @LastEditors: luozheng 1732036298@qq.com - * @LastEditTime: 2024-04-08 19:42:10 + * @LastEditTime: 2024-04-09 15:27:19 * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/countdown/include/CountDownModel.h */ #ifndef COUNTDOWN_MODEL_H #define COUNTDOWN_MODEL_H #include +#include "source.h" +#include "audio_manager.h" +#include "../../../../../../middleware/services/media/foundation/player/interfaces/kits/player.h" namespace OHOS { + using OHOS::Media::Player; + using OHOS::Media::Source; + using namespace OHOS::Media; + using namespace Audio; + using Audio::AudioManager; + + // 计时器铃声播放监听类 + class CountDownRingPlayerListener : public InterruptListener + { + public: + CountDownRingPlayerListener() {} + ~CountDownRingPlayerListener() {} + + void SetOwner(std::shared_ptr player); + void RestFlag(); + bool IsPaused(); + bool IsDelayed(); + bool IsResumed(); + bool IsBeginStopped(); + bool IsEndStopped(); + void StopCountDownRing(); + void StartCountDownRing(); + void OnInterrupt(int32_t type, int32_t hint) override; + + private: + std::shared_ptr player_{nullptr}; + bool isPaused_{false}; + bool isDelayed_{false}; + bool isResumed_{false}; + bool isBeginStopped_{false}; + bool isEndStopped_{false}; + }; + + /*处理计时器铃声媒体播放事件的类*/ + class CountDownRingPlayerCallbackImpl : public OHOS::Media::PlayerCallback + { + public: + CountDownRingPlayerCallbackImpl() {} + ~CountDownRingPlayerCallbackImpl() {} + /*媒体播放完毕时被调用*/ + void OnPlaybackComplete(); + /*当播放过程中发生错误时,此方法将被调用,提供了错误类型和错误代码以供分析和处理。*/ + void OnError(int32_t errorType, int32_t errorCode); + /*在播放过程中,为处理某些信息而调用该方法,信息类型和额外数据通过参数提供。*/ + void OnInfo(int type, int extra); + /*当跳转操作完成时(例如快进到某个特定位置),该方法被调用*/ + void OnRewindToComplete(); + }; + class CountDownModel { public: @@ -28,11 +80,34 @@ namespace OHOS void CountDown_PauseTimer(void); void CountDown_ResumeTimer(uint32_t interval); + /*播放器相关函数*/ + int CountDownRingPlayerInit(const char *RingMusicName); + int InitializeAndPlayRingtone(void); + int StartRingtonePlayback(void); + int StopRingtonePlaybackAndReleaseResources(void); + void RequestStartRingtone(void); + void RequestStopRingtone(void); + int ResetRingtonePlayback(void); + + public: static int g_CountDownTimes; private: CountDownModel() {} ~CountDownModel() {} + CountDownModel(const CountDownModel &) = delete; + CountDownModel &operator=(const CountDownModel &) = delete; + + std::string uri; + std::shared_ptr playerCallback{nullptr}; + std::shared_ptr playerCtr{nullptr}; + std::map header; + std::shared_ptr source{nullptr}; + std::shared_ptr playerInterruptListener{nullptr}; + AudioSession sessionId; + AudioInterrupt interrupt; + const char *RingMusicPath = "/user/music/alarm.mp3"; // 铃声路径 + std::string countdownDuration{nullptr}; std::string RingTime{"00:00:00"}; // 响铃时间 std::string CountTime{"00:00:00"}; // 倒计时时间 diff --git a/code/sdk/application/wearable/fd230app/nativeui/countdown/include/MainCountDownPresenter.h b/code/sdk/application/wearable/fd230app/nativeui/countdown/include/MainCountDownPresenter.h index fc0b9e271..dea71c490 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/countdown/include/MainCountDownPresenter.h +++ b/code/sdk/application/wearable/fd230app/nativeui/countdown/include/MainCountDownPresenter.h @@ -2,7 +2,7 @@ * @Author: luozheng 1732036298@qq.com * @Date: 2024-04-07 18:15:53 * @LastEditors: luozheng 1732036298@qq.com - * @LastEditTime: 2024-04-08 20:17:52 + * @LastEditTime: 2024-04-09 15:40:05 * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/countdown/include/MainCountDownPresenter.h */ #ifndef MAIN_COUNTDOWN_PRESENTER_H diff --git a/code/sdk/application/wearable/fd230app/nativeui/countdown/src/CountDownModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/countdown/src/CountDownModel.cpp index 148092692..eafcd0e7a 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/countdown/src/CountDownModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/countdown/src/CountDownModel.cpp @@ -2,7 +2,7 @@ * @Author: luozheng 1732036298@qq.com * @Date: 2024-04-07 18:15:53 * @LastEditors: luozheng 1732036298@qq.com - * @LastEditTime: 2024-04-08 20:43:16 + * @LastEditTime: 2024-04-09 15:38:14 * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/countdown/src/CountDownModel.cpp */ #include "countdown/include/CountDownModel.h" @@ -102,6 +102,213 @@ namespace OHOS return RingTime; } + /* + * @brief 初始化音乐播放器以播放一个指定的铃声文件 + * @param {char*} RingMusicName 铃声文件 + */ + int CountDownModel::CountDownRingPlayerInit(const char *RingMusicName) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::CountDownRingPlayerInit"); + /* ------------------------------- 1.播放文件路径设置 ------------------------------- */ + uri = RingMusicName; + /* -------------------------------- 2.播放器对象创建 ------------------------------- */ + if (playerCtr.get() == nullptr) + { + playerCtr = std::make_shared(); + if (playerCtr.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerCtr new fail"); + return OHOS_FAILURE; + } + } + /* ------------------------------- 3.播放器回调对象创建 ------------------------------ */ + if (playerCallback.get() == nullptr) + { + playerCallback = std::make_shared(); + if (playerCallback.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerCallback new fail"); + return OHOS_FAILURE; + } + } + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[CountDownModel] PlayerInit success!"); + return OHOS_SUCCESS; + } + + /* + * @brief 对铃声播放器进行设置并开始播放铃声。 + */ + int CountDownModel::InitializeAndPlayRingtone(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::InitializeAndPlayRingtone"); + /* -------------------------------- 1.检查播放器实例 ------------------------------- */ + int32_t ret; + int32_t state; + if (playerCtr.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerCtr.get() == nullptr"); + return OHOS_FAILURE; + } + playerCtr->GetPlayerState(state); + /* -------------------------------- 2.设置播放器回调 ------------------------------- */ + playerCtr->SetPlayerCallback(playerCallback); + /* -------------------------------- 3.创建并设置音频源 -------------------------------- */ + source = std::make_shared(uri, header); + if (source.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] source.get() == fail"); + return OHOS_FAILURE; + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Player url:%s", uri.c_str()); + playerCtr->SetSource(*source); + /* --------------------------------- 4.配置播放器 -------------------------------- */ + playerCtr->SetAudioStreamType(AUDIO_STREAM_MUSIC); // 设置播放器的音频流类型 + playerCtr->Prepare(); // 准备播放器对象以播放音频。 + /* -------------------------------- 5.请求音频焦点 -------------------------------- */ + AudioManager &amIntance = AudioManager::GetInstance(); + sessionId = amIntance.MakeSessionId(); + if (sessionId == AUDIO_SESSION_ID_NONE) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] sessionId invalid!!"); + return OHOS_FAILURE; + } + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "[CountDownModel] MakeSessionId = %d", sessionId); + playerInterruptListener = std::make_shared(); // 创建音频中断监听器 + if (playerInterruptListener.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerInterruptListener playerInterruptListener.get() == nullptr"); + return OHOS_FAILURE; + } + playerInterruptListener->SetOwner(playerCtr); + interrupt = {AUDIO_STREAM_MUSIC, sessionId, playerInterruptListener}; + // 激活音频中断 5s超时 + if (amIntance.ActivateAudioInterrupt(interrupt) == INTERRUPT_FAILED) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ActivateAudioInterrupt faild"); + return OHOS_FAILURE; + } + // playerCtr->SetVolume(50, 50); // 将左声道和右声道音量都设置为50 + playerCtr->SetAudioSessionId(sessionId); + // 播放 + playerCtr->Play(); + return OHOS_SUCCESS; + } + + /* + * @brief 开始铃声的播放 + */ + int CountDownModel::StartRingtonePlayback(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::StartRingtonePlayback"); + if (CountDownRingPlayerInit(RingMusicPath) != OHOS_SUCCESS) + { + // 错误处理,例如记录日志或者返回错误状态码 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::CountDownRingPlayerInit error!!"); + return OHOS_FAILURE; + } + + if (InitializeAndPlayRingtone() != OHOS_SUCCESS) + { + // 错误处理,例如记录日志或者返回错误状态码 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::InitializeAndPlayRingtone error!!"); + return OHOS_FAILURE; + } + return OHOS_SUCCESS; + } + + /* + * @brief 停止播放铃声,重置并释放播放器资源,并去激活之前设置的音频中断。 + */ + int CountDownModel::StopRingtonePlaybackAndReleaseResources(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::StopRingtonePlaybackAndReleaseResources"); + int32_t ret = 0; + int32_t state = 0; + AudioManager &amIntance = AudioManager::GetInstance(); + if (playerCtr.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerCtr.get() == nullptr"); + return OHOS_FAILURE; + } + playerCtr->GetPlayerState(state); + if (state == PlayerStates::PLAYER_STARTED || state == PlayerStates::PLAYER_PAUSED) + { + ret = playerCtr->Stop(); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Failed to stop the player"); + return OHOS_FAILURE; + } + } + ret = playerCtr->Reset(); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Failed to reset the player"); + return OHOS_FAILURE; + } + ret = playerCtr->Release(); + playerCtr.reset(); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Failed to release the player"); + return OHOS_FAILURE; + } + if (amIntance.DeactivateAudioInterrupt(interrupt) != 0) + { + return OHOS_FAILURE; + } + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Reset, ret:%d", ret); + return OHOS_SUCCESS; + } + + int CountDownModel::ResetRingtonePlayback(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CountDownModel::ResetRingtonePlayback"); + int32_t ret = 0; + int32_t state = 0; + if (playerCtr.get() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] playerCtr is null"); + return OHOS_FAILURE; + } + playerCtr->GetPlayerState(state); + if (state == PlayerStates::PLAYER_STARTED || state == PlayerStates::PLAYER_PAUSED) + { + ret = playerCtr->Stop(); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Failed to stop the player"); + return OHOS_FAILURE; + } + } + ret = playerCtr->Reset(); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownModel] Failed to reset the player"); + return OHOS_FAILURE; + } + return OHOS_SUCCESS; + } + + template + static void PostRingtoneEvent(Func function) + { + GraphicService::GetInstance()->PostGraphicEvent( + std::bind(function, CountDownModel::GetInstance())); + } + + /*触发铃声的开始*/ + void CountDownModel::RequestStartRingtone(void) + { + PostRingtoneEvent(&CountDownModel::StartRingtonePlayback); + } + + /*触发铃声的停止*/ + void CountDownModel::RequestStopRingtone(void) + { + PostRingtoneEvent(&CountDownModel::StopRingtonePlaybackAndReleaseResources); + } + /* ----------------------------------- 定时器 ---------------------------------- */ /* @@ -150,6 +357,12 @@ namespace OHOS return; } + if (MainCountDownView::GetInstance()->GetStartCountDownView()->GetPlayOrPauseToggleButton() == nullptr) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDown_TimerCallbackProc] GetPlayOrPauseToggleButton is NULL"); + return; + } + if (CountDownModel::GetInstance()->DisplayCountDownDuration() == nullptr) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDown_TimerCallbackProc] DisplayCountDownDuration is NULL"); @@ -159,15 +372,21 @@ namespace OHOS // 检查倒计时是否结束 if (CountDownModel::g_CountDownTimes <= 0) { + MainCountDownView::GetInstance()->GetStartCountDownView()->GetPlayOrPauseToggleButton()->SetState(false); + MainCountDownView::GetInstance()->GetStartCountDownView()->GetPlayOrPauseToggleButton()->SetTouchable(false); CountDownModel::GetInstance()->CountDown_StopTimer(); // 停止定时器 MainCountDownView::GetInstance()->GetStartCountDownView()->GetShowCountDownTimelabel()->SetText("倒计时结束"); // 进行倒计时结束时的额外操作,比如播放声音、显示通知等 + // CountDownModel::GetInstance()->StartRingtonePlayback(); + CountDownModel::GetInstance()->RequestStartRingtone(); } else { // 更新显示 MainCountDownView::GetInstance()->GetStartCountDownView()->GetShowCountDownTimelabel()->SetText(CountDownModel::GetInstance()->DisplayCountDownDuration()); } + + return; } /* @@ -273,4 +492,117 @@ namespace OHOS } } + /* ----------------------- CountDownRingPlayerListener ---------------------- */ + + void CountDownRingPlayerListener::SetOwner(std::shared_ptr player) + { + player_ = player; + } + + /*重置标志位*/ + void CountDownRingPlayerListener::RestFlag() + { + isPaused_ = false; + isDelayed_ = false; + isResumed_ = false; + isBeginStopped_ = false; + isEndStopped_ = false; + } + + bool CountDownRingPlayerListener::IsPaused() + { + return isPaused_; + } + + bool CountDownRingPlayerListener::IsDelayed() + { + return isDelayed_; + } + + bool CountDownRingPlayerListener::IsResumed() + { + return isResumed_; + } + + bool CountDownRingPlayerListener::IsBeginStopped() + { + return isBeginStopped_; + } + + bool CountDownRingPlayerListener::IsEndStopped() + { + return isEndStopped_; + } + + static void Start(void) + { + CountDownModel::GetInstance()->RequestStartRingtone(); + } + + static void Stop(void) + { + CountDownModel::GetInstance()->RequestStopRingtone(); + } + + /*开始计时器铃声播放*/ + void CountDownRingPlayerListener::StartCountDownRing(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownRingPlayerListener::StartCountDownRing] start"); + GraphicService::GetInstance()->PostGraphicEvent(Start); + } + + /*停止计时器铃声播放*/ + void CountDownRingPlayerListener::StopCountDownRing(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CountDownRingPlayerListener::StopCountDownRing] start"); + GraphicService::GetInstance()->PostGraphicEvent(Stop); + } + + /*响应外部的音频中断事件*/ + void CountDownRingPlayerListener::OnInterrupt(int32_t type, int32_t hint) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "OnInterrupt go in, type %d, hint %d.", type, hint); + if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE) + { + isDelayed_ = true; + } + + if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_STOP) + { + StopCountDownRing(); + } + else if (type == INTERRUPT_TYPE_END && isDelayed_ == true) + { + // 重新开始计时器的铃声播放 + StartCountDownRing(); + isDelayed_ = false; + } + return; + } + + /* --------------------- CountDownRingPlayerCallbackImpl -------------------- */ + void CountDownRingPlayerCallbackImpl::OnPlaybackComplete(void) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "OnPlaybackComplete"); + CountDownModel::GetInstance()->RequestStopRingtone(); + CountDownModel::GetInstance()->RequestStartRingtone(); + } + + void CountDownRingPlayerCallbackImpl::OnError(int32_t errorType, int32_t errorCode) + { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "OnError test, errorType %d, errorCode %d", errorType, errorCode); + // 此处实现代码处理错误事件 + } + + void CountDownRingPlayerCallbackImpl::OnInfo(int type, int extra) + { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "OnInfo test, type %d, extra %d.", type, extra); + // 此处实现代码处理普通事件 + } + + void CountDownRingPlayerCallbackImpl::OnRewindToComplete(void) + { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "OnRewindToComplete test"); + // 此处实现代码处理进度控制完成的事件 + } } diff --git a/code/sdk/application/wearable/fd230app/nativeui/countdown/src/MainCountDownPresenter.cpp b/code/sdk/application/wearable/fd230app/nativeui/countdown/src/MainCountDownPresenter.cpp index e64fd1bfd..a0a16ca69 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/countdown/src/MainCountDownPresenter.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/countdown/src/MainCountDownPresenter.cpp @@ -24,7 +24,8 @@ namespace OHOS MainCountDownPresenter::~MainCountDownPresenter() { - CountDownModel::GetInstance()->CountDown_StopTimer(); + CountDownModel::GetInstance()->CountDown_StopTimer(); // 清理定时器资源 + CountDownModel::GetInstance()->StopRingtonePlaybackAndReleaseResources(); // 清理播放器资源 g_pMainCountDownPresenter = nullptr; } @@ -162,7 +163,9 @@ namespace OHOS if (strcmp(view.GetViewId(), STARTCOUNTDOWNVIEWRETURNBUTTON) == 0) // 从开始倒计时视图退到倒计时主视图 { CountDownModel::GetInstance()->SetCountDownTime("00:00:00"); - CountDownModel::GetInstance()->SetRingTime(""); + CountDownModel::GetInstance()->SetRingTime("00:00:00"); + CountDownModel::GetInstance()->StopRingtonePlaybackAndReleaseResources(); + MainCountDownView::GetInstance()->GetStartCountDownView()->GetPlayOrPauseToggleButton()->SetTouchable(true); MainCountDownView::GetInstance()->GetStartCountDownView()->GetPlayOrPauseToggleButton()->SetState(false); p_MainCountDownView->ChangeView(START_COUNTDOWN, MAIN_COUNTDOWN); return true;