#c #multithreading #rtsp #live555
#c #многопоточность #rtsp #live555
Вопрос:
В настоящее время я сталкиваюсь с проблемой с live555.
Я написал Windows DLL для своего проекта, эта DLL предоставляет очень простой API для легкого запуска RTSP-клиента. Программа Unity загружает DLL, а затем использует API для получения фреймов.
представлены две основные функции :
bool startRTSP(bool isTCP);
bool stopRTSP();
Из-за особенностей библиотеки Live555 я не могу запустить RTSP в потоке unity. Итак, я создал новый поток при вызове startRTSP , и с некоторыми обратными вызовами фреймы отправляются в unity.
Однако, чтобы иметь возможность остановить RTSP из внешнего потока (поток unity, вызывающий stopRTSP), я использую eventLoopWatchVariable . Например, так запускается цикл событий RTSP :
env->taskScheduler().doEventLoop(amp;eventLoopWatchVariable);
Когда вызывается функция stop , переменной eventLoopWatchVariable присваивается значение 1 из потока unity.
Завершение цикла событий.
Сразу после завершения этого цикла событий вызываются функции очистки :
delete scheduler;
env->reclaim();
Я ожидал, что эта функция пройдет через RTSP-клиент и отключит их. (Например, отправка команды ДЕМОНТАЖА на сервер)
Но они явно этого не делают, и клиенты никогда не уничтожаются!
Я подозреваю, что это вызовет проблему повторного подключения к тому же потоку. (команды SETUP , DESCRIBE и PLAY отправляются, и ответы получены, но данные не поступают) Используя VLC или mplayer, я вижу, что сервер все еще работает в потоковом режиме, так что это не проблема сервера.
Как я могу попросить live555 закрыть RTSPClient и их дочерние элементы, когда eventLoopWatchVariable имеет значение 1?
Я не могу отправить команду ДЕМОНТАЖА на сервер, если eventLoop больше не выполняется. Так что я сейчас немного растерялся в отношении наилучшего способа сделать это.
Если у кого-нибудь есть идея по этому поводу, я хотел бы ее услышать!
Заранее спасибо.
Ответ №1:
Я не могу отправить команду ДЕМОНТАЖА на сервер, если eventLoop больше не выполняется.
Это неточно, основной цикл необходим для получения сообщений, а не для отправки сообщений.
Чтобы правильно закрыть клиентское соединение RTSP после основного цикла и перед выпуском среды, вы могли бы поступить следующим образом :
// wait for stop event
env->taskScheduler().doEventLoop(amp;eventLoopWatchVariable);
// send tear TEARDOWN
client->sendTeardownCommand(session, NULL);
// close subsession amp; session
Medium::close(session);
// close RTSP client
Medium::close(client);
// free environment amp; scheduler
env->reclaim();
delete scheduler;
Вы также можете дождаться ответа на удаление, выполнив обратный вызов sendTeardownCommand и снова запустив doEventLoop.
Комментарии:
1. Откуда берется переменная «session»? В частности, из main() из testProgs/testRTSPClient.cpp . Нужно ли мне создавать глобальную переменную для доступа к ней?
Ответ №2:
Вот правильный способ полного завершения работы rtsp-клиента. В этом ответе предполагается, что вы используете следующую программу в качестве основы для вашего клиента rtsp: testProgs/testRTSPClient.cpp (в комплекте с live555).
Сначала измените openURL(), чтобы каким-то образом вернуть «RTSPClient* rtspClient» обратно вызывающему. Затем используйте этот пример (продолжая с main() внутри testRTSPClient.cpp ):
RTSPClient* rtspClient = openURL(*env, argv[0], argv[1]);
// All subsequent activity takes place within the event loop:
env->taskScheduler().doEventLoop(amp;eventLoopWatchVariable);
//... do whatever stuff you want to do in the background...
//start this code when you want to stop the rtsp client
eventLoopWatchVariable = 1;
//run this code for each rtspClient that exists
StreamClientStateamp; scs = ((ourRTSPClient*)rtspClient)->scs;
rtspClient->sendTeardownCommand(*scs.session, NULL);
Medium::close(client->rtspClient);
//end code segment
env->reclaim();
env = NULL;
delete scheduler;
scheduler = NULL;