/*
* Copyright 2016, Dario Casalinuovo
* Distributed under the terms of the MIT License.
*/
#include "HTTPMediaIO.h"
#include <Handler.h>
#include <HttpRequest.h>
#include <UrlProtocolRoster.h>
#include "MediaDebug.h"
// 10 seconds timeout
#define HTTP_TIMEOUT 10000000
class FileListener : public BUrlProtocolListener {
public:
FileListener(HTTPMediaIO* owner)
:
BUrlProtocolListener(),
fRequest(NULL),
fAdapterIO(owner),
fInitSem(-1),
fRunning(false)
{
fInputAdapter = fAdapterIO->BuildInputAdapter();
fInitSem = create_sem(0, "http_streamer init sem");
}
virtual ~FileListener()
{
_ReleaseInit();
}
bool ConnectionSuccessful() const
{
return fRequest != NULL;
}
void ConnectionOpened(BUrlRequest* request)
{
fRequest = request;
fRunning = true;
}
void HeadersReceived(BUrlRequest* request, const BUrlResult& result)
{
fAdapterIO->UpdateSize();
}
void DataReceived(BUrlRequest* request, const char* data,
off_t position, ssize_t size)
{
if (request != fRequest) {
delete request;
return;
}
BHttpRequest* httpReq = dynamic_cast<BHttpRequest*>(request);
if (httpReq != NULL) {
const BHttpResult& httpRes
= (const BHttpResult&)httpReq->Result();
int32 status = httpRes.StatusCode();
if (BHttpRequest::IsClientErrorStatusCode(status)
|| BHttpRequest::IsServerErrorStatusCode(status)) {
fRunning = false;
} else if (BHttpRequest::IsRedirectionStatusCode(status))
return;
}
_ReleaseInit();
fInputAdapter->Write(data, size);
}
void RequestCompleted(BUrlRequest* request, bool success)
{
_ReleaseInit();
if (request != fRequest)
return;
fRequest = NULL;
}
status_t LockOnInit(bigtime_t timeout)
{
return acquire_sem_etc(fInitSem, 1, B_RELATIVE_TIMEOUT, timeout);
}
bool IsRunning()
{
return fRunning;
}
private:
void _ReleaseInit()
{
if (fInitSem != -1) {
release_sem(fInitSem);
delete_sem(fInitSem);
fInitSem = -1;
}
}
BUrlRequest* fRequest;
HTTPMediaIO* fAdapterIO;
BInputAdapter* fInputAdapter;
sem_id fInitSem;
bool fRunning;
};
HTTPMediaIO::HTTPMediaIO(BUrl url)
:
BAdapterIO(B_MEDIA_STREAMING | B_MEDIA_SEEKABLE, HTTP_TIMEOUT),
fReq(NULL),
fListener(NULL),
fReqThread(-1),
fUrl(url),
fIsMutable(false)
{
CALLED();
}
HTTPMediaIO::~HTTPMediaIO()
{
CALLED();
if (fReq != NULL) {
fReq->Stop();
status_t status;
wait_for_thread(fReqThread, &status);
delete fReq;
}
}
void
HTTPMediaIO::GetFlags(int32* flags) const
{
*flags = B_MEDIA_STREAMING | B_MEDIA_SEEK_BACKWARD;
if (fIsMutable)
*flags = *flags | B_MEDIA_MUTABLE_SIZE;
}
ssize_t
HTTPMediaIO::WriteAt(off_t position, const void* buffer, size_t size)
{
return B_NOT_SUPPORTED;
}
status_t
HTTPMediaIO::SetSize(off_t size)
{
return B_NOT_SUPPORTED;
}
status_t
HTTPMediaIO::Open()
{
CALLED();
fListener = new FileListener(this);
fReq = BUrlProtocolRoster::MakeRequest(fUrl, fListener);
if (fReq == NULL)
return B_ERROR;
fReqThread = fReq->Run();
if (fReqThread < 0)
return B_ERROR;
status_t ret = fListener->LockOnInit(HTTP_TIMEOUT);
if (ret != B_OK)
return ret;
return BAdapterIO::Open();
}
bool
HTTPMediaIO::IsRunning() const
{
if (fListener != NULL)
return fListener->IsRunning();
else if (fReq != NULL)
return fReq->IsRunning();
return false;
}
status_t
HTTPMediaIO::SeekRequested(off_t position)
{
return BAdapterIO::SeekRequested(position);
}
void
HTTPMediaIO::UpdateSize()
{
// At this point we decide if our size is fixed or mutable,
// this will change the behavior of our parent.
off_t size = fReq->Result().Length();
if (size > 0)
BAdapterIO::SetSize(size);
else
fIsMutable = true;
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fTotalSize.