728x90
반응형
package com.gitsn.gs_phone.Media;
import android.annotation.SuppressLint;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
public class File_Thread extends Thread{
boolean isRun = false;
LinkedBlockingQueue<byte[]> dataQueue = new LinkedBlockingQueue<>();
File outputFile = null;
private static String _SDPath = "";
String _path2 = "/RecodeDir";
//---------------------------------------------------------------------
private BufferedOutputStream mBOStream;
private final int WAVE_CHANNEL_MONO = 1; //wav 파일 헤더 생성시 채널 상수값
private final int HEADER_SIZE = 0x2c; // 44
private final int RECORDER_BPP = 16;
private final int RECORDER_SAMPLERATE = 0xac44; // 44100
private int mAudioLen = 0;
@SuppressLint("MissingPermission")
public void startFileSave() {
if(isRun){
return;
}
isRun = true;
try {
isExist();
_SDPath = Environment.getExternalStorageDirectory().getAbsolutePath();
String _path3 = getTime()+".wav";
outputFile = new File(_SDPath+_path2+"/"+_path3);
mBOStream = new BufferedOutputStream(new FileOutputStream(outputFile));
super.start();
} catch (FileNotFoundException e) {
Log.d("WLOG_FILE", "File saved to: FileNotFoundException");
}
Log.d("WLOG_FILE", "File saved to: start");
}
/*
* 기존 wav 파일에 헤더 부분에 데이터 길이 수정
* */
void updateWavHeader(File wav) throws IOException {
byte[] sizes = ByteBuffer
.allocate(8)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt((int) (wav.length() - 8)) // ChunkSize
.putInt((int) (wav.length() - 44)) // Chunk Size
.array();
RandomAccessFile accessWave = null;
try {
accessWave = new RandomAccessFile(wav, "rw"); // 읽기-쓰기 모드로 인스턴스 생성
// ChunkSize
accessWave.seek(4); // 4바이트 지점으로 가서
accessWave.write(sizes, 0, 4); // 사이즈 채움
// Chunk Size
accessWave.seek(40); // 40바이트 지점으로 가서
accessWave.write(sizes, 4, 4); // 채움
} catch (IOException ex) {
// 예외를 다시 던지나, finally 에서 닫을 수 있음
throw ex;
} finally {
if (accessWave != null) {
try {
accessWave.close();
Log.d("WLOG_FILE", "File saved to: " + outputFile.getAbsolutePath());
} catch (IOException ex) {
// 무시
Log.d("WLOG_FILE", "File saved to: IOException ");
}
}
}
}
public void stopFileSave(){
if(!isRun){
return;
}
isRun = false;
super.interrupt();
}
public void pushData(byte [] data){
try {
dataQueue.put(data);
} catch (InterruptedException e) {
}
}
@Override
public void run() {
super.run();
try {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
mBOStream.write(getFileHeader());
while (isRun) {
byte[] datas = dataQueue.take();
mBOStream.write(datas);
}
}
catch (IOException e) {
Log.e("WLOG_FILE", "IOException");
}
catch (InterruptedException e) {
Log.e("WLOG_FILE", "InterruptedException");
try {
mBOStream.flush();
mBOStream.close();
updateWavHeader(outputFile);
Log.e("WLOG_FILE", "저장완료 ");
} catch (IOException ex) {
Log.e("WLOG_FILE", "mBOStream.flush- IOException");
}
}
}
/**
* .wav 파일 헤더 만들기
* */
private byte[] getFileHeader() {
byte[] header = new byte[HEADER_SIZE];
int totalDataLen = mAudioLen + 40;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * WAVE_CHANNEL_MONO/8;
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] = (byte)1; // format = 1 (PCM방식)
header[21] = 0;
header[22] = WAVE_CHANNEL_MONO;
header[23] = 0;
header[24] = (byte) (RECORDER_SAMPLERATE & 0xff);
header[25] = (byte) ((RECORDER_SAMPLERATE >> 8) & 0xff);
header[26] = (byte) ((RECORDER_SAMPLERATE >> 16) & 0xff);
header[27] = (byte) ((RECORDER_SAMPLERATE >> 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) RECORDER_BPP * WAVE_CHANNEL_MONO/8; // block align
header[33] = 0;
header[34] = RECORDER_BPP; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(mAudioLen & 0xff);
header[41] = (byte)((mAudioLen >> 8) & 0xff);
header[42] = (byte)((mAudioLen >> 16) & 0xff);
header[43] = (byte)((mAudioLen >> 24) & 0xff);
return header;
}
private boolean isExist() {
//' give user permission
//' <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
_SDPath = Environment.MEDIA_MOUNTED;
return false;
}
_SDPath = Environment.getExternalStorageDirectory().getAbsolutePath();
//'GSLog.d(_SDPath);
File file = new File(_SDPath + _path2);
//' check path
if (!file.exists()) {
file.mkdirs();
}
return true;
}
private String getTime(){
Date currentTime = new Date();
// 원하는 형식의 날짜 포맷 지정
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
// 포맷에 맞게 날짜를 문자열로 변환
String formattedTime = dateFormat.format(currentTime);
return formattedTime;
}
}
https://blog.naver.com/PostView.naver?blogId=wonminst&logNo=90130101793
728x90
반응형
'Android' 카테고리의 다른 글
Android Studio / Inteli J 디버깅 (0) | 2024.03.13 |
---|---|
wifi direct (p2p) 정리 (0) | 2024.02.23 |
android.hardware.usb.action.USB_ACCESSORY_ATTACHED (0) | 2024.01.23 |
Android Swtich 스위치 ( 커스텀 ) (0) | 2024.01.11 |
Android cutout 영역 ( IOS의 노치 영역 ) (0) | 2023.09.06 |