Failed stop, Android app with TarsosDSP - android

I want to implement an android app using TarsosDSP package on this link:
https://github.com/srubin/TarsosDSP/releases/tag/TarsosDSPAndroid-v3-MAD
I created two buttons for startRecording and stopRecording, my app does "start" but doesnn't "stop". My MainActivity is this:
public class MainActivity extends ActionBarActivity {
private Button start;
private Button stop;
MicrophoneAudioDispatcher audioDispatcher = new MicrophoneAudioDispatcher(44100, 2048, 1024);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setButtonHandlers();
start = (Button) findViewById(R.id.btStart);
stop = (Button) findViewById(R.id.btStop);
}
private void setButtonHandlers() {
((Button)findViewById(R.id.btStart)).setOnClickListener(btnClick);
((Button)findViewById(R.id.btStop)).setOnClickListener(btnClick);
}
private void startRecording() {
audioDispatcher.run();
}
private void stopRecording() {
audioDispatcher.stop();
}
private View.OnClickListener btnClick = new View.OnClickListener() {
public void onClick(View v) {
switch(v.getId()){
case R.id.btStart:{
startRecording();
break;
}
case R.id.btStop:{
stopRecording();
break;
}
}
};
};
}
The class "MicrophoneAudioDispatcher" is on this link:
https://github.com/srubin/TarsosDSP/blob/master/src/be/hogent/tarsos/dsp/MicrophoneAudioDispatcher.java
I don't understand this error. Can someone help me?
Thanks in advance.

You have to initial a thread for AudioDispatcher instead to call AudioDispatcher.run() directly.
dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050, 1024, 0);
dispatcher.addAudioProcessor(new PitchProcessor(PitchProcessor.PitchEstimationAlgorithm.FFT_YIN, 22050, 1024, new PitchDetectionHandler() {
#Override
public void handlePitch(PitchDetectionResult pitchDetectionResult,
AudioEvent audioEvent) {
final float pitchInHz = pitchDetectionResult.getPitch();
runOnUiThread(new Runnable() {
#Override
public void run() {
mFrequencyView.setText(String.valueOf(pitchInHz));
}
});
}
}));
new Thread(dispatcher, "Audio Dispatcher").start();
The thread will keep running until you call AudioDispatcher.stop(). It is important to avoid the thread remains on background.
#Override
protected void onPause() {
super.onPause();
dispatcher.stop();
}

First of all, the link you mentioned (TarsosDSPAndroid-v3-MAD) is a TarsosDSP fork that is compatible with Android. Since some time it isn't needed anymore, as described on official site:
the fork of TarsosDSP kindly provided by GitHub user srubin, created for a programming assignment at UC Berkley, is not needed any more.
And what relates to your main question, you shouldn't manually call run() of AudioDispatcher, it should be called from separate thread like mentioned in the link above, something like this:
new Thread(dispatcher,"Audio Dispatcher").start();

Related

Threading and parallelism in Android

I'm very new to Android development. Can anyone help me with this snippet, I don't know why it works perfectly although I'm updating my TextView from the worker thread.
When I say works perfectly, I mean the TextView shows the value count without any problem.
So, My question is - "Is it really possible to update the UI from background thread and if not, where I'm wrong"
public class MainActivity extends AppCompatActivity {
TextView textView ;
private int count;
Button btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textview);
btn = findViewById(R.id.startbtn);
btn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
listen();
}
});
}
public void listen(){
new Thread(new Runnable() {
#Override
public void run() {
long time = System.currentTimeMillis();
while(System.currentTimeMillis()<=time +10000) {
count++;
}
textView.setText(count+"");
}
}).start();
}
}
Use
runOnUiThread(new Runnable() {
#Override
public void run() {
// Add UI code here
}
});
All UI updates should be done on the main thread.

UI Hangs When While Loop is Placed Inside Runnable

