Android 推送手机音频数据到RTMP服务器 AACtoRTMP
Android平台上使用AudioRecord采集音视频数据,通过MediaCodec对音视频实施硬编码,回调aac数据流,然后通过librtmp推送到服务器,案例紧写了RTMP的,RTSP的照搬即可,以下是部分代码,具体代码可以看源码连接:https://github.com/printlybyte/AndroidPCMtoAAC_RTMP_RTSP
推流器:DefaultRtmpPublisher
public class DefaultRtmpPublisher implements RtmpPublisher {
private RtmpConnection rtmpConnection;
public DefaultRtmpPublisher(ConnectCheckerRtmp connectCheckerRtmp) {
rtmpConnection = new RtmpConnection(connectCheckerRtmp);
}
@Override
public boolean connect(String url) {
return rtmpConnection.connect(url);
}
@Override
public boolean publish(String publishType) {
return rtmpConnection.publish(publishType);
}
@Override
public void close() {
rtmpConnection.close();
}
@Override
public void publishVideoData(byte[] data, int size, int dts) {
rtmpConnection.publishVideoData(data, size, dts);
}
@Override
public void publishAudioData(byte[] data, int size, int dts) {
rtmpConnection.publishAudioData(data, size, dts);
}
@Override
public void setVideoResolution(int width, int height) {
rtmpConnection.setVideoResolution(width, height);
}
@Override
public void setAuthorization(String user, String password) {
rtmpConnection.setAuthorization(user, password);
}
}
连接器:RtmpConnection
public class RtmpConnection implements RtmpPublisher {
private static final String TAG = "RtmpConnection";
private static final Pattern rtmpUrlPattern =
Pattern.compile("^rtmp://([^/:]+)(:(\\d+))*/([^/]+)(/(.*))*$");
private static final Pattern rtmpsUrlPattern =
Pattern.compile("^rtmps://([^/:]+)(:(\\d+))*/([^/]+)(/(.*))*$");
private int port;
private String host;
private String appName;
private String streamName;
private String publishType;
private String swfUrl;
private String tcUrl;
private String pageUrl;
private Socket socket;
private String socketExceptionCause = "";
private RtmpSessionInfo rtmpSessionInfo;
private RtmpDecoder rtmpDecoder;
private BufferedInputStream inputStream;
private BufferedOutputStream outputStream;
private Thread rxPacketHandler;
private volatile boolean connected = false;
private volatile boolean publishPermitted = false;
private final Object connectingLock = new Object();
private final Object publishLock = new Object();
private int currentStreamId = 0;
private int transactionIdCounter = 0;
private int videoWidth;
private int videoHeight;
private ConnectCheckerRtmp connectCheckerRtmp;
//for secure transport
private boolean tlsEnabled;
//for auth
private String user = null;
private String password = null;
private String salt = null;
private String challenge = null;
private String opaque = null;
private boolean onAuth = false;
public RtmpConnection(ConnectCheckerRtmp connectCheckerRtmp) {
this.connectCheckerRtmp = connectCheckerRtmp;
}
private void handshake(InputStream in, OutputStream out) throws IOException {
Handshake handshake = new Handshake();
handshake.writeC0(out);
handshake.writeC1(out); // Write C1 without waiting for S0
out.flush();
handshake.readS0(in);
handshake.readS1(in);
handshake.writeC2(out);
out.flush();
handshake.readS2(in);
}
@Override
public boolean connect(String url) {
Matcher rtmpMatcher = rtmpUrlPattern.matcher(url);
Matcher rtmpsMatcher = rtmpsUrlPattern.matcher(url);
Matcher matcher;
if (rtmpMatcher.matches()) {
matcher = rtmpMatcher;
tlsEnabled = false;
} else if (rtmpsMatcher.matches()) {
matcher = rtmpsMatcher;
tlsEnabled = true;
} else {
connectCheckerRtmp.onConnectionFailedRtmp(
"Endpoint malformed, should be: rtmp://ip:port/appname/streamname");
return false;
}
tcUrl = url.substring(0, url.lastIndexOf('/'));
swfUrl = "";
pageUrl = "";
host = matcher.group(1);
String portStr = matcher.group(3);
port = portStr != null ? Integer.parseInt(portStr) : 1935;
appName = matcher.group(4);
streamName = matcher.group(6);
// socket connection
Log.d(TAG, "connect() called. Host: "
+ host
+ ", port: "
+ port
+ ", appName: "
+ appName
+ ", publishPath: "
+ streamName);
rtmpSessionInfo = new RtmpSessionInfo();
rtmpDecoder = new RtmpDecoder(rtmpSessionInfo);
try {
if (!tlsEnabled) {
socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, 3000);
} else {
socket = CreateSSLSocket.createSSlSocket(host, port);
if (socket == null) throw new IOException("Socket creation failed");
}
inputStream = new BufferedInputStream(socket.getInputStream());
outputStream = new BufferedOutputStream(socket.getOutputStream());
Log.d(TAG, "connect(): socket connection established, doing handhake...");
handshake(inputStream, outputStream);
Log.d(TAG, "connect(): handshake done");
} catch (IOException e) {
Log.e(TAG, "Error", e);
connectCheckerRtmp.onConnectionFailedRtmp("Connect error, " + e.getMessage());
return false;
}
// Start the "main" handling thread
rxPacketHandler = new Thread(new Runnable() {
@Override
public void run() {
try {
Log.d(TAG, "starting main rx handler loop");
handleRxPacketLoop();
}