contrib-drivers icon indicating copy to clipboard operation
contrib-drivers copied to clipboard

Speaker only works once

Open gustavotemple opened this issue 8 years ago • 9 comments

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;
            }
        }
    }
}

gustavotemple avatar Oct 22 '17 19:10 gustavotemple

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 avatar Oct 24 '17 17:10 Fleker

@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)

gustavotemple avatar Oct 24 '17 17:10 gustavotemple

So when you tried the sample, the speaker did stop and restart as expected?

Fleker avatar Oct 24 '17 21:10 Fleker

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.

gustavotemple avatar Oct 25 '17 15:10 gustavotemple

Maybe there's a threading issue

Fleker avatar Oct 25 '17 18:10 Fleker

@Fleker, do you mean in the Firebase ValueEventListener thread?

gustavotemple avatar Oct 25 '17 18:10 gustavotemple

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?

Fleker avatar Oct 26 '17 00:10 Fleker

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;
            }
        }
    }
}

gustavotemple avatar Oct 26 '17 13:10 gustavotemple

Can you play an MP3 file with this driver ??

prasaanth-selvakumar avatar Apr 11 '18 10:04 prasaanth-selvakumar