I am trying to create a metronome sound, however, what isn't working is the ability to mute it. I would like the ability to mute it without stopping the TimerTask since I want the rate to be consistent once it is unmuted. Here is my code:
public class Metronome {
private boolean mute;
private boolean playing = false;
private Timer mainTimer;
private SoundPool mSoundPool;
int mSoundID;
public Metronome(Context context) {
mSoundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
mSoundID = mSoundPool.load(context, R.raw.metronome, 1);
}
public void play(float pace, boolean mute) {
mainTimer = new Timer();
MyTimerTask mainTimerTask = new MyTimerTask();
mainTimer.schedule(mainTimerTask, 0, Math.round(pace * 1000));
this.mute = mute;
playing = true;
}
public void stop() {
mainTimer.cancel();
mainTimer.purge();
playing = false;
}
public boolean isPlaying() {
return playing;
}
public void setMute(boolean mute) {
this.mute = mute;
if (mute) {
mSoundPool.setVolume(mSoundID, 0, 0);
} else {
mSoundPool.setVolume(mSoundID, 1, 1);
}
}
private void playSound() {
if (!mute) {
mSoundPool.play(mSoundID, 1, 1, 1, 0, 1);
}
}
class MyTimerTask extends TimerTask {
#Override
public void run() {
playSound();
}
}
}
However, calling setMute(true) does not work. Does anyone know how I can mute my SoundPool?
Figured it out. It works when I use static methods and variables.
public class Metronome {
public static boolean mute = false;
public static boolean playing = false;
private static Timer mainTimer;
private static SoundPool soundPool;
private static int soundID;
public static void loadSound(Context context) {
soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
soundID = soundPool.load(context, R.raw.metronome, 1);
}
public static void play(float pace, boolean isMuted) {
mainTimer = new Timer();
MyTimerTask mainTimerTask = new MyTimerTask();
mainTimer.schedule(mainTimerTask, 0, Math.round(pace * 1000));
mute = isMuted;
playing = true;
}
public static void stop() {
mainTimer.cancel();
mainTimer.purge();
playing = false;
}
static class MyTimerTask extends TimerTask {
#Override
public void run() {
playSound();
}
private void playSound() {
if (!mute) {
soundPool.play(soundID, 1, 1, 1, 0, 1);
}
}
}
}
Related
I am trying to play a sound clip from a fragment, but the sound is not playing. I am not getting any errors in console and no crashing, just no sound is played. yes, my volume is up and nothing is muted. All relevant code is below
int soundId;
int currentSound;
SoundPool sp;
boolean pressed;
boolean loaded;
sp = new SoundPool(5, AudioManager.STREAM_MUSIC,0);
currentSound = R.raw.whatarethose;
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int i, int i1) {
loaded = true;
}
});
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(loaded) {
soundId = sp.load(getActivity(), currentSound, 1);
sp.play(soundId, 1, 1, 0, 0, 1);
}
}
});
You are loading the sound in the button click. try to load the sound after yu set the OnCompleteListener, before the click.
int soundId;
int currentSound;
SoundPool sp;
boolean pressed;
boolean loaded;
sp = new SoundPool(5, AudioManager.STREAM_MUSIC,0);
currentSound = R.raw.whatarethose;
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int i, int i1) {
loaded = true;
}
});
soundId = sp.load(getActivity(), currentSound, 1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(loaded) {
sp.play(soundId, 1, 1, 0, 0, 1);
}
}
});
I want to implement video player (ExoPlayer) in my android app. Player must play video (not big, ~2-3 minutes) from some url. On nexus 5 it works well, but on phone "Samsung GT-I8552 Galaxy Win" unfortunately it doesnt work. There are exception logs after compiling and starting app:
Internal runtime error.
java.lang.IllegalStateException
at android.media.MediaCodec.dequeueOutputBuffer(Native Method)
And this is my code:
private SurfaceView surfaceView;
private ExoPlayer player;
private MediaCodecVideoTrackRenderer videoRenderer;
private MediaCodecAudioTrackRenderer audioRenderer;
private CustomMediaController mediaController;
private String userAgent;
private final int RENDERER_COUNT = 8;
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int BUFFER_SEGMENT_COUNT = 256;
private static final int minBufferMs = 10000;
private static final int minRebufferMs = 5000;
private final String videoUrl_2 = "someurl...";
...
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
player = ExoPlayer.Factory.newInstance(RENDERER_COUNT, minBufferMs, minRebufferMs);
userAgent = Util.getUserAgent(this, "MyPlayer");
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DataSource dataSource = new DefaultUriDataSource(context, null, userAgent);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(Uri.parse(videoUrl_2), dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
videoRenderer = new MediaCodecVideoTrackRenderer(context,
sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT);
player.prepare(videoRenderer, audioRenderer);
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surfaceView.getHolder().getSurface());
player.setPlayWhenReady(true);
CustomMediaPlayerControl customMediaPlayerControl = new CustomMediaPlayerControl(player);
mediaController = new CustomMediaController(context);
mediaController.setMediaPlayer(customMediaPlayerControl);
mediaController.setAnchorView(surfaceView);
mediaController.setEnabled(true);
My class CustomMediaPlayerControl:
public class CustomMediaPlayerControl implements MediaController.MediaPlayerControl {
private ExoPlayer player;
public CustomMediaPlayerControl(ExoPlayer player) {
this.player = player;
}
#Override
public void start() {
player.setPlayWhenReady(true);
}
#Override
public void pause() {
player.setPlayWhenReady(false);
}
#Override
public int getDuration() {
return (int) player.getDuration();
}
#Override
public int getCurrentPosition() {
return (int) player.getCurrentPosition();
}
#Override
public void seekTo(int pos) {
player.seekTo(pos);
}
#Override
public boolean isPlaying() {
return player.getPlayWhenReady();
}
#Override
public int getBufferPercentage() {
return (int) player.getBufferedPercentage();
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return 0;
}
}
And my class CustomMediaController:
public class CustomMediaController extends MediaController {
private MediaController.MediaPlayerControl playerControl;
public CustomMediaController(Context context) {
super(context);
}
#Override
public void setMediaPlayer(MediaController.MediaPlayerControl playerControl) {
super.setMediaPlayer(playerControl);
this.playerControl = playerControl;
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (playerControl.canSeekForward() && keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
playerControl.seekTo(playerControl.getCurrentPosition() + 15000); // milliseconds
show();
}
return true;
} else if (playerControl.canSeekBackward() && keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
playerControl.seekTo(playerControl.getCurrentPosition() - 5000); // milliseconds
show();
}
return true;
}
return super.dispatchKeyEvent(event);
}
}
ExoPlayer have a minimal sdk level 16 requirement.
ExoPlayer’s standard audio and video components rely on Android’s MediaCodec API, which was released in Android 4.1 (API level 16). Hence they do not work on earlier versions of Android.
From: https://google.github.io/ExoPlayer/guide.html
i´m new to Android programming and I have a Question.
I have a Countdown that will count down from 60 to zero when i am touching the screen.
I want now that this Countdown will survive the Activity lifecycling even when onDestroy is called. So I need a Service for that.
Wenn the countdown is finished a notification will be send. But if the user want to open the App again before the countdown in the Service is finished, no notification should be sended and the service has to be stopped.
What is the best practice to implement those features? What is here the way to go?
Thank you very much for answers!
My approach is that I have a class with the countdown methods and the service
//Countdownclass
TimerClass.java
public class TimerClass {
private static final String TAG = "MyLog";
private static final long TIMERINTERVAL = 1000;
//Eigenschaften --------------------------------------------------------------------
private boolean isActiv = false;
private Paint paint;
private long timerTime;
private double actualTime;
private int x;
private int y;
private CountDownTimer countDownTimer;
private String timeString;
//Konstruktor --------------------------------------------------------------------
public TimerClass(int x, int y) {
this.x = x;
this.y = y;
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.YELLOW);
paint.setAntiAlias(true);
paint.setTextAlign(Align.RIGHT);
paint.setTextSize(70);
}
public TimerClass() {
}
//Methoden --------------------------------------------------------------------
public void draw(Canvas canvas) {
if(isActiv) {
canvas.drawText(timeString, x, y, paint);
}
}
public void createTimer(long timerTime) {
this.timerTime = timerTime;
countDownTimer = new CountDownTimer(timerTime, TIMERINTERVAL) {
#Override
public void onTick(long millisUntilFinished) {
actualTime = (double) millisUntilFinished / TIMERINTERVAL;
NumberFormat nf = new DecimalFormat("##.#");
nf.format(actualTime);
if(actualTime < 10) {
new DecimalFormat();
timeString = "0:0" + nf.format(actualTime - 1);
} else {
timeString = "0:" + nf.format(actualTime - 1);
}
}
#Override
public void onFinish() {
isActiv = false;
}
};
}
public void timerStart() {
countDownTimer.start();
isActiv = true;
}
public void timerStop() {
if(isActiv) {
countDownTimer.cancel();
}
isActiv = false;
}
public boolean isActiv() {
return isActiv;
}
public void setActiv(boolean isActiv) {
this.isActiv = isActiv;
}
public double getActualTime() {
return actualTime;
}
public void setActualTime(double actualTime) {
this.actualTime = actualTime;
}
And my Service:
public class TimerService extends Service {
//class with the countdowntimer
private TimerClass timerClass;
private long startTime;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
timerClass = new TimerClass();
startTime = (long) timerClass.getActualTime();
timerClass.createTimer(startTime);
}
#Override
public void onDestroy() {
timerClass.timerStop();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
timerClass.timerStart();
if(timerClass.getActualTime() <= 0) {
// send the notification
}
return super.onStartCommand(intent, flags, startId);
}
I wanted to start the Service in my mainActivies onPause method and stop it when onResume is called. But i´ve have tried it many times and failed.. so i have no code for my service in my activity.
( Sorry for my broken english :( )
I have the following Live Wallpaper:
public class GLWallpaperVideoDemo extends GLWallpaperService {
public static final String folder = "video";
public static final String TAG = "GLWVD";
public static String videoName="VIDEOWALL.avi";
//video variables
public int videoWidth,videoHeight;
public boolean videoWideScreen=false;
VideoRenderer renderer = null;
public GLWallpaperVideoDemo() {
super();
Log.e(TAG,"constructor()");
}
#Override
public void onCreate() {
Log.e(TAG,"onCreate()");
super.onCreate();
//transfer video to sdcard
Log.d(TAG,"transferring video asset to sdcard");
copyVideoToCard();
Log.d(TAG,"transferred");
//if videoName == blankVideo, then don't load anything
//TODO
NativeCalls.initVideo();
Log.d(TAG,"Opening video");
NativeCalls.loadVideo("file:/"+"sdcard/"
+GLWallpaperVideoDemo.videoName);
//set video dimensions (now that we opened the video)
videoWidth = NativeCalls.getVideoWidth();
videoHeight = NativeCalls.getVideoHeight();
videoWideScreen = ( videoWidth > videoHeight ) ? true : false;
}
private VideoEngine mEngine=null;
#Override
public Engine onCreateEngine() {
Log.e(TAG,"onCreateEngine()");
mEngine = new VideoEngine();
return mEngine;
}
class VideoEngine extends GLEngine {
VideoEngine() {
super();
Log.e(TAG,"VideoEngine VideoEngine()");
if(renderer==null)renderer = new VideoRenderer(GLWallpaperVideoDemo.this,
this);
setRenderer(renderer);
//setRenderMode(RENDERMODE_WHEN_DIRTY);
setRenderMode(RENDERMODE_CONTINUOUSLY);
}
VideoRenderer getRenderer() { return renderer; }
}
}
And this is the renderer:
public class VideoRenderer implements GLWallpaperService.Renderer {
static private String TAG="Renderer>>>>>>>>>>>>";
static boolean runOnce = false;
//MediaPlayer mediaPlayer = MediaPlayer.create(MyApp.getContext(), R.raw.gunfireusedforboardstage);
//screen variables
int screenWidth=50,screenHeight=50;
int drawWidth, drawHeight; //dimensions of fit-to-screen video
int paddingX, paddingY; //padding for fit-to-screen-video
//texture variables
int powWidth,powHeight;
//pointers
GLWallpaperVideoDemo mParent;
GLWallpaperVideoDemo.VideoEngine mParentEngine;
//lock
static public Object lock = new Object();
//fps
long fpsTime;
public int framecount;
public VideoRenderer() {
super();
Log.e(TAG,"Constructor()");
}
public VideoRenderer(GLWallpaperVideoDemo p,
GLWallpaperVideoDemo.VideoEngine e) {
super();
mParent = p;
mParentEngine = e;
Log.e(TAG,"constructor()");
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.e(TAG, "onSurfaceCreated()");
}
void process(int width, int height) {
setScreenDimensions( width, height );
Log.d(TAG,"Killing texture");
NativeCalls.closeOpenGL();
setTextureDimensions( screenWidth, screenHeight );
setFitToScreenDimensions( mParent.videoWidth,
mParent.videoHeight );
if ( !runOnce ) {
Log.e(TAG,"Preparing frame");
NativeCalls.prepareStorageFrame();
}
NativeCalls.initOpenGL();
runOnce = true;
}
//This gets called whenever you preview the wallpaper or set the
//wallpaper
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.e(TAG,"onSurfaceChanged()");
synchronized(lock) {
process(width, height);
}
}
public void onDrawFrame(GL10 gl) {
synchronized(lock) {
//Log.d(TAG,"Drawing ....");
NativeCalls.getFrame(); // from video
NativeCalls.drawFrame(); // using openGL
if(framecount>300)framecount=0;
framecount++;
//Log.e("framecount",Integer.toString(framecount));
if(framecount==117 || framecount==124 ||framecount==137 ||framecount==145||framecount==159||framecount==167)
{new Thread(new Runnable() {
public void run() {
MediaPlayer mp= MediaPlayer.create(MyApp.getContext(), R.raw.gunfireusedforboardstage);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
};
});
}
}).start();}
if (MyDebug.showFPS) {
final float fpsRate;
fpsRate = 1000f/((float) (SystemClock.uptimeMillis()
- fpsTime) );
fpsTime = SystemClock.uptimeMillis();
Log.d(TAG,
TAG+"drawFrame(): fps: "
+String.valueOf(fpsRate)
);
}
}
}
Now you see the variable framecount inside the renderer?
It gets reinitialized every time open the settings of the Wallpaper !!!
The result is that the renderer continues its work, but framecount is set again to 0,
the consequence is that the frames are not in sync with the MediaPlayer anymore.
SOLVED:
I made the variable static :-)
I am working on making a metronome that slowing speeds up as it runs and I need help with the sendMessageDelayed function.
First, I tried the Thread.sleep() But is was too laggy. I later I read there that it "Does not return until at least the specified number of milliseconds has elapsed".
Next, I read-about/tried using if statements with the SystemClock.elapsedRealtime() such as:
long nextbeep = SystemClock.elapsedRealtime() + waitms;
while(nextbeep > SystemClock.elapsedRealtime()){
//wait
}//end while
mpbeep.start();
but it made the CPU run too hard and the beep was uneven.
Edit: this is what worked for me:
bstart.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
textviewone.setText("start");
beepandwait();
}// void onClick
});// end b start listener
public void beepandwait() {
mSoundManager.playSound(soundnumber); //beep
mHandler.sendMessageDelayed(mHandler.obtainMessage(1), currentms); //wait
}//end beep and wait
private Handler mHandler = new Handler() {
public void handleMessage(Message m) {
beepandwait(); //and repeat
}//end handleMessage
};//Handler
Here is how to make sounds without lagging the system:
package com.bgryderclock.example;
import java.util.HashMap;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class SoundManager {
private SoundPool mSoundPool;
private HashMap<Integer, Integer> mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
public SoundManager()
{
}
public void initSounds(Context theContext) {
mContext = theContext;
mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap<Integer, Integer>();
mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
}
public void addSound(int Index,int SoundID)
{
mSoundPoolMap.put(Index, mSoundPool.load(mContext, SoundID, 1));
}
public void playSound(int index) {
int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f);
}
public void playLoopedSound(int index) {
int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, -1, 1f);
}
}