--- /dev/null
+/*
+* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+* 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 "ttsd_main.h"
+#include "ttsd_data.h"
+#include "PlayerThread.h"
+
+
+using namespace std;
+
+void PlayerThread::runThread(PlayerThread* player)
+{
+ SLOG(LOG_INFO, tts_tag(), "[Player] Run player thread");
+ player->runPlayer();
+ SLOG(LOG_INFO, tts_tag(), "[Player] Exit player thread");
+}
+
+PlayerThread::PlayerThread(PlayUtteranceCallback threadFucntion)
+{
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Constructor");
+ __currentUid = TTS_INVALID_UID;
+ __playerAvailable = true;
+ __playUtterance = threadFucntion;
+
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Start thread");
+ __playerThread = thread(runThread, this);
+}
+
+PlayerThread::~PlayerThread()
+{
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Destructor");
+ unique_lock<mutex> controlLock(__controlMutex);
+ __playerAvailable = false;
+ __playUtterance = nullptr;
+
+ tryToStopPlayer();
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Thread is stopped or waiting");
+
+ __threadCond.notify_all();
+ __playerThread.join();
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Finish thread");
+}
+
+void PlayerThread::tryToStopPlayer()
+{
+ __currentUid = TTS_INVALID_UID;
+
+ unique_lock<mutex> stopCheckLock(__stopCheckMutex);
+ cv_status ret = __stopCheckCond.wait_for(stopCheckLock, chrono::milliseconds(500));
+ if (ret == cv_status::timeout) {
+ SLOG(LOG_WARN, tts_tag(), "[PlayerThread] Timeout stop request");
+ }
+}
+
+bool PlayerThread::isPlayerAvailable()
+{
+ return __playerAvailable.load();
+}
+
+unsigned int PlayerThread::getCurrentUid()
+{
+ return __currentUid.load();
+}
+
+bool PlayerThread::isCurrentUid(unsigned int uid)
+{
+ if (0 > ttsd_data_is_client(uid)) {
+ return false;
+ }
+
+ if (uid != __currentUid.load()) {
+ return false;
+ }
+
+ return true;
+}
+
+void PlayerThread::requestPlay(unsigned int uid)
+{
+ lock_guard<mutex> lock(__controlMutex);
+ if (false == isPlayerAvailable()) {
+ SLOG(LOG_ERROR, tts_tag(), "[PlayerThread] Player is already finished.");
+ return;
+ }
+
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Play request. uid(%u)", uid);
+ __currentUid = uid;
+ __threadCond.notify_all();
+}
+
+void PlayerThread::requestStop()
+{
+ lock_guard<mutex> lock(__controlMutex);
+ if (false == isPlayerAvailable()) {
+ SLOG(LOG_ERROR, tts_tag(), "[PlayerThread] Player is already finished.");
+ return;
+ }
+
+ unsigned int uid = __currentUid.load();
+ if (uid == TTS_INVALID_UID) {
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Thread is already stopped");
+ return;
+ }
+
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Stop request. current played uid(%u)", uid);
+ tryToStopPlayer();
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Stop playing");
+}
+
+void PlayerThread::runPlayer()
+{
+ unique_lock<mutex> lock(__threadMutex);
+ if (nullptr == __playUtterance) {
+ SLOG(LOG_ERROR, tts_tag(), "[PlayerThread] Play utterance callback is not set");
+ return;
+ }
+
+ while (isPlayerAvailable()) {
+ SLOG(LOG_INFO, tts_tag(), "[PlayerThread] Wait playing");
+ if (isThreadStopped()) {
+ __threadCond.wait(lock);
+ }
+
+ while (false == isThreadStopped()) {
+ unsigned int uid = getCurrentUid();
+ SLOG(LOG_INFO, tts_tag(), "[Player] Current player uid(%u)", uid);
+ __playUtterance(this, uid);
+ }
+
+ __stopCheckCond.notify_all();
+ }
+}
+
+bool PlayerThread::isThreadStopped()
+{
+ bool isStopped = (TTS_INVALID_UID == __currentUid.load()) || (false == isPlayerAvailable());
+ return isStopped;
+}
--- /dev/null
+/*
+* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+* 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 __TTSD_PLAYER_MANAGER_H_
+#define __TTSD_PLAYER_MANAGER_H_
+
+
+#include <mutex>
+#include <condition_variable>
+#include <thread>
+#include <atomic>
+#include <queue>
+
+class PlayerThread {
+public:
+ typedef void (*PlayUtteranceCallback)(PlayerThread* player_instance, unsigned int uid);
+
+ PlayerThread(PlayUtteranceCallback threadFucntion);
+ ~PlayerThread();
+
+ unsigned int getCurrentUid();
+ bool isCurrentUid(unsigned int uid);
+
+ void requestPlay(unsigned int uid);
+ void requestStop();
+private:
+ static void runThread(PlayerThread* player);
+
+ void runPlayer();
+ void tryToStopPlayer();
+ bool isPlayerAvailable();
+ bool isThreadStopped();
+
+private:
+ std::atomic<unsigned int> __currentUid;
+ std::atomic<bool> __playerAvailable;
+
+ std::thread __playerThread;
+ std::mutex __threadMutex;
+ std::mutex __controlMutex;
+ std::mutex __stopCheckMutex;
+ std::condition_variable __threadCond;
+ std::condition_variable __stopCheckCond;
+
+ PlayUtteranceCallback __playUtterance;
+};
+
+
+#endif /* __TTSD_PLAYER_MANAGER_H_ */