Ошибка Android SIGSEGV при записи звука

1

Мне нужна твоя помощь. Я пытаюсь записать некоторый звук с помощью класса Androids AudioRecord. В большинстве случаев это работает очень хорошо, но иногда я получаю ошибку 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
    Ошибка возникает время от времени, но не воспроизводится специальным «списком задач». Иногда ошибка возникает при первой записи, иногда много записей позже. Я думаю, вы, возможно, правы, что это асинхронная проблема, потому что я использую отдельный поток записи звука в файл. Я попытаюсь взглянуть немного глубже на эту часть кода.
Показать ещё 1 комментарий
Теги:
audio
segmentation-fault
sigsegv

5 ответов

3
Лучший ответ

Спасибо, что снова указал на SIGSEV, я немного прочитал его, потому что я не знал его значения. Теперь я делаю:) Я согласен с CommonsWare, что вы должны сообщить изготовителю/модему прошивки. Но я также думаю, что это не поможет вам в течение полезного промежутка времени. Возможно, мы найдем способ изменить ваш код таким образом, чтобы больше не вызывать ошибку.

Как правило, ваш код выглядит неплохо. То, что я думаю, не полностью безопасно и правильно, так это то, как вы останавливаете рекордер.

  • Вместо того, чтобы использовать флаг isRecording, я бы использовал флаг isCancelled. Таким образом, вы записываете пока (! IsCancelled). И когда вы хотите остановить запись, вы просто установите isCancelled в true и вызовите recorder.stop().
  • После остановки записи вы можете позвонить сразу после writeAudioDataToFile() в потоке аудиозаписей, свою логику для отображения диалогового окна выполнения и для копирования файла. Я бы не использовал дополнительный поток для этих вещей, так как мы все еще в потоке аудиозаписей, и ваш пользовательский интерфейс не заблокирован.
  • Когда вызывать recorder.release(), он освобождает память... Документы "Освобождает исходные ресурсы AudioRecord". Я точно не знаю, может ли это повлиять на проблему. В текущем коде, который вы указали, вы вызываете recorder.release(), в то время как теоретически записывающее устройство может читать (не зная, является ли класс потокобезопасным). Возможно, вы также можете попытаться вызвать его после того, как скопировали все свои файлы, даже если я думаю, что все должно быть хорошо после того, как рекордер действительно остановился и ваш выходной поток будет закрыт.

Надеюсь, я смогу немного помочь, и вы сможете найти способ.

2

Спасибо за ваши предложения. Я немного перестраиваю код, и теперь он работает. По крайней мере, я не получил ошибку примерно за один день (дольше, чем раньше: D).

Я изменил метод writeAudioDataToFile(), так что теперь это освобождение и т.д. тоже (после isRecording установлено значение false в методе stopRecording()). Я также не создаю второй Thread больше, но обрабатываю все вещи в 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. Вы знаете, как мы называем это "если (ноль! = рекордер) {"? йода состояние: D
  • 0
    Lol ... Согласен - может быть, немного необычно: D
0

Ни один из вышеперечисленных решений не работал у меня. Вместо этого я увеличил буфер в конструкторе AudioRecord.

Минимальная буферизация рекомендует что-то между 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;
            }
0

В документации указано:

Чтобы получить соответствующий обратный вызов, связанный с этими слушатели, приложения должны создавать объекты MediaRecorder на потоках с запуском Looper (основной поток пользовательского интерфейса по умолчанию уже работает Looper).

Убедитесь, что вы создали рекордер в потоке пользовательского интерфейса. Возможно, также вызовите его методы в потоке пользовательского интерфейса.

0

A SIGSEGV не должно быть возможным из кода Java. Если это не был ваш код JNI, это указывает на недостаток прошивки.

Если вы используете модемную прошивку, пропустите эту информацию вместе с модемами прошивки.

Если вы используете оригинальную прошивку, поставляемую вместе с устройством, и это происходит только на одном устройстве, вы можете попытаться связаться с производителем устройства.

Если вы видите это на нескольких устройствах с оригинальной прошивкой, и вы можете создать образец проекта, который воспроизводит ошибку, опубликовать проект и трассировку стека трекер для Android, предполагая, что этот вопрос там еще не сообщается.

  • 0
    Вы правы. Я использую модовую прошивку (Cyanogenmod 7). Если я обнаружу, что это не проблема с моим исходным кодом, а с системой, я сделаю, как вы и предполагали.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню