/* * Copyright 2016, Dario Casalinuovo. All rights reserved. * Distributed under the terms of the MIT License. */ #include "RTSPMediaIO.h" #define LIVE555_VERBOSITY 1 RTSPMediaIO::RTSPMediaIO(BUrl ourUrl) : BAdapterIO( B_MEDIA_STREAMING | B_MEDIA_MUTABLE_SIZE | B_MEDIA_SEEK_BACKWARD, B_INFINITE_TIMEOUT), fUrl(ourUrl), fClient(NULL), fScheduler(NULL), fLoopWatchVariable(0), fLoopThread(-1) { fScheduler = BasicTaskScheduler::createNew(); fEnv = BasicUsageEnvironment::createNew(*fScheduler); } RTSPMediaIO::~RTSPMediaIO() { fClient->Close(); ShutdownLoop(); status_t status; if (fLoopThread != -1) wait_for_thread(fLoopThread, &status); } ssize_t RTSPMediaIO::WriteAt(off_t position, const void* buffer, size_t size) { return B_NOT_SUPPORTED; } status_t RTSPMediaIO::SetSize(off_t size) { return B_NOT_SUPPORTED; } status_t RTSPMediaIO::Open() { fClient = new HaikuRTSPClient(*fEnv, fUrl.UrlString(), 0, this); if (fClient == NULL) return B_ERROR; fClient->sendDescribeCommand(continueAfterDESCRIBE); fLoopThread = spawn_thread(_LoopThread, "two minutes hate thread", B_NORMAL_PRIORITY, this); if (fLoopThread <= 0 || resume_thread(fLoopThread) != B_OK) return B_ERROR; return fClient->WaitForInit(5000000); } int32 RTSPMediaIO::_LoopThread(void* data) { static_cast(data)->LoopThread(); return 0; } void RTSPMediaIO::LoopThread() { fEnv->taskScheduler().doEventLoop(&fLoopWatchVariable); fLoopThread = -1; } void RTSPMediaIO::ShutdownLoop() { fLoopWatchVariable = 1; } HaikuRTSPClient::HaikuRTSPClient(UsageEnvironment& env, char const* rtspURL, portNumBits tunnelOverHTTPPortNum, RTSPMediaIO* interface) : RTSPClient(env, rtspURL, LIVE555_VERBOSITY, "Haiku RTSP Streamer", tunnelOverHTTPPortNum, -1), iter(NULL), session(NULL), subsession(NULL), streamTimerTask(NULL), duration(0.0f), fInterface(interface), fInitPort(-1) { fInitPort = create_port(1, "RTSP Client wait port"); } HaikuRTSPClient::~HaikuRTSPClient() { } void HaikuRTSPClient::Close() { delete iter; if (session != NULL) { UsageEnvironment& env = session->envir(); env.taskScheduler().unscheduleDelayedTask(streamTimerTask); Medium::close(session); } } status_t HaikuRTSPClient::WaitForInit(bigtime_t timeout) { status_t status = B_ERROR; if (read_port_etc(fInitPort, NULL, &status, sizeof(status), B_RELATIVE_TIMEOUT, timeout) < 0) { return B_ERROR; } close_port(fInitPort); delete_port(fInitPort); fInitPort = -1; return status; } void HaikuRTSPClient::NotifyError() { fInterface->ShutdownLoop(); status_t status = B_ERROR; write_port(fInitPort, NULL, &status, sizeof(status)); } void HaikuRTSPClient::NotifySucces() { status_t status = B_OK; write_port(fInitPort, NULL, &status, sizeof(status)); } BInputAdapter* HaikuRTSPClient::GetInputAdapter() const { return fInterface->BuildInputAdapter(); }