Speaker only works once
Hello @mangini,
I am using the last version of the speaker (0.3), it works very well when I interact with others hardware components, but, when I put inside a firebase callback, the method "stop" works only once.
Do you know why?
package com.example.androidthings.doorbell;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.things.contrib.driver.pwmspeaker.Speaker;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.io.IOException;
public class DoorbellActivity extends Activity {
private static final String TAG = DoorbellActivity.class.getSimpleName();
private static final String ALARM = "alarm";
private static final int FREQ = 7000;
private Speaker mSpeaker;
private DatabaseReference alarmRef;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Doorbell Activity created.");
try {
mSpeaker = new Speaker(BoardDefaults.getPwmPin());
mSpeaker.stop();
alarmRef = FirebaseDatabase.getInstance().getReference().child(ALARM);
alarmRef.addValueEventListener(alarmListener);
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
private final ValueEventListener alarmListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i(TAG, "alarmListener");
Boolean value = (Boolean) dataSnapshot.getValue();
try {
if (value) {
mSpeaker.play(FREQ);
} else {
mSpeaker.stop();
}
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError);
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mSpeaker != null) {
try {
mSpeaker.stop();
mSpeaker.close();
} catch (IOException e) {
Log.e(TAG, "Error closing speaker", e);
} finally {
mSpeaker = null;
}
}
}
}
Calling stop appears to disable the PWM but shouldn't completely prevent it from being inaccessible.
This may be a bug in the platform. Can you try a few other approaches and file a bug if your issue continues? This does appear to be unexpected behavior.
@Fleker,
I tried to do this approach (Handler.post) too:
https://github.com/androidthings/drivers-samples/blob/32f4ef79318afc922ba902da5524e709d16feb30/pwmspeaker/src/main/java/com/example/androidthings/driversamples/SpeakerActivity.java#L54
But the result was the same (the error happen just when I put inside a firebase callback)
So when you tried the sample, the speaker did stop and restart as expected?
Yes, because of this line:
https://github.com/androidthings/drivers-samples/blob/32f4ef79318afc922ba902da5524e709d16feb30/pwmspeaker/src/main/java/com/example/androidthings/driversamples/SpeakerActivity.java#L98
The speaker stop and restart by itself, there isn't something external controlling the flow.
Maybe there's a threading issue
@Fleker, do you mean in the Firebase ValueEventListener thread?
The sample uses a separate handler for playback events. Can you copy that design and see whether that allows the speaker to work as expected?
The same thing happen, the "stop" only works once:
package com.example.androidthings.doorbell;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import com.google.android.things.contrib.driver.pwmspeaker.Speaker;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.io.IOException;
public class DoorbellActivity extends Activity {
private static final String TAG = DoorbellActivity.class.getSimpleName();
private static final String ALARM = "alarm";
private static final int FREQ = 7000;
private boolean alarm;
private Speaker mSpeaker;
private HandlerThread mHandlerThread;
private Handler mHandler;
private DatabaseReference alarmRef;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Doorbell Activity created.");
try {
mSpeaker = new Speaker(BoardDefaults.getPwmPin());
mSpeaker.stop();
mHandlerThread = new HandlerThread("pwm-playback");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
alarmRef = FirebaseDatabase.getInstance().getReference().child(ALARM);
alarmRef.addValueEventListener(alarmListener);
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
private final Runnable mPlaybackRunnable = new Runnable() {
@Override
public void run() {
if (mSpeaker == null) {
return;
}
try {
if (alarm) {
mSpeaker.play(FREQ);
} else {
mSpeaker.stop();
}
} catch (IOException e) {
Log.e(TAG, "Error playing speaker", e);
}
}
};
private final ValueEventListener alarmListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i(TAG, "alarmListener");
alarm = (boolean) dataSnapshot.getValue();
mHandler.post(mPlaybackRunnable);
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled: " + databaseError);
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mHandler != null) {
mHandler.removeCallbacks(mPlaybackRunnable);
mHandlerThread.quitSafely();
}
if (mSpeaker != null) {
try {
mSpeaker.stop();
mSpeaker.close();
} catch (IOException e) {
Log.e(TAG, "Error closing speaker", e);
} finally {
mSpeaker = null;
}
}
}
}
Can you play an MP3 file with this driver ??