Инициализация Android AudioRecord прерывается каждый раз
Моя проблема проста для объяснения - я пытаюсь создать объект AudioRecord, но он не может инициализироваться (т.е. после конструктора getState возвращает 0, указывая на сбой). Я запускаю это из Eclipse на MotoDroid 1, работающем под управлением ОС 2.2.1. Мой AndroidManifest.xml есть, AFAIK, используя правильное разрешение, RECORD_AUDIO (я не знаю, как это подтвердить):
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<activity android:name=".SphinxMic"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Для создания AudioRecord я делаю следующее:
bufferSize = AudioRecord.getMinBufferSize(8000, CHANNEL_IN_MONO, ENCODING_PCM_8BIT);
audioRecorder = new AudioRecord(AudioSource.MIC, 8000, CHANNEL_IN_MONO, ENCODING_PCM_8BIT, 50*bufferSize);
if (audioRecorder.getState() != AudioRecord.STATE_INITIALIZED)
throw new Exception("AudioRecord init failed");
audioRecorder.getState() возвращает 0 (т.е. STATE_UNINITIALIZED)
Я не нашел каких-либо полных примеров использования этого API, и я очень новичок в Android, поэтому решение может быть чем-то простым. Что я могу сделать, чтобы узнать, почему это не удается?
Несколько человек задавали похожие вопросы, но у них, должно быть, были разные проблемы, чем у меня, потому что исправления, которые они одобряют, мне не помогли. Наиболее заметно this. Но одобренное решение вызывает недоумение и все равно не работает для меня. Я также пробовал различные битовые скорости (8000, 16000, 11025, 44100), как моно, так и стерео и 8 и 16 бит. Никакая комбинация не возвращается как успешно инициализированная.
Ответы
Ответ 1
Я потратил несколько часов на решение этой проблемы и выяснил, что перемещение
<uses-permission android:name="android.permission.RECORD_AUDIO" />
вне блока приложений действительно его решила!
...
</application>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>
Ответ 2
Другая возможная проблема:
В моем манифесте было разрешено разрешение RECORD_AUDIO
, но для уровня API 23 мне также нужно было запросить разрешение во время выполнения.
Ответ 3
Попробуйте 16 бит. Это то, что работает для меня:
try {
// Create a new AudioRecord object to record the audio.
bufferSize = AudioRecord.getMinBufferSize(frequency,channelConfiguration,audioEncoding);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
frequency, channelConfiguration,
audioEncoding, bufferSize);
} catch (Throwable t) {
Log.e("AudioRecord","Recording Failed");
}
И у меня есть следующие переменные:
int frequency = 8000;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
Ответ 4
В случае, если кто-либо должен запросить разрешения на доступ к диску вручную для API 23+, здесь один из методов, который я использовал. Просто замените permission.RECORD_AUDIO
на соответствующие биты. Логика метода зависит от нескольких битов, которые являются внешними (например, strings.xml
, ActivityCompat
, Snackbar
), но думал, что это может кому-то помочь.
/**
* Requests the Storage permissions.
* If the permission has been denied previously,
* a SnackBar will prompt the user to grant the
* permission, otherwise it is requested directly.
*/
private void requestStoragePermissions() {
// Newer versions Android 18+
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
/**
* Permissions required to read and write storage.
*/
final String[] PERMISSIONS_STORAGE = {
permission.READ_EXTERNAL_STORAGE,
permission.WRITE_EXTERNAL_STORAGE,
};
final boolean readResult =
ActivityCompat.shouldShowRequestPermissionRationale(
this, permission.READ_EXTERNAL_STORAGE);
final boolean writeResult =
ActivityCompat.shouldShowRequestPermissionRationale(
this, permission.WRITE_EXTERNAL_STORAGE);
if (readResult || writeResult) {
// Provide an additional rationale to the user if the permission was not granted
// and the user would benefit from additional context for the use of the permission.
// For example, if the request has been denied previously.
Log.i(TAG,
"Displaying disk permission rationale to provide additional context.");
// Display a SnackBar with an explanation and a button to trigger the request.
Snackbar.make(mainView, R.string.permission_storage_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCompat
.requestPermissions(MainActivity.this,
PERMISSIONS_STORAGE,
REQUEST_STORAGE);
}
})
.show();
} else {
// Storage permissions have not been granted. Request them directly.
ActivityCompat.requestPermissions(
this, PERMISSIONS_STORAGE, REQUEST_STORAGE);
}
}
}