⛏️ index : haiku.git

/*
 * 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<RTSPMediaIO *>(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();
}