Клиент, указанный ниже, предназначен для запуска приложения oflaDemo, работающего на red5 на localhost. Он содержит промо-ролика с фильмом.Red5 Воспроизведение RTMPClient начинает отбрасывать сообщения, если проигрывается полный поток
Проблема в том, что клиент читает 15 секунд фильма и зависает. Зачем?
Чтобы скомпилировать программу ниже, просто скачайте red5 отсюда http://wiki.red5.org/wiki/1_0_RC1, установите его и запустите. Откройте корневую страницу http://localhost:5080 и перейдите на страницу установки демонстрационных версий. Установите образец oflaDemo
. Затем перейдите на страницу tolaDemo и проверьте, работает ли она.
Затем создайте новый проект Java со всеми баночками из red5 в качестве библиотеки. Запустите его с запуском red5.
Клиент связывается с сервером через порт 1935.
Структура приложения следующим образом:
1) connect()
метод подключается к приложению
connectCallback
2) от результата предыдущей операции создается новый поток; Библиотечная функция не используется для введения пользовательского потока класса
3) createStreamCallback
это инъекционное на результате создания потока
4) пользовательский поток MyClientStream
; он просто печатает то, что было отправлено
На моей машине я работаю до отметки времени 15203 и висит.
public class SSCCE_RTMPPlayer extends RTMPClient{
private String server = "localhost";
private int port = 1935;
private String application = "oflaDemo";
private String filename = "avatar.flv";
private static boolean finished = false;
public static void main(String[] args) throws InterruptedException {
final SSCCE_RTMPPlayer player = new SSCCE_RTMPPlayer();
player.connect();
synchronized(SSCCE_RTMPPlayer.class) {
if(!finished) SSCCE_RTMPPlayer.class.wait();
}
System.out.println("Ended");
}
public void connect() {
connect(server, port, application, connectCallback);
setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
}
});
}
private IPendingServiceCallback connectCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
invoke("createStream", null, createStreamCallback);
}
};
private IPendingServiceCallback createStreamCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
Integer streamIdInteger = (Integer) call.getResult();
MyClientStream myClientStream = new MyClientStream();
myClientStream.setStreamId(streamIdInteger.intValue());
myClientStream.setConnection(conn);
conn.addClientStream(myClientStream);
play(streamIdInteger.intValue(), filename, 0, -2);
}
};
protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
super.onInvoke(conn, channel, header, notify, rtmp);
System.out.println("onInvoke, header = " + header.toString());
System.out.println("onInvoke, notify = " + notify.toString());
System.out.println("onInvoke, rtmp = " + rtmp.toString());
};
public static class MyClientStream extends AbstractClientStream implements IEventDispatcher {
@Override
public void start() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void dispatchEvent(IEvent event) {
System.out.println("AudioListenerClientStream.dispachEvent()" + event.toString());
}
}
}
ОБНОВЛЕНИЕ 1
версия с обычными setStreamEventDispatcher()
ведет себя таким же образом.
public class SSCCE_RTMPPlayer2 extends RTMPClient {
private String server = "localhost";
private int port = 1935;
private String application = "oflaDemo";
private String filename = "avatar.flv";
private static boolean finished = false;
public static void main(String[] args) throws InterruptedException {
final SSCCE_RTMPPlayer2 player = new SSCCE_RTMPPlayer2();
player.connect();
synchronized(SSCCE_RTMPPlayer.class) {
if(!finished) SSCCE_RTMPPlayer.class.wait();
}
System.out.println("Ended");
}
public void connect() {
setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
}
});
setStreamEventDispatcher(streamEventDispatcher);
connect(server, port, application, connectCallback);
}
private IEventDispatcher streamEventDispatcher = new IEventDispatcher() {
@Override
public void dispatchEvent(IEvent event) {
System.out.println("AudioListenerClientStream.dispachEvent()" + event.toString());
}
};
private IPendingServiceCallback connectCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
createStream(createStreamCallback);
}
};
private IPendingServiceCallback createStreamCallback = new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
Integer streamIdInteger = (Integer) call.getResult();
play(streamIdInteger.intValue(), filename, 0, -2);
}
};
protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
super.onInvoke(conn, channel, header, notify, rtmp);
System.out.println("onInvoke, header = " + header.toString());
System.out.println("onInvoke, notify = " + notify.toString());
System.out.println("onInvoke, rtmp = " + rtmp.toString());
/*
ObjectMap<String, String> map = (ObjectMap) notify.getCall().getArguments()[0];
String code = map.get("code");
if (StatusCodes.NS_PLAY_STOP.equals(code)) {
synchronized(SSCCE_RTMPPlayer.class) {
finished = true;
SSCCE_RTMPPlayer.class.notifyAll();
}
disconnect();
System.out.println("Disconnected");
}
*/
};
}
UPDATE 2
Я обнаружил, что пакеты начинают падать после того, как происходит зависание. Метод падение RTMPProtocolEncoder#dropMessage()
UPDATE 3
Я вижу, что «tardiness` растет со скоростью в режиме реального времени. Когда оно превышает значение 8000, начинается сброс.
ОБНОВЛЕНИЕ 4
Более точно, на стороне сервера, процесс начинает отбрасывать пакеты, примерно через 8 секунд прошло. Это, вероятно, значение 8000, которое является временем допуска. В тот же момент время метки пакета достигает 15-16 секунд. Клиент играет до этого времени и останавливается только тогда.
Таким образом, изображение того, что сервер опережает клиента 2 раза, и когда он достигает определенного предела, он не ждет, но начинает отбрасывать пакеты.
Похоже, что правильное поведение будет ждать, пока клиент достигнет отметки времени и продолжит ...
UPDATE 5
Возможно класс клиента поток не предназначен для прослушивания потока от сервера и поэтому не содержит соответствующую логику синхронизации?
MAGIC SOLUTION
Наблюдая различия в журнале во время воспроизведения потока с oflaDemo клиента и моего приложения, я обнаружил, что стандартный клиент сообщает размер буфера 5000 мс, а мой клиент не делает. Я не понимаю, как это может играть, но когда я добавил RTMP-пинг в свое приложение, он начинает работать. Волшебная линия следует
conn.ping(new Ping(Ping.CLIENT_BUFFER, streamId, 5000));
Поскольку его роль просто переложить опоздание на этом значение, я полагаю, что в целом проблема связана с RED5 ошибкой, что делает его неспособным правильно рассчитать опоздания.
Если у вас или у кого-нибудь есть идеи для улучшения расчетов, я бы хотел их услышать. –