Preface
Recently I received a request to implement IM communication without using a third-party SDK. Text chat has been implemented through MQTT, and the best solution that comes to voice function is to upload and download recording files. There may be better solutions, but I didn’t expect that if you have any suggestions, please help me guide you.
premise :
1. Authorization application: Add:
<uses-permission android:name=".WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name=".READ_EXTERNAL_STORAGE" /> <uses-permission android:name=".RECORD_AUDIO" />
Corresponding to read and write files and recording permissions.
2. The recording file must be written to the corresponding folder. This folder must be created first and thrown into the onCreate() of Application or Activity, but it must be created first.
Code implementation process :
1. Create a MediaRecorder object;
2. Call the setAudioSource() method to set the source of the sound, which is generally passed in;
3. Call setOutputFormat() to set the format of the recorded audio file;
4. Call setAudioRncoder(), setAudioEncodingBitRate(int bitRate), setAudioSamlingRate(int SamplingRate) to set the recorded encoding format, encoding bit rate, sampling rate, etc. Of course, not everyone needs it. Adjust it according to the specific business (setAudioEncodingBitRate(96000), the encoding bit rate is generally 96000);
5. Call the setOutputFile(String path) method to set the storage location of the recorded audio file;
6. Call the Prepare() method of the MediaRecoder object to prepare for recording;
7. Call the start() method of the MediaRecoder object to start recording;
8. After the end, call the stop() method of the MediaRecoder object to stop recording and call the release() method to release the resource. Examples are as follows:
public class TestActivity extends BaseActivity { private ActivityChatBinding testBinding; private MediaRecorder mediaRecorder; private boolean isRecorded; @Override public void initView() { testBinding = (getLayoutInflater()); setContentView(()); initMsgAndSth(); checkPermission(); } private void initMsgAndSth(){ String record_Home = ()+"/Sample"; //Declare storage path, use absolute path to anything //btnTalk is a Button (new () { @Override public void onClick(View v) { if (isRecorded) stopRecordAudio(); else startRecordAudio(record_Home); } }); } private void stopRecordAudio() { // Some 5.0 models will report errors, it is recommended to grab exceptions here if(mediaRecorder !=null){ try { ();//Stop recording ();//Release resources mediaRecorder =null; }catch (Exception exception){ ();//Reset ();//Release resources mediaRecorder =null; } (this,"Stop recording",Toast.LENGTH_SHORT).show(); } } private void startRecordAudio(String path) { //Folder must be created first, otherwise the error message will not be found here. File audioFile = new File(path); if (!()) { (); } else if (!()) { (); (); } File file = new File(path + ""); if(!()){ try { (); } catch (IOException e) { (); } } if(mediaRecorder == null){ mediaRecorder = new MediaRecorder(); ();//Set the microphone /* * Set the format to save the output file: THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP (3gp format * , H263 video/ARM audio encoding), MPEG-4, RAW_AMR (only supports audio and the audio encoding requirement is AMR_NB) */ (.AMR_NB); (.AMR_NB);//Set the audio file encoding format (path+""); } try { (); // prepare before starting (); isRecorded = true; (this,"Start recording",Toast.LENGTH_SHORT).show(); } catch (IllegalStateException el){ (); } catch (RuntimeException e){ (); } catch (Exception e){ (); } } /** * Simple permission application logic */ private void checkPermission() { if (.SDK_INT >= Build.VERSION_CODES.M) { String[] permissions = new String[]{.RECORD_AUDIO,.WRITE_EXTERNAL_STORAGE}; for (String permission : permissions) { if ((this, permission) != PackageManager.PERMISSION_GRANTED) { (this, permissions, 200); return; } } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { (requestCode,permissions,grantResults); if (.SDK_INT >= Build.VERSION_CODES.M && requestCode == 200) { for (int i = 0; i < ; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { Intent intent = new Intent(); (Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = ("package", getPackageName(), null); (uri); startActivityForResult(intent, 200); return; } } } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { (requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == 200) { checkPermission(); } } }
The relevant API differences have been written in detail and the layout is very simple, so I won't post them here. What should be paid special attention to hereThe order of call cannot be changed, otherwise it is easy to report an error, and the prompt information of the error is not necessarily enough to locate the problem due to the incorrect call order.
Step on a pit
According to the previous prompt, I felt that I could play happily by avoiding all pitfalls, but the operation was reported by an error. Some models did not print specific logs, so I could only do it myself.
1、Android Q:
Sometimes, according to the classification of errors, you can still catch some clues. If it is an Android Q device, it reports an IO exception or a Permission Denied error, then check whether there is this sentence in the application tag in the list file:
android:requestLegacyExternalStorage="true"
If not, you must add it.
The reason is that starting from Android 10, in order to access all files stored externally, exceptDynamic application permissionandAuthorization statementIn addition, this sentence must be added to the main project forApply for external storage of all documentspermissions.
2、RuntimeException:setAudioSource failed
If the program runs, see
RuntimeException: setAudioSource failed
If an error is reported, please make sure that the logic related to the application permissions is correct, and there are also applications for the relevant permissions in the list file. However, if (although it is very rare, I encountered it) after adding permissions, you still report this error. Please enter the mobile phone settings-app, find the application you posted, and give it permission. In addition to prompting authorization for the first time during the debugging process, some models will not prompt again when installing again. This is equivalent to the user not granting relevant recording and sdcard read and write permissions, and the program will still report an error. Therefore, it is recommended to make a logical judgment before starting recording and other logic.
In addition, there is another situation where this error occurs. After recording, the recording is not called () to release the resource, and it is in the stop state. At this time, it is easy to report this error by preparing and starting. At this time, the error is not much different from the original stack error information, and it is difficult to locate, so pay special attention.
3、MediaRecorder: stop failed
After calling start(), the operation to call stop() is immediately performed. This error will be reported because no valid audio or video data is generated. This scenario is very common in instant messaging. You can stop() by letting the thread sleep for a short period of time (prompt for at least 1 second). The official documentation notes also explain this: Note that a RuntimeException is intentionally thrown to the application, if no valid audio/video data has been received when stop() is called.
Summarize
This is the end of this article about the implementation of Android recording function and the implementation of pitfalls. For more related content about Android recording function, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!