ساخت اپلیکیشن ضبط صدا با کاتلین (Kotlin) — به زبان ساده

۳۲۹ بازدید
آخرین به‌روزرسانی: ۱ مهر ۱۴۰۲
زمان مطالعه: ۵ دقیقه
دانلود PDF مقاله
ساخت اپلیکیشن ضبط صدا با کاتلین (Kotlin) — به زبان ساده

فریمورک مالتی‌مدیا در اندروید از ضبط و پخش صدا نیز پشتیبانی می‌کند. در این مطلب مراحل ساخت یک اپلیکیشن ضبط صدا را بررسی می‌کنیم که قابلیت ضبط کردن صدا و ذخیره‌سازی آن در حافظه داخلی دستگاه اندرویدی را دارد. این کار با استفاده از MediaRecorder که از سوی SDK اندروید ارائه شده است صورت می‌گیرد. همچنین با روش تقاضای آنی «دسترسی‌های کاربر» (User Permissions) و شیوه کار با حافظه داخلی یک دستگاه اندرویدی آشنا خواهیم شد.

997696

ایجاد رابط کاربری (UI)

ابتدا باید رابط کاربری اپلیکیشن ضبط صدای خودمان را بسازیم.

این رابط از یک طرح‌بندی ساده با 3 دکمه تشکیل یافته است که برای آغاز، مکث/ ازسرگیری و توقف ضبط صدا استفاده می‌شوند.

1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout
3        xmlns:android="http://schemas.android.com/apk/res/android"
4        xmlns:tools="http://schemas.android.com/tools"
5        android:layout_width="match_parent" android:layout_height="match_parent"
6        tools:context=".MainActivity">
7
8    <TextView
9            android:id="@+id/textview_sound_recorder_heading"
10            android:layout_width="wrap_content"
11            android:layout_height="wrap_content"
12            android:text="Sound Recorder"
13            android:layout_centerHorizontal="true"
14            android:textSize="32dp"
15            android:textStyle="bold"
16            android:textColor="#000"
17            android:layout_marginTop="32dp"
18    />
19
20    <Button
21            android:id="@+id/button_start_recording"
22            android:layout_width="wrap_content"
23            android:layout_height="wrap_content"
24            android:text="Start"
25            android:layout_alignParentBottom="true"
26            android:layout_marginLeft="32dp"
27            android:layout_marginBottom="32dp"
28            android:layout_centerVertical="true"/>
29
30    <Button
31            android:id="@+id/button_pause_recording"
32            android:layout_width="wrap_content"
33            android:layout_height="wrap_content"
34            android:text="Pause"
35            android:layout_alignParentBottom="true"
36            android:layout_centerHorizontal="true"
37            android:layout_marginBottom="32dp"/>
38
39    <Button
40            android:id="@+id/button_stop_recording"
41            android:layout_width="wrap_content"
42            android:layout_height="wrap_content"
43            android:text="Stop"
44            android:layout_alignParentBottom="true"
45            android:layout_alignParentRight="true"
46            android:layout_marginBottom="32dp"
47            android:layout_marginRight="32dp"/>
48</RelativeLayout>

تقاضای مجوزهای مورد نیاز

پس از ایجاد رابط کاربری می‌توانیم با استفاده از MediaRecorder شروع به ساخت اپلیکیشن خود بکنیم. اما قبل از آن باید مجوز دسترسی‌های مورد نیاز خود برای ضبط صدا و استفاده از حافظه داخلی را از کاربر بخواهیم. این کار با چند خط کد ساده در فایل AndroidManifest.xml ممکن است:

1<uses-permission android:name="android.permission.RECORD_AUDIO"/>
2<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

همچنین پیش از استفاده عملی از MediaRecorder لازم است که بررسی کنیم آیا کاربر واقعاً مجوز دسترسی‌ها را ارائه کرده است یا نه؛ این کار را در فایل MainActivity.kt انجام می‌دهیم:

