package cn.ptaxi.yuekeduocx.driver.utils; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; import android.util.Log; import com.google.gson.Gson; import com.tbruyelle.rxpermissions2.RxPermissions; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import cn.ptaxi.yuekeduocx.driver.netUtls.Api; import cn.ptaxi.yuekeduocx.driver.netUtls.HttpManager; import cn.ptaxi.yuekeduocx.driver.netUtls.MyDefaultObserver; import cn.ptaxi.yuekeduocx.driver.netUtls.MyUploadObserver; import lombok.NonNull; /** * 录音录制上传管理器 */ public class AudioRecorderUploadManager { private static final String TAG = "AudioRecorderManager"; private static AudioRecorderUploadManager INSTANCE; private final Gson gson = new Gson(); //本地缓存 private final SharedPreferences sharedPreferences; //录制工具 private final AudioRecoderUtils audioRecoderUtils = new AudioRecoderUtils(); //录制音频存放路径 private final String saveDir; //订单id private String orderId; //订单类型 private String orderType; public static AudioRecorderUploadManager getInstance(@NonNull Context context) { if (INSTANCE == null) { INSTANCE = new AudioRecorderUploadManager(context); } return INSTANCE; } private AudioRecorderUploadManager(@NonNull Context context) { sharedPreferences = context.getSharedPreferences("audioFiles", Context.MODE_PRIVATE); saveDir = getSaveDir(context); } /** * 开始录制 * * @param activity 页面 * @param orderId 订单id * @param orderType 订单类型 */ @SuppressLint("CheckResult") public void startRecord(@NonNull Activity activity, String orderId, String orderType) { if (TextUtils.isEmpty(orderId) || TextUtils.isEmpty(orderType)) { return; } if (audioRecoderUtils.isRecording()) { if (orderId.equalsIgnoreCase(this.orderId) && orderType.equalsIgnoreCase(this.orderType)) { Log.d(TAG, "now recording orderType:" + orderType + " orderId:" + orderId); return; } stopRecord(orderId, orderType); } this.orderId = orderId; this.orderType = orderType; new RxPermissions(activity).request(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe( aBoolean -> { if (!aBoolean) { Log.d(TAG, "had not permission"); return; } File outputFile = new File(saveDir, orderId + "-" + orderType + "-" + System.currentTimeMillis() + ".m4a"); audioRecoderUtils.startRecordM4a(outputFile.getAbsolutePath()); if (audioRecoderUtils.isRecording()) { saveAudioFile(orderId, orderType, audioRecoderUtils.getFilePath()); } }, Throwable::printStackTrace ); } /** * 保存录制音频文件 * * @param orderId 订单id * @param orderType 订单类型 * @param file 音频文件 */ private void saveAudioFile(String orderId, String orderType, @NonNull String file) { SharedPreferences.Editor edit = sharedPreferences.edit(); HashSet files = new HashSet<>(getFiles(orderId, orderType)); files.add(file); edit.putStringSet(getKey(orderId, orderType), files); edit.apply(); } /** * 设置录制音频文件 * * @param orderId 订单id * @param orderType 订单类型 * @param file 音频文件 */ private void setAudioFile(String orderId, String orderType, @NonNull String file) { SharedPreferences.Editor edit = sharedPreferences.edit(); HashSet files = new HashSet<>(); files.add(file); edit.putStringSet(getKey(orderId, orderType), files); edit.apply(); } /** * 获取录音文件保存路径 * * @param context 上下文 */ private String getSaveDir(@NonNull Context context) { File filesDir = context.getExternalFilesDir(null); if (filesDir == null || !filesDir.exists()) { filesDir = context.getFilesDir(); } File dir = new File(filesDir, "audio"); if (!dir.exists()) { boolean result = dir.mkdirs(); if (!result) { return filesDir.getAbsolutePath(); } } return dir.getAbsolutePath(); } /** * 获取key * * @param orderId 订单id * @param orderType 订单类型 */ private String getKey(String orderId, String orderType) { return orderType + "-" + orderId; } /** * 获取上传结果key * * @param orderId 订单id * @param orderType 订单类型 */ private String getUploadResultKey(String orderId, String orderType) { return orderType + "-" + orderId + "-UploadResult"; } /** * 结束录制 * * @param orderId 订单id * @param orderType 订单类型 */ public void stopRecord(String orderId, String orderType) { if (!TextUtils.isEmpty(orderId) && !TextUtils.isEmpty(orderType) && orderId.equalsIgnoreCase(this.orderId) && orderType.equalsIgnoreCase(this.orderType) && audioRecoderUtils.isRecording()) { audioRecoderUtils.stopRecord(); ArrayList files = new ArrayList<>(getFiles(orderId, orderType)); Collections.sort(files, String::compareTo); ArrayList uploadFiles = new ArrayList<>(); for (String file : files) { if (TextUtils.isEmpty(file)) { continue; } File audioFile = new File(file); if (!audioFile.exists()) { continue; } uploadFiles.add(audioFile); } mergeAudioFiles(orderId, orderType, uploadFiles); } } /** * 合并音频文件 * * @param orderId 订单id * @param orderType 订单类型 * @param audioFiles 音频录制文件容器 */ private void mergeAudioFiles(String orderId, String orderType, @NonNull List audioFiles) { if (audioFiles.isEmpty()) { return; } File outPut = new File(saveDir, "mergeAudio-" + orderId + "-" + orderType + "-" + System.currentTimeMillis() + ".m4a"); FFmpegUtil.contactAudios(audioFiles, outPut.getAbsolutePath(), (executionId, isSuccess, outPutFile) -> { File file = isSuccess ? new File(outPutFile) : audioFiles.get(audioFiles.size() - 1); deleteOriginAudioFile(orderId, orderType, file); uploadAudioFile(orderId, orderType, file); }); } /** * 删除原始音频文件 * * @param orderId 订单id * @param orderType 订单类型 * @param mergeAudioFile 合并的录制音频文件 */ private void deleteOriginAudioFile(String orderId, String orderType, @NonNull File mergeAudioFile) { Set files = getFiles(orderId, orderType); for (String s : files) { if (TextUtils.isEmpty(s)) { continue; } File file1 = new File(s); if (file1.exists() && !file1.equals(mergeAudioFile)) { boolean delete = file1.delete(); } } setAudioFile(orderId, orderType, mergeAudioFile.getAbsolutePath()); } /** * 上传音频文件 * * @param orderId 订单id * @param orderType 订单类型 * @param file 录制音频文件 */ private void uploadAudioFile(String orderId, String orderType, @NonNull File file) { HttpManager.getInstance().post(Api.upImage, file, new MyUploadObserver() { @Override public void success(String responseString) { Log.d(TAG, "upload success file==>" + file.getAbsolutePath() + " url==>" + responseString); saveAudioFileUploadResult(orderId, orderType, responseString); deleteAudioFiles(orderId, orderType); saveOrderAudioUrl(orderId, orderType, responseString); } @Override protected void onError(int code, String msg, String resposeString) { super.onError(code, msg, resposeString); Log.d(TAG, "upload failed file==>" + file.getAbsolutePath()); } @Override protected boolean shouldShowErrorToast() { return false; } }, 3); } /** * 设置订单录音链接 * * @param orderId 订单id * @param orderType 订单类型 * @param url 链接 */ private void saveOrderAudioUrl(String orderId, String orderType, @NonNull String url) { Map params = new HashMap<>(); params.put("orderId", orderId); params.put("orderType", orderType); params.put("fileUrl", url); HttpManager.getInstance().post(Api.updateVoice, params, new MyDefaultObserver() { @Override public void success(String responseString) { removeAudioFileUploadResult(orderId, orderType); } @Override protected boolean shouldShowErrorToast() { return false; } }, 3); } /** * 获取录制音频文件 * * @param orderId 订单id * @param orderType 订单类型 */ @NonNull private Set getFiles(String orderId, String orderType) { String key = getKey(orderId, orderType); Set set = sharedPreferences.getStringSet(key, new HashSet<>()); return set == null ? new HashSet<>() : set; } /** * 删除所有录制音频文件 * * @param orderId 订单id * @param orderType 订单类型 */ private void deleteAudioFiles(String orderId, String orderType) { Set files = getFiles(orderId, orderType); for (String s : files) { if (TextUtils.isEmpty(s)) { continue; } File file1 = new File(s); if (file1.exists()) { boolean delete = file1.delete(); } } sharedPreferences.edit().remove(getKey(orderId, orderType)).apply(); } /** * 保存录制音频文件上传地址 * * @param orderId 订单id * @param orderType 订单类型 * @param url 上传之后的文件地址 */ private void saveAudioFileUploadResult(String orderId, String orderType, @NonNull String url) { sharedPreferences.edit().putString(getUploadResultKey(orderId, orderType), url).apply(); } /** * 移除录制音频文件上传地址 * * @param orderId 订单id * @param orderType 订单类型 */ private void removeAudioFileUploadResult(String orderId, String orderType) { sharedPreferences.edit().remove(getUploadResultKey(orderId, orderType)).apply(); } }