android异或加密

2020-07-04  本文已影响0人  星_025f
异或加密 参考文档:https://www.cnblogs.com/whoislcj/p/5944917.html
音频播放 参考文档:https://www.jianshu.com/p/74fa2b1ac61f
什么是异或加密?

异或运算中,如果某个字符(或数值)x 与 一个数值m 进行异或运算得到y,则再用y 与 m 进行异或运算就可以还原为 x ,因此应用这个原理可以实现数据的加密解密功能。

异或运算使用场景?

两个变量的互换(不借助第三个变量)

数据的简单加密解密

异或加密解密实现?

1.固定key的方式

这种方式加密解密 算法一样

public byte[] encrypt(byte[] bytes) {

        if (bytes == null) {

            return null;

        }

        int len = bytes.length;

        int key = 0x12;

        for (int i = 0; i < len; i++) {

            bytes[i] ^= key;

        }

        return bytes;

    }

测试加密解密

//加密

byte[] bytes = encrypt("whoislcj".getBytes());

//加密

String str1 =newString(encrypt(bytes));//解密

2.不固定key的方式

加密实现

publicbyte[] encrypt(byte[] bytes) {

        if(bytes ==null) {

            returnnull;

        }

        intlen = bytes.length;

        intkey = 0x12;

        for(inti = 0; i < len; i++) {

            bytes[i] = (byte) (bytes[i] ^ key);

            key = bytes[i];

        }

        return bytes;

    }

解密实现

publicbyte[] decrypt(byte[] bytes) {

        if(bytes ==null) {

            returnnull;

        }

        intlen = bytes.length;

        intkey = 0x12;

        for(inti = len - 1; i > 0; i--) {

            bytes[i] = (byte) (bytes[i] ^ bytes[i - 1]);

        }

        bytes[0] = (byte) (bytes[0] ^ key);

        return bytes;

    }

测试

byte[] bytes = encrypt("whoislcj".getBytes());//加密

String str1 =newString(decrypt(bytes));//解密
运用

1.文本加密