1if (ContextCompat.checkSelfPermission(this,
2      Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
3      Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
4  val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
5  ActivityCompat.requestPermissions(this, permissions,0)
6}

نکته: این خطوط کد در ادامه به فراخوانی OnClickListener در دکمه start_recording انتقال خواهند یافت تا بتوانیم مطمئن باشیم که MediaRecorder بدون در اختیار داشتن دسترسی‌های لازم شروع به کار نمی‌کند.

اپلیکیشن ضبط صدا

ضبط و ذخیره‌سازی صدا

پس از تهیه مقدمات کار اینک نوبت آن رسیده است که به صورت عملی اقدام به ضبط و ذخیره‌سازی صدا بکنیم.

افزودن OnClickListeners

ابتدا باید یک OnClickListeners به دکمه‌های خود اضافه کنیم تا مطمئن شویم که به رویدادهای اجرا شده از سوی کاربر پاسخ می‌دهند. همان طور که پیش‌تر گفتیم وجود مجوز دسترسی‌های صحیح را پیش از افزودن فراخوانی OnClickListener به دکمه start_recording بررسی می‌کنیم.

1button_start_recording.setOnClickListener {
2    if (ContextCompat.checkSelfPermission(this,
3            Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
4            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
5        val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
6        ActivityCompat.requestPermissions(this, permissions,0)
7    } else {
8        startRecording()
9    }
10}
11
12button_stop_recording.setOnClickListener{
13    stopRecording()
14}
15
16button_pause_recording.setOnClickListener {
17    pauseRecording()
18}

پیکربندی MediaRecorder

سپس باید یک مسیر برای خروجی تعریف کرده و شروع به پیکربندی MediaRecorder خودمان کنیم.

1private var output: String? = null
2private var mediaRecorder: MediaRecorder? = null
3private var state: Boolean = false
4private var recordingStopped: Boolean = false
5
6override fun onCreate(savedInstanceState: Bundle?) {
7    super.onCreate(savedInstanceState)
8    setContentView(R.layout.activity_main)
9
10    output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
11    mediaRecorder = MediaRecorder()
12    
13    mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
14    mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
15    mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
16    mediaRecorder?.setOutputFile(output)
17}

در کد فوق مسیر به سوی ریشه حافظه دستگاه را یافته و نام فایل ضبط شده و نوع فایل را به آن اضافه می‌کنیم. پس از آن شیء MediaRecorder را ایجاد کرده و منبع صدا، انکودر صدا، قالب خروجی و فایل خروجی را تعریف می‌کنیم.

ضبط و ذخیره‌سازی صوت

کد مورد استفاده برای آغاز به کار MediaRecorder در رویداد OnClickListener برای دکمه start_recording قرار می‌گیرد:

1private fun startRecording() {
2    try {
3        mediaRecorder?.prepare()
4        mediaRecorder?.start()
5        state = true
6        Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
7    } catch (e: IllegalStateException) {
8        e.printStackTrace()
9    } catch (e: IOException) {
10        e.printStackTrace()
11    }
12}

همان طور که مشاهده می‌کنید ما باید تابع prepare را پیش از آن که اقدام به ضبط صدا بکنیم، فراخوانی کرده باشیم. همچنین آن را درون بلوک try-catch جاسازی کرده‌ایم تا مطمئن شویم که اپلیکیشن هنگامی که تابع prepares ناموفق باشد، از کار نمی‌افتد.

متد OnClickListeners دکمه Stop کاملاً شبیه به آن متدی است که در بخش قبل تعریف کردیم.

1private fun stopRecording(){
2    if(state){
3        mediaRecorder?.stop()
4        mediaRecorder?.release()
5        state = false
6    }else{
7        Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
8    }
9}

در کد فوق بررسی می‌کنیم که آیا MediaRecorder در حال حاضر و پیش از توقف عملی recording در حال اجرا است یا نه، چون اپلیکیشن در زمانی که متد stop هنگام عدم ضبط صدا فراخوانی شود، ممکن است موجب از کار افتادن برنامه شود. پس از آن متغیر state را به حالت false تغییر می‌دهیم تا مانع این بشویم که کاربر مجدداً روی دکمه stop بزند.

سپس باید OnClickListener را برای دکمه pause/resume تعریف کنیم.

1@SuppressLint("RestrictedApi", "SetTextI18n")
2@TargetApi(Build.VERSION_CODES.N)
3private fun pauseRecording() {
4    if(state) {
5        if(!recordingStopped){
6            Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
7            mediaRecorder?.pause()
8            recordingStopped = true
9            button_pause_recording.text = "Resume"
10        }else{
11            resumeRecording()
12        }
13    }
14}
15
16@SuppressLint("RestrictedApi", "SetTextI18n")
17@TargetApi(Build.VERSION_CODES.N)
18private fun resumeRecording() {
19    Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
20    mediaRecorder?.resume()
21    button_pause_recording.text = "Pause"
22    recordingStopped = false
23}

ما در این دو متد بررسی می‌کنیم که آیا MediaRecorder در حال اجرا است یا نه. اگر چنین باشد فرایند ضبط صدا را متوقف می‌کنیم و متن دکمه را به resume تغییر می‌دهیم. اگر دکمه دوباره کلیک شود فرایند ضبط صدا را از نقطه‌ای که باقی مانده بود از سر می‌گیریم.

در نهایت ما می‌توانیم ضبط صدا را آغاز کرده و با باز کردن فایل recording.mp3 که در حافظه داخلی دستگاه ذخیره شده است به آن گوش دهیم.

کد کامل اپلیکیشن ضبط صدا در کاتلین: MainActivity.kt

در ادامه کد منبع کامل اپلیکیشن ابتدایی ضبط صدا را مشاهده می‌کنید:

1package com.example.android.soundrecorder
2
3import android.Manifest
4import android.annotation.SuppressLint
5import android.annotation.TargetApi
6import android.content.pm.PackageManager
7import android.media.MediaRecorder
8import android.os.Build
9import android.support.v7.app.AppCompatActivity
10import android.os.Bundle
11import android.os.Environment
12import android.support.v4.app.ActivityCompat
13import android.support.v4.content.ContextCompat
14import android.widget.Toast
15import kotlinx.android.synthetic.main.activity_main.*
16import java.io.IOException
17
18class MainActivity : AppCompatActivity() {
19
20    private var output: String? = null
21    private var mediaRecorder: MediaRecorder? = null
22    private var state: Boolean = false
23    private var recordingStopped: Boolean = false
24
25    override fun onCreate(savedInstanceState: Bundle?) {
26        super.onCreate(savedInstanceState)
27        setContentView(R.layout.activity_main)
28
29        mediaRecorder = MediaRecorder()
30        output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
31
32        mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
33        mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
34        mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
35        mediaRecorder?.setOutputFile(output)
36
37        button_start_recording.setOnClickListener {
38            if (ContextCompat.checkSelfPermission(this,
39                    Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
40                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
41                val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
42                ActivityCompat.requestPermissions(this, permissions,0)
43            } else {
44                startRecording()
45            }
46        }
47
48        button_stop_recording.setOnClickListener{
49            stopRecording()
50        }
51
52        button_pause_recording.setOnClickListener {
53            pauseRecording()
54        }
55    }
56
57    private fun startRecording() {
58        try {
59            mediaRecorder?.prepare()
60            mediaRecorder?.start()
61            state = true
62            Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
63        } catch (e: IllegalStateException) {
64            e.printStackTrace()
65        } catch (e: IOException) {
66            e.printStackTrace()
67        }
68    }
69
70    @SuppressLint("RestrictedApi", "SetTextI18n")
71    @TargetApi(Build.VERSION_CODES.N)
72    private fun pauseRecording() {
73        if(state) {
74            if(!recordingStopped){
75                Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
76                mediaRecorder?.pause()
77                recordingStopped = true
78                button_pause_recording.text = "Resume"
79            }else{
80                resumeRecording()
81            }
82        }
83    }
84
85    @SuppressLint("RestrictedApi", "SetTextI18n")
86    @TargetApi(Build.VERSION_CODES.N)
87    private fun resumeRecording() {
88        Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
89        mediaRecorder?.resume()
90        button_pause_recording.text = "Pause"
91        recordingStopped = false
92    }
93
94    private fun stopRecording(){
95        if(state){
96            mediaRecorder?.stop()
97            mediaRecorder?.release()
98            state = false
99        }else{
100            Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
101        }
102    }
103}

بررسی فایل صدا

پس از ضبط کردن صدا باید به حافظه داخلی دستگاه اندرویدی خود بروید تا بتوانید به فایل ضبط شده گوش بدهید. اگر در مورد مسیر این کار مطمئن نیستید، مراحل کار را در ادامه توضیح داده‌ایم:

  1. اپلیکیشن file را روی دستگاه اندرویدی خود باز کنید.
  2. به بخش local بروید.
  3. به دنبال فایلی با نام recording.mp3 بگردید.

اپلیکیشن ضبط صدا

سخن پایانی

بدین ترتیب به پایان این راهنما با موضوع اپلیکیشن مقدماتی ضبط صدا در کاتلین رسیدیم. اینک شما با طرز کار MediaRecorder آشنا شده‌اید و می‌دانید که چگونه می‌توانید به صورت همزمان تقاضای دسترسی بکنید و چرا این کار مهم است. همچنین نکاتی را در مورد حافظه داخلی دستگاه اندرویدی و شیوه ذخیره‌سازی داده‌ها در آن آموختید. نسخه پیشرفته‌تری از این اپلیکیشن که مجهز به امکانات بیشتری مانند پخش صدای ضبط شده با استفاده از MediaPlayer است را می‌توانید در این ریپوی گیت‌هاب (+) مشاهده کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
android.jlelse
۲ دیدگاه برای «ساخت اپلیکیشن ضبط صدا با کاتلین (Kotlin) — به زبان ساده»

اجرا شد ولی فایلاش کجا میره هرچی گشتم پیدا نکردم

سلام خسته نباشید
@SuppressLint(“RestrictedApi”, “SetTextI18n”)
@TargetApi(Build.VERSION_CODES.N)
این دو کد برای چیه؟
button_pause_recording.text = “Pause”
و این کد به خطا بر برخوردم
Unresolved reference: button_pause_recording

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *