2012-06-30 36 views
1

我需要你的帮助。我试图用Androids AudioRecord类录制一些音频。 大部分时间这个工作得很好,但有时我得到一个SIGSEGV错误。录制音频时出现Android SIGSEGV错误

这里是同时录制的音频运行在一个单独的线程的代码:

private void startRecording() { 
    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 
      RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize); 

    recorder.startRecording(); 

    isRecording = true; 

    recordingThread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      writeAudioDataToFile(); 
     } 
    }, "AudioRecorder Thread"); 

    recordingThread.start(); 
} 

private void writeAudioDataToFile() { 
    byte data[] = new byte[bufferSize]; 
    String filename = getTempFilename(); 
    FileOutputStream os = null; 

    try { 
     os = new FileOutputStream(filename); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 

    int read = 0; 

    if (null != os) { 
     while (isRecording) { 
      read = recorder.read(data, 0, bufferSize); 

      if (AudioRecord.ERROR_INVALID_OPERATION != read) { 
       try { 
        os.write(data); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

     try { 
      os.close(); 
      os.flush(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

这里是我做的,当记录停止:

public void stopRecording() { 
    if (null != recorder) { 
     isRecording = false; 
     mRecordingBlocked = true; 
     mProgressDialog = RecorderDialog.newInstance(); 
     mProgressDialog.show(getFragmentManager(), "progressDialog"); 

     recorder.stop(); 
     recorder.release(); 

     recorder = null; 
     recordingThread = null; 

     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       String fileName = getFilename(); 
       copyWaveFile(getTempFilename(), fileName); 

       final TelephonyManager tm = (TelephonyManager) getActivity().getBaseContext().getSystemService(Context.TELEPHONY_SERVICE); 

       final String tmDevice, tmSerial, androidId; 
       tmDevice = "" + tm.getDeviceId(); 
       tmSerial = "" + tm.getSimSerialNumber(); 
       androidId = "" + android.provider.Settings.Secure.getString(getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); 

       UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode()); 
       String deviceId = deviceUuid.toString(); 
       App.db.insertEntry(deviceId, "Song title", fileName); 

       deleteTempFile(); 

       if (cbox_overdub.isChecked()) { 
        phrases.add(playAudio(fileName, true)); 
       } 
      } 
     }).start(); 
    } 

} 

private void copyWaveFile(String inFilename, String outFilename) { 
    FileInputStream in; 
    FileOutputStream out; 
    long totalAudioLen = 0; 
    long totalDataLen; 
    long longSampleRate = RECORDER_SAMPLERATE; 
    int channels = 2; 
    long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8; 

    try { 
     AppLog.logString("begin copyWaveFile try{}"); 
     File file = new File(inFilename); 
     in = new FileInputStream(file); 
     byte[] bytes = new byte[(int) file.length()]; 
     totalAudioLen = in.getChannel().size(); 
     totalDataLen = totalAudioLen + 36; 
     in.read(bytes); 
     in.close(); 

     out = new FileOutputStream(outFilename); 
     AppLog.logString("fos created"); 

     WriteWaveFileHeader(out, totalAudioLen, totalDataLen, 
       longSampleRate, channels, byteRate); 
     AppLog.logString("wave header written"); 

     int bufferLength = 1024; 
     publishProgress(0); 
     for (int i = 0; i < bytes.length; i += bufferLength) { 
      int progress = (int) ((i/(float) bytes.length) * 100); 
      publishProgress(progress); 
      if (bytes.length - i >= bufferLength) { 
       out.write(bytes, i, bufferLength); 
      } else { 
       out.write(bytes, i, bytes.length - i); 
      } 
     } 
     publishProgress(100); 
     AppLog.logString("progress complete"); 
     mRecordingBlocked = false; 
     mProgressDialog.dismiss(); 

     out.close(); 
     out.flush(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

看来以后出现此错误AudioRecord的实例已经停止。然后,我将临时temp_record.wav(SD卡)的内容复制到目的地(SD卡),并设置适当的波形文件标题。

我无法从以下调试信息中筛选出任何有用的信息。我希望有人有一个想法。谢谢!

这里的logcat的输出:

06-30 14:47:53.311: INFO/DEBUG(9381): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 
06-30 14:47:53.311: INFO/DEBUG(9381): Build fingerprint: 'otorola/RTGB/umts_milestone2:2.3.4/MILS2_U6_4.1-22/1317097892:user/release-keys' 
06-30 14:47:53.311: INFO/DEBUG(9381): pid: 9459, tid: 9525 >>> de.intermeco.android.apps.ilaugh <<< 
06-30 14:47:53.311: INFO/DEBUG(9381): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 4640e000 
06-30 14:47:53.311: INFO/DEBUG(9381): r0 4640e000 r1 00000000 r2 fffffd49 r3 4670da18 
06-30 14:47:53.311: INFO/DEBUG(9381): r4 4640e000 r5 4640e000 r6 fffffd49 r7 4670da18 
06-30 14:47:53.311: INFO/DEBUG(9381): r8 a904cf6a r9 0000000a 10 a904cfad fp a904cff0 
06-30 14:47:53.311: INFO/DEBUG(9381): ip a9060074 sp 4670d9e0 lr afd11704 pc afd113dc cpsr 20000050 
06-30 14:47:53.311: INFO/DEBUG(9381): d0 6472656767756265 d1 0037fff00020000c 
06-30 14:47:53.311: INFO/DEBUG(9381): d2 fff5ffd8fff5ffdb d3 ffe0ffd8ffd9ffd8 
06-30 14:47:53.311: INFO/DEBUG(9381): d4 fff2ffe50008ffd4 d5 ffdafffafff20000 
06-30 14:47:53.311: INFO/DEBUG(9381): d6 fff40003ffcf0003 d7 ffe30013ffe1fffd 
06-30 14:47:53.311: INFO/DEBUG(9381): d8 0000000000989680 d9 0000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d10 0000000000000000 d11 0000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d12 0000000000000000 d13 0000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d14 0000000000000000 d15 0000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d16 000000c24003a7e0 d17 4000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d18 3ff0000000000000 d19 0000000000000000 
06-30 14:47:53.311: INFO/DEBUG(9381): d20 b96377ce858a5d48 d21 3929f5135cb87c55 
06-30 14:47:53.311: INFO/DEBUG(9381): d22 3e21ee9ebdb4b1c4 d23 bda8fae9be8838d4 
06-30 14:47:53.319: INFO/DEBUG(9381): d24 0000000000000000 d25 0000000000000000 
06-30 14:47:53.319: INFO/DEBUG(9381): d26 0000000000000000 d27 ffffffffffffffff 
06-30 14:47:53.319: INFO/DEBUG(9381): d28 0100010001000100 d29 0100010001000100 
06-30 14:47:53.319: INFO/DEBUG(9381): d30 4086800000000000 d31 3ff0000000000000 
06-30 14:47:53.319: INFO/DEBUG(9381): scr 60000010 
06-30 14:47:53.483: INFO/DEBUG(9381): #00 pc 000113dc /system/lib/libc.so (pthread_mutex_lock) 
06-30 14:47:53.483: INFO/DEBUG(9381): #01 pc 00011700 /system/lib/libc.so (__pthread_cond_timedwait_relative) 
06-30 14:47:53.483: INFO/DEBUG(9381): #02 pc 0002d658 /system/lib/libmedia.so 
06-30 14:47:53.483: INFO/DEBUG(9381): code around pc: 
06-30 14:47:53.483: INFO/DEBUG(9381): afd113bc e3a02001 ebfffe82 e1a00005 e8bd87f0 
06-30 14:47:53.483: INFO/DEBUG(9381): afd113cc 00036024 e92d47f0 e2504000 0a000019 
06-30 14:47:53.483: INFO/DEBUG(9381): afd113dc e5946000 e5947000 e2166903 1a000017 
06-30 14:47:53.483: INFO/DEBUG(9381): afd113ec e5945000 e1a02004 e2055a02 e1a00005 
06-30 14:47:53.483: INFO/DEBUG(9381): afd113fc e3851001 ebffed7f e3500000 13856002 
06-30 14:47:53.483: INFO/DEBUG(9381): code around lr: 
06-30 14:47:53.483: INFO/DEBUG(9381): afd116e4 e1a03007 e1a02006 e2011001 e1a00004 
06-30 14:47:53.483: INFO/DEBUG(9381): afd116f4 ebfffd9a e1a04000 e1a00005 ebffff32 
06-30 14:47:53.483: INFO/DEBUG(9381): afd11704 e374006e 03a0006e 13a00000 e8bd81f0 
06-30 14:47:53.483: INFO/DEBUG(9381): afd11714 e304cdd3 e3043240 e92d4010 e341c062 
06-30 14:47:53.483: INFO/DEBUG(9381): afd11724 e1a0e002 e24dd008 e340300f e1a0200d 
06-30 14:47:53.483: INFO/DEBUG(9381): stack: 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a0 04000804 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a4 00000001 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a8 001c6b58 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9ac 00000262 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b0 0000ee6b 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b4 afd0fe34 /system/lib/libc.so 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b8 001edbb0 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9bc afd13bc1 /system/lib/libc.so 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c0 001b0470 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c4 001c6b58 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c8 00000241 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9cc 3b9aca00 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d0 00000000 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d4 00989680 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d8 df002777 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9dc e3a070ad 
06-30 14:47:53.483: INFO/DEBUG(9381): #00 4670d9e0 00000000 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9e4 4640e000 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9e8 fffffd49 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9ec 4670da18 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f0 a904cf6a /system/lib/libmedia.so 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f4 0000000a 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f8 a904cfad /system/lib/libmedia.so 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9fc afd11704 /system/lib/libc.so 
06-30 14:47:53.483: INFO/DEBUG(9381): #01 4670da00 4640e000 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da04 4640e004 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da08 4670da98 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da0c 000000c8 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da10 a904cf6a /system/lib/libmedia.so 
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da14 a902d65b /system/lib/libmedia.so 
+0

嗨克里斯,我认为这是不可能的,以帮助这些信息。调试日志不显示任何提示。你能重现错误吗?你能提供任何代码失败吗?我有一种感觉,那就是某种异步问题。 –

+0

不时发生错误,但不能用特殊的“待办事项列表”重现。有时候,错误发生在第一条记录,有时候会有很多记录。我想你可能是对的,这是一个异步的问题,因为我正在使用一个单独的线程将音频写入文件。我会尝试在代码的这一部分看起来更深一层。 – Chris

+0

我加了一些相关的代码。 – Chris

回答

3

感谢您再次指出SIGSEV,因为我不知道它的意思,所以我多读了一点。现在我做:) 我同意CommonsWare,你应该通知制造商/ modder的固件。 但我也认为它不能帮助你进一步在有用的时间跨度。也许我们找到一种方法来修改代码,以避免再次引发错误。

通常你的代码看起来相当不错。我认为不完全安全和适当的是你停止录音机的方式。

  1. 而不是使用isRecording标志我会使用isCancelled标志。所以你记录while(!isCancelled)。当你想停止录音时,只需将isCancelled设置为true并调用recorder.stop()即可。
  2. 录制停止后,您可以在音频录音器线程的writeAudioDataToFile()之后立即调用您的逻辑以显示进度对话框并复制文件。我不会为这些东西使用额外的线程,因为我们仍然在录音机线程中,并且您的UI未被阻止。
  3. 何时调用recorder.release(),它释放内存......文档“释放本机AudioRecord资源。”我不确切地知道,如果这对问题有影响的话。在您提供的当前代码中,您可以调用recorder.release(),理论上记录器可以读取(不知道该类是否是线程安全的)。也许你也可以尝试在复制所有文件后调用它,即使我认为在记录器真正停止并且输出流关闭后应该没问题。

希望我可以帮助一点,你能找到一种方法。

0

一个SIGSEGV不应该从Java代码是可能的。除非这是你的JNI代码,否则这将表明固件存在缺陷。

如果您正在运行修改过的固件,请将此信息传递给固件模块。

如果您正在运行设备附带的原始固件,并且这只发生在一台设备上,您可以尝试联系设备制造商。

如果您在具有原始固件的多台设备上看到此情况,并且您可以创建一个重现错误的示例项目,请在the Android issue tracker上发布项目和堆栈跟踪,假设此问题尚未在此报告。

+0

你说得对。我正在使用改装的固件(Cyanogenmod 7)。如果我发现这对我的源代码没有任何问题,但是对于系统,我会按照您的设想进行操作。 – Chris

2

谢谢你的建议。 我重建了一段代码,现在它似乎工作。 至少我没有得到大约一天的错误(比以前更长:D)。

我改变了方法writeAudioDataToFile(),以便现在释放等等也在那里完成(在stopRecording()方法中将isRecording设置为false之后)。我也不创建第二个线程,但处理RecorderThread中的所有内容。

因此,这似乎为我现在的工作:

private void writeAudioDataToFile() { 
    byte data[] = new byte[bufferSize]; 
    String filename = getTempFilename(); 
    FileOutputStream os = null; 

    try { 
     os = new FileOutputStream(filename); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 

    int read = 0; 

    if (null != os) { 
     while (isRecording) { 
      read = recorder.read(data, 0, bufferSize); 

      if (AudioRecord.ERROR_INVALID_OPERATION != read) { 
       try { 
        os.write(data); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

     try { 
      os.close(); 
      os.flush(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     recorder.stop(); 
     recorder.release(); 
     recorder = null; 

     String fileName = getFilename(); 
     copyWaveFile(getTempFilename(), fileName); 

     final TelephonyManager tm = (TelephonyManager) getActivity().getBaseContext().getSystemService(Context.TELEPHONY_SERVICE); 

     final String tmDevice, tmSerial, androidId; 
     tmDevice = "" + tm.getDeviceId(); 
     tmSerial = "" + tm.getSimSerialNumber(); 
     androidId = "" + android.provider.Settings.Secure.getString(getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); 

     UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode()); 
     String deviceId = deviceUuid.toString(); 
     App.db.insertEntry(deviceId, "Song title", fileName); 

     deleteTempFile(); 

     if (cbox_overdub.isChecked()) { 
      phrases.add(playAudio(fileName, true)); 
     } 
    } 
} 

public void stopRecording() { 
    if (null != recorder) { 
     Toast.makeText(getActivity(), "Stop Recording", Toast.LENGTH_SHORT).show(); 
     ((ImageView) getActivity().findViewById(R.id.btnMic)).setImageDrawable(getActivity().getResources().getDrawable(R.drawable.btn_mic)); 
     isRecording = false; 
     mRecordingBlocked = true; 

     mProgressDialog = RecorderDialog.newInstance(); 
     mProgressDialog.show(getFragmentManager(), "progressDialog"); 
    } 
} 

private void publishProgress(int progress) { 
    ProgressDialog pd = ((ProgressDialog) mProgressDialog.getDialog()); 
    if (pd != null) pd.setProgress(progress); 
} 

谢谢你了!

+0

太棒了,现在看起来线程安全:)。大声笑我已经想提到最后一个帖子:D。你知道我们怎么称呼这个“if(null!= recorder){”?尤达条件:D –

+0

大声笑......同意 - 也许有点不寻常:D – Chris

0

的文档状态:

为了接收与这些 听众相关联的相应的回调,应用程序都需要创建MediaRecorder上运行默认(主UI线程与一个环线对象 已经有Looper运行)。

确保您在UI线程上创建了刻录机。也许还可以在UI线程上调用它的方法。

0

上述解决方案都不适用于我。相反,我增加了AudioRecord构造函数中的缓冲区。

根据参数和设备,最小buffersize建议介于1k和4k之间。看来我的算法在缓冲区满之前从缓冲区读取数据太慢,所以我得到了segv(说实话我只是猜测后果)。

将缓冲区增强为我需要AudioRecord数据两倍的值后,它就像魅力一样。

  bufferSize = AudioRecord.getMinBufferSize(sampleAudioBitRate, 
        AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 

      if (bufferSize < sampleSize * 2) 
       bufferSize = sampleSize * 2; 

      audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleAudioBitRate, 
        AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); 
      if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { 
       Log.w(TAG, "audioRecord not initialized"); 
       return; 
      }