1/*
2 * Copyright 2016, Dario Casalinuovo. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "RTSPMediaIO.h"
8
9
10#define LIVE555_VERBOSITY 1
11
12
13RTSPMediaIO::RTSPMediaIO(BUrl ourUrl)
14	:
15	BAdapterIO(
16		B_MEDIA_STREAMING | B_MEDIA_MUTABLE_SIZE | B_MEDIA_SEEK_BACKWARD,
17		B_INFINITE_TIMEOUT),
18	fUrl(ourUrl),
19	fClient(NULL),
20	fScheduler(NULL),
21	fLoopWatchVariable(0),
22	fLoopThread(-1)
23{
24	fScheduler = BasicTaskScheduler::createNew();
25	fEnv = BasicUsageEnvironment::createNew(*fScheduler);
26}
27
28
29RTSPMediaIO::~RTSPMediaIO()
30{
31	fClient->Close();
32
33	ShutdownLoop();
34
35	status_t status;
36	if (fLoopThread != -1)
37		wait_for_thread(fLoopThread, &status);
38}
39
40
41ssize_t
42RTSPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
43{
44	return B_NOT_SUPPORTED;
45}
46
47
48status_t
49RTSPMediaIO::SetSize(off_t size)
50{
51	return B_NOT_SUPPORTED;
52}
53
54
55status_t
56RTSPMediaIO::Open()
57{
58	fClient = new HaikuRTSPClient(*fEnv, fUrl.UrlString(),
59		0, this);
60	if (fClient == NULL)
61		return B_ERROR;
62
63	fClient->sendDescribeCommand(continueAfterDESCRIBE);
64
65	fLoopThread = spawn_thread(_LoopThread, "two minutes hate thread",
66		B_NORMAL_PRIORITY, this);
67
68	if (fLoopThread <= 0 || resume_thread(fLoopThread) != B_OK)
69		return B_ERROR;
70
71	return fClient->WaitForInit(5000000);
72}
73
74
75int32
76RTSPMediaIO::_LoopThread(void* data)
77{
78	static_cast<RTSPMediaIO *>(data)->LoopThread();
79	return 0;
80}
81
82
83void
84RTSPMediaIO::LoopThread()
85{
86	fEnv->taskScheduler().doEventLoop(&fLoopWatchVariable);
87	fLoopThread = -1;
88}
89
90
91void
92RTSPMediaIO::ShutdownLoop()
93{
94	fLoopWatchVariable = 1;
95}
96
97
98HaikuRTSPClient::HaikuRTSPClient(UsageEnvironment& env, char const* rtspURL,
99		portNumBits tunnelOverHTTPPortNum, RTSPMediaIO* interface)
100	:
101	RTSPClient(env, rtspURL, LIVE555_VERBOSITY, "Haiku RTSP Streamer",
102		tunnelOverHTTPPortNum, -1),
103	iter(NULL),
104	session(NULL),
105	subsession(NULL),
106	streamTimerTask(NULL),
107	duration(0.0f),
108	fInterface(interface),
109	fInitPort(-1)
110{
111	fInitPort = create_port(1, "RTSP Client wait port");
112}
113
114
115HaikuRTSPClient::~HaikuRTSPClient()
116{
117}
118
119
120void
121HaikuRTSPClient::Close()
122{
123	delete iter;
124	if (session != NULL) {
125		UsageEnvironment& env = session->envir();
126		env.taskScheduler().unscheduleDelayedTask(streamTimerTask);
127		Medium::close(session);
128	}
129}
130
131
132status_t
133HaikuRTSPClient::WaitForInit(bigtime_t timeout)
134{
135	status_t status = B_ERROR;
136	if (read_port_etc(fInitPort, NULL, &status,
137			sizeof(status), B_RELATIVE_TIMEOUT, timeout) < 0) {
138		return B_ERROR;
139	}
140
141	close_port(fInitPort);
142	delete_port(fInitPort);
143	fInitPort = -1;
144	return status;
145}
146
147
148void
149HaikuRTSPClient::NotifyError()
150{
151	fInterface->ShutdownLoop();
152	status_t status = B_ERROR;
153	write_port(fInitPort, NULL, &status, sizeof(status));
154}
155
156
157void
158HaikuRTSPClient::NotifySucces()
159{
160	status_t status = B_OK;
161	write_port(fInitPort, NULL, &status, sizeof(status));
162}
163
164
165BInputAdapter*
166HaikuRTSPClient::GetInputAdapter() const
167{
168	return fInterface->BuildInputAdapter();
169}
170