Use ConcurrentLinkedQueue to reduce CPU overhead

Since isEmpty method of ConcurrentLinkedQueue may take some time, and
therefore it would not detect new elements offered, we have to wait a time
out to ensure ConcurrentLinkedQueue can detect new elements.

Signed-off-by: Leo Ma <begeekmyfriend@gmail.com>
camera2
Leo Ma 9 years ago
parent e89a5caf12
commit e54db1cd8b

@ -3,9 +3,8 @@ package net.ossrs.sea.rtmp.io;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.SocketException; import java.net.SocketException;
import android.os.Handler; import java.util.Arrays;
import android.os.Looper; import java.util.concurrent.ConcurrentLinkedQueue;
import android.os.Message;
import android.util.Log; import android.util.Log;
import net.ossrs.sea.rtmp.packets.Command; import net.ossrs.sea.rtmp.packets.Command;
import net.ossrs.sea.rtmp.packets.RtmpPacket; import net.ossrs.sea.rtmp.packets.RtmpPacket;
@ -21,9 +20,10 @@ public class WriteThread extends Thread {
private RtmpSessionInfo rtmpSessionInfo; private RtmpSessionInfo rtmpSessionInfo;
private OutputStream out; private OutputStream out;
private Handler handler; private ConcurrentLinkedQueue<RtmpPacket> writeQueue = new ConcurrentLinkedQueue<RtmpPacket>();
private final Object txPacketLock = new Object();
private volatile boolean active = true;
private ThreadController threadController; private ThreadController threadController;
private Thread t;
public WriteThread(RtmpSessionInfo rtmpSessionInfo, OutputStream out, ThreadController threadController) { public WriteThread(RtmpSessionInfo rtmpSessionInfo, OutputStream out, ThreadController threadController) {
super("RtmpWriteThread"); super("RtmpWriteThread");
@ -34,31 +34,43 @@ public class WriteThread extends Thread {
@Override @Override
public void run() { public void run() {
t = this;
Looper.prepare(); while (active) {
handler = new Handler(Looper.myLooper()) { try {
@Override while (!writeQueue.isEmpty()) {
public void handleMessage(Message msg) { RtmpPacket rtmpPacket = writeQueue.poll();
try { final ChunkStreamInfo chunkStreamInfo = rtmpSessionInfo.getChunkStreamInfo(rtmpPacket.getHeader().getChunkStreamId());
RtmpPacket rtmpPacket = (RtmpPacket) msg.obj;
ChunkStreamInfo chunkStreamInfo = rtmpSessionInfo.getChunkStreamInfo(rtmpPacket.getHeader().getChunkStreamId());
chunkStreamInfo.setPrevHeaderTx(rtmpPacket.getHeader()); chunkStreamInfo.setPrevHeaderTx(rtmpPacket.getHeader());
rtmpPacket.writeTo(out, rtmpSessionInfo.getTxChunkSize(), chunkStreamInfo); rtmpPacket.writeTo(out, rtmpSessionInfo.getTxChunkSize(), chunkStreamInfo);
out.flush();
Log.d(TAG, "WriteThread: wrote packet: " + rtmpPacket + ", size: " + rtmpPacket.getHeader().getPacketLength()); Log.d(TAG, "WriteThread: wrote packet: " + rtmpPacket + ", size: " + rtmpPacket.getHeader().getPacketLength());
if (rtmpPacket instanceof Command) { if (rtmpPacket instanceof Command) {
rtmpSessionInfo.addInvokedCommand(((Command) rtmpPacket).getTransactionId(), ((Command) rtmpPacket).getCommandName()); rtmpSessionInfo.addInvokedCommand(((Command) rtmpPacket).getTransactionId(), ((Command) rtmpPacket).getCommandName());
} }
} catch (SocketException se) { }
Log.e(TAG, "WriteThread: Caught SocketException during write loop, shutting down", se); out.flush();
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, se); } catch (SocketException se) {
} catch (IOException ex) { Log.e(TAG, "WriteThread: Caught SocketException during write loop, shutting down", se);
Log.e(TAG, "WriteThread: Caught IOException during write loop, shutting down", ex); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(this, se);
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); active = false;
continue;
} catch (IOException ioe) {
Log.e(TAG, "WriteThread: Caught IOException during write loop, shutting down", ioe);
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(this, ioe);
active = false;
continue;
}
// Waiting for next packet
Log.d(TAG, "WriteThread: waiting...");
synchronized (txPacketLock) {
try {
// isEmpty() may take some time, so time out should be set to wait next offer
txPacketLock.wait(1000);
} catch (InterruptedException ex) {
Log.w(TAG, "Interrupted", ex);
} }
} }
}; }
Looper.loop();
// Close outputstream // Close outputstream
try { try {
@ -75,14 +87,26 @@ public class WriteThread extends Thread {
/** Transmit the specified RTMP packet (thread-safe) */ /** Transmit the specified RTMP packet (thread-safe) */
public void send(RtmpPacket rtmpPacket) { public void send(RtmpPacket rtmpPacket) {
if (rtmpPacket != null) { if (rtmpPacket != null) {
Message msg = Message.obtain(); writeQueue.offer(rtmpPacket);
msg.obj = rtmpPacket; }
handler.sendMessage(msg); synchronized (txPacketLock) {
txPacketLock.notify();
}
}
/** Transmit the specified RTMP packet (thread-safe) */
public void send(RtmpPacket... rtmpPackets) {
writeQueue.addAll(Arrays.asList(rtmpPackets));
synchronized (txPacketLock) {
txPacketLock.notify();
} }
} }
public void shutdown() { public void shutdown() {
Log.d(TAG, "Stopping write thread..."); Log.d(TAG, "Stopping write thread...");
Looper.myLooper().quit(); active = false;
synchronized (txPacketLock) {
txPacketLock.notify();
}
} }
} }

Loading…
Cancel
Save