异或加密 参考文档: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.视频加密
网友评论