//写入文件
public static void setFileContent(String path,String value,boolean append){

boolean isFirst =false;

    File file =new File(path);

    if(!file.exists()){

try {

file.createNewFile();

        }catch (IOException e) {

e.printStackTrace();

        }

isFirst =true;

    }

try {

FileOutputStream outputStream =new FileOutputStream(path,append);

        //文件第一次创建 写入加密头部信息

        if(isFirst){
         //读取头部信息判断文件被加密
          byte[] titleByte = {'a','b','c','d','e','f'};

            outputStream.write(titleByte);

        }

byte[] valueArray = value.getBytes();

        byte[] result =encrypt(valueArray);

        outputStream.write(result);

        outputStream.close();

    }catch (FileNotFoundException e) {

e.printStackTrace();

    }catch (IOException e) {

e.printStackTrace();

    }

}
//读取文件
public static String  getFileMag(String filePath){
        StringBuffer stringBuffer = new StringBuffer();
        byte[] bytes = new byte[1024];
        byte[] bytes2;
        try {
            FileInputStream inputStream = new FileInputStream(filePath);
            int index;
            while ((index = inputStream.read(bytes)) != -1) {
               //如果数据比较大,第一次读取去除前面加密的字节
                bytes2 = new byte[index - 6];
                System.arraycopy(bytes, 6, bytes2, 0,index - 6);
                stringBuffer.append(new String(encrypt(bytes2)));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }

 public static byte[] encrypt(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
       byte[] titleByte = {'a','b','c','d','e','f'};
        int len = bytes.length;
        Log.e(TAG, "encrypt: len == " + len);
        for (int i = 0; i < len; i++) {
           /*
          //使用位置进行判断加密,如果多次往同一个文件中写数据会导致数据错乱。123  456分两次写。4写进去下标为1,读出来下标为2 
          if(i % 2 == 0){
                bytes[i] ^= titleByte[1];
            }else{
                bytes[i] ^= titleByte[0];
            }*/
            int ii =  bytes[i];
            bytes[i] ^= titleByte[0];
        }
        return bytes;
    }

2.图片加密

1.SurfaceView + camera进行拍照。
2.onPictureTaken回调中对data数据进行加密保存
3.读取文件存在byte数组,解密后转化成bitmap。显示在imageview



import android.hardware.Camera;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PictureCallback {

    private SurfaceView surface_view;
    private SurfaceHolder surfaceHolder;
    private Camera camera;

    private static String TAG = "CameraActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);


        surface_view = findViewById(R.id.surface_view);


        surfaceHolder = surface_view.getHolder();

        surfaceHolder.addCallback(this);

    }


    public void take_photo(View view){

        if (camera != null) {
            camera.takePicture(null, null,this);
        }

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPictureSize(1920,1080);


       // camera.setDisplayOrientation(90);
        try {
            camera.setPreviewDisplay(surfaceHolder);
            camera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {

                }
            });

            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        if(camera != null){
            camera.release();
            camera = null;
        }
    }

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        Log.e(TAG, "onPictureTaken: " + data.length);

        String photoPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/11.png";

        File photoFile = new File(photoPath);
        if(photoFile.exists()){
            photoFile.delete();
        }
        try {
            photoFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }


        try {
            FileOutputStream outputStream = new FileOutputStream(photoFile);
            outputStream.write(encrypt2(data));
            //outputStream.write(data);

            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    public static byte[] encrypt2(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        byte[] titleByte = {'a','b','c','d','e','f'};
        int len = bytes.length;
        Log.e(TAG, "encrypt: len == " + len);
        for (int i = 0; i < len; i++) {
            bytes[i] ^= titleByte[0];
        }
        return bytes;
    }
}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraActivity">

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <Button
        android:onClick="take_photo"
        android:text="拍照"
        android:layout_marginBottom="20dp"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


</RelativeLayout>
public void look_camera(View view){
        String photoPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/11.png";
        final byte[] aaa = imageToByteArray(photoPath);

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = BitmapFactory.decodeByteArray(aaa,0,aaa.length);
                iv_image.setImageBitmap(bitmap);
            }
        });


    }
 public static byte[] imageToByteArray(String path) {
        // 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
        byte[] data = null;
        // 读取图片字节数组
        try {

            InputStream in = new FileInputStream(path);

            data = new byte[in.available()];

            in.read(data);


            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return encrypt2(data);
    }

3.音频加密

1.采用AudioRecord录制文件的pcm裸数据
2.增加头部信息,加密编译成MP4文件。(头部信息也要加密转换,不能还是能够播放,有杂音但是能听清)
3.使用audioTrack读取文件byte数据,直接write播放

1.录制
public class RecordService extends Service {


    MainActivity mainActivity;
    // 音频获取源
    private int audioSource = MediaRecorder.AudioSource.MIC;
    // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
    private static int sampleRateInHz = 44100;
    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
    private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
    private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    // 缓冲区字节大小
    private int bufferSizeInBytes = 0;
    private AudioRecord audioRecord;
    public static boolean isRecord = false;// 设置正在录制的状态
    public static boolean isAVRecord = false;// 判断视频是否正在录制

    private String TAG = "RecordService";


    private File file;
    private String audioFile;
    private String newAudioFile;
    private File[] files;//获取路劲文件下的所有文件数组
    private List<String> fileDatas;//存储所有文件的路劲名
    private List<String> fileNames;//存储所有文件的文件名

    private String rawFile;
    private String rawName;
    private String rawNameRes;
    private Timer timer, setTvTime;
    private String audioName;
    private String audioFile1;
    //private ToneGenerator toneGenerator;

    @Override
    @Deprecated
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);


    }


    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.

        Log.d(TAG, "onBind: ");
        return new MyBinder();
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        startRecorder();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        super.onDestroy();
        close();
        //把没有转换的裸文件转换
        getDatas();
        rawToWav();
        isAVRecord = false;
    }

    public void setActivity(MainActivity mainActivity) {

        this.mainActivity = mainActivity;

    }


    public class MyBinder extends Binder {

        public RecordService getService() {

            return RecordService.this;

        }

    }


    /**
     * 开始录制操作
     */
    public void startRecorder() {
        Log.e(TAG, "wfx ---->> startRecorder");
        createNewFile();
        creatAudioRecord();
        audioRecord.startRecording();
        // 让录制状态为true
        isRecord = true;
        // 开启音频文件写入线程
        new Thread(new AudioRecordThread()).start();
        //创建一个timer类来实现录制时间实现
        setTvTime = new Timer();
        setTvTime.schedule(new TimerTask() {
            long duration = 0;
            @Override
            public void run() {
                duration += 1000;
                if(MainActivity.isVisible){
                    Message message = new Message();
                    message.obj = duration;
                    message.what = 333;
                    MainActivity.handler.sendMessage(message);
                }

            }
        }, 1000, 1000);
    }

    /**
     * 停止录音操作
     */
    public void stopRecorder() {
        close();
    }

    public void close() {
        if (audioRecord != null) {         
            if (setTvTime != null) {
                setTvTime.cancel();
                setTvTime = null;
            }
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
            if (audioRecord != null) {
                isRecord = false;//停止文件写入
                audioRecord.stop();
                audioRecord.release();//释放资源
                audioRecord = null;
                //把没有转换的裸文件转换
                getDatas();
                rawToWav();
            }
        }
    }


    public void creatAudioRecord() {
        if (audioRecord != null) {
            stopRecorder();
        }
        // 获得缓冲区字节大小
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
                channelConfig, audioFormat);
        // 创建AudioRecord对象
        audioRecord = new AudioRecord(audioSource, sampleRateInHz,
                channelConfig, audioFormat, bufferSizeInBytes);
    }


    class AudioRecordThread implements Runnable {
        @Override
        public void run() {
            writeDateTOFile();//往文件中写入裸数据
        }
    }

    FileOutputStream fos = null;
    /**
     * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
     * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,
     * 比如你要做一个爱说话的TOM
     * 在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
     */
    private void writeDateTOFile() {
        MyApplication.recordingTime = MyApplication.recordingTimeSharedPreferences.getLong("recordingTime", 5 * 60 * 1000);
        audioFile = getAudioFile();//先创建一个存储裸数据的文件
        fos = null;
        try {
            file = new File(audioFile);
            fos = new FileOutputStream(file);// 建立一个可存取字节的文件
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    fos.close();// 关闭写入流
                    audioFile = getAudioFile();//新建一个文件保存裸数据
                    file = new File(audioFile);
                    //Log.d("print", "run: 创建文件");
                    fos = new FileOutputStream(file);// 建立一个可存取字节的文件
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, MyApplication.recordingTime, MyApplication.recordingTime);
       // }, 60 * 1000, 60 * 1000);
        while (isRecord) {
            // new一个byte数组用来存一些字节数据,大小为缓冲区大小
            byte[] audiodata = new byte[bufferSizeInBytes];
            int readsize = 0;
            //往文件中写入数据
            readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
            if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
                try {
                    fos.write(encrypt2(audiodata));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
    // 这里得到可播放的音频文件
    private void copyWaveFile(String inFilename, String outFilename) {
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
        long longSampleRate = sampleRateInHz;
        int channels = 2;
        long byteRate = 16 * sampleRateInHz * channels / 8;
        byte[] data = new byte[bufferSizeInBytes];
        try {
            in = new FileInputStream(inFilename);
            out = new FileOutputStream(outFilename);
            totalAudioLen = in.getChannel().size();
            totalDataLen = totalAudioLen + 36;
            WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                    longSampleRate, channels, byteRate);
            while (in.read(data) != -1) {
              //  out.write(encrypt2(data));
                out.write(data);
            }
            in.close();
            out.close();
            //删除裸数据文件
            File file = new File(inFilename);
            file.delete();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。每种格式的文件都有
     * 自己特有的头文件。
     */
    private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
                                     long totalDataLen, long longSampleRate, int channels, long byteRate)
            throws IOException {
        Log.e(TAG, "WriteWaveFileHeader: totalAudioLen == " + totalAudioLen + "  totalDataLen == " + totalDataLen + "  longSampleRate" + longSampleRate
         +  "  channels== " + channels +  "  byteRate == " + byteRate);
        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (2 * 16 / 8); // block align
        header[33] = 0;
        header[34] = 16; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        out.write(encrypt2(header), 0, 44);
      // out.write(header, 0, 44);
    }
    /**
     * @return:得到裸数据文件
     */
    private String getAudioFile() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_hh-mm-ss");//定义时间格式
        String time = format.format(new Date());//把当前时间转化为指定格式
        audioName = MyApplication.getnowTimeFileName() + "/"  + getPoliceNum() + "_" +time ;
        audioFile1 = audioName + CameraSettings.RECROD_DEFAULT.FILE_RAW;
        

        return audioFile1;
    }


    /**
     * @return:得到新文件
     */
    private String getNewAudioFile(String name) {
        String newAudioFile = MyApplication.getnowTimeFileName() +  "/" + name + ".wav";
        return newAudioFile;
    }

    /**
     * 得到目录下所有文件
     */
    private List<File> getAllFile(String name) {
        List<File> fileList = new ArrayList<>();
        File parentFile = new File(name);
        File[] tempList = parentFile.listFiles();
        for (int i = 0; i < tempList.length; i++) {
            if(tempList[i].isDirectory()){
                fileList.add(tempList[i]);
            }
        }
        return fileList;

    }

    /**
     * 获取路径下的所有.raw文件
     */
    public void getDatas() {
       // String fileName = MyApplication.getnowTimeFileName();
       // File file = new File(fileName);
        List<File> fileResultList = getAllFile(CameraSettings.RECROD_DEFAULT.DEFAULT_CARD+File.separator+CameraSettings.RECROD_DEFAULT.AUDIO_DIR);
        fileDatas = new ArrayList<>();
        fileNames = new ArrayList<>();
        for (int j = 0; j < fileResultList.size();j++) {
            File file = fileResultList.get(j);

            files = getFiles(file);
            if(files == null ){
                return ;
            }
            for (int i = 0; i < files.length; i++) {
                String fileS = files[i].getName().substring(
                        files[i].getName().indexOf("."));
                if (fileS.toLowerCase().equals(".raw")) {
                    //获取路径
                    fileDatas.add(files[i].getPath());
                    //获取文件名
                    fileNames.add(files[i].getName());
                }
            }

        }

    }


    /**
     * 把raw文件转换成wav文件
     */
    public void rawToWav() {
        for (int i = 0; i < fileDatas.size(); i++) {
            //获取路径
            rawFile = fileDatas.get(i);
            //获取文件名
            rawName = fileNames.get(i);
            rawNameRes = rawName.substring(0, rawName.length() - 4);
            new Thread(new Runnable() {
                @Override
                public void run() {
                   // copyWaveFile(rawFile, getNewAudioFile(rawNameRes));
                    Log.d(TAG, "run: " + rawFile.substring(0, rawFile.length() - 4)  + ".wav");
                    copyWaveFile(rawFile, rawFile.substring(0, rawFile.length() - 4)  + ".wav");
                }
            }).start();
            SystemClock.sleep(20);
        }
    }

    /**
     * 得到文件下的所有文件数组
     *
     * @param file
     * @return
     */
    public File[] getFiles(File file) {
        File[] files = file.listFiles();
        return files;
    }

    /**
     * 创建存储录音文件的文件夹
     */
    public void createNewFile() {
        if (FileUtils.isExtrapositionSdState()) {
            File file = new File(MyApplication.getnowTimeFileName());
            if (!file.exists()) {// 如果不存在就创建
                file.mkdirs();
            }
        } else {
            Toast.makeText(this, R.string.please_check_sd_card, Toast.LENGTH_LONG).show();
        }
    }


    public static byte[] encrypt2(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        byte[] titleByte = {'a','b','c','d','e','f'};
        int len = bytes.length;
        for (int i = 0; i < len; i++) {
            bytes[i] ^= titleByte[0];
        }
        return bytes;
    }

}

2.播放

public class MUsicActivity extends AppCompatActivity implements View.OnClickListener {

    private Chronometer chronometer;
    int miss = 0;
    private Button btn_start,btn_stop,btn_play;
    private AudioTracker mAudioTracker;
    String audioFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/55.wav";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_m_usic);

        chronometer = findViewById(R.id.chronometer);
        btn_start = findViewById(R.id.btn_start);
        btn_stop = findViewById(R.id.btn_stop);
        btn_play = findViewById(R.id.btn_play);


        btn_start.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
        btn_play.setOnClickListener(this);

        chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                miss++;
                chronometer.setText(FormatMiss(miss));
            }
        });


    }



    public static String FormatMiss(int miss){
        String hh=miss/3600>9?miss/3600+"":"0"+miss/3600;
        String  mm=(miss % 3600)/60>9?(miss % 3600)/60+"":"0"+(miss % 3600)/60;
        String ss=(miss % 3600) % 60>9?(miss % 3600) % 60+"":"0"+(miss % 3600) % 60;
        return hh+":"+mm+":"+ss;
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()){

            case R.id.btn_start:

                mAudioTracker = new AudioTracker(this);
                File pcmFile = new File(audioFilePath);
                mAudioTracker.createAudioTrack(pcmFile.getAbsolutePath());
                mAudioTracker.start();

                break;
            case R.id.btn_stop:

                try {
                    mAudioTracker.stop();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                break;
            case R.id.btn_play:
                break;

        }


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mAudioTracker.release();
    }
}
public class AudioTracker {
    private static final String TAG = "AudioTracker";
    // 采样率 44100Hz,所有设备都支持
    private final static int SAMPLE_RATE = 44100;
    // 单声道,所有设备都支持
    private final static int CHANNEL = AudioFormat.CHANNEL_IN_STEREO;
    // 位深 16 位,所有设备都支持
    private final static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    // 缓冲区字节大小
    private int mBufferSizeInBytes = 0;
    // 播放对象
    private AudioTrack mAudioTrack;
    // 文件名
    private String mFilePath;
    // 状态
    private volatile Status mStatus = Status.STATUS_NO_READY;
    // 单任务线程池
    private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();

