Added Android code
[wl-app.git] / Android / folioreader / src / main / java / com / folioreader / ui / folio / mediaoverlay / MediaController.java
1 package com.folioreader.ui.folio.mediaoverlay;
2
3 import android.annotation.TargetApi;
4 import android.content.Context;
5 import android.media.MediaPlayer;
6 import android.os.Build;
7 import android.os.Handler;
8 import android.speech.tts.TextToSpeech;
9 import android.support.v7.app.AppCompatActivity;
10 import android.util.Log;
11
12 import com.folioreader.Constants;
13 import com.folioreader.model.event.MediaOverlayPlayPauseEvent;
14 import com.folioreader.model.event.MediaOverlaySpeedEvent;
15 import com.folioreader.model.media_overlay.OverlayItems;
16 import com.folioreader.util.UiUtil;
17
18 import org.readium.r2_streamer.model.publication.SMIL.Clip;
19 import org.readium.r2_streamer.model.publication.SMIL.MediaOverlays;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Locale;
26
27 /**
28  * @author gautam chibde on 21/6/17.
29  */
30
31 public class MediaController {
32
33     private static final String TAG = MediaController.class.getSimpleName();
34
35     public enum MediaType {
36         TTS, SMIL,
37     }
38
39     private MediaType mediaType;
40     private MediaControllerCallbacks callbacks;
41     private Context context;
42
43     //**********************************//
44     //          MEDIA OVERLAY           //
45     //**********************************//
46     private MediaOverlays mediaOverlays;
47     private List<OverlayItems> mediaItems = new ArrayList<>();
48     private int mediaItemPosition = 0;
49     private MediaPlayer mediaPlayer;
50
51     private Clip currentClip;
52
53     private boolean isMediaPlayerReady;
54     private Handler mediaHandler;
55
56     //*********************************//
57     //              TTS                //
58     //*********************************//
59     private TextToSpeech mTextToSpeech;
60     private boolean mIsSpeaking = false;
61
62     public MediaController(Context context, MediaType mediaType, MediaControllerCallbacks callbacks) {
63         this.mediaType = mediaType;
64         this.callbacks = callbacks;
65         this.context = context;
66     }
67
68     private Runnable mHighlightTask = new Runnable() {
69         @Override
70         public void run() {
71             int currentPosition = mediaPlayer.getCurrentPosition();
72             if (mediaPlayer.getDuration() != currentPosition) {
73                 if (mediaItemPosition < mediaItems.size()) {
74                     int end = (int) currentClip.end * 1000;
75                     if (currentPosition > end) {
76                         mediaItemPosition++;
77                         currentClip = mediaOverlays.clip(mediaItems.get(mediaItemPosition).getId());
78                         if (currentClip != null) {
79                             callbacks.highLightText(mediaItems.get(mediaItemPosition).getId());
80                         } else {
81                             mediaItemPosition++;
82                         }
83                     }
84                     mediaHandler.postDelayed(mHighlightTask, 10);
85                 } else {
86                     mediaHandler.removeCallbacks(mHighlightTask);
87                 }
88             }
89         }
90     };
91
92     public void resetMediaPosition() {
93         mediaItemPosition = 0;
94     }
95
96     public void setSMILItems(List<OverlayItems> overlayItems) {
97         this.mediaItems = overlayItems;
98     }
99
100     public void next() {
101         mediaItemPosition++;
102     }
103
104     public void setTextToSpeech(final Context context) {
105         mTextToSpeech = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
106             @Override
107             public void onInit(int status) {
108                 if (status != TextToSpeech.ERROR) {
109                     mTextToSpeech.setLanguage(Locale.getDefault());
110                     mTextToSpeech.setSpeechRate(0.70f);
111                 }
112
113                 mTextToSpeech.setOnUtteranceCompletedListener(
114                         new TextToSpeech.OnUtteranceCompletedListener() {
115                             @Override
116                             public void onUtteranceCompleted(String utteranceId) {
117                                 ((AppCompatActivity) context).runOnUiThread(new Runnable() {
118                                     @Override
119                                     public void run() {
120                                         if (mIsSpeaking) {
121                                             callbacks.highLightTTS();
122                                         }
123                                     }
124                                 });
125                             }
126                         });
127             }
128         });
129     }
130
131     public void setUpMediaPlayer(MediaOverlays mediaOverlays, String path, String mBookTitle) {
132         this.mediaOverlays = mediaOverlays;
133         mediaHandler = new Handler();
134         try {
135             mediaItemPosition = 0;
136             String uri = Constants.LOCALHOST + mBookTitle + "/" + path;
137             mediaPlayer = new MediaPlayer();
138             mediaPlayer.setDataSource(uri);
139             mediaPlayer.prepare();
140             isMediaPlayerReady = true;
141         } catch (IOException e) {
142             Log.d(TAG, e.getMessage());
143         }
144     }
145
146     public void setSpeed(MediaOverlaySpeedEvent.Speed speed) {
147         switch (speed) {
148             case HALF:
149                 setPlaybackSpeed(0.5f);
150                 break;
151             case ONE:
152                 setPlaybackSpeed(1.0f);
153                 break;
154             case ONE_HALF:
155                 setPlaybackSpeed(1.5f);
156                 break;
157             case TWO:
158                 setPlaybackSpeed(2.0f);
159                 break;
160         }
161     }
162
163     @TargetApi(Build.VERSION_CODES.M)
164     private void setPlaybackSpeed(float speed) {
165         if (mediaType == MediaType.SMIL) {
166             if (mediaPlayer != null && mediaPlayer.isPlaying()) {
167                 mediaPlayer.setPlaybackParams(mediaPlayer.getPlaybackParams().setSpeed(speed));
168             }
169         } else {
170             mTextToSpeech.setSpeechRate(speed);
171         }
172     }
173
174     public void stateChanged(MediaOverlayPlayPauseEvent event) {
175         if (event.isStateChanged()) {
176             if (mediaPlayer != null) {
177                 mediaPlayer.pause();
178             }
179             if (mTextToSpeech != null && mTextToSpeech.isSpeaking()) {
180                 mTextToSpeech.stop();
181             }
182         } else {
183             if (event.isPlay()) {
184                 UiUtil.keepScreenAwake(true, context);
185             } else {
186                 UiUtil.keepScreenAwake(false, context);
187             }
188             if (mediaType == MediaType.SMIL) {
189                 playSMIL();
190             } else {
191                 if (mTextToSpeech.isSpeaking()) {
192                     mTextToSpeech.stop();
193                     mIsSpeaking = false;
194                     callbacks.resetCurrentIndex();
195                 } else {
196                     mIsSpeaking = true;
197                     callbacks.highLightTTS();
198                 }
199             }
200         }
201     }
202
203     private void playSMIL() {
204         if (mediaPlayer != null && isMediaPlayerReady) {
205             if (mediaPlayer.isPlaying()) {
206                 mediaPlayer.pause();
207             } else {
208                 currentClip = mediaOverlays.clip(mediaItems.get(mediaItemPosition).getId());
209                 if (currentClip != null) {
210                     mediaPlayer.start();
211                     mediaHandler.post(mHighlightTask);
212                 } else {
213                     mediaItemPosition++;
214                     mediaPlayer.start();
215                     mediaHandler.post(mHighlightTask);
216                 }
217             }
218         }
219     }
220
221     public void speakAudio(String sentence) {
222         if (mediaType == MediaType.TTS) {
223             HashMap<String, String> params = new HashMap<>();
224             params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "stringId");
225             mTextToSpeech.speak(sentence, TextToSpeech.QUEUE_FLUSH, params);
226         }
227     }
228
229     public void stop() {
230         if (mTextToSpeech != null) {
231             if (mTextToSpeech.isSpeaking()) {
232                 mTextToSpeech.stop();
233             }
234             mTextToSpeech.shutdown();
235         }
236         if (mediaPlayer != null && mediaPlayer.isPlaying()) {
237             mediaPlayer.stop();
238             mediaPlayer.release();
239             mediaPlayer = null;
240             mediaHandler.removeCallbacks(mHighlightTask);
241         }
242     }
243 }