国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android13音頻錄制適配

這篇具有很好參考價(jià)值的文章主要介紹了Android13音頻錄制適配。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

Android13音頻錄制適配

前言:

之前寫過一篇音頻錄制的文章,當(dāng)時(shí)是在Android10以下的手機(jī)可以成功錄制和播放,但是Android10及以上手機(jī)提示創(chuàng)建文件失敗,最近做過Android13的適配,索性一起把之前的錄音也適配了,記錄一下適配的過程。

1.Manifest添加Android13文件讀寫適配:

<!--存儲(chǔ)圖像或者視頻權(quán)限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" android:maxSdkVersion="32"/>

<!--錄制音頻權(quán)限-->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>

2.Android13文件讀寫權(quán)限請(qǐng)求:

private void requestBasicPermission() {
    final RxPermissions rxPermissions = new RxPermissions(this);
    StringBuilder rationaleSb = new StringBuilder();
    StringBuilder deniedSb = new StringBuilder();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        permissions = new String[]{
                Manifest.permission.READ_MEDIA_AUDIO,
                Manifest.permission.READ_MEDIA_VIDEO,
                Manifest.permission.READ_MEDIA_IMAGES,
                Manifest.permission.RECORD_AUDIO,
        };
    } else {
        permissions = new String[]{
                Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE,};
    }
    rxPermissions.requestEach(permissions).subscribe(new Observer<Permission>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {
        }

        @Override
        public void onNext(@NonNull Permission permission) {
            if (permission.granted) {
                // 用戶已經(jīng)同意該權(quán)限
                Log.d(TAG, "權(quán)限:" + permission.name + " 已開啟");
            } else if (permission.shouldShowRequestPermissionRationale) {
                // 用戶拒絕了該權(quán)限,沒有選中『不再詢問』(Never ask again),那么下次再次啟動(dòng)時(shí)。還會(huì)提示請(qǐng)求權(quán)限的對(duì)話框
                Log.d(TAG, "權(quán)限:" + permission.name + " 權(quán)限拒絕,但沒有選中 不再詢問");
                if (rationaleSb.toString().contains(StringUtils.getPermissionName(MainActivity.this,permission.name))) {
                    return;
                }
                rationaleSb.append(StringUtils.getPermissionName(MainActivity.this,permission.name));
                rationaleSb.append("、");
            } else {
                // 用戶拒絕了該權(quán)限,而且選中『不再詢問』
                Log.d(TAG, "權(quán)限:" + permission.name + " 權(quán)限拒絕,并且選中 不再詢問");
                if (deniedSb.toString().contains(StringUtils.getPermissionName(MainActivity.this,permission.name))) {
                    return;
                }
                deniedSb.append(StringUtils.getPermissionName(MainActivity.this,permission.name));
                deniedSb.append("、");
            }
        }

        @Override
        public void onError(@NonNull Throwable e) {
            Log.d(TAG, "permission  onError");
        }

        @Override
        public void onComplete() {
            if (TextUtils.isEmpty(rationaleSb) && TextUtils.isEmpty(deniedSb)) {
                Log.d(TAG, "permission.name ,權(quán)限已經(jīng)允許");
                startAudioRecord();
            } else {
                if (!TextUtils.isEmpty(deniedSb)) {
                    showTipDialog(deniedSb, 0);
                } else if (!TextUtils.isEmpty(rationaleSb)) {
                    showTipDialog(rationaleSb, 1);
                }
            }
        }
    });
}

安卓13外放不允許錄制內(nèi)置音頻嗎,Android音視頻開發(fā),音視頻,android

