1 # this file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Romain Chanoir <romain.chanoir@viacesi.fr>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Android audio services
19 # You can get a sound by loading it with a `SoundPool` or a `MediaPlayer`
20 # the recommended way to load a sound is by it's resource ID or it's name
21 # other ways are for advanced use
26 import assets_and_resources
30 import android.media.MediaPlayer;
31 import android.media.SoundPool;
32 import java.io.IOException;
33 import android.media.AudioManager;
34 import android.content.Context;
35 import android.util.Log;
38 # AudioManager of the application, used to manage the audio mode
39 extern class NativeAudioManager in "Java" `{ android.media.AudioManager `}
41 redef type SELF: NativeAudioManager
43 fun mode: Int in "Java" `{ return recv.getMode(); `}
44 fun mode
=(i
: Int) in "Java" `{ recv.setMode((int)i); `}
45 fun wired_headset_on: Bool in "Java" `{ return recv.isWiredHeadsetOn(); `}
46 fun wired_headset_on
=(b
: Bool) in "Java" `{ recv.setWiredHeadsetOn(b); `}
47 fun speakerphone_on: Bool in "Java" `{ return recv.isSpeakerphoneOn(); `}
48 fun speakerphone_on
=(b
: Bool) in "Java" `{ recv.setSpeakerphoneOn(b); `}
49 fun manage_audio_mode in "Java" `{
51 if (recv
.isWiredHeadsetOn
()) {
52 recv
.setSpeakerphoneOn
(false);
54 recv
.setSpeakerphoneOn
(true);
60 # Media Player from Java, used to play long sounds or musics, not simultaneously
61 # This is a low-level class, use `MediaPlater` instead
62 extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
64 redef type SELF: NativeMediaPlayer
66 new in "Java" `{ return new MediaPlayer(); `}
67 fun start in "Java" `{ recv.start(); `}
68 fun prepare
in "Java" `{
71 }catch(IOException e) {
72 Log.e("Error preparing the Media Player", e.getMessage());
77 fun create
(context
: NativeActivity, id
: Int): NativeMediaPlayer in "Java" `{ return recv.create(context, (int)id); `}
78 fun pause in "Java" `{ recv.pause(); `}
79 fun stop
in "Java" `{ recv.stop(); `}
80 fun playing: Bool in "Java" `{ return recv.isPlaying(); `}
81 fun release
in "Java" `{ recv.release(); `}
82 fun duration: Int in "Java" `{ return recv.getDuration(); `}
83 fun looping
: Bool in "Java" `{ return recv.isLooping(); `}
84 fun looping=(b: Bool) in "Java" `{ recv.setLooping(b); `}
85 fun volume
=(vol
: Float) in "Java" `{ recv.setVolume((float)vol, (float)vol); `}
86 fun both_volume(left_volume, right_volume: Float) in "Java" `{ recv.setVolume((float)left_volume, (float)right_volume); `}
87 fun stream_type
=(stream_type
: Int) in "Java" `{ recv.setAudioStreamType((int)stream_type); `}
88 fun data_source_fd(fd: NativeFileDescriptor, start_offset, length: Int) in "Java" `{
90 recv
.setDataSource
(fd
, start_offset
, length
);
91 }catch
(IOException e
) {
92 Log.e
("Error loading the Media Player with a file descriptor", e
.getMessage
());
96 fun data_source_path(path: JavaString) in "Java" `{
98 recv
.setDataSource
(path
);
99 }catch
(IOException e
) {
100 Log.e
("Error loading the Media Player", e
.getMessage
());
104 fun reset in "Java" `{ recv.reset(); `}
107 # Sound Pool from Java, used to play sounds simultaneously
108 # This is a low-level class, use `SoundPool`instead
109 extern class NativeSoundPool in "Java" `{ android.media.SoundPool `}
111 redef type SELF: NativeSoundPool
113 new(max_streams, stream_type, src_quality: Int) in "Java" `{
114 return new SoundPool((int
)max_streams
, (int
)stream_type
, (int
)src_quality
);
116 fun load_asset_fd(afd: NativeAssetFileDescriptor, priority: Int): Int in "Java" `{ return recv.load(afd, (int)priority); `}
117 fun load_id
(context
: NativeActivity, resid
, priority
: Int): Int in "Java" `{ return recv.load(context, (int)resid, (int)priority); `}
118 fun load_path(path: JavaString, priority: Int): Int in "Java" `{ return recv.load(path, (int)priority); `}
119 fun play
(sound_id
: Int, left_volume
, right_volume
: Float, priority
, l
: Int, rate
: Float): Int in "Java" `{
120 return recv.play((int)sound_id, (float)left_volume, (float)right_volume, (int)priority, (int)l, (float)rate);
122 fun pause
(stream_id
: Int) in "Java" `{ recv.pause((int)stream_id); `}
123 fun auto_pause in "Java" `{ recv.autoPause(); `}
124 fun auto_resume
in "Java" `{ recv.autoResume(); `}
125 fun resume(stream_id: Int) in "Java" `{ recv.resume((int)stream_id); `}
126 fun set_loop
(stream_id
, l
: Int) in "Java" `{ recv.setLoop((int)stream_id, (int)l); `}
127 fun set_priority(stream_id, priority: Int) in "Java" `{ recv.setPriority((int)stream_id, (int)priority); `}
128 fun set_rate
(stream_id
: Int, rate
: Float) in "Java" `{ recv.setRate((int)stream_id, (float)rate); `}
129 fun set_volume(stream_id: Int, left_volume, right_volume: Float) in "Java" `{ recv.setVolume((int)stream_id, (float)left_volume, (float)right_volume); `}
130 fun stop
(stream_id
: Int) in "Java" `{ recv.stop((int)stream_id); `}
131 fun unload(sound_id: Int): Bool in "Java" `{ return recv.unload((int)sound_id); `}
132 fun release
in "Java" `{ recv.release(); `}
136 # Used to play sound, best suited for sounds effects in apps or games
138 private var nsoundpool: NativeSoundPool is noinit
139 # The maximum number of simultaneous streams for this SoundPool
140 var max_streams = 10 is writable
142 # The audio stream type, 3 is STREAM_MUSIC, default for game application
143 var stream_type = 3 is writable
145 # The sample-rate converter quality, currently has no effect
146 var src_quality = 0 is writable
148 # Left volume value, range 0.0 to 1.0
149 var left_volume = 1.0 is writable
151 # Right volume value, range 0.0 to 1.0
152 var right_volume = 1.0 is writable
154 # Playback rate, 1.0 = normal playback, range 0.5 to 2.0
155 var rate = 1.0 is writable
157 # Loop mode, 0 = no loop, -1 = loop forever
158 var looping = 0 is writable
161 private var priority = 1
163 init do self.nsoundpool = new NativeSoundPool(max_streams, stream_type, src_quality)
165 # Load the sound from an asset file descriptor
166 # this function is for advanced use
167 fun load_asset_fd(afd: NativeAssetFileDescriptor): Sound do
168 return new SoundSP(null, nsoundpool.load_asset_fd(afd, priority), self)
171 # Load the sound from it's resource id
172 fun load_id(context: NativeActivity, id:Int): Sound do
173 return new SoundSP(null, nsoundpool.load_id(context, id, priority), self)
176 # Load the sound from the specified path
177 fun load_path(path: String): Sound do
178 sys.jni_env.push_local_frame(1)
179 var return_value = new SoundSP(0, nsoundpool.load_path(path.to_java_string, priority), self)
180 sys.jni_env.pop_local_frame
184 # Play a sound from a sound ID
185 # return non-zero streamID if successful, zero if failed
186 fun play(id: Int): Int do
187 return nsoundpool.play(id, left_volume, right_volume, priority, looping, rate)
190 # Load a sound by it's name in the resources, the sound must be in the `res
/raw
` folder
191 fun load_name(resource_manager: ResourcesManager, context: NativeActivity, sound: String): Sound do
192 var id = resource_manager.raw_id(sound)
193 return new SoundSP(id, nsoundpool.load_id(context, id, priority), self)
196 # Pause a playback stream
197 fun pause_stream(stream_id: Int) do nsoundpool.pause(stream_id)
199 # Pause all active_streams
200 fun auto_pause do nsoundpool.auto_pause
202 # Resume all previously active streams
203 fun auto_resume do nsoundpool.auto_resume
205 # Resume a playback stream
206 fun resume(stream_id: Int) do nsoundpool.resume(stream_id)
208 # Set loop mode on a stream
209 fun stream_loop=(stream_id, looping: Int) do nsoundpool.set_loop(stream_id, looping)
211 # Change stream priority
212 fun stream_priority=(stream_id, priority: Int) do nsoundpool.set_priority(stream_id, priority)
214 # Change playback rate
215 fun stream_rate=(stream_id: Int, rate: Float) do nsoundpool.set_rate(stream_id, rate)
218 fun stream_volume(stream_id: Int, left_volume, right_volume: Float) do
219 nsoundpool.set_volume(stream_id, left_volume, right_volume)
222 # Stop a playback stream
223 fun stop_stream(stream_id: Int) do nsoundpool.stop(stream_id)
225 # Unload a sound from a sound ID
226 fun unload(sound: SoundSP): Bool do return nsoundpool.unload(sound.soundpool_id)
228 fun destroy do nsoundpool.release
231 # Used to play sounds, designed to use with medium sized sounds or streams
232 # The Android MediaPlayer has a complex state diagram that you'll need to
233 # respect if you want your MediaPlayer to work fine, see the android doc
235 private var nmedia_player: NativeMediaPlayer
237 # The sound associated with this mediaplayer
238 var sound: nullable Sound
240 # Create a new MediaPlayer, but no sound is attached, you'll need
241 # to use `load_sound
` before using it
242 init do self.nmedia_player = new NativeMediaPlayer
244 # Init the mediaplayer with a sound resource id
245 init from_id(context: NativeActivity, id: Int) do
246 self.nmedia_player = new NativeMediaPlayer
247 self.nmedia_player = nmedia_player.create(context, id)
248 self.sound = new SoundMP(id, self)
251 # Load a sound for a given resource id
252 fun load_sound(id: Int, context: NativeActivity): Sound do
253 self.nmedia_player = self.nmedia_player.create(context, id)
254 self.sound = new SoundMP(id, self)
255 return self.sound.as(not null)
258 # Starts or resume playback
259 # REQUIRE `self.sound
!= null`
265 # Stops playback after playback has been stopped or paused
266 # REQUIRE `self.sound
!= null`
272 # Prepares the player for playback, synchronously
273 # REQUIRE `self.sound
!= null`
276 nmedia_player.prepare
280 # REQUIRE `self.sound
!= null`
286 # Checks whether the mediaplayer is playing
287 fun playing: Bool do return nmedia_player.playing
289 # Releases the resources associated with this MediaPlayer
291 nmedia_player.release
295 # Reset MediaPlayer to its initial state
296 fun reset do nmedia_player.reset
298 # Sets the datasource (file-pathor http/rtsp URL) to use
299 fun data_source(path: String): Sound do
300 sys.jni_env.push_local_frame(1)
301 nmedia_player.data_source_path(path.to_java_string)
302 sys.jni_env.pop_local_frame
303 self.sound = new SoundMP(null, self)
304 return self.sound.as(not null)
306 # Sets the data source (NativeFileDescriptor) to use
307 fun data_source_fd(fd: NativeFileDescriptor, start_offset, length: Int): Sound do
308 nmedia_player.data_source_fd(fd, start_offset, length)
309 self.sound = new SoundMP(null, self)
310 return self.sound.as(not null)
313 # Checks whether the MediaPlayer is looping or non-looping
314 fun looping: Bool do return nmedia_player.looping
316 # Sets the player to be looping or non-looping
317 fun looping=(b: Bool) do nmedia_player.looping = b
319 # Sets the volume on this player
320 fun volume=(volume: Float) do nmedia_player.volume = volume
322 # Sets the left volume and the right volume of this player
323 fun both_volume(left_volume, right_volume: Float) do nmedia_player.both_volume(left_volume, right_volume)
325 # Sets the audio stream type for this media player
326 fun stream_type=(stream_type: Int) do nmedia_player.stream_type = stream_type
329 # Represents an android sound that can be played by a SoundPool or a MediaPlayer
330 # The only way to get a sound is by a MediaPlayer, a SoundPool, or the App
333 # The resource ID of this sound
339 # Sound implemented with a SoundPool
343 # The SoundPool who loaded this sound
344 var soundpool: SoundPool
346 # The SoundID of this sound in his SoundPool
347 var soundpool_id: Int
349 private init (id: nullable Int, soundpool_id: Int, soundpool: SoundPool) do
351 self.soundpool_id = soundpool_id
352 self.soundpool = soundpool
355 redef fun play do soundpool.play(soundpool_id)
358 # Sound Implemented with a MediaPlayer
362 # The MediaPlayer who loaded this sound
363 var media_player: MediaPlayer
365 private init (id: nullable Int, media_player: MediaPlayer) do
367 self.media_player = media_player
370 redef fun play do self.media_player.start
375 fun default_mediaplayer: MediaPlayer is cached do return new MediaPlayer
376 fun default_soundpool: SoundPool is cached do return new SoundPool
378 # Get the native audio manager
379 private fun audio_manager: NativeAudioManager import native_activity in "Java" `{
380 return (AudioManager)App_native_activity(recv
).getSystemService
(Context.AUDIO_SERVICE);
383 # Manages whether the app sound need to be in headphones mode or not
384 # TODO: this method is not ideal, need to find a better way
385 fun manage_audio_mode import native_activity in "Java" `{
386 AudioManager manager
= (AudioManager)App_native_activity(recv
).getSystemService
(Context.AUDIO_SERVICE);
388 if (manager
.isWiredHeadsetOn
()) {
389 manager
.setSpeakerphoneOn
(false);
391 manager
.setSpeakerphoneOn
(true);
395 # Retrieve a sound with a soundpool in the `assets
` folder using it's name
396 # Used to play short songs, can play multiple sounds simultaneously
397 fun load_sound(path: String): Sound do
398 return default_soundpool.load_asset_fd(asset_manager.open_fd(path))
401 # Retrieve a music with a media player in the `assets
`folder using it's name
402 # Used to play long sounds or musics, can't play multiple sounds simultaneously
403 fun load_music(path: String): Sound do
404 var fd = asset_manager.open_fd(path)
405 var sound = default_mediaplayer.data_source_fd(fd.file_descriptor, fd.start_offset, fd.length)
409 # same as `load_sound
` but load the sound from the `res\raw
` folder
410 fun load_sound_from_res(sound_name: String): Sound do
411 return default_soundpool.load_name(resource_manager,self.native_activity, sound_name)
414 # same as `load_music
` but load the sound from the `res\raw
` folder
415 fun load_music_from_res(music: String): Sound do
416 return default_mediaplayer.load_sound(resource_manager.raw_id(music), self.native_activity)