I'm writing an app that will display the current download speed which will be updated every second. My Runnable class is able to update the UI with the value, but when I try to place it inside a loop so that it will continuously run and update the UI TextView every second, the app now hangs.
This is my MainActivity.java:
public class MainActivity extends Activity implements SpeedMeter.TaskRunnableSpeedMeterMethods{
private Thread mSpeedMeterThread;
private Handler mHandler;
private TextView downloadSpeedOutput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadSpeedOutput = (TextView) findViewById(R.id.speed);
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message inputMessage) {
SpeedMeter speedMeter = (SpeedMeter) inputMessage.obj;
downloadSpeedOutput.setText(Long.toString(speedMeter.getmDownloadSpeedKB()));
}
};
SpeedMeter speedMeter = new SpeedMeter(this);
speedMeter.run();
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
}
#Override
public void setSpeedMeterThread(Thread currentThread) {
mSpeedMeterThread = currentThread;
}
#Override
public void setInternetSpeed(SpeedMeter speedMeter) {
Message completeMessage = mHandler.obtainMessage(1, speedMeter);
completeMessage.sendToTarget();
}
}
And here's the other SpeedMeter.java:
public class SpeedMeter implements Runnable {
final TaskRunnableSpeedMeterMethods mMainActivity;
private long mDownloadSpeedKB;
public SpeedMeter(TaskRunnableSpeedMeterMethods mainActivity) {
mMainActivity = mainActivity;
}
#Override
public void run() {
mMainActivity.setSpeedMeterThread(Thread.currentThread());
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
// while(true) {
long rxBytesPrevious = TrafficStats.getTotalRxBytes();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long rxBytesCurrent = TrafficStats.getTotalRxBytes();
long downloadSpeed = rxBytesCurrent - rxBytesPrevious;
setmDownloadSpeedKB(downloadSpeed/1000);
mMainActivity.setInternetSpeed(this);
// }
}
public long getmDownloadSpeedKB() {
return mDownloadSpeedKB;
}
public void setmDownloadSpeedKB(long mDownloadSpeedKB) {
this.mDownloadSpeedKB = mDownloadSpeedKB;
}
interface TaskRunnableSpeedMeterMethods {
void setSpeedMeterThread(Thread currentThread);
void setInternetSpeed(SpeedMeter speedMeter);
}
}
Any help will be appreciated!
You didnt start your runnable as a new thread instead you called the run function like a normal function (so u do the while loop on ur UI thread which blocks it)
replace
speedMeter.run();<br />
SpeedMeter speedMeter = new SpeedMeter(this);
with
new Thread(new SpeedMeter(this)).start();
see https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html for more infos on how to start a Runnable :)
The ideal way to do this would be to create an AsyncTask that would post a message to your UI thread, after it complete the task in the doInBackground() call.
Standards
also the interface structure you are following does not make sense and does not follow good standards. Usually an interface is used as a callback, which is basically what you are doing. But the standard is to say onSomethingChangedA() or onSomethingChangedB() from OnSomethingChangedListener interface.
I think your loop is always true so app hangs its better to create a boolean and use while(mboolean) and put this in your loop
if(something){
mboolean=false;
}
you can also use CountDownTimer.
for example:
new CountDownTimer(miliseconds,1000)
//if you have download speed and download size you can find miliseconds
#Override
public void onTick(long l) {
//something you want to do every seconds
}
#Override
public void onFinish() {
//something you want to do on finish
}

Android: Pause and resume a thread within an activity

EDIT: I've found that what I'm describing below only occurs on my emulated device (Nexus 5, target api 19, 4.4.2 with Intel Atom (x86) cpu), but NOT on my physical device (HTC One)....
EDIT2: Edit1 was due to an IllegalStateException that I didnt catch. Added some code to check if the thread was already running before trying to start it. This combined with the accepted answer resolved my issue.
I have implemented an activty that starts a new thread in the activity's onCreate method, like this:
...
private boolean running;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
running = true;
new Thread(null, work, "myThread").start();
}
Runnable work = new Runnable() {
#Override
public void run() {
while (running) {
//Doing work
}
}
};
I'm "pausing" my thread with my activity's onPause method, like this:
#Override
protected void onPause() {
running = false;
super.onPause();
}
So I thought that resuming it would be just as easy...ยจ
#Override
protected void onResume(){
running = true;
super.onResume();
}
but my thread isn't resuming. Any ideas why? Thankful for any help.
Marcus
All of the answers i think have some issues about your running variable because you can not write and read a variable from two different Threads without synchronized block so i post my own answer:
package com.example.threadandtoast;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
public class MonitorObject{
public boolean running = true;
public String message = "";
public boolean mustBePost = true;
}
Thread t;
int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted
// when i pause, you can see it and track it in DDMS
Runnable work = new Runnable() {
boolean myRunning;
#Override
public void run() {
synchronized(mSync) {
myRunning = mSync.running;
}
while (myRunning) {
runOnUiThread(new Runnable() { // in order to update the UI (create Toast)
#Override // we must switch to main thread
public void run() {
// i want to read the message so i must use synchronized block
synchronized(mSync) {
// i use this variable to post a message just for one time because i am in an infinite loop
// if i do not set a limit on the toast i create it infinite times
if(mSync.mustBePost){
Toast.makeText(MainActivity.this, mSync.message, Toast.LENGTH_SHORT).show();
// the message post so i must set it to false
mSync.mustBePost = false;
// if i am going to pause set mSync.running to false so at the end of infinite loop
//of thread he reads it and leaves the loop
if(mSync.message.equals("Main Activity is going to pause")){
mSync.running=false;
}
}
}
}
});
synchronized(mSync) {
myRunning = mSync.running;
}
}
}
};
final MonitorObject mSync = new MonitorObject();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onPause() {
super.onPause();
synchronized(mSync) {
// mSync.running = false; you can not set it here because
// it is possible for the thread to read it and exit the loop before he posts your message
mSync.mustBePost=true;
mSync.message = "Main Activity is going to pause";
}
}
#Override
protected void onResume(){
super.onResume();
threadNameCounter++;
synchronized(mSync) {
mSync.running = true;
mSync.mustBePost=true;
mSync.message = "Main Activity is going to resume";
}
t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter));
t.start();
}
}
Or you can use this code:
public class MainActivity extends ActionBarActivity {
Thread t;
int threadNameCounter = 0; // i use this variable to make sure that old thread is deleted
// when i pause, you can see it in DDMS
String message = "";
boolean isPost = false;
Runnable work = new Runnable() {
#Override
public void run() {
while (true) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(!isPost){
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
isPost = true;
if( message.equals("Main Activity is going to pause")){
t.interrupt();
}
}
}
});
if(Thread.currentThread().isInterrupted()){
break;
}
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onPause() {
super.onPause();
message = "Main Activity is going to pause";
isPost = false;
}
#Override
protected void onResume(){
super.onResume();
message = "Main Activity is going to resume";
isPost = false;
threadNameCounter++;
t = new Thread(work,"My Name is " + String.valueOf(threadNameCounter));
t.start();
}
}
you can also use semaphore or wait-notify approach.
i put public String message = ""; and public boolean mustBePost = true; in to mSync object but it is
not necessary because only main thread have an access to them.
if you have any problem please ask.
The statement running = false; will stop execution of the Thread, instead of pausing it. Use two variables: One for stopping current Thread, and another for pausing and resuming the Thread, as follow:
boolean isThreadPause=false;
Runnable work = new Runnable() {
#Override
public void run() {
while (running) {
if (!isThreadPause) {
// Doing work
}
}
}
};
In the onPause event of the Activity, set isThreadPause to true, and in the onResume event, set isThreadPause to false.
This is because your Runnable object stops when the while loop stops. You could try this:
Runnable work = new Runnable() {
#Override
public void run() {
while () {
if(running){
//Doing work
}
}
}
};

