1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us>
2#
3# Permission is hereby granted, free of charge, to any person
4# obtaining a copy of this software and associated documentation files
5# (the "Software"), to deal in the Software without restriction,
6# including without limitation the rights to use, copy, modify, merge,
7# publish, distribute, sublicense, and/or sell copies of the Software,
8# and to permit persons to whom the Software is furnished to do so,
9# subject to the following conditions:
10#
11# The above copyright notice and this permission notice shall be
12# included in all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20# WITH THE SOFTWARE OR
21
22from __future__ import division, absolute_import, with_statement, print_function, unicode_literals
23from renpy.compat import *
24
25import renpy
26import jnius # @UnresolvedImport
27
28from renpy.audio.audio import MusicContext
29
30VideoPlayer = jnius.autoclass("org.renpy.android.VideoPlayer")
31
32
33class AndroidVideoChannel(object):
34
35    def __init__(self, name, file_prefix="", file_suffix="", default_loop=None):
36
37        # A list of queued filenames.
38        self.queue = [ ]
39
40        # The filename that's currently playing.
41        self.filename = None
42
43        # The videoplayer that's currently playing.
44        self.player = None
45
46        # The name assigned to this channel. This is used to look up
47        # information about the channel in the MusicContext object.
48        self.name = name
49
50        # The name of the mixer this channel uses. Set below, as there's
51        # no good default.
52        self.mixer = None
53
54        # The time the music in this channel was last changed.
55        self.last_changed = 0
56
57        # The callback that is called if the queue becomes empty.
58        self.callback = None
59
60        # Ignored.
61        self.synchro_start = False
62        self.wait_stop = False
63        self.loop = [ ]
64
65        # A prefix and suffix that are used to create the full filenames.
66        self.file_prefix = file_prefix
67        self.file_suffix = file_suffix
68
69        if default_loop is None:
70            # By default, should we loop the music?
71            self.default_loop = True
72            # Was this set explicitly?
73            self.default_loop_set = False
74
75        else:
76            self.default_loop = default_loop
77            self.default_loop_set = True
78
79    def get_context(self):
80        """
81        Returns the MusicContext corresponding to this channel, taken from
82        the context object. Allocates a MusicContext if none exists.
83        """
84
85        mcd = renpy.game.context().music
86
87        rv = mcd.get(self.name)
88        if rv is None:
89            rv = mcd[self.name] = MusicContext()
90
91        return rv
92
93    context = property(get_context)
94
95    def copy_context(self):
96        """
97        Copies the MusicContext associated with this channel, updates the
98        ExecutionContext to point to the copy, and returns the copy.
99        """
100
101        mcd = renpy.game.context().music
102
103        ctx = self.get_context().copy()
104        mcd[self.name] = ctx
105        return ctx
106
107    def start(self):
108        """
109        Starts playing the first video in the queue.
110        """
111
112        if not self.queue:
113            return
114
115        filename = self.queue.pop(0)
116
117        print("Playing", filename)
118
119        with renpy.loader.load(filename) as f:
120            real_fn = f.name
121            base = getattr(f, "base", -1)
122            length = getattr(f, "length", -1)
123
124        self.filename = filename
125        self.player = VideoPlayer(real_fn, base, length)
126
127    def stop(self):
128
129        if self.player is not None:
130            self.player.stop()
131            self.player = None
132
133        self.filename = None
134
135    def get_playing(self):
136
137        if self.player is None:
138            return None
139
140        if self.player.isPlaying():
141            return self.filename
142
143    def periodic(self):
144
145        # This should be set from something that checks to see if our
146        # mixer is muted.
147        force_stop = self.context.force_stop
148
149        if force_stop:
150            self.dequeue()
151            self.stop()
152            return
153
154        if self.get_playing():
155            return
156
157        if self.queue:
158            self.start()
159
160    def dequeue(self, even_tight=False):
161        """
162        Clears the queued music, except for a first item that has
163        not been started.
164        """
165
166        if self.get_playing():
167            self.queue = [ ]
168        else:
169            self.queue = self.queue[:1]
170
171    def interact(self):
172        """
173        Called (mostly) once per interaction.
174        """
175
176        self.periodic()
177
178    def fadeout(self, secs):
179        """
180        Causes the playing music to be faded out for the given number
181        of seconds. Also clears any queued music.
182        """
183
184        self.stop()
185        self.queue = [ ]
186
187    def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None, loop_only=False, relative_volume=1.0):
188        self.queue.extend(filenames)
189
190    def set_volume(self, volume):
191        pass
192
193    def get_pos(self):
194        pass
195
196    def set_pan(self, pan, delay):
197        pass
198
199    def set_secondary_volume(self, volume, delay):
200        pass
201
202    def pause(self):
203        if self.player is not None:
204            self.player.pause()
205
206    def unpause(self):
207        if self.player is not None:
208            self.player.unpause()
209
210    def reload(self):
211        return
212
213    def read_video(self):
214        return None
215
216    def video_ready(self):
217        return 1
218