Время на прочтение
7 мин
Количество просмотров 7.4K
Мультимедийный фреймворк Android поддерживает запись и воспроизведение аудио. В этой статье я покажу, как разработать простое приложение для звукозаписи, которое будет записывать аудио и сохранять его в локальном хранилище Android-устройства с помощью MediaRecorder
из Android SDK.
Вы также узнаете, как запросить разрешения у пользователя в режиме реального времени и как работать с локальным хранилищем Android-устройства.
Создание пользовательского интерфейса
Сперва нам нужно создать интерфейс для звукозаписи. Это простой layout с тремя кнопками, которые будут использоваться для запуска, приостановки/возобновления и остановки записи.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview_sound_recorder_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sound Recorder"
android:layout_centerHorizontal="true"
android:textSize="32dp"
android:textStyle="bold"
android:textColor="#000"
android:layout_marginTop="32dp"/>
<Button
android:id="@+id/button_start_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:layout_alignParentBottom="true"
android:layout_marginLeft="32dp"
android:layout_marginBottom="32dp"
android:layout_centerVertical="true"/>
<Button
android:id="@+id/button_pause_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"/>
<Button
android:id="@+id/button_stop_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="32dp"
android:layout_marginRight="32dp"/>
</RelativeLayout>
Запрос требуемых разрешений
После создания пользовательского интерфейса мы можем начать использовать MediaRecorder
для реализации основной функциональности нашего приложения. Но сначала нам нужно запросить необходимые разрешения для записи аудио и доступа к локальному хранилищу. Cделаем мы это это с помощью нескольких простых строк кода в нашем файле AndroidManifest.xml
:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Также нужно проверить, одобрил ли пользователь разрешения, прежде чем мы сможем использовать наш MediaRecorder
. Сделаем это в Activity MainActivity.kt
:
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
}
Примечание: позже эти строки кода будут перемещены в OnClickListener
кнопки начала записи аудио, чтобы мы могли убедиться, что MediaRecorder
не будет запущен без необходимых разрешений.
Запись и сохранение аудио
Добавление OnClickListeners
Добавим слушатели к кнопкам, чтобы они реагировали на пользовательские события. Как я упоминал ранее, проверка на наличие необходимых разрешений будет добавлена в OnClickListener кнопки начала записи аудио:
button_start_recording.setOnClickListener {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
} else {
startRecording()
}
}
button_stop_recording.setOnClickListener{
stopRecording()
}
button_pause_recording.setOnClickListener {
pauseRecording()
}
Настройка MediaRecorder
Далее нам нужно указать путь для сохранения аудио и настроить MediaRecorder.
private var output: String? = null
private var mediaRecorder: MediaRecorder? = null
private var state: Boolean = false
private var recordingStopped: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
mediaRecorder = MediaRecorder()
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(output)
}
Мы берём путь к корню нашего внешнего хранилища и добавляем в него имя нашей записи и тип файла. После этого мы создаём объект MediaRecorder
и определяем источник звука, аудиокодер, формат и файл для записи.
Запись и сохранение аудио
Код, используемый для запуска MediaRecorder
, определяется в OnClickListener
кнопки начала записи аудио:
private fun startRecording() {
try {
mediaRecorder?.prepare()
mediaRecorder?.start()
state = true
Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
Как видите, нужно вызвать функцию prepare
, прежде чем мы сможем начать запись. Мы также встраиваем вызов в блок try-catch, чтобы приложение не сломалось при сбое функции prepare
.
OnClickListeners
кнопки остановки записи очень похож на код выше.
private fun stopRecording() {
if (state) {
mediaRecorder?.stop()
mediaRecorder?.release()
state = false
} else {
Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
}
}
Здесь мы проверяем, работает ли в данный момент MediaRecorder
, прежде чем мы остановим запись, потому что наше приложение сломается, если метод stop
будет вызван, в то время как MediaRecorder
не будет запущен. После этого мы меняем переменную состояния на false
, чтобы пользователь не мог снова нажать кнопку остановки.
Нам осталось определить OnClickListener
для кнопки приостановки/возобновления.
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun pauseRecording() {
if (state) {
if (!recordingStopped) {
Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
mediaRecorder?.pause()
recordingStopped = true
button_pause_recording.text = "Resume"
} else {
resumeRecording()
}
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun resumeRecording() {
Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
mediaRecorder?.resume()
button_pause_recording.text = "Pause"
recordingStopped = false
}
В этих двух методах мы проверяем, работает ли MediaRecorder
. Если работает, мы приостановим запись и изменим текст кнопки для возобновления. При повторном нажатии запись возобновится.
Наконец, мы можем записать аудио и прослушать его, открыв файл recording.mp3
, который будет сохранён в нашем локальном хранилище. Просто откройте проводник файлов и сделайте поиск по имени файла recording.mp3
.
Исходный код
Вот полный исходный код нашего приложения:
package com.example.android.soundrecorder
import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.pm.PackageManager
import android.media.MediaRecorder
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import java.io.IOException
class MainActivity : AppCompatActivity() {
private var output: String? = null
private var mediaRecorder: MediaRecorder? = null
private var state: Boolean = false
private var recordingStopped: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mediaRecorder = MediaRecorder()
output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(output)
button_start_recording.setOnClickListener {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
} else {
startRecording()
}
}
button_stop_recording.setOnClickListener{
stopRecording()
}
button_pause_recording.setOnClickListener {
pauseRecording()
}
}
private fun startRecording() {
try {
mediaRecorder?.prepare()
mediaRecorder?.start()
state = true
Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun pauseRecording() {
if (state) {
if (!recordingStopped) {
Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
mediaRecorder?.pause()
recordingStopped = true
button_pause_recording.text = "Resume"
} else {
resumeRecording()
}
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun resumeRecording() {
Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
mediaRecorder?.resume()
button_pause_recording.text = "Pause"
recordingStopped = false
}
private fun stopRecording(){
if (state) {
mediaRecorder?.stop()
mediaRecorder?.release()
state = false
} else {
Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
}
}
}
Заключение
Теперь вы знаете, как работает MediaRecorder
, как запрашивать разрешения в режиме реального времени и почему это важно делать. Вы также узнали о локальном хранилище вашего устройства Android и о том, как хранить в нём данные.
Более сложная версия этого приложения, в которой есть некоторые дополнительные функции, такие как воспроизведение ваших записей с помощью MediaPlayer
, доступна на Github.
В этом руководстве мы создадим базовое приложение для записи звука. Оно работает аналогично встроенному приложению Android recorder, но имеет очень простой пользовательский интерфейс.
ПРИМЕЧАНИЕ: Этот туториал предназначен для новичков и начинающих разработчиков Android. Я предполагаю, что вы уже знакомы с некоторыми основами программирования Android.
Вы узнаете о классе MediaRecorder, как получить разрешения пользователя (в Android M и выше) и как получить доступ к внешнему хранилищу на android.
Давайте начнем разработку!
Самый распространенный способ записи медиа — это класс MediaRecorder. В нашем файле MainActivity.java мы создадим myAudioRecorder из класса MedianRecorder. Мы предоставим ему источник звука (микрофон) и зададим формат вывода 3Gpp. Для хранения записи будем использовать место на внешнем хранилище.
private MediaRecorder myAudioRecorder; output = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myrecording.3gp"; myAudioRecorder = new MediaRecorder(); myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); myAudioRecorder.setOutputFile(output);
Примечание: С каждой новой записью предыдущая будет удаляться, так как каждая запись записывается в один и тот же файл.
В случае если вы хотите сохранить все файлы, вы можете сохранить их в отдельных файлах. (Воспринимайте это как личное задание!)
Используются три кнопки:
1) START
2) STOP
3) PLAY
start = (Button)findViewById(R.id.button1); stop = (Button) findViewById(R.id.button2); play = (Button)findViewById(R.id.button3); start.setOnClickListener(this); stop.setOnClickListener(this); play.setOnClickListener(this);
Функция прослушивания:
@Override public void onClick(View v){ switch (v.getId()){ case R.id.button1: start(v); break; case R.id.button2: stop(v); break; case R.id.button3: try { play(v); } catch (IOException e){ Log.i("IOException", "Error in play"); } break; default: break; } }
Интуитивно понятно, что кнопки работают так, как они названы. Теперь мы присоединим объект myAudioRecorder к событиям onClickListener отдельных кнопок, чтобы начать и сохранить запись. Для кнопок START и STOP:
public void start(View view){ try{ myAudioRecorder.prepare(); myAudioRecorder.start(); } catch (IllegalStateException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } start.setEnabled(false); stop.setEnabled(true); Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_SHORT).show(); } public void stop(View view){ myAudioRecorder.stop(); myAudioRecorder.release(); myAudioRecorder = null; stop.setEnabled(false); play.setEnabled(true); Toast.makeText(getApplicationContext(), "Audio recorded successfully", Toast.LENGTH_SHORT).show(); }
Toast показывает «Запись началась», когда начинается запись. Аналогично мы видим toast, когда запись сохраняется. Для PLAY мы прочитаем выходной файл и воспроизведем его через объект MediaPlayer. Снова отображается toast для воспроизведения аудио. Нам нужно добавить блоки try-catch в различных местах, чтобы избежать сбоев.
public void play(View view) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException { MediaPlayer m = new MediaPlayer(); m.setDataSource(output); m.prepare(); m.start(); Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_SHORT).show(); }
В UI (пользовательском интерфейсе) мы просто добавим три кнопки, как указано выше. Файл activity_main.xml выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.india.recorder.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" android:text="Start" android:id="@+id/button1"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="175dp" android:text="Stop" android:id="@+id/button2"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="300dp" android:text="Play" android:id="@+id/button3"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Welcome to Recorder!" android:layout_centerHorizontal="true" android:fontFamily="sans-serif" android:layout_marginTop="400dp" android:textSize="25dp" android:textColor="#008080"/> </RelativeLayout>
Нам понадобятся разрешения пользователей для доступа к MIC и хранилищу, поэтому мы добавим разрешения в Android_Manifest.xml
ПРИМЕЧАНИЕ: Разрешения изменились в Android M. Теперь разрешения запрашиваются во время выполнения, а не во время установки, как это было в Android M.
Чтобы решить эту проблему, мы добавим проверку в наш код, чтобы определить версию Android mobile, с которой мы работаем, и действовать соответствующим образом.
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 200: permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; permissionToWriteAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED; break; } if (!permissionToRecordAccepted ) MainActivity.super.finish(); if (!permissionToWriteAccepted ) MainActivity.super.finish(); }
Добавьте необходимые разрешения в Android.manifest для record_audio и file_storage.
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Теперь соберите проект и запустите приложение. Оно должно запросить разрешения, когда вы откроете его в первый раз.
Все должно работать, как ожидалось.
Полный файл MainActivity.java выглядит следующим образом:
package com.example.india.recorder; import android.Manifest; import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Build; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final int RECORD_AUDIO = 0; private MediaRecorder myAudioRecorder; private String output = null; private Button start, stop, play; private boolean permissionToRecordAccepted = false; private boolean permissionToWriteAccepted = false; private String [] permissions = {"android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int requestCode = 200; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(permissions, requestCode); } start = (Button)findViewById(R.id.button1); stop = (Button) findViewById(R.id.button2); play = (Button)findViewById(R.id.button3); start.setOnClickListener(this); stop.setOnClickListener(this); play.setOnClickListener(this); stop.setEnabled(false); play.setEnabled(false); output = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myrecording.3gp"; myAudioRecorder = new MediaRecorder(); myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); myAudioRecorder.setOutputFile(output); } @Override public void onClick(View v){ switch (v.getId()){ case R.id.button1: start(v); break; case R.id.button2: stop(v); break; case R.id.button3: try { play(v); } catch (IOException e){ Log.i("IOException", "Error in play"); } break; default: break; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 200: permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; permissionToWriteAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED; break; } if (!permissionToRecordAccepted ) MainActivity.super.finish(); if (!permissionToWriteAccepted ) MainActivity.super.finish(); } public void start(View view){ try{ myAudioRecorder.prepare(); myAudioRecorder.start(); } catch (IllegalStateException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } start.setEnabled(false); stop.setEnabled(true); Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_SHORT).show(); } public void stop(View view){ myAudioRecorder.stop(); myAudioRecorder.release(); myAudioRecorder = null; stop.setEnabled(false); play.setEnabled(true); Toast.makeText(getApplicationContext(), "Audio recorded successfully", Toast.LENGTH_SHORT).show(); } public void play(View view) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException { MediaPlayer m = new MediaPlayer(); m.setDataSource(output); m.prepare(); m.start(); Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_SHORT).show(); } }
Диктофон — делаем запись с микрофона
2-й курс/Закрытая зона
Запускаем встроенный диктофон
MediaRecorder
Создаём собственный диктофон
AudioRecord
Запускаем встроенный диктофон
Для начала попробуем запустить встроенный диктофон. Несмотря на то, что в эмуляторе нет значка приложения «Диктофон», он там есть. И мы можем запустить его с помощью намерения. Добавим на экран активности кнопку для запуска приложения и напишем код.
// Kotlin
class MainActivity : AppCompatActivity() {
private val RQS_RECORDING = 1
private var savedUri: Uri? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button: Button = findViewById(R.id.button)
button.setOnClickListener {
val intent = Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
startActivityForResult(intent, RQS_RECORDING)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == RQS_RECORDING) {
if(data?.data != null){
savedUri = data.data
println("Saved url: ${savedUri?.path}")
}
}
}
}
// Java
final static int RQS_RECORDING = 1;
Uri savedUri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button recordButton = findViewById(R.id.buttonRecord);
recordButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(
MediaStore.Audio.Media.RECORD_SOUND_ACTION);
startActivityForResult(intent, RQS_RECORDING);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RQS_RECORDING) {
savedUri = data.getData();
Toast.makeText(MainActivity.this,
"Saved: " + savedUri.getPath(), Toast.LENGTH_LONG).show();
}
}
Запустив приложение «Диктофон», вы можете записать сообщение и закрыть программу. Путь к файлу с аудиоданными вернётся в вашу программу через метод onActivityResult() и будет представлять строку типа external/audio/media/382. Вы можете поискать созданный файл в папке SD-карты. Этот способ работает на эмуляторе, а на обычных устройствах диктофон может и не вернуть данные. А на некоторых устройствах может не оказаться диктофона.
В любом случае у вас возникнут трудности с доступом к созданным файлам, так как вы не принимаете участия в процессе создания файла. Вам надо потрудиться, чтобы разобраться, как хранятся файлы, записанные в системном приложении.
MediaRecorder
Класс android.media.MediaRecorder позволяет делать записи записи медиафрагментов, включая аудио и видео. MediaRecorder действует как конечный автомат. Вы задаёте различные параметры, такие как устройство-источник и формат. После установки запись может выполняться как угодно долго, пока не будет остановлена.
Алгоритм записи
Сначала определимся с источником (свойство MediaRecorder.AudioSource):
- MIC — встроенный микрофон
- VOICE_UPLINK — исходящий голосовой поток при телефонном звонке (вы говорите)
- VOICE_DOWNLINK — входящий голосовой поток при телефонном звонке (вам говорят)
- VOICE_CALL — запись телефонного звонка
- CAMCORDER — микрофон, связанный с камерой (если доступен)
- VOICE_RECOGNITION — микрофон, используемый для распознавания голоса (если доступен)
- VOICE_COMMUNICATION – аудио поток с микрофона будет «заточен» под VoIP (если доступен)
Если указанный источник не поддерживается текущим устройством, то будет использован микрофон по умолчанию.
Далее определимся с форматом записываемого звука (свойство MediaRecorder.OutputFormat):
- THREE_GPP — формат 3GPP
- MPEG_4 — формат MPEG4
- AMR_NB — формат AMR_NB (подходит для записи речи)
- AMR_WB
- RAW_AMR
Определимся с сжатием звука (свойство MediaRecorder.AudioEncoder).
- AAC
- AMR_NB
- AMR_WB
Указываем путь к файлу, в котором будут сохранены аудиоданные (метод setOutputFile())
Подготавливаем и запускаем запись (методы prepare() и start()). Остановить запись можно при помощи метода stop().
Создаём собственный диктофон
Напишем простейший диктофон для записи мяуканья кота на микрофон.
Вы вошли на сайт, как гость.
Необходимо зарегистрироваться, чтобы прочитать статью
Дополнительные материалы
Реклама
В этом уроке:
— пишем звук с помощью MediaRecorder
Воспроизводить звук мы научились, теперь попробуем его записать. Для этого можно использовать MediaRecorder. Этот же класс используется и для записи видео, но об этом поговорим в следующих уроках. Пока нас интересует звук.
Чтобы MediaRecorder записал для вас звук, он должен знать:
— источник звука
— формат записи
— аудио-кодек
— имя файла
Если вкратце, то кодек – это способ сжатия данных. А под форматом, я так понимаю, здесь подразумевается контейнер, т.е. способ хранения. Я не буду углубляться в эти вопросы, т.к. не являюсь специалистом. В инете сейчас очень много статей на эту тему.
В хелпе есть пример, в котором используется кодек AMR-NB и формат 3GPP. Их я и буду использовать в своем примере.
Напишем простое приложение, которое будет записывать звук с микрофона и даст возможность прослушать то, что записали.
Создадим проект:
Project name: P1291_MediaRecorderAudio
Build Target: Android 2.3.3
Application name: MediaRecorderAudio
Package name: ru.startandroid.develop.p1291mediarecorderaudio
Create Activity: MainActivity
Добавим строки в strings.xml:
<string name="record">Record</string> <string name="play">Play</string> <string name="start">Start</string> <string name="stop">Stop</string>
Рисуем экран main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/record"> </TextView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="recordStart" android:text="@string/start"> </Button> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="recordStop" android:text="@string/stop"> </Button> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="@string/play"> </TextView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="playStart" android:text="@string/start"> </Button> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="playStop" android:text="@string/stop"> </Button> </LinearLayout> </LinearLayout>
Скрин:
Две верхние кнопки стартуют и останавливают запись, две нижние – воспроизведение записанного.
MainActivity.java:
package ru.startandroid.develop.p1291mediarecorderaudio; import java.io.File; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.view.View; public class MainActivity extends Activity { private MediaRecorder mediaRecorder; private MediaPlayer mediaPlayer; private String fileName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); fileName = Environment.getExternalStorageDirectory() + "/record.3gpp"; } public void recordStart(View v) { try { releaseRecorder(); File outFile = new File(fileName); if (outFile.exists()) { outFile.delete(); } mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mediaRecorder.setOutputFile(fileName); mediaRecorder.prepare(); mediaRecorder.start(); } catch (Exception e) { e.printStackTrace(); } } public void recordStop(View v) { if (mediaRecorder != null) { mediaRecorder.stop(); } } public void playStart(View v) { try { releasePlayer(); mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(fileName); mediaPlayer.prepare(); mediaPlayer.start(); } catch (Exception e) { e.printStackTrace(); } } public void playStop(View v) { if (mediaPlayer != null) { mediaPlayer.stop(); } } private void releaseRecorder() { if (mediaRecorder != null) { mediaRecorder.release(); mediaRecorder = null; } } private void releasePlayer() { if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } @Override protected void onDestroy() { super.onDestroy(); releasePlayer(); releaseRecorder(); } }
В onCreate задаем имя файла, куда будет записываться звук.
Так же, как и для MediaPlayer, в хелпе есть подробная схема состояний и действий для MediaRecorder. Советую ознакомиться.
В recordStart мы избавляемся от старого рекордера. Затем удаляем файл для записи, если он уже существует. Далее создаем и настраиваем рекордер используя ряд методов.
setAudioSource. Указываем источник звука – микрофон (MIC). Кроме микрофона есть еще несколько источников:
VOICE_CALL — звук при голосовом разговоре по телефону
VOICE_DOWNLINK — только входящая часть VOICE_CALL
VOICE_UPLINK — только исходящая часть VOICE_CALL
CAMCORDER — микрофон, связанный с веб-камерой
VOICE_RECOGNITION — с микрофона будет записываться исходный аудио поток без преобразований, чтобы получить максимальное качество. Используется для распознавания речи
VOICE_COMMUNICATION – аудио поток с микрофона будет «заточен» под VoIP
Если три последних варианта не поддерживаются текущим устройством, то будет использован микрофон по умолчанию.
setOutputFormat. Указываем формат – 3GPP (THREE_GPP). Остальные форматы можно посмотреть здесь.
setAudioEncoder. Указываем кодек для сжатия аудио — AMR_NB. Остальные кодеки можно посмотреть здесь.
setOutputFile. Указываем имя файла, в который будет вести запись.
После всех настроек вызываем метод prepare, который подготовит рекордер к записи и стартуем запись методом start.
В recordStop останавливаем запись методом stop. После этого метода необходимо заново настроить рекордер, если вы снова хотите его использовать. Просто снова вызвать start не получится. На схеме это показано. Кстати, метод reset также сбрасывает все настройки рекордера и после него необходимо заново указывать источник. формат, кодек, файл. Но объект новый создавать необязательно.
В playStart и playStop стартуем и останавливаем воспроизведение записанного файла. Тут ничего нового для нас, все это обсуждалось в Уроке 126.
В методе releaseRecorder мы освобождаем все ресурсы рекордера методом release. После этого объект уже нельзя использовать и необходимо создавать и настраивать новый.
В манифесте необходимо прописать права на запись звука и работу с SD:
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
После запуска приложения вы сможете записать звук с микрофона и прослушать его.
Распишу еще несколько интересных методов.
setAudioChannels – можно задать режим записи 1 (моно) или 2 (стерео)
setAudioEncodingBitRate и setAudioSamplingRate задают соответственно битрейт и сэмплрейт. Если опять же вкратце, то битрейт – это насколько качественно пишется звук, сэмплрейт – как часто считываются данные с микрофона. Подробности можно узнать у гугла.
setMaxDuration позволяет указать максимальную длительность записи. По достижении этого времени (в мсек), запись остановится, а слушатель, указанный в MediaRecorder.OnInfoListener, получит код what = MEDIA_RECORDER_INFO_MAX_DURATION_REACHED.
setMaxFileSize позволяет указать максимальный размер файла. По достижении указанного размера (в байтах), запись остановится, а слушатель, указанный в MediaRecorder.OnInfoListener, получит код what = MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED.
Разумеется, эти методы надо вызывать перед вызовом prepare
На следующем уроке:
— пишем звук с помощью AudioRecorder
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
Доброго времени суток, Хэшкод!
Возникла необходимость в собственном простом диктофоне, умеющем писать телефонный разговор. Делаю так:
MediaRecorder mRecorder = new MediaRecorder();
Recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); // если заменить VOICE_CALL на MIC то звук без проблем пишется с микрофона, прим. К.О. :)
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
mRecorder.setOutputFile(mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
try {
mRecorder.prepare();
} catch (IOException e) {
}
mRecorder.start();
В итоге получается файл весом 6 байт, который явно не содержит запись разговора.
На аналогичном Хэшкоду сайте одни рекомендуют использовать приведенный выше код, другие уверяют что запись телефонного разговора невозможна в Android в принципе. Прошу помощи с приведенным выше кодом и/или также подтверждения/опровержения того, что запись беседы невозможна. Спасибо за внимание
задан 12 июл 2012 в 16:39
ChavezChavez
4525 серебряных знаков14 бронзовых знаков
4
Со всей ответственностью заявляю, что без хака это невозможно. Об этом говорит feature request, который висит в Google уже давно безо всякой надежды на его реализацию. Фтыкать сюда
С другой стороны на рынке есть некоторые приложения, которые позволяют это делать, но опять же с большими ограничениями. Все реализации написаны на основе хака радиомодулей некоторых известных кристаллов.
Update
Запись собственного голоса возможна — доступ к микрофону есть, а вот голос собеседника закрыт.
ответ дан 12 июл 2012 в 20:08
BarmaleyBarmaley
80.7k7 золотых знаков72 серебряных знака152 бронзовых знака
4
Тоже исследовал этот момент и тоже писал этот кусок кода. Результат был тот же(малый или пустой файл). Потом гуглил много и нашел такой момент: запись собеседника допустима только в некоторых странах, у гугла даже сервис кажется есть, то бишь регулируется на уровне законодательства, надо понимать.
Ну и хаки, как уже писали.
ответ дан 13 июл 2012 в 10:09
DroidAlexDroidAlex
5,70718 серебряных знаков30 бронзовых знаков
По какой-то причине нужно сохранить телефонный разговор? В большинстве смартфонов на Андроиде сделать это очень просто. Для этого можно использовать встроенную опцию или сторонние приложения. А вот владельцам Айфонов такая функция недоступна. Но что делать, если важно не потерять информацию? В этом материале расскажем, как записать разговор по телефону на Андроид и Айфон.
Нельзя сделать универсальную инструкцию для абсолютно всех моделей телефонов. Но мы объясним, какие способы можно использовать для записи. А пользователь сам выберет тот, который актуален для его гаджета. Фото: apkpure.com
Можно ли записывать разговор
На этот вопрос ответит статья 138 УК РФ. Запись частного телефонного звонка не запрещена в России. Но при условии — что вы в нём участвуете. Поэтому записывать своё общение вы можете, это не противозаконно. А вот если вы не участвуете в телефонном звонке и решили специально записать его, то это уже незаконно. За такое умышленное действие можно получить штраф 80 000 рублей или наказание в виде исправительных работ до 1 года.
Нужно ли предупреждать собеседника о том, что ведется запись? Если разговор касается бытовых вопросов, вы участвуете в нём и не собираетесь передавать аудио третьим лицам, обнародовать его — делать это необязательно.
Без согласия собеседника незаконно получать информацию, которая касается персональных данных, коммерческой тайны, сведений о частной жизни. Если вы не предупредили о записи, а разглашение информации привело к потере репутации собеседника, вам будет грозить административная ответственность и штраф до 10 000 рублей для физ лиц.
Если вы живете в другой стране, лучше ознакомиться с местным законодательством. Так как запись звонков может быть вообще запрещена или разрешена в случае уведомления другого говорящего о том, что идёт запись.
Как записать телефонный разговор
На Андроид
Важно: такая опция может вообще отсутствовать на вашей модели смартфона. Проверить это можно в меню «Настройки» — «Приложения». Если утилиты с названием «Диктофон» нет, то встроенная опция отсутствует.
Как записать телефонный разговор на Андроид? Нужно:
- выбрать номер и набрать его;
- на экране вызова появится кнопка «Запись» (обычно находится в правом нижнем углу). Кнопка станет активной после того, как второй абонент «поднимет трубку». Тогда сразу можно нажать на «Запись» (она начнётся). Остановить её можно, нажав второй раз на кнопку.
Также запись автоматически завершится после того, как вы «положите трубку».
Простой способ записать входящий или исходящий звонок. Иллюстрация: Елизавета Чупикова, Фотосклад.Эксперт
Также иногда возможно включить автоматическую запись. Спрятана настройка обычно в: меню «Настройки» — «Приложения» — «Телефон» — «Запись вызовов». Здесь нужно активировать бегунок у фразы «Записывать вызовы автоматически».
Где сохраняются записи?
Есть несколько вариантов:
- отдельная папка в утилите «Проводник». Например, в Xiaomi: MIUI — sound_recorder — call_rec;
- в приложении «Диктофон». Нужно зайти в программу — нажать на 3 полоски в правом нижнем углу — выбрать «Записи вызовов»;
- в журнале вызовов. Встречается не во всех моделях. Но, например, есть в Redmi 9С. В журнале будет значок микрофона у того звонка, который записан.
Достаточно нажать на микрофон, чтобы открылась запись, после чего её можно прослушать, удалить, переслать. Иллюстрация: Елизавета Чупикова, Фотосклад.Эксперт
Если встроенной опции нет, можно воспользоваться сторонними приложениями. Например, Запись звонков: CallRec. В программе можно оставлять комментарии к звонкам, синхронизировать записи с GoogleDisk.
Все подобные утилиты похожи. Они чаще всего условно бесплатные. В обычную версию входит ограниченный набор опций. Например, в CallRec можно записывать аудио без ограничений. Но послушать можно только 1 минуту, нельзя переслать аудио сразу из приложения в мессенджеры. Также есть баннеры с визуальной рекламой, которые могут отвлекать. В платной версии нет рекламы и есть доступ ко всем возможностям.
На Айфоне
У iOS нет такой встроенной функции. Поэтому единственное решение — пользоваться сторонними утилитами, которые можно скачать в AppStore. Стоит отметить, что все подобные приложения платные. Даже если само скачивание бесплатное, то за полноценное использование (запись, прослушивание, скачивание треков) придётся платить.
Примеры программ из AppStore:
– Call Recorder — IntCall, Call Recorder Lite for iPhone, RecMyCalls — приложения с высоким рейтингом на английским языке. Записанные файлы можно пересылать в мессенджеры и по почте, сохранять на виртуальное облако. Цена за тарифы варьируется от региона и оператора. Во время разговора создаётся третий виртуальный участник (грубо говоря — это само приложение), который записывает и сохраняет разговор. Поэтому важно, чтобы оператор поддерживал возможность конференц-связи;
– TapeACall Pro: Запись звонков — утилита на русском, цена — 999 рублей. Работает, как и все подобные приложения, за счёт создания промежуточного, третьего, виртуального абонента. Важно, чтобы оператор поддерживал функцию конференц-связи (где могут общаться 3 участника). По дизайну подобно англоязычным, указанным выше.
Как записать телефонный разговор на Айфоне? Использовать для этого приложение из AppStore. Фото: apps.apple.com
Как записать разговор на диктофон
Казалось бы — что может быть проще? Но к сожалению, это невозможно. Опцию нельзя включить, пока активен вызов. Что делать? Использовать встроенную функцию записи, стороннее приложение или другой телефон.
В последнем случае звонок можно поставить на «громкую связь» (кнопка «Громкая связь» или «Динамик» на экране вызова), а второй смартфон с включенным диктофоном держать рядом.
Также можно не включать громкую связь, а просто увеличить громкость вызова до максимума (несколько раз нажать на клавишу повышения громкости). Этот вариант подойдёт, если динамики громкие. В противном случае разговор будет плохо слышно, второй телефон придётся подносить ближе, а из-за этого возможно появление скрипящих, фонящих шумов.
Где диктофон на Андроид и как его включить
Найти его можно:
- через Проводник;
- в меню, где собраны все приложения.
Если приложение не установлено, его можно скачать из PlayMarket или другого магазина приложений, которое вы используете (например: App Gallery, GetApps, RuStore).
Стандартная программа для записи голоса выглядит подобно на любом смартфоне. Немного различается дизайн (цвет, форма, размер кнопок), расположение пунктов в меню настроек.
Рассмотрим использование диктофона на примере смартфона XIaomi. Иллюстрация: Елизавета Чупикова, Фотосклад.Эксперт
Чтобы открыть утилиту, нужно нажать на значок «Диктофон».
На новом экране появится:
- значок шестерёнки в правом верхнем углу. Это меню. Тут можно изменить формат и качество записи, включить/выключить цветовые индикаторы записи поверх других приложений и т. д.;
- три полоски в правом нижнем углу — ваш список записей;
- красная кнопка — начать. Как только вы на неё нажмёте — на экране начнут меняться числа — это время (часы, минуты и секунды) записи. Чтобы остановить её, нужно снова нажать на красную кнопку. Флажок слева делит аудио на части (ставит метки, к которым можно моментально перемещаться во время прослушивания). Галочка справа — сохранить.
После этого приложение предложит сохранить аудио под нужным названием.
Запись звука на диктофон в iOS
На разных версиях iOS принцип работы этого приложения одинаковый, но дизайн немного отличается. Найти нужную программу можно в папке «Утилиты». Для записи звука можно использовать как встроенный, так и внешний микрофон.
На экране, как и у Андроида, будет красная кнопка. Если на неё нажать, начнётся запись. На экране начнут «бежать» цифры. Чтобы приостановить процесс, нужно нажать снова на кнопку в центре (на этот раз на ней будут нарисованы 2 красные вертикальные полоски). Прослушать запись можно нажав на серый треугольник. Чтобы сохранить аудио, нужно нажать на кнопку «Готово».
Как записать разговор на диктофон на Айфоне. Фото: help.apple.com, mirinfo.ru
Аудио будет называться «Новая запись (+ присвоенный номер)». Также название может дублировать вашу геопозицию, если включена геолокация.
Где хранятся записи? В самом приложении. Вы открываете его и видите список всех аудио в хронологическом порядке. Каждую мелодию можно открыть, обрезать, прослушать, настроить качество звука, переслать другому пользователю.
Использовать «Диктофон» на iOS можно поверх других устройств. За исключением тех, что воспроизводят звук. В этом случае запись будет прервана. В iPhone 14 Pro и iPhone 14 Pro Max рабочее пространство расширено и Dynamic Island используется для управления диктофоном.
Читайте также:
Обзор-сравнение всех моделей Apple iPhone 14 2022
Перечисленные способы помогут вам записать разговор вживую или по телефону. Но помните, что перед записью важно убедиться, что вы не нарушаете законодательство страны, в которой находитесь.