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