# limitations under the License.
# Android audio services, wraps a part of android audio API
+# This module modifies the default behaviour of the audio loading:
+# It is first loaded from the `res/raw` folder.
+# The file extension is not needed for the `res/raw` loading part.
+# If it didn't work, it is loaded from the `assets` folder.
+# The file extension is needed for the `assets` loading part.
+#
+# `assets` contains the portable version of sounds, since the `res` folder exsists only in android projects.
#
# For this example, the sounds "test_sound" and "test_music" are located in the "assets/sounds" folder,
# they both have ".ogg" extension. "test_sound" is a short sound and "test_music" a music track
import java
import java::io
intrude import assets_and_resources
-import native_app_glue # FIXME update this module to use nit_activity
+import activities
import app::audio
in "Java" `{
self.setDataSource(fd, start_offset, length);
return 1;
}catch(Exception e) {
- Log.e("Error loading the Media Player with a file descriptor", e.getMessage());
return 0;
}
`}
# Load a sound for a given resource id
fun load_sound(id: Int, context: NativeActivity): Music do
+ # FIXME: maybe find a better way to handle this situation
+ # If two different music are loaded with the same `MediaPlayer`,
+ # a new `NativeMediaPlayer` will be created for the secondd music
+ # and the nit program will loose the handle to the previous one
+ # If the previous music is playing, we need to stop it
+ if playing then
+ stop
+ reset
+ destroy
+ end
self.nmedia_player = self.nmedia_player.create(context, id)
if self.nmedia_player.is_java_null then
self.error = new Error("Failed to load a sound")
end
redef class PlayableAudio
- redef init do app.add_to_sounds(self)
+ # Flag to know if the user paused the sound
+ # Used when the app pause all sounds or resume all sounds
+ var paused: Bool = false
+
+ redef init do add_to_sounds(self)
end
redef class Sound
redef fun load do
if is_loaded then return
- var nam = app.asset_manager.open_fd(self.name)
- if nam.is_java_null then
- self.error = new Error("Failed to get file descriptor for " + self.name)
- var retval_resources = app.default_soundpool.load_name_rid(app.resource_manager, app.native_activity, self.name)
- if retval_resources == -1 then
- self.error = new Error("Failed to load" + self.name)
+ var retval_resources = app.default_soundpool.load_name_rid(app.resource_manager, app.native_activity, self.name.strip_extension)
+ if retval_resources == -1 then
+ self.error = new Error("failed to load" + self.name)
+ var nam = app.asset_manager.open_fd(self.name)
+ if nam.is_java_null then
+ self.error = new Error("Failed to get file descriptor for " + self.name)
else
- self.soundpool_id = retval_resources
- self.soundpool = app.default_soundpool
- self.error = null
- self.soundpool.error = null
+ var retval_assets = app.default_soundpool.load_asset_fd_rid(nam)
+ if retval_assets == -1 then
+ self.error = new Error("Failed to load" + self.name)
+ else
+ self.soundpool_id = retval_assets
+ self.soundpool = app.default_soundpool
+ self.error = null
+ self.soundpool.error = null
+ end
end
else
- var retval_assets = app.default_soundpool.load_asset_fd_rid(nam)
- if retval_assets == -1 then
- self.error = new Error("Failed to load" + self.name)
- else
- self.soundpool_id = retval_assets
- self.soundpool = app.default_soundpool
- self.error = null
- self.soundpool.error = null
- end
+ self.soundpool_id = retval_resources
+ self.soundpool = app.default_soundpool
+ self.error = null
+ self.soundpool.error = null
end
is_loaded = true
end
redef fun play do
- if self.error != null then return
if not is_loaded then load
+ if self.error != null then return
soundpool.play(soundpool_id)
end
redef fun pause do
if self.error != null or not self.is_loaded then return
soundpool.pause_stream(soundpool_id)
+ paused = true
end
redef fun resume do
if self.error != null or not self.is_loaded then return
soundpool.resume(soundpool_id)
+ paused = false
end
end
redef fun load do
if is_loaded then return
- var nam = app.asset_manager.open_fd(self.name)
- if nam.is_java_null then
- self.error = new Error("Failed to get file descriptor for " + self.name)
- var mp_sound_resources = app.default_mediaplayer.load_sound(app.resource_manager.raw_id(self.name), app.native_activity)
- if mp_sound_resources.error != null then
- self.error = mp_sound_resources.error
+ var mp_sound_resources = app.default_mediaplayer.load_sound(app.resource_manager.raw_id(self.name.strip_extension), app.native_activity)
+ if mp_sound_resources.error != null then
+ self.error = mp_sound_resources.error
+ var nam = app.asset_manager.open_fd(self.name)
+ if nam.is_java_null then
+ self.error = new Error("Failed to get file descriptor for " + self.name)
else
- self.media_player = app.default_mediaplayer
- self.error = null
- self.media_player.error = null
+ var mp_sound_assets = app.default_mediaplayer.data_source_fd(nam)
+ if mp_sound_assets.error != null then
+ self.error = mp_sound_assets.error
+ else
+ self.media_player = app.default_mediaplayer
+ self.error = null
+ self.media_player.error = null
+ end
end
else
- var mp_sound_assets = app.default_mediaplayer.data_source_fd(nam)
- if mp_sound_assets.error != null then
- self.error = mp_sound_assets.error
- else
- self.media_player = app.default_mediaplayer
- self.error = null
- self.media_player.error = null
- end
+ self.media_player = app.default_mediaplayer
+ self.error = null
+ self.media_player.error = null
end
is_loaded = true
end
redef fun play do
- if self.error != null then return
if not is_loaded then load
+ if self.error != null then return
media_player.start
end
redef fun pause do
if self.error != null or not self.is_loaded then return
media_player.pause
+ paused = true
end
redef fun resume do
if self.error != null or not self.is_loaded then return
play
+ paused = false
end
end
redef class App
- # Sounds handled by the application, when you load a sound, it's added to this list.
- # This array is used in `pause` and `resume`
- private var sounds = new Array[PlayableAudio]
# Returns the default MediaPlayer of the application.
# When you load a music, it goes in this MediaPlayer.
# Sets the stream of the app to STREAM_MUSIC.
# STREAM_MUSIC is the default stream used by android apps.
- private fun manage_audio_stream import native_activity, native_app_glue in "Java" `{
+ private fun manage_audio_stream import native_activity in "Java" `{
App_native_activity(self).setVolumeControlStream(AudioManager.STREAM_MUSIC);
`}
# Retrieves a music with a media player in the `assets` folder using its name.
# Used to play long sounds or musics, can't play multiple sounds simultaneously
- redef fun load_music(path: String): Music do
+ redef fun load_music(path) do
var fd = asset_manager.open_fd(path)
if not fd.is_java_null then
return add_to_sounds(default_mediaplayer.data_source_fd(fd)).as(Music)
return add_to_sounds(default_mediaplayer.load_sound(resource_manager.raw_id(music), self.native_activity)).as(Music)
end
- # Factorizes `sounds.add` to use it in `load_music`, `load_sound`, `load_music_from_res` and `load_sound_from_res`
- private fun add_to_sounds(sound: PlayableAudio): PlayableAudio do
- sounds.add(sound)
- return sound
- end
-
- redef fun pause do
+ redef fun on_pause do
super
- for s in sounds do s.pause
+ for s in sounds do
+ # Pausing sounds that are not already paused by user
+ # `s.paused` is set to false because `pause` set it to true
+ # and we want to know which sound has been paused by the user
+ # and which one has been paused by the app
+ if not s.paused then
+ s.pause
+ s.paused = false
+ end
+ end
audio_manager.abandon_audio_focus
end
- redef fun init_window do
+ redef fun on_create do
super
audio_manager.request_audio_focus
manage_audio_stream
end
- redef fun resume do
+ redef fun on_resume do
super
audio_manager.request_audio_focus
- for s in sounds do s.resume
+ for s in sounds do
+ # Resumes only the sounds paused by the App
+ if not s.paused then s.resume
+ end
+ end
+end
+
+redef class Sys
+
+ # Sounds handled by the application, when you load a sound, it's added to this list.
+ # This array is used in `pause` and `resume`
+ private var sounds = new Array[PlayableAudio]
+
+ # Factorizes `sounds.add` to use it in `load_music`, `load_sound`, `load_music_from_res` and `load_sound_from_res`
+ private fun add_to_sounds(sound: PlayableAudio): PlayableAudio do
+ sounds.add(sound)
+ return sound
end
end