7

안녕하세요,
임 전화를 (모두 밖으로 및 incomming)를 기록하고 프로세스가 내 응용 프로그램의 종료 시점에서 (데이터를 기록 촉진합니다 안드로이드에 대한 해결책 작업 는 오디오 파일 데이터에 개최 수 없습니다 전화 메모리). 상태가 CALL_STATE_OFFHOOK이면 녹음 서비스를 시작하는 PhoneStateListener.LISTEN_CALL_STATE가있는 BroadcastReceiver를 구현했습니다. 그런 다음 서비스를 시작하면 전화 녹음을 시도하는 새 스레드가 시작되고 PhoneStateListener.LISTEN_CALL_STATE가있는 다른 BroadcastReceiver는 전화 상태가 TelephonyManager.CALL_STATE_IDLE로 변경되면 녹음을 중지하는 메서드를 호출합니다.통화 기록/처리 서비스! - 안드로이드

생성 된 오디오 파일이 비어 있습니다. 내 서비스의 recorder.stop() 메소드가 호출되면 예외가 발생합니다. 오류는 어디에 있습니까? 내가 더 잘할 수 있을까?

우선 (단독) 브로드 캐스트 리시버 :

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

    } 
} 

서비스 :

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

승인 :

<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" /> 

예외 출력 :

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) 
+0

의를 사용해보십시오 양쪽 (업 링크 및 다운 링크)에 대해 기록 된? – MAC

답변

4

내 삼성 갤럭시에 작은 수정과 코드를 테스트했습니다 S2. 예외없이 꽤 괜찮아. 서비스를 사용하여 통화가 성공적으로 녹음되었습니다. 내가 발견 한 한 가지 문제는 서비스가 두 번 시작되었다는 것입니다 (브로드 캐스트 수신기가 두 번 시작되었고 TelephonyManager.PhoneStateListner가 상태 OFFHOOK로 두 번 호출 됨).메소드 setAudioSource에서 VOICE_CALL에서 VOICE_UPLINK로 상수를 변경해야합니다. Java enum 정의와 C 헤더의 enum이 다른 것 같습니다. 전화는

+0

놀라운, 잘 작동합니다! 고마워요! 너무 나쁜 Ive 이미 공학 논문 주제 변경 :) –

1

android documentation은 start()가 start() 전에 호출되면이 예외가 throw됩니다.

stop() 메서드를 호출하기 전에 녹음 플래그가 설정되어 있는지 확인해야합니다. 아마도 이것은 당신의 실수를 제거 할 것입니다.

그러나 어떤 이유로 인해 데이터베이스 코드 때문에 start()가 호출되지 않고 이것이 실제 문제입니다. 내가 심비안 휴대폰 용으로 개발 된 응용 프로그램을 안드로이드 포트에 시도 할 때 나는 비슷한 요구 사항을 가지고

+0

recorder.start() 메서드에 도달 했으므로 빈 오디오 파일을 생성한다는 사실을 잊어 버렸습니다. 더 많은 부울 플래그 기록은 recorder.start() 이전의 그 위치에서만 true로 설정됩니다. 그래서이 방법이 가장 가능성이 높습니다. –

1

Pejter.

일부 연구 끝에 나는 오늘날 사용 가능한 대부분의 (어쩌면 모든 경우에도) 안드로이드 전화에서 불가능할 것이라는 슬픈 결론에 도달했습니다.

Android 1.6 이후로 필요한 API가 있음에도 불구하고 대부분의 Android 휴대 전화는 하드웨어 아키텍처 또는 펌웨어 구현으로 인해이 기능을 지원하지 않습니다. 기본적으로, 문제는 메인 폰 프로세서가베이스 밴드 오디오 스트림에 액세스하지 못한다는 것입니다. 일반적으로 로컬 마이크에 액세스 할 수 있으므로 일부 전화기에서는 로컬 사용자와 가능하면 원격 사용자의 희미한 신호가 이어 피스와 마이크 사이의 음향 결합을 통해 마이크에 도달하는 것이 가능합니다. 이것은 내 응용 프로그램의 요구 사항에 충분하지 않았기 때문에 여전히 Android 버전이 없습니다.

저는 여러분의 문제를 해결하지 못한다는 것을 알고 있습니다. (아마도 여러분이 얻는 예외와 관련이 없을 수도 있습니다.) 어쩌면 여러분의 시간 낭비를 막을 수 있습니다.다음에 좀 걸릴 수 있습니다 자세한 내용은

:

  1. http://code.google.com/p/android/issues/detail?id=2117

  2. https://groups.google.com/d/topic/android-developers/AbU85mtDgQw/discussion

+0

http://media.tumblr.com/tumblr_los755Kzxe1qf51e1.jpg
주제가 상황이 변경되면 알려주세요. 해결 방법을 찾지 못하면이 글에 기여할 것입니다. –

1

mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); 

대신 어이가 유 양쪽을 기록하는 작업입니다

mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);