3.權(quán)限請(qǐng)求彈框:

    private void showPermissionDialog(StringBuilder permissionName, int permissionType) {
        if (null != mPermissionDialog && mPermissionDialog.isShowing()) {
            mPermissionDialog.dismiss();
            mPermissionDialog = null;
        }
        if (0 == permissionType) {
            mPermissionDialog = new PermissionDialog(MainActivity.this,
                    "請(qǐng)授權(quán)相關(guān)權(quán)限以確保相關(guān)功能能正常運(yùn)行:" + permissionName
                            .toString().substring(0, permissionName.length() - 1), PermissionDialog.BUTTON_RIGHT_FLAG,
                    "確定", "知道了",
                    null, this::startAudioRecord);
            mPermissionDialog.show();
        } else if (1 == permissionType) {
            mPermissionDialog = new PermissionDialog(MainActivity.this,
                    "請(qǐng)授權(quán)相關(guān)權(quán)限以確保相關(guān)功能能正常運(yùn)行:" + permissionName
                            .toString().substring(0, permissionName.length() - 1), PermissionDialog.BUTTON_RIGHT_FLAG,
                    "取消", "知道了",
                    null, this::startAudioRecord);
            mPermissionDialog.show();
        }
    }

4.完整的權(quán)限請(qǐng)求dialog類:

package com.example.audiorecorddemo.dialog;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import com.example.audiorecorddemo.R;


/**
 * 權(quán)限請(qǐng)求彈框
 */
public class PermissionDialog extends Dialog implements View.OnClickListener {
    private TextView mTvTitle, mTvTip, mTvLeftBtn, mTvRightBtn;
    private View mLineTip;

    private Window mWindow;

    private String mTileStr, mTipStr;
    private int mBtnSelectType;
    private String mLeftStr, mRightStr;

    private DialogTipLeftClickListener mLeftClickListener;
    private DialogTipRightClickListener mRightClickListener;
    // 左右button顯示
    public static final int BUTTON_BOTH_FLAG = 1;
    // 僅左button顯示
    public static final int BUTTON_LEFT_FLAG = 2;
    // 僅右button顯示
    public static final int BUTTON_RIGHT_FLAG = 3;


    private boolean needShowCheck = false;

    public PermissionDialog(Context context, String titleStr, String tipStr, int buttonType, String leftStr,
                            String rightStr, DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener) {
        super(context);
        mWindow = getWindow();
        mTileStr = titleStr;
        mTipStr = tipStr;
        mBtnSelectType = buttonType;
        mLeftStr = leftStr;
        mRightStr = rightStr;
        mLeftClickListener = leftClickListener;
        mRightClickListener = rightClickListener;
    }

    public PermissionDialog(Context context, String tipStr, int buttonType, String leftStr,
                            String rightStr, DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener) {
        this(context, "", tipStr, buttonType, leftStr, rightStr, leftClickListener, rightClickListener);
    }

    public PermissionDialog(Context context, String tipStr, String leftStr, String rightStr,
                            DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener) {
        this(context, "", tipStr, BUTTON_BOTH_FLAG, leftStr, rightStr, leftClickListener, rightClickListener);
    }

    public PermissionDialog(Context context, String tipStr, String rightStr,
                            DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener) {
        this(context, "", tipStr, BUTTON_BOTH_FLAG, "", rightStr, leftClickListener, rightClickListener);
    }

    public PermissionDialog(Context context, String tipStr, DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener) {
        this(context, "", tipStr, BUTTON_BOTH_FLAG, "", "", leftClickListener, rightClickListener);
    }

