I added sound effects to android game after I set up the rewarded advertises with admob on Unity. Here is my script for rewarded ads:
string adUnitId = "ca-app-pub-5920324855307233/4458481507";
RewardBasedVideoAd rewardBasedVideo = null;
void Start () {
managerScript = gameObject.GetComponent<GameManager>();
isCalled = false;
rewardBasedVideo = RewardBasedVideoAd.Instance;
}
public void adButton(){
isCalled = true;
AdRequest request = new AdRequest.Builder().Build();
rewardBasedVideo.OnAdRewarded += HandleRewardBasedVideoRewarded;
rewardBasedVideo.LoadAd(request, adUnitId);
}
void Update(){
if(isCalled == true){
adButton();
showAd();
}
}
public void showAd(){
if (rewardBasedVideo.IsLoaded()){
rewardBasedVideo.Show();
}
}
public void HandleRewardBasedVideoRewarded(object sender, Reward args){
isCalled = false;
managerScript.revival();
managerScript.Loading.SetActive(false);
rewardBasedVideo.OnAdRewarded -= HandleRewardBasedVideoRewarded;
}
Here is my script for sound effects (sound script):
public AudioClip Death;
public static bool toggled;
public static Sounds Instance;
public void DeathSound(){
if(toggled == true){
GetComponent<AudioSource>().PlayOneShot(Death);
}
}
public void SoundToggle(){
if(toggled == false){
toggled = true;
}else if(toggled == true){
toggled = false;
}
}
Finally how I call for a sound in another script:
Sounds sound;
GameObject soundManager;
public void Start(){
soundManager = GameObject.Find("Sound Manager");
sound = soundManager.GetComponent<Sounds>();
}
public void Death(){
sound.DeathSound();
}
The problem is for some reason when the boolean "toggled" is true in the Sound script, the HandleRewardBasedVideoRewarded method does not occur after the rewarded video advertise finishes. When sound is not toggled the method is called after the advertise and works fine. How is the sound effects being on affecting the method that happens after an advertise finishes? This problem is bothering me. Can someone help?
Update:
I tried disabling sound before the ad is loaded and then re enabling it after the ad. The problem still happens. Im not 100% certain but maybe the toggle bool has some effect, but I dont know how.
Either your code is not complete in the question or you made a mistake because GetComponent<AudioSource>().PlayOneShot(Death) is not being called anywhere in the script. You are calling DeathSound() from Death() but nothing is calling Death() to call DeathSound() which actually plays the sound. Take a closer look at your code. Call Death() function from somewhere and your sound should play.
EDIT:
Did not read your question well first time.
Before you call the showAd() function, Check if the audio is playing then stop playing it. Also change your Death from AudioClip to AudioSource. If possible don't use static in your code. It will introduce lots of other problems. If you want to share variables between scenes, you can do that with the PlayerPrefs class instead of using static variables.
public void showAd(){
if (Death.isPlaying)
{
Death.Stop();
}
if (rewardBasedVideo.IsLoaded()){
rewardBasedVideo.Show();
}
}
Related
hi I am using the sound class for my music so it will loop correctly (as advised here Libgdx: Lags in soundtrack looping) but when i close the app(it stills runs in the background) and open it again the sound starts to play over the previous sound, how can i avoid this?
This is my current music handler class
public class MusicHandler {
private Sound bgMusic;
public MusicHandler(Sound backgroundMusic){
bgMusic = backgroundMusic;
}
public void update(boolean play){
if(play){
bgMusic.loop();
}
else{
bgMusic.pause();
}
}
public void dispose(){
bgMusic.dispose();
}
}
Using the Vitamio media player, I do not see a constant for when the video actually starts rendering (as there has been for the normal android MediaPlayer since api 17). onPreparedListeners do not detect when the rendering physically starts, and, as a result, the black screen prior to the video starting is seemingly unavoidable.
Is there any way to detect when the video has actually started rendering in Vitamio?
Though it's a bit of a hack, I found that this way works wonders:
Create a boolean, defaulted to false, which determines whether or not buffering has completed for the first time.
Set an onInfoListener on your Vitamio VideoView.
Look for MediaPlayer.MEDIA_INFO_BUFFERING_END
If the boolean you created is false, then set it to true and wait, with a while loop, until yourVideoView.getCurrentPosition() != 0. Note that 0 may be too low -- sometimes getCurrentPosition will return a number higher than zero before it has started, but typically the returned value will be no higher than 1000 / (the fps of your video). I used 40.
Execute desired code (remove other views to make the VideoView visible, or add the VideoView to the layout).
In an OnCompletionListener, set the created boolean back to false.
public class AnimationCanvas extends VideoView{
public static AnimationCanvas animationCanvas;
private static boolean bufferedOnce = false;
public AnimationCanvas(Context context, AttributeSet attrs){
super(context, attrs);
animationCanvas = this;
getHolder().addCallback(this);
this.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (!bufferedOnce && what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
bufferedOnce = true;
while (getCurrentPosition() < 40) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
MainActivity.frameLayout.removeView(MainCanvas.mainCanvas);
return true;
}
return false;
}
});
this.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
bufferedOnce = false;
MainActivity.frameLayout.addView(MainCanvas.mainCanvas);
MainActivity.frameLayout.removeView(animationCanvas);
}
});
}
EDIT: Note that another option is to create a separate Runnable which does the waiting (while(vv.getCurrentPosition() < 40){}) and then, in the same Runnable, call runOnUIThread() to run a second runnable which alters / removes / adds views if needed (Views can only be touched by the thread in which they were created.) This way, there is no need for an onInfoListener -- just start the first Runnable in an onPreparedListener.
I am playing a music in Libgdx game. I wish to have a listener like this to play the music and do a specific process after that. But the program control never reaches the onCompletionListerner part.
private void playMusic() {
gameMusic = Gdx.audio.newMusic(Gdx.files.internal("data/bgm.mp3"));
gameMusic.play();
gameMusic.setOnCompletionListener(Music.OnCompletionListener(){
#Override
public void onCompletion(Music aMusic){
actionResolver.getLeaderboardGPGS();
}
}
);
Just add new before Music.OnCompletionListener() and it should work.
gameMusic.setOnCompletionListener(new Music.OnCompletionListener() {
#Override
public void onCompletion(Music aMusic) {
actionResolver.getLeaderboardGPGS();
}
});
Since you're passing an object (that implements OnCompletionListener), it has to be created with new as always.
I'm trying to use a MediaPlayer instance to play several audio files individually, in response to various sensor events.
I've found that when I load up the clip to be played right before calling MediaPlayer.start(), the audio clip will play fine. However, the application takes a major performance hit. Ideally, each audio clip should be loaded into the MediaPlayer immediately after the last one was played, leaving the MediaPlayer ready to start playback the instant the SensorEvent comes in.
I would expect this to be simple, but now that I made the change the audio just doesn't play. PlayAudioClip() is definitely still being called as expected, but something is going wrong after that. No errors are thrown, so I don't think the MediaPlayer is changing state, but could something be interfering with in the time that it's waiting to play?
Here is a simplified version of my code:
public class MainActivity extends Activity implements SensorEventListener {
private Random numGenerator;
private SensorManager manager;
private Sensor accelerometer;
private MediaPlayer mediaPlayer;
private Uri[] audioClips;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVariables();
prepareNextAudioClip(); //load first audioClip
}
#Override
public void onSensorChanged(SensorEvent event) {
if(conditionsRight()){
playAudioClip();
}
}
}
private void playAudioClip() {
mediaPlayer.start();
prepareNextAudioClip();
}
private void prepareNextAudioClip() {
try {
mediaPlayer.reset();
Uri audioClip = audioclips[(int) Math.floor(numGenerator.nextDouble()*audioClips.length)];
mediaPlayer.setDataSource(this, audioClip);
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
//Code below here isn't very important... handling setup and teardown
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
protected void onResume() {
super.onResume();
manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
}
private void initVariables() {
audioClips = new Uri[]{
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio1),
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio2),
Uri.parse("android.resource://com.example.afraidofflying/" + R.raw.audio3)
};
numGenerator = new Random();
mediaPlayer = new MediaPlayer();
manager = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if(null == accelerometer) finish();
}
protected void onPause() {
super.onPause();
manager.unregisterListener(this);
}
protected void onDestroy(){
mediaPlayer.release();
mediaPlayer = null;
}
}
PS: This has all been assuming I'll only use one instance of MediaPlayer but I'd also like input on if you think using multiple MediaPlayers and delegating each of them 1 audio clip would be advisable. My intuition is no because for my purposes I'd have to use 10-20 MediaPlayers, but it would be good to hear outside perspectives on it.
It's because you're resetting player right after starting playback.
private void playAudioClip() {
mediaPlayer.start(); //starting playback
prepareNextAudioClip(); //reset
}
if you want to play files in queue, than you can use one instance. But if you have to play several files simultaneusly, then you need to have several media player instances.
I think you have to look at subtle points regarding using Mediaplayer class
In your code you used:
initVariables();
prepareNextAudioClip(); //load first audioClip
initVariables() seems ok, Now lets see prepareNextAudioClip()
...
mediaPlayer.reset();
...
...
mediaPlayer.prepare();
The above code seems to corrupt Mediaplayer state machine. Please refer to http://developer.android.com/reference/android/media/MediaPlayer.html for details on using new, prepare,reset. It is better to write defensive MediaPlayer code using Errorlistener
Here's the problem, I want to change play button to pause button when the video stream starts playing in videoview but I don't know how to detect that event?
There is a great article about MediaPlayer in here - http://www.malmstein.com/blog/2014/08/09/how-to-use-a-textureview-to-display-a-video-with-custom-media-player-controls/
You can set infoListener on your VideoView
setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// Here the video starts
return true;
}
return false;
}
I ended up using VideoView.setOnPreparedListener. This was enough to cover my problem (play button drawable change to pause)
accepted answer here is not 100% accurate.
sometimes onprepared is call 3 seconds before first frame is being rendered. i suggest having a callback on that event (MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START)
mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) {
if (i == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START){
//first frame was bufered - do your stuff here
}
return false;
}
});
see media info documantaion for more callbacks of info/warning:
https://developer.android.com/reference/android/media/MediaPlayer.html#MEDIA_INFO_VIDEO_RENDERING_START
As far as I know, there is no event sent when video start playing in VideoView, but I can think of two options:
Create a version of VideoView by yourself, that sends event in those cases.
Use MediaController (which is default in VideoView)
If you want to follow option one - you can get the source of VideoView from here
isPlaying() can be called to test whether the MediaPlayer object is in the Started
Android MediaPlayer.isPlaying()
Another way to detect if videoview started is using videoView.getCurrentPosition(). getCurrentPosition() returns 0 if streaming not started.
protected Runnable playingCheck = new Runnable() {
public void run() {
while (true) {
if (vw.getCurrentPosition() != 0) {
// do what you want when playing started
break;
} else {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Then call:
new Thread(playingCheck).start();
Please try this :
final Handler h = new Handler();
h.postDelayed( new Runnable() {
public void run() {
if (videoView.getCurrentPosition() != 0) {
((ProgressBar) rootView.findViewById(R.id.pgStreaming)).setVisibility(View.GONE);
} else {
h.postDelayed(this, 250);
}
}
}, 250);