So I'm trying to take multiple pictures at regular time intervals, however I get a "takePicture Failed" Exception after the first picture is previewed on the surfaceView.
Here's my takePictures() method which is called when a button is pressed:
public void takePictures() {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
camera = Camera.open();
if (camera != null) {
try {
camera.setPreviewDisplay(surfaceView.getHolder());
camera.startPreview();
camera.takePicture(null, null, new CustomPictureCallbcak(this, cacheDir, imageView, 3, 5000));
}
catch (Exception e) {
e.printStackTrace();
}
}
}
else {
Toast.makeText(this, "No camera found.", Toast.LENGTH_SHORT).show();
}
}
And here's the onPictureTaken() method of CustomPictureCallback :
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//get date info for file name
SimpleDateFormat sdf = new SimpleDateFormat("ddmmyyyyhhmmss");
String date = sdf.format(new Date());
String fileDir = createImageFileName(date);
//write the image to cache
writeImageToCache(fileDir, data);
//display file name in a toast notification
Toast.makeText(c, fileDir, Toast.LENGTH_SHORT).show();
//show picture on imageview
imageView.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
//retake images
this.camera = camera;
while (numOfImagesAlreadyTaken <= numOfImages) {
Thread thread = new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
numOfImagesAlreadyTaken++;
CustomPictureCallbcak.this.camera.stopPreview();
sleep(delay);
CustomPictureCallbcak.this.camera.takePicture(null, null, CustomPictureCallbcak.this);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
Toast.makeText(c, "Total images taken: " + numOfImagesAlreadyTaken, Toast.LENGTH_SHORT).show();
//release camera
camera.release();
camera = null;
}
As Aleksander Lidtke suggested, I created a single thread inside my takePictures() method and put a while loop inside it:
public void takePictures(final int numOfPictures, final int delay) {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Thread thread = new Thread() {
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
while (numOfPicturesAlreadyTaken <= numOfPictures) {
try {
camera = Camera.open();
camera.setPreviewDisplay(surfaceView.getHolder());
camera.startPreview();
camera.takePicture(null, null, new CustomPictureCallbcak(MainActivity.this, cacheDir, imageView));
numOfPicturesAlreadyTaken++;
sleep(delay);
}
catch (Exception e) {
e.printStackTrace();
Log.d("TEST", e.getMessage());
}
}
}
};
thread.start();
}
else {
Toast.makeText(this, "No camera found.", Toast.LENGTH_SHORT).show();
}
}
Related
I am using camera 2 api am using this code
private void createCameraPreviewSession() {
try {
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
mPreviewCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewCaptureRequestBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
if(mCameraDevice == null) {
return;
}
try {
mPreviewCaptureRequest = mPreviewCaptureRequestBuilder.build();
mCameraCaptureSession = session;
mCameraCaptureSession.setRepeatingRequest(
mPreviewCaptureRequest,
mSessionCaptureCallback,
mBackgroundHandler
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Toast.makeText(
getApplicationContext(),
"create camera session failed!",
Toast.LENGTH_SHORT
).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
this is the lockfocus methods, I noticed that it produce black image with zero size file after shutting the image
if(getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")){
photoButton.setEnabled(true);
mState = STATE__WAIT_LOCK;
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_START);
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);
mCameraCaptureSession.capture(mPreviewCaptureRequestBuilder.build(),
mSessionCaptureCallback, mBackgroundHandler);
this is my capturing an image
CaptureRequest.Builder captureStillBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureStillBuilder.addTarget(mImageReader.getSurface());
if (isAutoFocusSupported())
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_AUTO);
else
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureStillBuilder.set(CaptureRequest.JPEG_ORIENTATION,
ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
try {
mImageFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
mCaptureResult = result;
unLockFocus();
}
};
mCameraCaptureSession.stopRepeating();
mCameraCaptureSession.capture(
captureStillBuilder.build(), captureCallback, null
);
does anyone experience this and how did you fix this issue?
I am building android app which have to listen all the time (constantly) a voice and catch a key word like eg help. I am using now MediaRecorder to get an amplitude, then if is loud (eg 20000), I call pocketsphinx speechrecognizer. The problem is that when speechrecognizer caught (or not) the key word I can't jump back to MediaRecorder, the app is crashed. Of course my app must work in the background (24 h/day) so my implementation is in Service, so my MediaRecorder is in separate thread.
I know that pocketsphinx can check also the amplitude (a scream), but how to make it? And is pocketsphinx (get amplitude) better solution to trigger the speech recognizer? Below my class, I would be very appreciate for any help.
#Override
public IBinder onBind(Intent intent) {
return null;
}
private final class ServiceHandler extends Handler{
public ServiceHandler(Looper looper){
super(looper);
}
#Override
public void handleMessage(Message msg){
outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/record.3gp";
getVoiceRecord();
}
}
#Override
public void onCreate() {
thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
//change to START_STICKY
Log.d("tag", "on start command");
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
serviceHandler.sendMessage(msg);
return Service.START_NOT_STICKY;
}
private void getVoiceRecord() {
startRecorder();
start = System.currentTimeMillis();
Log.d("tag", "Time started at " + start);
while (true){
if(recorder!=null){
amplitude = recorder.getMaxAmplitude();
if(amplitude>20000){
Toast.makeText(getApplicationContext(), "Scream detected",
Toast.LENGTH_LONG).show();
Log.d("tag", "Scream detected " + 20 * Math.log10(amplitude) + " amplitude: " + amplitude);
stopRecorder();
Log.d("tag", "Finish recording");
getSpeech();
}
finish = System.currentTimeMillis();
if(finish-start>50000){
//loop = false;
stopRecorder();
Log.d("tag", "Finish recording");
if(recorder==null){
recorder.reset();
startRecorder();
start = System.currentTimeMillis();
}
}
}
}//end of while loop
}
private void getSpeech() {
try {
Assets assets = new Assets(ScreamService.this);
File assetDir = assets.syncAssets();
setupRecognizer(assetDir);
} catch (IOException e) {
//return e;
}
reset();
}
private void stopRecorder() {
try{
recorder.stop();
recorder.reset();
recorder.release();
recorder = null;
Log.d("tag", "Stop recording");
}catch (IllegalStateException e) {
e.printStackTrace();
Log.d("tag", "Media Recorder did not stop " + e);
try {
Thread.sleep(2000);
recorder.stop();
recorder.release();
recorder = null;
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}catch (RuntimeException e) {
e.printStackTrace();
Log.d("tag", "Media Recorder did not stop " + e);
}
}
private void startRecorder() {
Log.d("tag", "Start recording... ");
try {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(outputFile);
recorder.prepare();
recorder.start();
} catch (IOException e) {
e.printStackTrace();
Log.d("tag", "Media Recorder did not start IOExeption " + e);
} catch (IllegalStateException e) {
e.printStackTrace();
Log.d("tag", "Media Recorder did not start Ilegal State Trace" + e);
}
}
#Override
public void onDestroy() {
super.onDestroy();
recognizer.cancel();
recognizer.shutdown();
Toast.makeText(this, "Scream Service & recognizer Stopped.", Toast.LENGTH_SHORT).show();
}
#Override
public void onPartialResult(Hypothesis hypothesis) {
}
/**
* This callback is called when we stop the recognizer.
*/
#Override
public void onResult(Hypothesis hypothesis) {
if (hypothesis != null) {
String text = hypothesis.getHypstr();
//makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
Log.d("tag", "onResult " + text);
if(text.equals("help") || text.equals("help me")) {
recognizer.stop();
recognizer.cancel();
this.startService(new Intent(this, SendMessage.class));
getVoiceRecord();
}
}else {
Log.d("tag", "onResult is null");
}
}
#Override
public void onBeginningOfSpeech() {
//Log.d("tag", "onBeginningOfSpeech ");
}
#Override
public void onEndOfSpeech() {
counter++;
if(counter>5){
//recognizer.stop();
recognizer.cancel();
counter=0;
getVoiceRecord();
Log.d("tag", "Speech recognizer is killed");
}else {
//Log.d("tag", "onEndOfSpeech ");
reset();
}
}
private void reset() {
recognizer.stop();
recognizer.startListening("menu");
}
private void setupRecognizer(File assetsDir) throws IOException {
Log.d("tag", "default setup");
recognizer = defaultSetup()
.setAcousticModel(new File(assetsDir, "en-us-ptm"))
.setDictionary(new File(assetsDir, "cmudict-en-us.dict"))
// To disable logging of raw audio comment out this call (takes a lot of space on the device)
.setRawLogDir(assetsDir)
// Threshold to tune for keyphrase to balance between false alarms and misses
.setKeywordThreshold(1e-45f)
// Use context-independent phonetic search, context-dependent is too slow for mobile
.setBoolean("-allphone_ci", true)
.getRecognizer();
recognizer.addListener(this);
// Create grammar-based search for selection between demos
File menuGrammar = new File(assetsDir, "menu.gram");
recognizer.addGrammarSearch("menu", menuGrammar);
}
#Override
public void onError(Exception error) {
Log.d("tag", "error "+error.getMessage());
}
#Override
public void onTimeout() {
Log.d("tag", "onTimeout");
}
You can modify pocketsphinx sources to compute amplitude of recorded audio data before you pass it into recognizer. In SpeechRecognizer.java RecognizerThread class:
.........
while (!interrupted()
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
int nread = recorder.read(buffer, 0, buffer.length);
if (-1 == nread) {
throw new RuntimeException("error reading audio buffer");
} else if (nread > 0) {
// int max = 0;
// for (int i = 0; i < nread; i++) {
// max = Math.max(max, Math.abs(buffer[i]));
// }
// Log.e("!!!!!!!!", "Level is: " + max);
// You can decide to skip buffer here
decoder.processRaw(buffer, nread, false, false);
......
I am trying to do a code in an asynctask that takes a picture from the camera and send it to a server over UDP 100 times. However, the PictureCallback isn't called. Can someone please help me?
this is what i tried:
public class MainAsyncTask extends AsyncTask<Void, String, Void> {
protected static final String TAG = null;
public MainActivity mainAct;
public MainAsyncTask(MainActivity mainActivity)
{
super();
this.mainAct = mainActivity;
}
#Override
protected Void doInBackground(Void... params) {
DatagramSocket clientSocket = null;
InetAddress IPAddress = null;
try {
clientSocket = new DatagramSocket();
IPAddress = InetAddress.getByName("192.168.1.15");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte [] data;
DatagramPacket sendPacket;
try {
for (int i=0; i < 100; i++)
{
publishProgress("");
File file = new File(Environment.getExternalStorageDirectory()+ File.separator +"img.jpg");
while (!file.exists() || file.length() == 0);
Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+ File.separator +"img.jpg");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes);
data = bytes.toByteArray();
sendPacket = new DatagramPacket(data, data.length, IPAddress, 3107);
clientSocket.send(sendPacket);
file.delete();
}
clientSocket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
publishProgress(e.getMessage());
}
return null;
}
public static void takeSnapShots(MainActivity mainAct)
{
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera)
{
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(Environment.getExternalStorageDirectory()+File.separator+"img"+".jpg");
outStream.write(data);
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally
{
camera.stopPreview();
camera.release();
camera = null;
}
Log.d(TAG, "onPictureTaken - jpeg");
}
};
SurfaceView surface = new SurfaceView(mainAct.getApplicationContext());
Camera camera = Camera.open();
try {
camera.setPreviewDisplay(surface.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();
camera.takePicture(null,null,jpegCallback);
}
protected void onProgressUpdate(String... progress) {
takeSnapShots(mainAct);
}
#Override
protected void onPostExecute(Void result)
{
}
}
I don't think that AsyncTask is the most convenient tool to do the job.
You need a SurfaceView that is not simply created out of nowhere, but connected to the screen. You should initialize your camera only once, and you cannot call camera.takePicture() in a loop. You can call takePicture() from onPictureTaken() callback, but you should also remember that you cannot work with sockets from the UI thread. Luckily, you can follow the Google recommendations.
the recommended way to access the camera is to open Camera on a separate thread.
and
Callbacks will be invoked on the event thread open(int) was called from.
If you open camera in a new HandlerThread, as shown here, the picture callbacks will arrive on that beckground thread, which may be used also for networking.
Also, I recommend you to send directly the JPEG buffer that you receive from the camera. I believe that overhead of saving image to file, reading the file to bitmap, and compressing the latter to another JPEG may be way too much. To control the image size, choose appropriate picture size. Note that the size should be selected from the list of sizes supported by the specific camera.
public class CameraView extends SurfaceView
implements SurfaceHolder.Callback, Camera.PictureCallback {
private static final String TAG = "CameraView";
private Camera camera;
private HandlerThread cameraThread;
private Handler handler;
private boolean bCameraInitialized = false;
private int picturesToTake = 0;
public CameraView(Context context, AttributeSet attr) {
super(context, attr);
// install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
getHolder().addCallback(this);
}
#Override public void surfaceCreated(SurfaceHolder holder) {
cameraThread = new HandlerThread("CameraHandlerThread");
cameraThread.start();
handler = new Handler(cameraThread.getLooper());
hanlder.post(new Runnable() {
#Override public void run() {
openRearCamera();
bCameraInitialized = false;
}
});
}
#Override public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
Log.d(TAG, "Camera release");
camera.release();
camera = null;
bCameraInitialized = false;
}
}
// finalize the camera init now that we know preview size
#Override public void surfaceChanged(SurfaceHolder holder, int format, final int w, final int h) {
Log.w(TAG, "surfaceChanged(" + w + ", " + h + ")");
if (!bCameraInitialized) {
cameraSetup(w, h);
bCameraInitialized = true;
}
}
private void openRearCamera() {
if (camera != null) {
Log.e(TAG, "openRearCamera(): camera is not null");
return;
}
try {
camera = Camera.open(0);
Log.d(TAG, "Camera ready " + String.valueOf(camera));
}
catch (Throwable e) {
Log.e(TAG, "openRearCamera(): Camera.open() failed", e);
}
}
private void cameraSetup(int w, int h) {
if (camera == null) {
Log.e(TAG, "cameraSetup(): camera is null");
return;
}
Log.d(TAG, "Camera setup");
try {
Camera.Parameters params = camera.getParameters();
// still picture settings - be close to preview size
Camera.Size pictureSize = params.getSupportedPictureSizes()[0];
params.setPictureSize(pictureSize.width, optimalPictureSize.height);
camera.setParameters(params);
camera.setPreviewDisplay(getHolder());
camera.startPreview();
}
catch (Throwable e) {
Log.e(TAG, "Failed to finalize camera setup", e);
}
}
private void sendJpeg(byte[] data) {
DatagramSocket clientSocket = null;
InetAddress IPAddress = null;
try {
clientSocket = new DatagramSocket();
IPAddress = InetAddress.getByName("192.168.1.15");
}
catch (Exception e) {
Log.e(TAG, "failed to initialize client socket", e);
}
DatagramPacket sendPacket;
sendPacket = new DatagramPacket(data, data.length, IPAddress, 3107);
clientSocket.send(sendPacket);
Log.d(TAG, "sent image");
}
#Override public void onPictureTaken(byte[] data, Camera camera) {
sendJpeg(data);
camera.startPreview();
takePictures(picturesToTake-1);
}
public void takePictures(int n) {
if (n > 0) {
picturesToTake = n;
Log.d(TAG, "take " + n + " images");
camera.takePicture(null, null, this);
}
else {
Log.d(TAG, "all images captured");
}
}
}
The class above is a compilation from several projects, with error checking reduced to minimum for brevity. It may require some fixes to compile. You simply add a <CameraView /> to your activity layout, and call its takePictures when the user clicks a button or something.
Do you call to your AsyncTask like this? Just to create the AsyncTask is not enouge.
new MainAsyncTask(ActivityContext).execute();
You can't do this
camera.setPreviewDisplay(surface.getHolder());
From the docs:
http://developer.android.com/reference/android/hardware/Camera.html#setPreviewDisplay(android.view.SurfaceHolder)
"The SurfaceHolder must already contain a surface when this method is called. If you are using SurfaceView, you will need to register a SurfaceHolder.Callback with addCallback(SurfaceHolder.Callback) and wait for surfaceCreated(SurfaceHolder) before calling setPreviewDisplay() or starting preview."
You'd have to do something like this:
SurfaceHolder surfaceHolder = surface.getHolder();
surfaceHolder.addCallback(new Callback() {
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
camera.takePicture(null,null,jpegCallback);
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
}
);
I am looking to start a Service to keep music playing from my app when the user closes it. I have done a lot of searching around and all I am really looking for is a simple example that will allow me to start the service and music when the user presses a button. And when the user comes back to the app at some other point and presses another button then I want to bind to the service and stop the music playback. I have done a lot of searching around and I was hoping that someone could give me a clear explanation of how this all works and maybe even a code example.
to play song in Sd card using this snippet code:
public void playSong(int songIndex) {
// Play song
try {
mp.reset();
mp.setDataSource(songsListingSD.get(songIndex).get("songPath"));
mp.prepare();
mp.start();
// Displaying Song title
String songTitle = songsListingSD.get(songIndex).get("songTitle");
songTitleLabel.get().setText(songTitle);
// Changing Button Image to pause image
btnPlay.get().setImageResource(R.drawable.ic_media_pause);
// set Progress bar values
songProgressBar.get().setProgress(0);
songProgressBar.get().setMax(100);
// Updating progress bar
updateProgressBar();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
more example code for android mediaplayer run in service,you can make reference to this tutorial.
I have implemented this musi cservcie class which is working fine
public class MusicSrvice extends Service implements MediaPlayer.OnErrorListener,MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener{
public static final String ACTION_STOP="com.example.music4u.ACTION_STOP";
public static final String ACTION_PLAY="com.example.music4u.ACTION_PLAY";
public static final String ACTION_PAUSE="com.example.music4u.ACTION_PAUSE";
private final IBinder mBinder = new ServiceBinder();
MediaPlayer mPlayer;
String path="";
private int length = 0;
private boolean isPlaying = false;
private static final int NOTIFICATION_ID = 1;
public MusicSrvice() { }
public class ServiceBinder extends Binder {
MusicSrvice getService()
{
return MusicSrvice.this;
}
}
#Override
public IBinder onBind(Intent arg0){return mBinder;}
#Override
public void onCreate (){
super.onCreate();
AudioManager amanager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
int maxVolume = amanager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
amanager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, 0);
mPlayer=new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// mPlayer = MediaPlayer.create(this, R.raw.jingle);
mPlayer.setOnErrorListener(this);
if(mPlayer!= null)
{
mPlayer.setLooping(true);
//mPlayer.setVolume(100,100);
}
/* mPlayer.setOnErrorListener(new OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int
extra){
onError(mPlayer, what, extra);
return true;
}
});*/
}
#Override
public int onStartCommand (Intent intent, int flags, int startId)
{
if(intent.getExtras()!=null){
path =intent.getExtras().getString("path");
}
Context c = getApplicationContext();
if (intent != null) {
String action = intent.getAction();
if(action!=null){
// if (!TextUtils.isEmpty(action)) {
if (action.equals(ACTION_STOP)) {
pauseMusic(path);
}}
}
//}
/// path = intent.getStringExtra(EXTRA_FILENAME);
if (path == null) {
Log.w("logtag", "PlayService::onStart recording == null, returning");
//return;
}
Log.i("", "PlayService will play " + path);
try {
if(mPlayer!=null){
mPlayer.reset();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setDataSource(path);
mPlayer.setLooping(false);
mPlayer.prepare();
Log.d("logtag", "PlayService player.prepare() returned");
mPlayer.start();
CustomNotification();
isPlaying = true;
Log.i("logtag", "player.start() returned");}
else
{
Log.i("logtag", "mediaplayer null");
}
//updateNotification(true);
} catch (java.io.IOException e) {
Log.e("", "PlayService::onStart() IOException attempting player.prepare()\n");
Toast t = Toast.makeText(getApplicationContext(), "PlayService was unable to start playing recording: " + e, Toast.LENGTH_LONG);
t.show();
// return;
} catch (java.lang.Exception e) {
Toast t = Toast.makeText(getApplicationContext(), "MusicPlayer was unable to start playing recording: " + e, Toast.LENGTH_LONG);
t.show();
Log.e("", "PlayService::onStart caught unexpected exception", e);
}
return START_STICKY;
}
public void pauseMusic(String path)
{
if(mPlayer.isPlaying())
{
mPlayer.pause();
length=mPlayer.getCurrentPosition();
}
else{
mPlayer.reset();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mPlayer.setDataSource(path);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mPlayer.setLooping(false);
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("logtag", "PlayService player.prepare() returned");
mPlayer.start(); }
}
public void playNextSong(String path)
{
mPlayer.stop();
mPlayer.reset();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mPlayer.setDataSource(path);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mPlayer.setLooping(false);
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("logtag", "PlayService player.prepare() returned");
mPlayer.start();
}
public boolean isplaying(){
if(mPlayer!= null)
{
return mPlayer.isPlaying();}
return false;
}
public void seekto(int duration){
if(mPlayer!= null)
{
mPlayer.seekTo(duration);}
}
public int getCurrentPosition(){
if(mPlayer!= null)
{
return mPlayer.getCurrentPosition();}
return 0;
}
public int getDuration(){
if(mPlayer!= null)
{
return mPlayer.getDuration();}
return 0;
}
public void resumeMusic()
{
if(mPlayer.isPlaying()==false)
{
mPlayer.seekTo(length);
mPlayer.start();
}
}
public void stopMusic()
{
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
#Override
public void onDestroy ()
{
super.onDestroy();
if(mPlayer != null)
{
try{
mPlayer.stop();
mPlayer.release();
}finally {
mPlayer = null;
}
}
}
#Override
public void onLowMemory() {
// TODO Auto-generated method stub
super.onLowMemory();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String message = "Sorry your system has low memory";
Notification notification = new Notification(android.R.drawable.ic_dialog_alert, message, System.currentTimeMillis());
notificationManager.notify(1, notification);
stopSelf();
}
public boolean onError(MediaPlayer mp, int what, int extra) {
Toast.makeText(this, "music player failed", Toast.LENGTH_SHORT).show();
if(mPlayer != null)
{
try{
mPlayer.stop();
mPlayer.release();
}finally {
mPlayer = null;
}
}
return false;
}
#Override
public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
}
public void release(){
mPlayer.release();
}
Im currently developing a Music Player and due to the fact that each time the orientation changes on the Phone and the Activity is re-created, I wanted the music to be played by a service. This way, the user is able to leave the activity without the music stopping..
Now.. I have this weird issue I been unable to solve... Each time I created the Activity and Inflate the GUI, the service is started. But the Service always gets Bounded after the Activity has send the data... So the music never starts... I know this happens because if I add a Button to resend the data, the Music starts playing... Here is my code for the activity:
public class Player extends Activity{
private Cursor audioCursor;
public static int position=0;
private int count;
private boolean pause = false,
play= false,
stop= false,
next= false,
back= false,
playerActive= true,
dataChanged= false,
finished= false,
playing= true;
private String action;
Messenger mService = null;
boolean mIsBound;
final Messenger mMessenger = new Messenger(new IncomingHandler());
private ServiceConnection mConnection=null;
static final int MSG_SET_BOOLEAN_VALUE = 5;
static final int MSG_SET_STRING_VALUE = 4;
static final int MSG_SET_INT_VALUE = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
Bundle extras = getIntent().getExtras();
action=extras.getString("action");
if(!(Background.isRunning()))
startService(new Intent(Player.this, Background.class));
doBindService();
if(action.equals("play")){
position=extras.getInt("position");
String[] proj = {
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.IS_MUSIC,
MediaStore.Audio.Media.ALBUM_ID};
audioCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
MediaStore.Audio.Media.IS_MUSIC, null,
MediaStore.Audio.Media.TITLE + " ASC");
startManagingCursor(audioCursor);
count = audioCursor.getCount();
inflatePlayer();
/////////////////////THIS IS THE CODE THAT ACTS BEFORE THE SERVICE CONNECTION
sendBoolToService(playerActive, "playerActive");
sendIntToService(position);
sendStringToService(action);
}
}
//THIS CODE MUST BE FASTER, BUT THE CONNECTION TAKES TOO LONG
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
Toast.makeText(getApplicationContext(), "ATTACHED!", Toast.LENGTH_LONG).show();
try {
Message msg = Message.obtain(null, Background.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
Toast.makeText(getApplicationContext(), "Connection failed!", Toast.LENGTH_LONG).show();
}
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
Toast.makeText(getApplicationContext(), "UNATTACHED!", Toast.LENGTH_LONG).show();
}
};
private void inflatePlayer(){
//LOTS OF CODE FOR THE GUI, NOTHING TO DO WITH THE SERVICE... SO I OMITTED IT
}
#Override
protected void onStop(){
playerActive=false;
try {
doUnbindService();
} catch (Throwable t) {
}
if(!playing)
stopService(new Intent(Player.this, Background.class));
super.onStop();
}
#Override
protected void onDestroy(){
playerActive=false;
audioCursor.close();
try {
doUnbindService();
} catch (Throwable t) {
}
if(!playing)
stopService(new Intent(Player.this, Background.class));
super.onDestroy();
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_INT_VALUE:
String str = Integer.toString(msg.getData().getInt("int1"));
Toast.makeText(getApplicationContext(), "Int Message: " + str, Toast.LENGTH_LONG).show();
break;
case MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
break;
case MSG_SET_BOOLEAN_VALUE:
dataChanged=msg.getData().getBoolean("dataChanged");
finished=msg.getData().getBoolean("finished");
playing=msg.getData().getBoolean("playing");
if(!playing){
if(finished){
finished=false;
finish();
}
}
default:
super.handleMessage(msg);
}
}
}
private void sendIntToService(int intvaluetosend) {
if (mService != null) {
try {
Bundle b = new Bundle();
b.putInt("int1", intvaluetosend);
Message msg = Message.obtain(null, MSG_SET_INT_VALUE);
msg.setData(b);
mService.send(msg);
} catch (RemoteException e) {
}
}
}
private void sendStringToService(String stringtosend) {
if (mService != null) {
try {
Bundle b = new Bundle();
b.putString("str1", stringtosend);
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mService.send(msg);
} catch (RemoteException e) {
}
}
}
private void sendBoolToService(boolean booltosend, String name) {
if (mService != null) {
try {
Bundle b = new Bundle();
b.putBoolean(name, booltosend);
Message msg = Message.obtain(null, MSG_SET_BOOLEAN_VALUE);
msg.setData(b);
mService.send(msg);
} catch (RemoteException e) {
}
}
}
void doBindService() {
bindService(new Intent(this, Background.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
Toast.makeText(getApplicationContext(), "BOUND!", Toast.LENGTH_LONG).show();
}
void doUnbindService() {
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, Background.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
}
}
unbindService(mConnection);
mIsBound = false;
Toast.makeText(getApplicationContext(), "UNBOUND!", Toast.LENGTH_LONG).show();
}
}
}
The Service:
public class Background extends Service {
private NotificationManager nm;
private Cursor audioCursor;
MediaPlayer mp = new MediaPlayer();
private int count;
private boolean pause = false,
play= false,
stop= false,
next= false,
back= false,
playerActive= true,
dataChanged= false,
finished= false,
playing= false;
private int position;
private String action;
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;
static final int MSG_SET_BOOLEAN_VALUE = 5;
final Messenger mMessenger = new Messenger(new IncomingHandler());
private static boolean isRunning = false;
private static final String TAG = "Background";
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
position=msg.getData().getInt("int1");
break;
case MSG_SET_STRING_VALUE:
action=msg.getData().getString("str1");
if(action.equals("play")){
String[] proj = { MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.IS_MUSIC,
MediaStore.Audio.Media.TITLE};
audioCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
MediaStore.Audio.Media.IS_MUSIC, null,
MediaStore.Audio.Media.TITLE + " ASC");
count = audioCursor.getCount();
audioCursor.moveToPosition(position);
int column_index = audioCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
String path = audioCursor.getString(column_index);
startAudioPlayer(path);
playing=true;
if(playerActive)
sendBool(playing, "playing");
}else{
startAudioPlayer(action);
playing=true;
if(playerActive)
sendBool(playing, "playing");
}
action=null;
break;
case MSG_SET_BOOLEAN_VALUE:
pause=msg.getData().getBoolean("pause");
play=msg.getData().getBoolean("play");
stop=msg.getData().getBoolean("stop");
next=msg.getData().getBoolean("next");
back=msg.getData().getBoolean("back");
playerActive=msg.getData().getBoolean("playerActive");
if(pause){
mp.pause();
play=false;
playing=false;
sendBool(playing, "playing");
pause=false;
}
if(play){
pause=false;
mp.start();
playing=true;
sendBool(playing, "playing");
play=false;
}
default:
super.handleMessage(msg);
}
}
}
private void sendInt(int intvaluetosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
Bundle b = new Bundle();
b.putInt("int1", intvaluetosend);
Message msg = Message.obtain(null, MSG_SET_INT_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
mClients.remove(i);
Log.d(TAG, "Int not send..."+e.getMessage());
}
}
}
private void sendString(String stringtosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
Bundle b = new Bundle();
b.putString("str1", stringtosend);
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
mClients.remove(i);
Log.d(TAG, "String not send..." +e.getMessage());
}
}
}
private void sendBool(boolean booltosend, String name) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
Bundle b = new Bundle();
b.putBoolean(name, booltosend);
Message msg = Message.obtain(null, MSG_SET_BOOLEAN_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
mClients.remove(i);
Log.d(TAG, "Bool not send..." +e.getMessage());
}
}
}
#Override
public void onCreate() {
super.onCreate();
showNotification();
isRunning=true;
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
CharSequence text = getText(R.string.maintit);
Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Player.class), 0);
notification.setLatestEventInfo(this, getText(R.string.app_name), text, contentIntent);
nm.notify(R.string.app_name, notification);
}
#Override
public void onDestroy() {
//REMEMBER TO SAVE DATA!
if(mp.isPlaying())
mp.stop();
mp.release();
isRunning=false;
audioCursor.close();
nm.cancel(R.string.app_name);
super.onDestroy();
}
public static boolean isRunning()
{
return isRunning;
}
public void startAudioPlayer(String path){
try {
if(mp.isPlaying())
mp.reset();
mp.setDataSource(path);
} catch (IllegalArgumentException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IllegalStateException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
}
try {
mp.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
}
mp.start();
}
}
I hope someone can help, im getting very frustrated with this! Also, Im pretty sure there is no problem with the media player, I tested it before without the service... the cursors also work properly... Thing is... Do I need to necessarily call the service from the GUI for it to play the music?? What am I doing wrong?
EDIT: The website wont allow me to answer my own question so I post the solution here:
Ok, finally found a solution!
I read that the interaction with the service is only available once the onCreate method has finished... So, I added a Timer and filled it with the methods I needed to run:
new Timer().schedule(new TimerTask(){
public void run(){
sendBoolToService(playerActive, "playerActive");
sendIntToService(position);
sendStringToService(action);
}
}, 1000);
AND VOILA! It works! :D Hope its useful to someone!
What you need to do is to move the code in onCreate() which is dependent on the service being available to your onServiceConnected() method in your ServiceConnection implementation:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
Toast.makeText(getApplicationContext(), "ATTACHED!", Toast.LENGTH_LONG).show();
try {
Message msg = Message.obtain(null, Background.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
sendBoolToService(playerActive, "playerActive");
sendIntToService(position);
sendStringToService(action);
} catch (RemoteException e) {
Toast.makeText(getApplicationContext(), "Connection failed!", Toast.LENGTH_LONG).show();
}
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
Toast.makeText(getApplicationContext(), "UNATTACHED!", Toast.LENGTH_LONG).show();
}
};
I would also look at your service implementation as I cannot understand why you are calling mService = new Messenger(service). Your IBinder instance should provide you with a mechanism for obtaining a reference to your service instance.
In my case, my issue was using android:process attribute for <service> element within Android Manifest, which is supposed to improve performance, but in reallity, maybe it does once the service is running, but it takes a very long while to reach onCreate() (and so also to reach onBind()). For me it was taking minutes. Now Apps and services run smooth and as expected.
I now this a very old question, but showing your Manifest file here makes sense.
More info:
https://developer.android.com/guide/topics/manifest/service-element