1 /// 2 /// Common methods for media sources that rely on C++11 threads. 3 /// @file threadedmediaplayer.cpp - pianod project 4 /// @author Perette Barella 5 /// @date 2014-10-26 6 /// @copyright Copyright 2012-2014 Devious Fish. All rights reserved. 7 /// 8 9 #include <config.h> 10 11 #include <cstdio> 12 #include <cstdint> 13 #include <cstring> 14 15 #include <thread> 16 #include <mutex> 17 #include <condition_variable> 18 #include <future> 19 #include <functional> 20 21 #include "fundamentals.h" 22 #include "mediaplayer.h" 23 #include "logging.h" 24 25 using namespace std; 26 27 namespace Media { 28 29 // Inform the player thread that it should pause/resume/quit. setThreadState(bool pause,bool quit)30 void ThreadedPlayer::setThreadState (bool pause, bool quit) { 31 unique_lock<mutex> lock (pause_mutex); 32 if (quit) 33 do_quit = true; 34 do_pause = do_quit ? false : pause; 35 pause_changed.notify_all(); 36 } 37 pause(void)38 void ThreadedPlayer::pause (void) { 39 setThreadState (true, false); 40 }; 41 abort()42 void ThreadedPlayer::abort () { 43 setThreadState (false, true); 44 } 45 checkForPauseOrQuit(void)46 bool ThreadedPlayer::checkForPauseOrQuit (void) { 47 bool quit = false; 48 49 unique_lock<mutex> lock (pause_mutex); 50 while (true) { 51 if (do_quit) { 52 // To avoid headaches, no partial initialization abortions. 53 if (ready ()) { 54 quit = true; 55 } 56 break; 57 } 58 if (!do_pause) { 59 break; 60 } 61 pausing(); 62 // Note: condition variable releases the mutex while waiting 63 pause_changed.wait (lock); 64 resuming(); 65 } 66 return quit; 67 }; 68 69 /** Start the player thread. Starts in a paused state. */ cue(void)70 void ThreadedPlayer::cue (void) { 71 packaged_task<RESPONSE_CODE (void)> package (bind (&ThreadedPlayer::playerThread, this)); 72 player_response = package.get_future(); 73 std::thread player (std::move (package)); 74 player_thread = std::move (player); 75 } 76 /** Calls resume() to starting playback. */ play(void)77 void ThreadedPlayer::play (void) { 78 setThreadState (false, false); 79 } 80 /** Get the player completion status, when it is done. 81 @throw If the player thread threw an exception, the promise/ 82 future holds it and get() rethrows it when asked for it. */ completionStatus()83 RESPONSE_CODE ThreadedPlayer::completionStatus() { 84 assert (player_thread.joinable()); 85 assert (player_response.valid()); 86 player_response.wait(); 87 RESPONSE_CODE response = player_response.get(); 88 return response; 89 } 90 /** Called when the playback thread is pausing. */ pausing(void)91 void ThreadedPlayer::pausing (void) { 92 } 93 /** Called when the playback thread is resuming playback. */ resuming(void)94 void ThreadedPlayer::resuming (void) { 95 } 96 ThreadedPlayer(void)97 ThreadedPlayer::ThreadedPlayer (void) { 98 } 99 ~ThreadedPlayer(void)100 ThreadedPlayer::~ThreadedPlayer (void) { 101 if (player_thread.joinable()) { 102 player_thread.join(); 103 } 104 } 105 } 106 107