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