Skip to content

Commit

Permalink
Merge pull request #19 from wzasd/1.3.1-wz-aac
Browse files Browse the repository at this point in the history
feat:增加 socket 命令停止服务
  • Loading branch information
wzasd authored Feb 7, 2022
2 parents cd759c1 + 6f44bc3 commit edd2867
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 83 deletions.
207 changes: 124 additions & 83 deletions app/src/main/java/org/cloud/sonic/android/AudioService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,21 @@
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.util.Log;


import org.cloud.sonic.android.recorder.mp3.Mp3EncodeThread;
import org.cloud.sonic.android.recorder.utils.ByteUtils;
import org.cloud.sonic.android.recorder.utils.FileUtils;
import org.cloud.sonic.android.recorder.utils.Logger;
import org.cloud.sonic.android.util.ADTSUtil;

import java.io.DataInputStream;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Locale;

/**
* @author Eason, sndcpy
Expand All @@ -64,19 +59,26 @@ public class AudioService extends Service {
private static final String SOCKET_NAME = "sonicaudioservice";


private static final int SAMPLE_RATE = 48000;
private static final int SAMPLE_RATE = 44100;
private static final int CHANNELS = 2;

private final Handler handler = new ConnectionHandler(this);
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private Thread recorderThread;
// private long presentationTimeUs;
// 处理 AAC 录制音频
private MediaRecorder mediaRecorder;
// 处理录制时候的数据流
private ParcelFileDescriptor parcelWrite;
private DataInputStream inputStream;
private MediaCodec mMediaCodec;
private AudioRecord mAudioRecord;


private final Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
String dispMesg = (String) msg.obj;
if (ACTION_STOP.equals(dispMesg)) {
stopSelf();
}
}
};


@SuppressLint("NewApi")
public static void start(Context context, Intent data) {
Expand All @@ -90,7 +92,6 @@ public static void start(Context context, Intent data) {
@SuppressLint("NewApi")
public void onCreate() {
super.onCreate();
// initTransferACC();
Notification notification = createNotification(false);

NotificationChannel channel = new NotificationChannel(CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_NONE);
Expand All @@ -116,12 +117,18 @@ public int onStartCommand(Intent intent, int flags, int startId) {
Intent data = intent.getParcelableExtra(EXTRA_MEDIA_PROJECTION_DATA);
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, data);

if (mediaProjection != null) {
startRecording();
//必须要在子线程里接收消息
new Thread(this::acceptMsg).start();
} else {
Log.w(TAG, "Failed to capture audio");
stopSelf();
}



return START_NOT_STICKY;
}

Expand Down Expand Up @@ -195,80 +202,125 @@ private static AudioRecord createAudioRecord(MediaProjection mediaProjection) {
return builder.build();
}

private MediaRecorder createMediaRecorder(AudioRecord recorder){
MediaRecorder mediaRecorder = new MediaRecorder();
//配置采集方式,这里用的是麦克风的采集方式
mediaRecorder.setAudioSource(recorder.getAudioSource());
//配置输出方式,这里用的是AAC
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
//配置采样频率,频率越高月接近原始声音,Android所有设备都支持的采样频率为44100
mediaRecorder.setAudioSamplingRate(44100);
//配置文件的编码格式,AAC是比较通用的编码格式
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
//配置码率,这里一般通用的是96000
mediaRecorder.setAudioEncodingBitRate(96000);
//设置获取音频流的方式
mediaRecorder.setOutputFile(parcelWrite.getFileDescriptor());
return mediaRecorder;
//record audio
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startRecording() {
mAudioRecord = createAudioRecord(mediaProjection);
mAudioRecord.startRecording();
recordInternalAudio(mAudioRecord);
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
void recordInternalAudio(AudioRecord audioRecord) {
try {
mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, SAMPLE_RATE, CHANNELS);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 196000);
mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT);
ADTSUtil.initADTS(SAMPLE_RATE, CHANNELS);
mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
final int[] totalBytesRead = {0};
final Long[] mPresentationTime = {0L};
int trackId = 0;
mMediaCodec.setCallback(new MediaCodec.Callback() {

@Override
public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec, int i) {
ByteBuffer codecInputBuffer = mediaCodec.getInputBuffer(i);
int capacity = codecInputBuffer.capacity();
byte[] buffer = new byte[capacity];
int readBytes = audioRecord.read(buffer, 0, buffer.length);
if (readBytes > 0) {
codecInputBuffer.put(buffer, 0, readBytes);
mediaCodec.queueInputBuffer(i, 0, readBytes, mPresentationTime[0], 0);
totalBytesRead[0] += readBytes;
mPresentationTime[0] = 1000000L * (totalBytesRead[0] / 2) / 44100;
}
}

//record audio
private void startRecording() {
//处理线性输出
intPipLine();
final AudioRecord recorder = createAudioRecord(mediaProjection);
mediaRecorder = createMediaRecorder(recorder);

//try not thread
recorderThread = new Thread(() -> {

try (LocalSocket socket = connect()) {
handler.sendEmptyMessage(MSG_CONNECTION_ESTABLISHED);
mediaRecorder.prepare();
mediaRecorder.start();
// recorder.startRecording();
// int BUFFER_MS = 15; // do not buffer more than BUFFER_MS milliseconds
byte[] buffer = new byte[900];
// short[] buf = new short[SAMPLE_RATE * CHANNELS * BUFFER_MS / 1000];
while (true) {
// int r = recorder.read(buf, 0, buf.length);
int read = inputStream.read(buffer);
// encodePCMToAAC(buf,socket.getOutputStream());
if (read != -1) {
byte[] data = Arrays.copyOfRange(buffer, 0, read);
socket.getOutputStream().write(data, 0, read);
@Override
public void onOutputBufferAvailable(@NonNull MediaCodec codec, int outputBufferIndex, @NonNull MediaCodec.BufferInfo mBufferInfo) {
if (mBufferInfo.flags == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
Logger.i("AudioService", "AAC的配置数据");
} else {
byte[] oneADTSFrameBytes = new byte[7 + mBufferInfo.size];
ADTSUtil.addADTS(oneADTSFrameBytes);
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);
outputBuffer.get(oneADTSFrameBytes, 7, mBufferInfo.size);
try (LocalSocket socket = connect()) {
socket.getOutputStream().write(oneADTSFrameBytes, 0, oneADTSFrameBytes.length);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
// ignore
} finally {
// recorder.stop();
mediaRecorder.stop();
stopSelf();
}
});
recorderThread.start();

@Override
public void onError(@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {

e.printStackTrace();
stopSelf();
}

@Override
public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat) {

}
});

} catch (IOException e) {
e.printStackTrace();
}
mMediaCodec.start();

}

private boolean isRunning() {
return recorderThread != null;
return true;
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onDestroy() {
super.onDestroy();
mediaProjection.stop();
mAudioRecord.release();
mMediaCodec.stop();
mMediaCodec.release();
stopForeground(true);
if (recorderThread != null) {
recorderThread.interrupt();
recorderThread = null;
}

}

private NotificationManager getNotificationManager() {
return (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}


@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void acceptMsg() {
InputStream mInputStream = null;
try (LocalSocket mSocket = connect()) {
while (true) {
try {
byte[] buffer = new byte[1024];
mInputStream = mSocket.getInputStream();
int count = mInputStream.read(buffer);
String key = new String(Arrays.copyOfRange(buffer, 0, count));
Log.d(TAG, "ServerActivity mSocketOutStream==" + key);
Message msg = mHandler.obtainMessage();
msg.obj = key;
msg.sendToTarget();
} catch (IOException e) {
Log.d(TAG, "exception==" + e.fillInStackTrace().getMessage());
e.printStackTrace();
}
}
} catch (IOException e1) {
e1.printStackTrace();
}/**/
}

