I am writing a game using Monogame for Android.
In my music manager, I have some code like this:
private void ChangeMusic()
{
if (!MediaPlayer.GameHasControl)
{
return;
}
// ... Play music
}
I am finding that MediaPlayer.GameHasControl is always returning true, regardless of what is happening on the phone. I have tried playing music in every music app I have on my phone (including Samsung Music player and Google Play Music), and then starting my app, and MediaPlayer.GameHasControl is still true.
Is this expected? Has anyone seen this work before?
Took a look at the MonoGame source, and GameHasControl just isn't even implemented on Android.
public static bool GameHasControl
{
get
{
#if IOS
...
#elif WINDOWS_PHONE
...
#else
// TODO: Fix me!
return true;
#endif
}
}
Anyone interested in the subject should check out this article:
http://developer.android.com/training/managing-audio/index.html
Related
I am making an internal calls application, when I call a number, the native android dialer opens and then instead of following the call in the native dialer, I follow the call in the app. The problem is that from the app it has no effect when I want to activate or deactivate the native dialer speaker. The native dialer is in the background, and the app is in the foreground, but for some reason when I try to activate the speaker from the app, to follow the call from here, it doesn't work. This only happens in versions of Android 11 and 12, however in versions of Android 8,9 and 10 it works perfectly, I can manipulate the speaker from the app, without going to the native dialer.
This is my code to activate and desactivate the speaker:
private fun enableSpeaker() {
audioManager?.let {
if (!it.isSpeakerphoneOn) {
audioManager!!.mode = AudioManager.MODE_IN_COMMUNICATION
audioManager!!.isSpeakerphoneOn = true
}
}
}
private fun disableSpeaker() {
audioManager?.let {
if (it.isSpeakerphoneOn) {
//audioManager.setMicrophoneMute(false)
audioManager!!.mode = AudioManager.MODE_NORMAL
audioManager!!.isSpeakerphoneOn = false
}
}
}
For Android 12 and above, use audioManager.setCommunicationDevice instead of audioManager.isSpeakerPhoneOn = true
More info here : https://developer.android.com/reference/kotlin/android/media/AudioManager#setCommunicationDevice(android.media.AudioDeviceInfo)
I'm using react-native-sound to playback looped audio files (exactly mp3 format). The problem is that there is a gap between the loops.
Here is my code example:
loadSound = (s) => {
let sound = new Sound(s, Sound.MAIN_BUNDLE, (error) => {
if (error) {
console.log('failed to load the sound', error);
return;
} else {
sound.setNumberOfLoops(-1);
}
});
return sound;
}
let sound = loadSound('campfire.mp3')
sound.play();
Is there any workaround how to make the loops to sound smooth?
Actually, this issue is open on github, but there is no solution yet...
There are gaps between loops because of the bug in Android MediaPlayer (which is used under the hood).
To fix the problem I've created the react-native-audio-exoplayer module, which has pretty same functionality as the react-native-sound, but it is based on the Android ExoPlayer. The API is a bit different but more robust and modern (have a look at the docs).
Later if I have time I'll do a pull request to introduce ExoPlayer in the react-native-sound.
But for now feel free to use react-native-audio-exoplayer as a good workaround (for now it's implemented only for Android).
Using the below version of the react-native-sounds fixed the gap issue.
https://github.com/Menardi/react-native-sound-gapless.git
From the README of the git repo:
Simply setting a track to loop on Android does not make it gapless,
instead leaving a short silence before restarting the track. However,
Android does actually support gapless playback between different
tracks. So, this fork essentially loads the same track twice, and gets
Android to handle the gapless playback for us. The downside is that
you will use more memory than before, because the track is loaded
twice. For most cases, this shouldn't matter, but you can profile your
app in Android Studio if you are concerned.
I have same issue with looping the sound. What I did to make it work is to call the same play sound function once sound play completed. I hope this will helps you.
function playBackground(){
bgSound = new Sound(bgMusic, (error, sound) => {
if (error) {
alert('error' + error.message);
return;
}
bgSound.play((success) => {
if(success)
{
// console.log("Play completed");
playBackground();
}
bgSound.release();
});
});
}
I am using cordova 6.4.0 with cordova-plugin-media for streaming radio-stations in an Android Application. Unfortunately there is a case, where the application is not responding properly anymore.
Let's say the user wants to stream a radiostation, but while the stream is loading, he wants to abort it (for example because the stream is down, or taking very long to load).
In this case I am not able to cancel the process!
media = new Media("http://direct.franceinfo.fr/live/franceinfo-midfi.mp3?ID=f9fbk29m84", mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus);
media.play();
Now I want to cancel the process of buffering the stream, but I'm not able to. The functions:
media.pause();
media.stop();
are throwing error messages in the ADB-log and are calling the mediaPlayer-onError callback.
D/AudioPlayer( 3362): AudioPlayer Error: pausePlaying() called during invalid state: 1
...
D/AudioPlayer( 3362): AudioPlayer Error: stopPlaying() called during invalid state: 1
The media.release() command stops the loading of the stream! However just releasing the stream without stopping it, causes other, rather big problems:
Most of the times the system reacts just very slow and hangs a few seconds, if you call media.release() on a media-object. But if you do this often, the system completly freezes. Meaning it does not accetp remote-control commands anymore.
The Adb-log is still working, but does not show any errors in this case. Only the POWER-Button is still working (it locks and unlocks the screen). The only way to recover from this screwed-up state, is to reboot the device.
How am I supposed to cancel a Media-stream if it is not playing, yet? Is this a bug in the plugin?
Attached is the code-snippet, that I use to handle the media-streaming-logic. Like described above... it basically works, but it slows down or even freezes device, if you call it multiple times.
function radioControl(action, media_src){
//media_src is a webradio-streamurl.
if(action == 'play') {
// Initial Play
if(media === null){
mediaCreateObject(media_src);
}
// If we get PLAY but on antoher station
else if(media.src != media_src){
mediaReleaseRessources();
mediaCreateObject(media_src);
}
//interrupt_timer = false;
if(media === null){
mediaCreateObject(media_src);
}
media.play();
}
else if (action === 'pause') {
//If we get "pause", but it didn't even start yet
if(media._duration == -1){
mediaReleaseRessources();
}
else{
media.pause();
}
}
}
function mediaCreateObject(media_src){
media = new Media(media_src, mediaPlayerSuccess, mediaPlayerFail, mediaPlayerStatus);
}
function mediaReleaseRessources(){
media.release();
}
I found out, that this is not a cordova issue, but an 8 year-old (!) android-bug, that was never fixed. See here:
https://code.google.com/p/android/issues/detail?id=959
MediaPlayer "crash" (deadlocks the calling thread) when resetting or releasing an unused MediaPlayer
Basically the problem is: If you try to "release" a media-object that is not playing (yet), it will deadlock the calling thread, which causes the freezing that I have mentioned in the question. Unfortunately they never fixed this bug, but just marked it as "obsolete". In Android 5.1.1. the bug apparently is still there. Maybe they fixed it in later versions.
I have made a rather ugly workaround for this problem, but it is working. Basically what I did is:
We save every media-object in a javaScript-object. If the user stops it, while it plays, we can just stop and delete the object. But if it is not playing, we leave this media-object in this javaScript-object media_objects = {};
Also we save the currently active_media stream in a variable.
If cordova calls the mediaPlayerStatusChange-callback we loop through the media_objects and check if the status of one of the "pending"-objects has now changed to "running". - Cordova justs calls the media-status-change-callback without any indictation what media-object exactly just changed the state. That is unfortunate, so we have to check if one of the pending-"obsolete" objects now started playing. If so, we can stop and release it. (If the object is actually playing, stop and release works like intended - only if it's not playing, it causes the crash)
function mediaPlayerStatusChange(status){
mediaReleaseRessources();
// handle status change....
// ......
}
function mediaReleaseRessources(){
for(var key in media_objects) {
// We can only stop-and release an object, if it is playing
// If an object started playing, the "_duration"-value is != -1
if(key !== active_media && media_objects[key]._duration != -1) {
media_objects[key].stop();
media_objects[key].release();
delete media_objects[key];
}
}
}
This solution works for me, however I am still interested in a better and cleaner way to handle multiple media-streams in cordova.
When my character crosses a finish line, I play a "win" sound. I have an AudioSource object to which I simply call PlayOneShot and pass it my AudioClip as:
public void PlayWon() {
if (GameData.Data.Settings.SoundsOn) {
AudioSource audio = GetComponent<AudioSource>();
audio.Stop();
audio.PlayOneShot(WinSound);
}
}
My settings for the AudioSource are this:
and the object where this is attached to is loaded in a Loader scene which is never destroyed. I ensure this by calling:
DontDestroyOnLoad(this);
on Awake.
My sound plays fine on iOS, iPhone and iPads. But when testing on my Samsung Galaxy Tab S, the sound plays and then pauses whilst the interstitial advert is displayed and then when dismissed, the sound carries on. I am using Chartboost and Admob and use the basic invoke:
if (Chartboost.hasInterstitial(CBLocation.LevelComplete)) {
Debug.Log("Showing CB Ad");
Chartboost.showInterstitial(CBLocation.LevelComplete);
}
else if (_admobInterstitial.IsLoaded()) {
Debug.Log("Showing Admob Ad");
_admobInterstitial.Show();
}
else {
Debug.Log("Neither cached, trying CB again");
Chartboost.cacheInterstitial(CBLocation.LevelComplete);
Chartboost.showInterstitial(CBLocation.LevelComplete);
}
Any ideas why my sounds cut out on this device? I don't have another Android device to test it on but I'm assuming it's an Android related problem. The sound cuts out on both Chartboost and Admob.
Thanks
You can use a coroutine for playing the sound. When the coroutine is finished, you can show ads.
private IEnumerator PlaySoundAndShowAd()
{
//play sound
yield return new WaitForSeconds(1.0f)
//show ads or do something.
}
Good day,
I'm currently building a website for myself (I'm a composer/producer), and I'm using Media Element for the main demo page. The page is under construction at the following link:
http://www.vincentrubinetti.com/listen.html
http://www.vincentrubinetti.com/listen.js
Below are what I think are the relevant functions and code:
function initPlayer()
{
player = new MediaElementPlayer('#listen_player',{
success: function (mediaElement, domObject)
{
mediaElement.addEventListener('play', resumeSong, false);
mediaElement.addEventListener('ended', playNextSong, false);
mediaElement.addEventListener('pause', pauseSong, false);
}
});
[omitted]
}
function setSong(element)
{
if (element != "")
{
unselectAllSongs();
document.getElementById(element).className = "listen_song_highlight";
[omitted]
var newSrc = document.querySelector("#"+element+" .listen_song_source").title;
player.pause();
player.setSrc(newSrc);
player.load();
}
}
function playSong(element)
{
document.querySelector("#"+element+" .listen_song_status").innerHTML = "playing";
player.play();
}
function playNextSong()
{
var newSong = document.querySelector(".listen_song_highlight + div.listen_song");
if (autoplay && newSong != null)
{
setSong(newSong.id);
playSong(newSong.id);
}
else
{
document.querySelector(".listen_song_highlight .listen_song_status").innerHTML = "stopped";
}
}
All the CSS end of this seems to be fine. It finds the next song on the list and sets the new source; I've verified it does this properly via alert and other debugging. However, on the Android default browser and the Dolphin browser, it seems to not be able to load the mp3 sometimes, and prematurely triggers the "ended" event to go to the next song. The result is that it appears to skip 2-3 songs after one is done playing. And it takes some finagling even to get it to play one, clicking on the song divs and the player play button. I can type in the same url that's in the html, and the browser will play/download it just fine, no problems accessing or loading it.
Here are the 3 mp3 files that repeat down the playlist, for reference. They are by me, but are placeholders for the real music.
NEW/music/creation.mp3
NEW/music/startup.mp3
NEW/music/win.mp3
Note that all of this works properly on Chrome, Firefox, IE8+, and Android Chrome (I haven't tested iPhone or iPad yet).
Is my diagnosis correct? Can anyone point me in the right direction? Is there any experience where MediaElement doesn't work properly on the Android default and Dolphin browsers?
I have the same problem in android (but with video...)
I was told that this is an issue with the file not being downloaded in time -- i.e. the browser starts the download, but since the file isn't downloaded it is 0:00 long, so the ended event is triggered.
If there is someway to make it so that the video / audio can be downloaded faster it solves the problem.
Strangely enough, if the device has good WiFi then this problem basically disappears.
See what John Dyer said about it here:
https://github.com/johndyer/mediaelement/issues/543