Android: Simple how to stop mediaplayer after given time

I am trying to play an mp3 file (with an onClickListener) and stop after 2 seconds. I tried the code below but it is not working. Could anyone please help?
final MediaPlayer mpsound = MediaPlayer.create(this, R.raw.media_player_sound);
ImageView sound = (ImageView) findViewById(R.id.button);
sound.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mpsound.start();{
sleep(2000);
mpsound.stop();
}
}
});
Why are you calling stop() on mpfrog if you are playing audio with mpsound? You need to call the stop() function on the mpsound MediaPlayer. Also, you might want to add the #Override annotation to your onClick() method.
for the override...
sound.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mpsound.start();{
sleep(2000);
mpsound.stop();
}
}
});
for a timer.....
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg){
mpsound.stop();
}
};
//Task for timer to execute when time expires
class SleepTask extends TimerTask {
#Override
public void run(){
handler.sendEmptyMessage(0);
}
}
//then in some other function...
Timer timer = new Timer("timer",true);
timer.schedule(new SleepTask(),2000);
You have to wait 2 seconds in different thread, for this case use your own created thread and wait there and stop player, or you can use CountDownTimer - very simple solution.
You can find same question aggregated here and here
In eclipse you can use autocomplete (ctrl + space by default) to fill automatically all inmplemented methods and #Overrides will already be there.

stop watch problem in android

i creating for stopwatch with start,stop i use following code it started but not stop. please help me.
my code:
public class StopWatch2 extends Activity implements Runnable{
// text view influenced by the Thread
private TextView threadModifiedText;
int time=0;
Button b1,b2,b3;
/** Called when the activity is first created. */
Thread currentThread = new Thread(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stopwatch);
b1=(Button)findViewById(R.id.button1);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
threadModifiedText = (TextView) findViewById(R.id.textView1);
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.start();
}
});
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.stop();
}
});
}
//Method you must override to control what the Thread is doing
#Override
public void run(){
try {
while(true){
currentThread.sleep(1000, 0);
threadHandler.sendEmptyMessage(0);
}
// signaling things to the outside world goes like this
} catch (InterruptedException e) {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
time++;
threadModifiedText.setText(""+time);
}
};
}
I think You should use a class level variable boolean shouldRun = true ;
in your run() method while should be used like this way
while(shouldRun)
{
//implementation
}
and in your b2.onClickListener() change shouldRun = false;
Edit:
For suspend and resume you can change the value of shouldRun to shouldRun = true; in the listener for resume button. Remember that when you stop the updates you should reset the time also. and in suspend the time should be remain same.
I implemented stopwatch for rotational puzzles solving time measurements and I have approached it somewhat differently.
For time measurements I use Handler object that triggers after DISPLAY_UPDATE_TIMEOUT. It is time after which you update display about time elapsed.
To start counting I use:
mLastStartTimestamp = System.currentTimeMillis();
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
and to stop it
mRepetitiveTimeoutHandler.removeCallbacks(processWatchTimer);
mStartStopElapsed = System.currentTimeMillis() - mLastStartTimestamp ;
updateTimeDisplay();
On each trigger of the handler I do the following:
private Runnable processWatchTimer = new Runnable()
{
public void run()
{
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
updateTimeDisplay();
}
};

Categories

Resources