private static final class ConnectionHandler extends Handler {

private AudioService service;
Expand All @@ -290,15 +342,4 @@ public void handleMessage(Message message) {
}
}
}

private void intPipLine() {
try {
ParcelFileDescriptor[] parcelFileDescriptors = ParcelFileDescriptor.createPipe();
ParcelFileDescriptor parcelRead = new ParcelFileDescriptor(parcelFileDescriptors[0]);
parcelWrite = new ParcelFileDescriptor(parcelFileDescriptors[1]);
inputStream = new DataInputStream(new ParcelFileDescriptor.AutoCloseInputStream(parcelRead));
} catch (IOException e) {
e.printStackTrace();
}
}
}
37 changes: 37 additions & 0 deletions app/src/main/java/org/cloud/sonic/android/util/ADTSUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.cloud.sonic.android.util;

public class ADTSUtil {
/** 只保存了ADTS头中不变化的那部分信息 */
private static long adtsPart = 0xFFF94000001FFCL;
/** 保存了ADTS头中的完整信息 */
private static long adtsFull;
private static byte byte_0;
private static byte byte_1;
private static byte byte_2;
private static byte byte_6;

/**
* 初始化ADTS头,计算出ADTS头中固定不变化的那些信息
* @param samplingFrequencyIndex 音频采样频率的索引
* @param channelCount 声道数量
*/
public static void initADTS(long samplingFrequencyIndex, long channelCount) {
adtsPart = adtsPart | (samplingFrequencyIndex << 34) | (channelCount << 30);
byte_0 = (byte) (adtsPart >>> 48); // 右移48 = (7字节 - 1) * 8
byte_1 = (byte) (adtsPart >>> 40); // 右移40 = (6字节 - 1) * 8
byte_2 = (byte) (adtsPart >>> 32); // 右移32 = (5字节 - 1) * 8
byte_6 = (byte) adtsPart; // 右移 0 = (1字节 - 1) * 8
}

/** 往oneADTSFrameBytes数组中的最前面7个字节中填入ADTS头信息 */
public static void addADTS(byte[] oneADTSFrameBytes) {
adtsFull = adtsPart | (oneADTSFrameBytes.length << 13);// 一个int32位,所以不用担心左移13位数据丢失的问题
oneADTSFrameBytes[0] = byte_0;
oneADTSFrameBytes[1] = byte_1;
oneADTSFrameBytes[2] = byte_2;
oneADTSFrameBytes[3] = (byte) (adtsFull >>> 24); // 右移24 = (4字节 - 1) * 8
oneADTSFrameBytes[4] = (byte) (adtsFull >>> 16); // 右移16 = (3字节 - 1) * 8
oneADTSFrameBytes[5] = (byte) (adtsFull >>> 8); // 右移 8 = (2字节 - 1) * 8
oneADTSFrameBytes[6] = byte_6;
}
}

0 comments on commit edd2867

Please sign in to comment.