L'enregistrement d'appel/service de traitement! - Android
Bonjour,
Je travaille sur une solution pour Android qui va enregistrer les appels (à la fois et incomming) et permettra de traiter davantage de données enregistrées (à la fin de ma demande, pas d'audio-fichier de données sera retenu sur la mémoire du téléphone). J'ai mis en œuvre BroadcastReceiver avec PhoneStateListener.LISTEN_CALL_STATE qui démarre un service d'enregistrement si l'état est CALL_STATE_OFFHOOK. Alors en service, j'ai commencer un nouveau thread qui tente l'enregistrement d'un appel, et un autre BroadcastReceiver avec PhoneStateListener.LISTEN_CALL_STATE, qui appelle une méthode pour arrêter l'enregistrement si le téléphone de l'état est modifié à TelephonyManager.CALL_STATE_IDLE.
Le fichier audio créé est vide.
Exception est levée lors de l'enregistreur.méthode stop() dans mon service est appelé. Où est l'erreur? Que pouvais-je faire de mieux?
Première (autonome) BroadcastReceiver:
package com.piotr.callerrecogniser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class CallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
MyPhoneStateListener phoneListener = new MyPhoneStateListener(context);
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
class MyPhoneStateListener extends PhoneStateListener {
public static final String tag = "CallerRecogniser - CallReceiver";
private Context context;
MyPhoneStateListener(Context c) {
super();
context = c;
}
public static final int NOTIFICATION_ID_RECEIVED = 0x1221;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
SharedPreferences preferences = context.getSharedPreferences("CallReceiver", Context.MODE_PRIVATE);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
break;
//If call is answered, run recording service. Also pass "phone_number" variable with incomingNumber to shared prefs, so service will be able to access that via shared prefs.
case TelephonyManager.CALL_STATE_OFFHOOK: //The call is answered
String phone_number = preferences.getString("phone_number",null);
Intent serv = new Intent(context,
CallRecordingService.class);
serv.putExtra("number", phone_number);
context.startService(serv);
break;
//If phone is ringing, save phone_number. This is done because incomingNumber is not saved on CALL_STATE_OFFHOOK
case TelephonyManager.CALL_STATE_RINGING:
SharedPreferences.Editor editor = preferences.edit();
editor.putString("phone_number", incomingNumber);
editor.commit();
break;
}
}
}
}
Service:
package com.piotr.callerrecogniser;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class CallRecordingService extends Service implements Runnable {
CallerRecogniserDB database = new CallerRecogniserDB(this);
String phoneNumber;
MediaRecorder recorder;
private final Handler mHandler = new Handler();
private final BroadcastReceiver myCallStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
MyPhoneStateListener phoneListener = new MyPhoneStateListener(
context);
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener,
PhoneStateListener.LISTEN_CALL_STATE);
}
class MyPhoneStateListener extends PhoneStateListener {
private Context context;
MyPhoneStateListener(Context c) {
super();
context = c;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
if (recording) {
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification not;
not = new Notification(R.drawable.ic_launcher,
"Phone call being processed",
System.currentTimeMillis());
Intent notIntent = new Intent();
PendingIntent contentIntent = PendingIntent
.getActivity(context, 0, notIntent, 0);
not.setLatestEventInfo(context, "CallRecordingService",
"Notification from idle",
contentIntent);
mNotificationManager.notify(NOTIFICATION_ID_RECEIVED,
not);
stopRecording();
}
break;
}
}
}
};
private static boolean recording = false;
private String INCOMING_CALL_ACTION = "android.intent.action.PHONE_STATE";
@Override
public void onCreate() {
//TODO Auto-generated method stub
super.onCreate();
IntentFilter intentToReceiveFilter = new IntentFilter();
intentToReceiveFilter.addAction(INCOMING_CALL_ACTION);
this.registerReceiver(myCallStateReceiver, intentToReceiveFilter, null,
mHandler);
Thread aThread = new Thread(this);
aThread.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO Auto-generated method stub
super.onStart(intent, startId);
phoneNumber = intent.getExtras().getString("number");
return START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
//TODO Auto-generated method stub
return null;
}
public static final int NOTIFICATION_ID_RECEIVED = 0x1221;
@Override
public void run() {
Looper.myLooper();
Looper.prepare();
//TODO Auto-generated method stub
database.open();
String[] numbers = database.getData(CallerRecogniserDB.KEY_NUMBER);
int index = -1;
outside_for: for (int i = 0; i < numbers.length; i++) {
String[] splitted = numbers[i].split(",");
for (String nu : splitted) {
if (nu.equals(phoneNumber)) {
index = i;
break outside_for;
}
}
}
database.close();
if (index >= 0) { //Phone number is in a database and it's state==0 =>
//it has no data recorded
//Notification that call is recorded
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" + phoneNumber + ".3gp");
try {
recorder.prepare();
} catch (Exception e) {
e.printStackTrace();
}
recording = true;
recorder.start();
}
}
void stopRecording() {
//Then clean up with when it hangs up:
recorder.stop();
recorder.release();
recording=false;
}
}
Autorisations:
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Exception de sortie:
11-28 14:28:44.385: E/MediaRecorder(22438): stop called in an invalid state: 8
11-28 14:28:44.400: D/AndroidRuntime(22438): Shutting down VM
11-28 14:28:44.425: W/dalvikvm(22438): threadid=1: thread exiting with uncaught exception (group=0x4001e578)
11-28 14:28:44.435: E/AndroidRuntime(22438): FATAL EXCEPTION: main
11-28 14:28:44.435: E/AndroidRuntime(22438): java.lang.IllegalStateException
11-28 14:28:44.435: E/AndroidRuntime(22438): at android.media.MediaRecorder.stop(Native Method)
11-28 14:28:44.435: E/AndroidRuntime(22438): at com.piotr.callerrecogniser.CallRecordingService.stopRecording(CallRecordingService.java:159)
11-28 14:28:44.435: E/AndroidRuntime(22438): at com.piotr.callerrecogniser.CallRecordingService$1$MyPhoneStateListener.onCallStateChanged(CallRecordingService.java:65)
11-28 14:28:44.435: E/AndroidRuntime(22438): at android.telephony.PhoneStateListener$2.handleMessage(PhoneStateListener.java:369)
11-28 14:28:44.435: E/AndroidRuntime(22438): at android.os.Handler.dispatchMessage(Handler.java:99)
11-28 14:28:44.435: E/AndroidRuntime(22438): at android.os.Looper.loop(Looper.java:123)
11-28 14:28:44.435: E/AndroidRuntime(22438): at android.app.ActivityThread.main(ActivityThread.java:3691)
11-28 14:28:44.435: E/AndroidRuntime(22438): at java.lang.reflect.Method.invokeNative(Native Method)
11-28 14:28:44.435: E/AndroidRuntime(22438): at java.lang.reflect.Method.invoke(Method.java:507)
11-28 14:28:44.435: E/AndroidRuntime(22438): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
11-28 14:28:44.435: E/AndroidRuntime(22438): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
11-28 14:28:44.435: E/AndroidRuntime(22438): at dalvik.system.NativeStart.main(Native Method)
quel a été le ACTION_FILTER pour le récepteur de radiodiffusion dans le manifeste?
OriginalL'auteur Piotr Sobecki | 2011-11-28
Vous devez vous connecter pour publier un commentaire.
J'ai tester votre code avec de petites modifications sur mon Samsung Galaxy S2. Il woks assez bonne, sans exceptions. Appel a été enregistré avec succès en utilisant le service.
Le seul problème que j'ai trouvé est que le service a commencé à deux reprises (Récepteur de Radiodiffusion a été commencé deux fois et TelephonyManager.PhoneStateListner appelé deux fois avec l'état DÉCROCHÉ:)
Je dois changer constante dans la méthode setAudioSource de VOICE_CALL à VOICE_UPLINK. Il ressemble à Java enum définition et enum en C d'en-tête sont différents. Appel a été enregistré pour les deux côtés (MONTANTE et DESCENDANTE)
OriginalL'auteur Eugene
Android la documentation précise que cette exception sera levée si stop() est appelée avant que des start().
Je voudrais ajouter un assurez-vous que votre enregistrement indicateur est défini avant d'appeler la méthode stop (). Ce sera probablement se débarrasser de l'erreur.
Cependant, pour quelque raison start() n'est jamais appelée, peut-être parce que de votre code de base de données, et qui est votre véritable problème.
OriginalL'auteur JeffS
Pejter,
J'ai eu une demande similaire quand j'ai essayé de port pour Android une application que j'ai développé pour les téléphones Symbian.
Après quelques recherches je suis arrivé à la triste conclusion que c'est probablement impossible sur la plupart (peut-être même sur tous) les téléphones Android disponible aujourd'hui.
Malgré le fait que l'API nécessaires depuis Android 1.6, la plupart des téléphones Android ne prennent pas en charge ce soit en raison de l'architecture du matériel ou du firmware de mise en œuvre. Fondamentalement, le problème est que le numéro de téléphone principal du processeur n'a pas accès à la bande de base flux audio. Habituellement, il n'ont accès aux locaux de microphone, ainsi, sur certains téléphones, il est possible d'enregistrer l'utilisateur local et éventuellement un faible signal de l'utilisateur distant qui atteint le microphone à travers le couplage acoustique entre l'écouteur et le micro. Ce n'était pas assez bon pour mes conditions de l'application, donc je n'ai pas encore une version d'Android.
Je sais que je ne suis pas la résolution de votre problème (et peut-être même sans rapport avec l'exception que vous l'obtenir), mais peut-être cela vous évitera de perdre votre temps.
Pour plus d'informations, vous pouvez prendre un coup d'oeil à l'adresse suivante:
http://code.google.com/p/android/issues/detail?id=2117
https://groups.google.com/d/topic/android-developers/AbU85mtDgQw/discussion
OriginalL'auteur Lior Hass
Essayez d'utiliser
au lieu de
OriginalL'auteur user2529014