    public PermissionDialog(Context context, String titleStr, String tipStr, int buttonType, String leftStr,
                            String rightStr, DialogTipLeftClickListener leftClickListener,
                            DialogTipRightClickListener rightClickListener, boolean needShowCheck) {
        this(context, titleStr, tipStr, buttonType, leftStr, rightStr, leftClickListener, rightClickListener);
        this.needShowCheck = needShowCheck;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_permiss_dialog);
        setCancelable(false);
        initView();
    }

    private void initView() {
        mTvTitle = findViewById(R.id.tv_dialog_corner_title);
        mTvTip = findViewById(R.id.tv_dialog_corner_tip);
        mLineTip = findViewById(R.id.view_dialog_corner_line);
        mTvLeftBtn = findViewById(R.id.tv_dialog_corner_left);
        mTvRightBtn = findViewById(R.id.tv_dialog_corner_right);


        // 初始化監(jiān)聽
        initListener();
        // 初始化數(shù)據(jù)
        initData();
    }

    private void initData() {
        // title
        if (!TextUtils.isEmpty(mTileStr)) {
            mTvTitle.setText(mTileStr);
            mTvTitle.setVisibility(View.VISIBLE);
        } else {
            mTvTitle.setVisibility(View.GONE);
        }
        // 提示
        if (!TextUtils.isEmpty(mTipStr)) {
            mTvTip.setText(mTipStr);
            mTvTip.setVisibility(View.VISIBLE);
        } else {
            mTvTip.setVisibility(View.GONE);
        }
        // 左邊按鈕
        if (!TextUtils.isEmpty(mLeftStr)) {
            mTvLeftBtn.setText(mLeftStr);
        }
        // 右邊按鈕
        if (!TextUtils.isEmpty(mRightStr)) {
            mTvRightBtn.setText(mRightStr);
        }
        // 按鈕狀態(tài)
        setButtonSelect(mBtnSelectType);

    }

    private void initListener() {
        mTvLeftBtn.setOnClickListener(this);
        mTvRightBtn.setOnClickListener(this);
    }

    private void setButtonSelect(int selectType) {
        if (mTvLeftBtn == null || mTvRightBtn == null || mLineTip == null) {
            return;
        }
        switch (selectType) {
            case BUTTON_LEFT_FLAG:
                mTvLeftBtn.setVisibility(View.VISIBLE);
                mTvRightBtn.setVisibility(View.GONE);
                mLineTip.setVisibility(View.GONE);
                break;
            case BUTTON_RIGHT_FLAG:
                mTvLeftBtn.setVisibility(View.GONE);
                mTvRightBtn.setVisibility(View.VISIBLE);
                mLineTip.setVisibility(View.GONE);
                break;
            case BUTTON_BOTH_FLAG:
            default:
                mTvLeftBtn.setVisibility(View.VISIBLE);
                mTvRightBtn.setVisibility(View.VISIBLE);
                mLineTip.setVisibility(View.VISIBLE);
                break;
        }
    }

    @Override
    public void onClick(View view) {
        int viewId = view.getId();
        if (R.id.tv_dialog_corner_left == viewId) {
            if (mLeftClickListener != null) {
                mLeftClickListener.onTipLeftClick();
            }
            if (isShowing()) {
                dismiss();
            }
        } else if (R.id.tv_dialog_corner_right == viewId) {
            if (mRightClickListener != null) {
                mRightClickListener.onTipRightClick();
            }
            if (isShowing()) {
                dismiss();
            }
        }
    }

    public interface DialogTipLeftClickListener {
        void onTipLeftClick();
    }

    public interface DialogTipRightClickListener {
        void onTipRightClick();
    }
}

5.文件管理類:

package com.example.audiorecorddemo.utils;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.example.audiorecorddemo.app.MyApp;

import java.io.File;

/**
 * @author: njb
 * @date: 2023/8/15 17:13
 * @desc:
 */
public class FileManager {
    // 媒體模塊根目錄
    private static final String SAVE_MEDIA_ROOT_DIR = Environment.DIRECTORY_DCIM;
    // 媒體模塊存儲(chǔ)路徑
    private static final String SAVE_MEDIA_DIR = SAVE_MEDIA_ROOT_DIR + "/RecordManager";
    private static final String SAVE_MEDIA_PHOTO_DIR = SAVE_MEDIA_DIR + "/photo";
    private static final String SAVE_MEDIA_AUDIO_DIR = SAVE_MEDIA_DIR + "/audio";
    private static final String SAVE_MEDIA_VIDEO_DIR = SAVE_MEDIA_DIR + "/video";
    // JPG后綴
    public static final String JPG_SUFFIX = ".jpg";
    // PNG后綴
    public static final String PNG_SUFFIX = ".png";
    // MP4后綴
    public static final String MP4_SUFFIX = ".mp4";