    private Handler mMainHandler = new Handler(Looper.getMainLooper());

    private Context mContext;

    public AudioTracker(Context context) {
        mContext = context;
    }

    public void createAudioTrack(String filePath) throws IllegalStateException {
        mFilePath = filePath;
        mBufferSizeInBytes = AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNEL, AUDIO_FORMAT);
        if (mBufferSizeInBytes <= 0) {
            throw new IllegalStateException("AudioTrack is not available " + mBufferSizeInBytes);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mAudioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .setLegacyStreamType(AudioManager.STREAM_MUSIC)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setEncoding(AUDIO_FORMAT)
                            .setSampleRate(SAMPLE_RATE)
                            .setChannelMask(CHANNEL)
                            .build())
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .setBufferSizeInBytes(mBufferSizeInBytes)
                    .build();
        } else {
            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, CHANNEL, AUDIO_FORMAT,
                    mBufferSizeInBytes, AudioTrack.MODE_STREAM);
        }
        mStatus = Status.STATUS_READY;
    }

    /**
     * 开始播放
     */
    public void start() throws IllegalStateException {
        if (mStatus == Status.STATUS_NO_READY || mAudioTrack == null) {
            throw new IllegalStateException("播放器尚未初始化");
        }
        if (mStatus == Status.STATUS_START) {
            throw new IllegalStateException("正在播放...");
        }
        Log.d(TAG, "===start===");
        mExecutorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    playAudioData();
                } catch (IOException e) {
                    Log.e(TAG, e.getMessage());
                    mMainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mContext, "播放出错", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });
        mStatus = Status.STATUS_START;
    }

    private void playAudioData() throws IOException {
        InputStream dis = null;
        try {
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "播放开始", Toast.LENGTH_SHORT).show();
                }
            });
            dis = new DataInputStream(new BufferedInputStream(new FileInputStream(mFilePath)));
            byte[] bytes = new byte[mBufferSizeInBytes];
            int length;
            mAudioTrack.play();
            // write 是阻塞的方法
            while ((length = dis.read(bytes)) != -1 && mStatus == Status.STATUS_START) {
                mAudioTrack.write(encrypt2(bytes), 0, length);
            }
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "播放结束", Toast.LENGTH_SHORT).show();
                }
            });
        } finally {
            if (dis != null) {
                dis.close();
            }
        }
    }

    public void stop() throws IllegalStateException {
        Log.d(TAG, "===stop===");
        if (mStatus == Status.STATUS_NO_READY || mStatus == Status.STATUS_READY) {
            throw new IllegalStateException("播放尚未开始");
        } else {
            mStatus = Status.STATUS_STOP;
            mAudioTrack.stop();
            release();
        }
    }

    public void release() {
        Log.d(TAG, "==release===");
        mStatus = Status.STATUS_NO_READY;
        if (mAudioTrack != null) {
            mAudioTrack.release();
            mAudioTrack = null;
        }
    }

    /**
     * 播放对象的状态
     */
    public enum Status {
        //未开始
        STATUS_NO_READY,
        //预备
        STATUS_READY,
        //播放
        STATUS_START,
        //停止
        STATUS_STOP
    }

    public static byte[] encrypt2(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        byte[] titleByte = {'a','b','c','d','e','f'};
        int len = bytes.length;
        for (int i = 0; i < len; i++) {
            bytes[i] ^= titleByte[0];
        }
        return bytes;
    }
}

4.视频加密

上一篇下一篇

猜你喜欢

热点阅读