Call recording/processing service! - Android
Hallo,
Im arbeiten an einer Lösung für Android, das für die Aufnahme Anrufe (sowohl aus-und eingehende) und Weiterverarbeitung der aufgezeichneten Daten (an das Ende meine Bewerbung, keine audio-Datei werden die Daten halten, die auf Telefon-Speicher). Ich habe BroadcastReceiver implementiert mit PhoneStateListener.LISTEN_CALL_STATE, dass eine Aufzeichnung startet service-wenn Staat CALL_STATE_OFFHOOK. Dann in Dienst ich einen neuen thread starten, der versucht, Aufzeichnung einen Anruf, und ein anderer BroadcastReceiver mit PhoneStateListener.LISTEN_CALL_STATE, dass eine Methode aufruft um die Aufnahme zu stoppen wenn das Telefon Status auf TelephonyManager.CALL_STATE_IDLE.
Die audio-Datei, die erstellt wird ist leer.
- Ausnahme wird ausgelöst, wenn der Rekorder.stop () - Methode in meinem Dienst aufgerufen wird. Wo ist ein Fehler? Was könnte ich besser machen?
Ersten (eigenständigen) 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;
}
}
Berechtigungen:
<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" />
Ausnahme Ausgabe:
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)
- hey, es funktioniert für u-Aufnahme beide Seiten ?
- was war das ACTION_FILTER für die broadcast-receiver im manifest?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Habe ich testen Sie Ihren code mit kleinen änderungen auf meinem Samsung Galaxy S2. Es woks ziemlich gut, ohne Ausnahmen. Anruf aufgezeichnet wurde erfolgreich an den Dienst.
Das einzige Problem, das ich fand ist, dass der Dienst gestartet wurde zweimal (Broadcast Receiver gestartet wurde zweimal und TelephonyManager.PhoneStateListner zweimal genannt mit Staat OFFHOOK)
Ich habe zu ändern Konstante in der Methode setAudioSource von VOICE_CALL zu VOICE_UPLINK. Es sieht aus wie die Java-enum-definition und enum in C-header unterschiedlich sind. Anruf aufgezeichnet wurde, die für beide Seiten (UPLINK und DOWNLINK)
Android Dokumentation besagt, dass diese Ausnahme wird geworfen, wenn die stop () - wird aufgerufen, bevor der start().
Ich würde hinzufügen stellen Sie sicher, dass Ihre Aufnahme-flag gesetzt ist, bevor der Aufruf der stop () - Methode. Dies wird wahrscheinlich loszuwerden Sie Ihre Fehler.
Jedoch aus irgendeinem Grund der start() nie aufgerufen wird, möglicherweise, weil Sie Ihre Datenbank-code, und das ist Ihr wirkliches Problem.
Pejter,
Ich hatte eine ähnliche Anforderung, wenn ich versuchte, Anschluss zu Android eine Anwendung, die ich entwickelt für Symbian-Handys.
Nach einigen Recherchen kam ich zu dem traurigen Schluss, dass dies wahrscheinlich nicht auf die meisten (vielleicht sogar auf allen) Android-Handys verfügbar heute.
Trotz der erforderlichen API seit Android 1.6, die meisten Android-Telefone unterstützen das nicht, entweder aufgrund von hardware-Architektur oder firmware-Implementierung. Im Grunde, das problem ist, dass die Haupt-Telefon-Prozessor haben nicht Zugang zu den Basisband-audio-stream. Es in der Regel nicht haben Zugang zu der lokalen Mikrofon, so dass bei einigen Telefonen ist es möglich, die zum aufzeichnen der lokalen Benutzer und möglicherweise ein schwaches signal von der remote-Benutzer erreicht, dass das Mikrofon durch die akustische Kopplung zwischen dem Hörer und dem Mikrofon. Dieses war nicht gut genug für meine Anwendung Anforderungen, so habe ich nicht noch eine Android-version.
Ich weiß, ich bin nicht die Lösung Ihres Problems (und es vielleicht auch nichts mit der Ausnahme, die Sie erhalten), aber vielleicht wird es sparen Sie Ihre Zeit verschwenden.
Weitere Informationen können Sie einen Blick auf die folgenden:
http://code.google.com/p/android/issues/detail?id=2117
https://groups.google.com/d/topic/android-developers/AbU85mtDgQw/discussion
Versuchen Sie es mit
statt