    /**
     * 保存圖片到系統(tǒng)相冊
     *
     * @param context
     * @param file
     */
    public static String saveImage(Context context, File file) {
        ContentResolver localContentResolver = context.getContentResolver();
        ContentValues localContentValues = getImageContentValues(context, file, System.currentTimeMillis());
        localContentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, localContentValues);

        Intent localIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        final Uri localUri = Uri.fromFile(file);
        localIntent.setData(localUri);
        context.sendBroadcast(localIntent);
        return file.getAbsolutePath();
    }

    public static ContentValues getImageContentValues(Context paramContext, File paramFile, long paramLong) {
        ContentValues localContentValues = new ContentValues();
        localContentValues.put("title", paramFile.getName());
        localContentValues.put("_display_name", paramFile.getName());
        localContentValues.put("mime_type", "image/jpeg");
        localContentValues.put("datetaken", Long.valueOf(paramLong));
        localContentValues.put("date_modified", Long.valueOf(paramLong));
        localContentValues.put("date_added", Long.valueOf(paramLong));
        localContentValues.put("orientation", Integer.valueOf(0));
        localContentValues.put("_data", paramFile.getAbsolutePath());
        localContentValues.put("_size", Long.valueOf(paramFile.length()));
        return localContentValues;
    }

    /**
     * 獲取App存儲(chǔ)根目錄
     */
    public static String getAppRootDir() {
        String path = getStorageRootDir();
        FileUtil.createOrExistsDir(path);
        return path;
    }

    /**
     * 獲取文件存儲(chǔ)根目錄
     */
    public static String getStorageRootDir() {
        File filePath = MyApp.getInstance().getExternalFilesDir("");
        String path;
        if (filePath != null) {
            path = filePath.getAbsolutePath();
        } else {
            path = MyApp.getInstance().getFilesDir().getAbsolutePath();
        }
        return path;
    }

    /**
     * 圖片地址
     */
    public static String getCameraPhotoPath() {
        return getFolderDirPath(SAVE_MEDIA_PHOTO_DIR);
    }



    /**
     * 視頻地址
     */
    public static String getCameraVideoPath() {
        return getFolderDirPath(SAVE_MEDIA_VIDEO_DIR);
    }

    public static String getCameraAudioPath() {
        return getSaveDir(SAVE_MEDIA_AUDIO_DIR);
    }

    public static String getFolderDirPath(String dstDirPathToCreate) {
        File dstFileDir = new File(Environment.getExternalStorageDirectory(), dstDirPathToCreate);
        if (!dstFileDir.exists() && !dstFileDir.mkdirs()) {
            Log.e("Failed to create file", dstDirPathToCreate);
            return null;
        }
        return dstFileDir.getAbsolutePath();
    }

    /**
     * 獲取具體模塊存儲(chǔ)目錄
     */
    public static String getSaveDir(@NonNull String directory) {
        String path = "";
        if (TextUtils.isEmpty(directory) || "/".equals(directory)) {
            path = "";
        } else if (directory.startsWith("/")) {
            path = directory;
        } else {
            path = "/" + directory;
        }
        path = getAppRootDir() + path;
        FileUtil.createOrExistsDir(path);
        return path;
    }
}

6.錄音方法:

主要就是文件的生成和創(chuàng)建,由于Android10以后不能隨意創(chuàng)建私有文件,所以生成的audio文件放到系統(tǒng)的DCIM、MUSIC、Download目錄下,并且是項(xiàng)目自己包名下:

安卓13外放不允許錄制內(nèi)置音頻嗎,Android音視頻開發(fā),音視頻,android

