package com.laifeng.sopcastsdk.stream.sender.sendqueue;
import com.laifeng.sopcastsdk.constant.SopCastConstant;
import com.laifeng.sopcastsdk.entity.Frame;
import com.laifeng.sopcastsdk.utils.SopCastLog;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import static com.laifeng.sopcastsdk.entity.Frame.FRAME_TYPE_AUDIO;
import static com.laifeng.sopcastsdk.entity.Frame.FRAME_TYPE_INTER_FRAME;
import static com.laifeng.sopcastsdk.entity.Frame.FRAME_TYPE_KEY_FRAME;
/**
* @Title: NormalSendQueue
* @Package com.laifeng.sopcastsdk.stream.sender.sendqueue
* @Description:
* @Author Jim
* @Date 2016/11/21
* @Time 上午10:33
* @Version
*/
public class NormalSendQueue implements ISendQueue {
private static final int NORMAL_FRAME_BUFFER_SIZE = 800;
private ArrayBlockingQueue<Frame> mFrameBuffer;
private int mFullQueueCount = NORMAL_FRAME_BUFFER_SIZE;
private AtomicInteger mTotalFrameCount = new AtomicInteger(0); //总个数
private AtomicInteger mGiveUpFrameCount = new AtomicInteger(0); //总个数
private AtomicInteger mInFrameCount = new AtomicInteger(0); //进入总个数
private AtomicInteger mOutFrameCount = new AtomicInteger(0); //输出总个数
private volatile boolean mScanFlag;
private SendQueueListener mSendQueueListener;
private ScanThread mScanThread;
public NormalSendQueue() {
mFrameBuffer = new ArrayBlockingQueue<>(mFullQueueCount, true);
}
@Override
public void start() {
mScanFlag = true;
mScanThread = new ScanThread();
mScanThread.start();
}
@Override
public void stop() {
mScanFlag = false;
mInFrameCount.set(0);
mOutFrameCount.set(0);
mTotalFrameCount.set(0);
mGiveUpFrameCount.set(0);
mFrameBuffer.clear();
}
public void setSendQueueListener(SendQueueListener listener) {
mSendQueueListener = listener;
}
@Override
public void setBufferSize(int size) {
mFullQueueCount = size;
}
public int getBufferFrameCount() {
return mTotalFrameCount.get();
}
public int getGiveUpFrameCount() {
return mGiveUpFrameCount.get();
}
@Override
public void putFrame(Frame frame) {
if(mFrameBuffer == null) {
return;
}
abandonData();
try {
mFrameBuffer.put(frame);
mInFrameCount.getAndIncrement();
mTotalFrameCount.getAndIncrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public Frame takeFrame() {
if(mFrameBuffer == null) {
return null;
}
Frame frame = null;
try {
frame = mFrameBuffer.take();
mOutFrameCount.getAndIncrement();
mTotalFrameCount.getAndDecrement();
} catch (InterruptedException e) {
//do nothing
}
return frame;
}
private void abandonData() {
if(mTotalFrameCount.get() >= (mFullQueueCount/ 2)) {
//从队列头部开始搜索,删除最早发现的连续P帧
boolean pFrameDelete = false;
boolean start = false;
for(Frame frame : mFrameBuffer) {
if(frame.frameType == FRAME_TYPE_INTER_FRAME) {
start = true;
}
if(start) {
if(frame.frameType == FRAME_TYPE_INTER_FRAME) {
mFrameBuffer.remove(frame);
mTotalFrameCount.getAndDecrement();
mGiveUpFrameCount.getAndIncrement();
pFrameDelete = true;
} else if(frame.frameType == FRAME_TYPE_KEY_FRAME) {
break;
}
}
}
boolean kFrameDelete = false;
//从队列头部开始搜索,删除最早发现的I帧
if(!pFrameDelete) {
for(Frame frame : mFrameBuffer) {
if(frame.frameType == FRAME_TYPE_KEY_FRAME) {
mFrameBuffer.remove(frame);
mTotalFrameCount.getAndDecrement();
mGiveUpFrameCount.getAndIncrement();
kFrameDelete = true;
break;
}
}
}
//从队列头部开始搜索,删除音频
if(!pFrameDelete && !kFrameDelete) {
for(Frame frame : mFrameBuffer) {
if(frame.frameType == FRAME_TYPE_AUDIO) {
mFrameBuffer.remove(frame);
mTotalFrameCount.getAndDecrement();
mGiveUpFrameCount.getAndIncrement();
break;
}
}
}
}
}
private class ScanThread extends Thread {
private static final int SCAN_MAX_TIME = 6;
private int mCurrentScanTime = 0;
private ArrayList<ScanSnapShot> mScanSnapShotList = new ArrayList<>();
@Override
public void run() {
while (mScanFlag) {
//达到仲裁次数了
if(mCurrentScanTime == SCAN_MAX_TIME) {
int averageDif = 0;
int negativeCounter = 0;
String strLog = "";
for (int i=0;i<SCAN_MAX_TIME;i++){
int dif = mScanSnapShotList.get(i).outCount - mScanSnapShotList.get(i).inCount;
if (dif<0) {
negativeCounter++;
}
averageDif += dif;
strLog = strLog + String.format("n%d:%d ", i, dif);
}
SopCastLog.d(SopCastConstant.TAG, strLog);
if (negativeCounter >= 4 || averageDif < -100){
//坏
SopCastLog.d(SopCastConstant.TAG, "Bad Send Speed.");
if(mSendQueueListener != null) {
mSendQueueListener.bad();
}
}
else{
//好
SopCastLog.d(SopCastConstant.TAG, "Good Send Speed.");
if(mSendQueueListener != null) {
mSendQueueListener.good();
}
}
//清空
mScanSnapShotList.clear();
mCurrentScanTime = 0;
}
mScanSnapShotList.add(new ScanSnapShot(mInFrameCount.get(), mOutFrameCount.get()));
mInFrameCount.set(0);
mOutFrameCount.set(0);
mCurrentScanTime++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class ScanSnapShot {
public int inCount;
public int outCount;
public ScanSnapShot(int inCount, int outCount) {
this.inCount = inCount;
this.outCount = outCount;
}
}
}