public void startRecord(WeakReference<Context> weakReference) {
    this.weakReference = weakReference;
    LogUtils.e(TAG, "開始錄音");
    //生成PCM文件
    String fileName = DateFormat.format("yyyy-MMdd-HHmmss", Calendar.getInstance(Locale.getDefault())) + ".pcm";
    File file = new File(FileManager.getCameraAudioPath(), "/ACC音頻/");
    if (!file.exists()) {
        file.mkdir();
    }
    String audioSaveDir = file.getAbsolutePath();
    LogUtils.e(TAG, audioSaveDir);
    recordFile = new File(audioSaveDir, fileName);
    LogUtils.e(TAG, "生成文件" + recordFile);
    //如果存在,就先刪除再創(chuàng)建
    if (recordFile.exists()) {
        recordFile.delete();
        LogUtils.e(TAG, "刪除文件");
    }
    try {
        recordFile.createNewFile();
        LogUtils.e(TAG, "創(chuàng)建文件");
    } catch (IOException e) {
        LogUtils.e(TAG, "未能創(chuàng)建");
        throw new IllegalStateException("未能創(chuàng)建" + recordFile.toString());
    }
    if (filePathList.size() == 2) {
        filePathList.clear();
    }
    filePathList.add(recordFile);
    try {
        //輸出流
        OutputStream os = new FileOutputStream(recordFile);
        BufferedOutputStream bos = new BufferedOutputStream(os);
        DataOutputStream dos = new DataOutputStream(bos);
        int bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, AudioFormat.CHANNEL_IN_STEREO, audioEncoding);
        if (ActivityCompat.checkSelfPermission(weakReference.get(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {

            return;
        }
       audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, AudioFormat.CHANNEL_IN_STEREO, audioEncoding, bufferSize);

        short[] buffer = new short[bufferSize];
        audioRecord.startRecording();
        LogUtils.e(TAG, "開始錄音");
        isRecording = true;
        while (isRecording) {
            int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
            for (int i = 0; i < bufferReadResult; i++) {
                dos.writeShort(buffer[i]);
            }
        }
        audioRecord.stop();
        dos.close();
    } catch (Exception e) {
        e.printStackTrace();
        LogUtils.e(TAG, "錄音失敗");
        showToast("錄音失敗");
    }
}

7.啟動(dòng)錄音:

btnRecord.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        buttonEnabled(false, true, true);
        startAudioRecord();
    }
});

8.停止錄音:

btnStop.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                buttonEnabled(true, true, false);
                mHandler.post(() -> Toast.makeText(MainActivity.this, "停止錄音", Toast.LENGTH_LONG).show());
                AudioManagerUtils.getInstance().pauseAudio();
            }
        });
    }
});

9.開始播放:

btnPlay.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        AudioManagerUtils.getInstance().playPcm(true);
        buttonEnabled(false, false, true);
    }
});

10.完整的測試代碼:

package com.example.audiorecorddemo;

import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.blankj.utilcode.util.LogUtils;
import com.example.audiorecorddemo.dialog.PermissionDialog;
import com.example.audiorecorddemo.utils.AudioManagerUtils;
import com.example.audiorecorddemo.utils.StringUtils;
import com.tbruyelle.rxpermissions3.Permission;
import com.tbruyelle.rxpermissions3.RxPermissions;

import java.lang.ref.WeakReference;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;

public class MainActivity extends AppCompatActivity {
    private Button btnRecord, btnPlay, btnStop;
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            3, 5,
            1, TimeUnit.MINUTES,
            new LinkedBlockingDeque<>(10),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());
    private String[] permissions = null;
    private PermissionDialog mPermissionDialog = null;
    /**
     * 被用戶拒絕的權(quán)限列表
     */
    private static final int MY_PERMISSIONS_REQUEST = 1001;
    private final String TAG = MainActivity.this.getClass().getSimpleName();
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestBasicPermission();
        initView();
    }

    private void requestBasicPermission() {
        final RxPermissions rxPermissions = new RxPermissions(this);
        StringBuilder rationaleSb = new StringBuilder();
        StringBuilder deniedSb = new StringBuilder();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            permissions = new String[]{
                    Manifest.permission.READ_MEDIA_AUDIO,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.RECORD_AUDIO,
            };
        } else {
            permissions = new String[]{
                    Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE,};
        }
        rxPermissions.requestEach(permissions).subscribe(new Observer<Permission>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
            }

            @Override
            public void onNext(@NonNull Permission permission) {
                if (permission.granted) {
                    LogUtils.d(TAG, "權(quán)限:" + permission.name + " 已開啟");
                } else if (permission.shouldShowRequestPermissionRationale) {
                    LogUtils.d(TAG, "權(quán)限:" + permission.name + " 權(quán)限拒絕,但沒有選中 不再詢問");
                    if (rationaleSb.toString().contains(StringUtils.getPermissionName(MainActivity.this,permission.name))) {
                        return;
                    }
                    rationaleSb.append(StringUtils.getPermissionName(MainActivity.this,permission.name));
                    rationaleSb.append("、");
                } else {
                    LogUtils.d(TAG, "權(quán)限:" + permission.name + " 權(quán)限拒絕,并且選中 不再詢問");
                    if (deniedSb.toString().contains(StringUtils.getPermissionName(MainActivity.this,permission.name))) {
                        return;
                    }
                    deniedSb.append(StringUtils.getPermissionName(MainActivity.this,permission.name));
                    deniedSb.append("、");
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                LogUtils.d(TAG, "permission  onError");
            }

            @Override
            public void onComplete() {
                if (TextUtils.isEmpty(rationaleSb) && TextUtils.isEmpty(deniedSb)) {
                    LogUtils.d(TAG, "permission.name ,權(quán)限已經(jīng)允許");
                    startAudioRecord();
                } else {
                    if (!TextUtils.isEmpty(deniedSb)) {
                        showPermissionDialog(deniedSb, 0);
                    } else if (!TextUtils.isEmpty(rationaleSb)) {
                        showPermissionDialog(rationaleSb, 1);
                    }
                }
            }
        });
    }

    private void showPermissionDialog(StringBuilder permissionName, int permissionType) {
        if (null != mPermissionDialog && mPermissionDialog.isShowing()) {
            mPermissionDialog.dismiss();
            mPermissionDialog = null;
        }
        if (0 == permissionType) {
            mPermissionDialog = new PermissionDialog(MainActivity.this,
                    "請(qǐng)授權(quán)相關(guān)權(quán)限以確保相關(guān)功能能正常運(yùn)行:" + permissionName
                            .toString().substring(0, permissionName.length() - 1), PermissionDialog.BUTTON_RIGHT_FLAG,
                    "確定", "知道了",
                    null, this::startAudioRecord);
            mPermissionDialog.show();
        } else if (1 == permissionType) {
            mPermissionDialog = new PermissionDialog(MainActivity.this,
                    "請(qǐng)授權(quán)相關(guān)權(quán)限以確保相關(guān)功能能正常運(yùn)行:" + permissionName
                            .toString().substring(0, permissionName.length() - 1), PermissionDialog.BUTTON_RIGHT_FLAG,
                    "取消", "知道了",
                    null, this::startAudioRecord);
            mPermissionDialog.show();
        }
    }

    private void initView() {
        btnRecord = findViewById(R.id.btn_record);
        btnPlay = findViewById(R.id.btn_play);
        btnStop = findViewById(R.id.btn_stop);

        btnRecord.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buttonEnabled(false, true, true);
                startAudioRecord();
            }
        });

        btnPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AudioManagerUtils.getInstance().playPcm(true);
                buttonEnabled(false, false, true);
            }
        });
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        buttonEnabled(true, true, false);
                        mHandler.post(() -> Toast.makeText(MainActivity.this, "停止錄音", Toast.LENGTH_LONG).show());
                        AudioManagerUtils.getInstance().pauseAudio();
                    }
                });
            }
        });
    }

    private void startAudioRecord() {
        threadPoolExecutor.execute(() -> {
            mHandler.post(() -> Toast.makeText(MainActivity.this, "開始錄音", Toast.LENGTH_LONG).show());
            AudioManagerUtils.getInstance().startRecord(new WeakReference<>(getApplicationContext()));
        });
    }

    private void buttonEnabled(boolean record, boolean play, boolean stop) {
        btnRecord.setEnabled(record);
        btnPlay.setEnabled(play);
        btnStop.setEnabled(stop);
    }

    @Override
    protected void onStop() {
        super.onStop();
        AudioManagerUtils.getInstance().pauseAudio();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        AudioManagerUtils.getInstance().releaseAudio();
    }

}

11.實(shí)現(xiàn)的效果如下:

安卓13外放不允許錄制內(nèi)置音頻嗎,Android音視頻開發(fā),音視頻,android

12.總結(jié):

  • 以上就是今天的內(nèi)容,錄制音頻時(shí)適配Android13.
  • Android13文件讀寫細(xì)分為三個(gè)權(quán)限 READ_MEDIA_AUDIO、READ_MEDIA_VIDEO、READ_MEDIA_IMAGES.
  • Android10以上文件創(chuàng)建和生成需要在公共目錄,不能隨意創(chuàng)建和讀寫.

13.項(xiàng)目的源碼地址:

https://gitee.com/jackning_admin/audio-record-demo-a文章來源地址http://www.zghlxwxcb.cn/news/detail-831396.html

到了這里,關(guān)于Android13音頻錄制適配的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android錄制音頻并使用ijkplayer播放

    在使用AudioRecorder時(shí),需要了解采樣率、頻道配置和PCM音頻格式數(shù)據(jù)的相關(guān)知識(shí); PCM:音頻的原始數(shù)據(jù)(AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT、AudioFormat.ENCODING_PCM_FLOAT等等);不同的PCM代表不同的位深 采樣率:錄音設(shè)備在單位時(shí)間內(nèi)對(duì)模擬信號(hào)采樣的多少,采樣頻

    2023年04月09日
    瀏覽(24)
  • 「專題速遞」回聲消除算法、低功耗音頻、座艙音頻系統(tǒng)、智能音頻技術(shù)、低延時(shí)音效算法、手機(jī)外放增強(qiáng)算法...

    「專題速遞」回聲消除算法、低功耗音頻、座艙音頻系統(tǒng)、智能音頻技術(shù)、低延時(shí)音效算法、手機(jī)外放增強(qiáng)算法...

    隨著多媒體和通信網(wǎng)絡(luò)技術(shù)的持續(xù)升級(jí),以及新型音視頻應(yīng)用場景的不斷涌現(xiàn),音頻處理技術(shù)正朝著更加智能化和沉浸化的方向迅猛發(fā)展。人們對(duì)音頻聽覺體驗(yàn)的要求也逐漸提高,無論是在何種場景下,都期望獲得更加清晰的聲音,并感受到身臨其境的沉浸感。 在數(shù)字時(shí)代,

    2024年02月08日
    瀏覽(21)
  • Android多媒體功能開發(fā)(11)——使用AudioRecord類錄制音頻

    Android多媒體功能開發(fā)(11)——使用AudioRecord類錄制音頻

    AudioRecord類優(yōu)點(diǎn)是能錄制到緩沖區(qū),能夠?qū)崿F(xiàn)邊錄邊播(AudioRecord + AudioTrack)以及對(duì)音頻的實(shí)時(shí)處理(如QQ電話)。缺點(diǎn)是輸出是PCM格式的原始采集數(shù)據(jù),如果直接保存成音頻文件,不能夠被播放器播放,所以必須用代碼實(shí)現(xiàn)數(shù)據(jù)編碼以及壓縮。 使用AudioRecord錄音的基本步驟是

    2023年04月09日
    瀏覽(24)
  • [SM6225][Android13]user版本默認(rèn)允許root和remount

    芯片: ?高通SM6225 版本: ?Android?13 kernel: ?msm-5.15 ? ? ? ?剛剛從Framework踏入性能的小殿堂,User版本默認(rèn)是不會(huì)開啟root權(quán)限的,而且一般調(diào)試需要設(shè)置一下CPU GPU DDR performance模式或者修改一些schedule util等調(diào)核調(diào)頻節(jié)點(diǎn)去對(duì)比復(fù)測,userdebug版本的話本身整機(jī)性能就比user卡很多,

    2024年02月09日
    瀏覽(43)
  • Android 13 適配指南

    Android 13 適配指南

    是的,你沒看錯(cuò),現(xiàn)在就要帶你適配 Android13 。 2022 的Google I/O 發(fā)布了 Android 13 beta 2 和 Android 13 Beta 1 國內(nèi)廠商的設(shè)備支持列表,雖然按照慣例, Android 13 應(yīng)該是年末才發(fā)布正式版,但是相信有的開發(fā)者已經(jīng)收到了平臺(tái)的 Android13 的適配要求,所以本篇也是結(jié)合 Oppo 的 Android 1

    2024年02月05日
    瀏覽(30)
  • Android(6-13)適配

    Android(6-13)適配

    Android 6 1、運(yùn)行時(shí)權(quán)限 android6.0以前,我們把a(bǔ)pp需要用到的權(quán)限全部羅列在Manifest清單文件中。安裝app時(shí)android系統(tǒng)會(huì)詢問用戶是否授予這些權(quán)限,拒絕后則無法安裝app。如果授予,則安裝app,之后無法修改授予狀態(tài)。 android6.0將權(quán)限分為普通權(quán)限(不涉及用戶隱私和安全)和危

    2024年02月02日
    瀏覽(23)
  • Android 13 變更及適配攻略

    Android 13 變更及適配攻略

    首先將我們項(xiàng)目中的 targetSdkVersion 和 compileSdkVersion 升至 33。 1.通知受限 對(duì)新安裝的應(yīng)用的影響: 如果用戶在搭載 Android 13 或更高版本的設(shè)備上安裝您的應(yīng)用,應(yīng)用的通知默認(rèn)處于關(guān)閉狀態(tài)。在您請(qǐng)求新的權(quán)限且用戶向您的應(yīng)用授予該權(quán)限之前,您的應(yīng)用都將無法發(fā)送通知。

    2024年02月03日
    瀏覽(20)
  • uniapp音頻組件,適配ios,Android

    uniapp音頻組件,適配ios,Android

    有個(gè)需求是需要有音頻的時(shí)長和拖動(dòng)進(jìn)度,我對(duì)音頻使用只停留在使用audio標(biāo)簽,在uniapp插件市場未找到適合的組件,在通過百度只找到下面的組件,了解使用uniapp簡單音頻組件上提到的音頻組件后進(jìn)行優(yōu)化如下: 1.不能在更新視頻鏈接后更新音頻組件的相關(guān)信息,使用了w

    2024年02月16日
    瀏覽(21)
  • android8、android13自適應(yīng)圖標(biāo)適配

    android8、android13自適應(yīng)圖標(biāo)適配

    前言:為了解決應(yīng)用圖標(biāo)在不同android手機(jī)上的外觀樣式問題,google官方在android8和android13兩個(gè)版本做了變更(這2個(gè)版本都提供了向下兼容),下文介紹適配方法以及 注意事項(xiàng)(此處有彩蛋) 。 一、android8(API27)適配 1、找到資源文件夾:mipmap-anydpi-v26(若舊的as里沒有默認(rèn)生成,

    2024年02月09日
    瀏覽(147)
  • Android13適配所有文件管理權(quán)限

    Android13適配所有文件管理權(quán)限

    很早之前在Android11上面就適配過所有文件管理權(quán)限,這次是海外版升級(jí)到Android13,由于選擇相冊用的是第三方庫,組內(nèi)的同事沒有上架Google的經(jīng)驗(yàn)直接就提交代碼,雖然功能沒有問題,但是上架的時(shí)候被打回了,于是記錄一下適配工作. 絕大多數(shù)需要共享存儲(chǔ)空間訪問權(quán)限的

    2024年01月22日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包