Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
325
Src/replicant/http/HTTPPlayback.cpp
Normal file
325
Src/replicant/http/HTTPPlayback.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
#include "http/api.h"
|
||||
#include "HTTPPlayback.h"
|
||||
#include "http/svc_http_demuxer.h"
|
||||
#include "service/ifc_servicefactory.h"
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
#include "nu/AutoChar.h"
|
||||
#endif
|
||||
#include "nu/strsafe.h"
|
||||
#include "nx/nxsleep.h"
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h> // TODO: replace with generic logging API
|
||||
#else
|
||||
#define ANDROID_LOG_INFO 0
|
||||
#define ANDROID_LOG_ERROR 1
|
||||
void __android_log_print(int, const char *, const char *, ...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
HTTPPlayback::HTTPPlayback()
|
||||
{
|
||||
http=0;
|
||||
demuxer=0;
|
||||
}
|
||||
|
||||
int HTTPPlayback::Initialize(nx_uri_t url, ifc_player *player)
|
||||
{
|
||||
int ret = PlaybackBase::Initialize(url, player);
|
||||
if (ret != NErr_Success)
|
||||
return ret;
|
||||
http=0;
|
||||
demuxer=0;
|
||||
ifc_playback::Retain(); /* the thread needs to hold a reference to this object so that it doesn't disappear out from under us */
|
||||
NXThreadCreate(&playback_thread, HTTPPlayerThreadFunction, this);
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
HTTPPlayback::~HTTPPlayback()
|
||||
{
|
||||
if (demuxer)
|
||||
demuxer->Release();
|
||||
if (http)
|
||||
jnl_http_release(http);
|
||||
}
|
||||
|
||||
nx_thread_return_t HTTPPlayback::HTTPPlayerThreadFunction(nx_thread_parameter_t param)
|
||||
{
|
||||
HTTPPlayback *playback = (HTTPPlayback *)param;
|
||||
NXThreadCurrentSetPriority(NX_THREAD_PRIORITY_PLAYBACK);
|
||||
nx_thread_return_t ret = playback->DecodeLoop();
|
||||
playback->ifc_playback::Release();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HTTPPlayback::Init()
|
||||
{
|
||||
http = jnl_http_create(2*1024*1024, 0);
|
||||
if (!http)
|
||||
return NErr_OutOfMemory;
|
||||
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
static void SetupHTTP(jnl_http_t http)
|
||||
{
|
||||
char accept[1024], user_agent[256];
|
||||
accept[0]=0;
|
||||
user_agent[0]=0;
|
||||
size_t accept_length=sizeof(accept)/sizeof(*accept);
|
||||
size_t user_agent_length=sizeof(user_agent)/sizeof(*user_agent);
|
||||
char *p_accept = accept, *p_user_agent=user_agent;
|
||||
|
||||
const char *application_user_agent = WASABI2_API_APP->GetUserAgent();
|
||||
StringCchCopyExA(p_user_agent, user_agent_length, application_user_agent, &p_user_agent, &user_agent_length, 0);
|
||||
|
||||
GUID http_demuxer_guid = svc_http_demuxer::GetServiceType();
|
||||
ifc_serviceFactory *sf;
|
||||
size_t n = 0;
|
||||
while (sf = WASABI2_API_SVC->EnumService(http_demuxer_guid, n++))
|
||||
{
|
||||
svc_http_demuxer *l = (svc_http_demuxer*)sf->GetInterface();
|
||||
if (l)
|
||||
{
|
||||
const char *this_accept;
|
||||
size_t i=0;
|
||||
while (this_accept=l->EnumerateAcceptedTypes(i++))
|
||||
{
|
||||
if (accept == p_accept) // first one added
|
||||
StringCchCopyExA(p_accept, accept_length, this_accept, &p_accept, &accept_length, 0);
|
||||
else
|
||||
StringCchPrintfExA(p_accept, accept_length, &p_accept, &accept_length, 0, ", %s", this_accept);
|
||||
}
|
||||
|
||||
const char *this_user_agent = l->GetUserAgent();
|
||||
if (this_user_agent)
|
||||
{
|
||||
StringCchPrintfExA(p_user_agent, user_agent_length, &p_user_agent, &user_agent_length, 0, " %s", this_user_agent);
|
||||
}
|
||||
|
||||
l->CustomizeHTTP(http);
|
||||
l->Release();
|
||||
}
|
||||
}
|
||||
if (accept != p_accept)
|
||||
jnl_http_addheadervalue(http, "Accept", accept);
|
||||
jnl_http_addheadervalue(http, "User-Agent", user_agent);
|
||||
jnl_http_addheadervalue(http, "Connection", "close");
|
||||
|
||||
}
|
||||
|
||||
static NError FindDemuxer(nx_uri_t uri, jnl_http_t http, ifc_http_demuxer **demuxer)
|
||||
{
|
||||
GUID http_demuxer_guid = svc_http_demuxer::GetServiceType();
|
||||
ifc_serviceFactory *sf;
|
||||
|
||||
bool again;
|
||||
int pass=0;
|
||||
do
|
||||
{
|
||||
size_t n = 0;
|
||||
again=false;
|
||||
while (sf = WASABI2_API_SVC->EnumService(http_demuxer_guid, n++))
|
||||
{
|
||||
svc_http_demuxer *l = (svc_http_demuxer*)sf->GetInterface();
|
||||
if (l)
|
||||
{
|
||||
NError err = l->CreateDemuxer(uri, http, demuxer, pass);
|
||||
if (err == NErr_Success)
|
||||
return NErr_Success;
|
||||
|
||||
if (err == NErr_TryAgain)
|
||||
again=true;
|
||||
}
|
||||
}
|
||||
pass++;
|
||||
} while (again);
|
||||
return NErr_NoMatchingImplementation;
|
||||
}
|
||||
|
||||
int HTTPPlayback::Internal_Connect(uint64_t byte_position)
|
||||
{
|
||||
int http_ver = byte_position?1:0;
|
||||
|
||||
if (byte_position != 0)
|
||||
{
|
||||
char str[512];
|
||||
StringCchPrintfA(str, 512, "Range: bytes=%llu-", byte_position);
|
||||
|
||||
jnl_http_addheader(http, str);
|
||||
}
|
||||
//jnl_http_allow_accept_all_reply_codes(http);
|
||||
#ifdef _WIN32
|
||||
jnl_http_connect(http, AutoChar(filename->string), http_ver, "GET");
|
||||
#else
|
||||
jnl_http_connect(http, filename->string, http_ver, "GET");
|
||||
#endif
|
||||
|
||||
/* wait for connection */
|
||||
time_t start_time = time(0);
|
||||
|
||||
int http_status;
|
||||
do
|
||||
{
|
||||
int ret = PlaybackBase::Sleep(10, PlaybackBase::WAKE_STOP);
|
||||
if (ret == PlaybackBase::WAKE_STOP)
|
||||
return NErr_Interrupted;
|
||||
|
||||
ret = jnl_http_run(http);
|
||||
if (ret == HTTPGET_RUN_ERROR)
|
||||
return NErr_ConnectionFailed;
|
||||
if (start_time + 15 < time(0))
|
||||
return NErr_TimedOut;
|
||||
|
||||
http_status = jnl_http_get_status(http);
|
||||
} while (http_status == HTTPGET_STATUS_CONNECTING || http_status == HTTPGET_STATUS_READING_HEADERS);
|
||||
|
||||
if (http_status == HTTPGET_STATUS_ERROR)
|
||||
{
|
||||
switch(jnl_http_getreplycode(http))
|
||||
{
|
||||
case 400:
|
||||
return NErr_BadRequest;
|
||||
case 401:
|
||||
// TODO: deal with this specially
|
||||
return NErr_Unauthorized;
|
||||
case 403:
|
||||
// TODO: deal with this specially?
|
||||
return NErr_Forbidden;
|
||||
case 404:
|
||||
return NErr_NotFound;
|
||||
case 405:
|
||||
return NErr_BadMethod;
|
||||
case 406:
|
||||
return NErr_NotAcceptable;
|
||||
case 407:
|
||||
// TODO: deal with this specially
|
||||
return NErr_ProxyAuthenticationRequired;
|
||||
case 408:
|
||||
return NErr_RequestTimeout;
|
||||
case 409:
|
||||
return NErr_Conflict;
|
||||
case 410:
|
||||
return NErr_Gone;
|
||||
case 500:
|
||||
return NErr_InternalServerError;
|
||||
case 503:
|
||||
return NErr_ServiceUnavailable;
|
||||
|
||||
default:
|
||||
return NErr_ConnectionFailed;
|
||||
|
||||
}
|
||||
}
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
nx_thread_return_t HTTPPlayback::DecodeLoop()
|
||||
{
|
||||
player->OnLoaded(filename);
|
||||
|
||||
int ret = Init();
|
||||
if (ret != NErr_Success)
|
||||
{
|
||||
player->OnError(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetupHTTP(http);
|
||||
|
||||
/* connect, then find an ifc_http_demuxer */
|
||||
ret = Internal_Connect(0);
|
||||
|
||||
if (ret == NErr_Success && FindDemuxer(filename, http, &demuxer) == NErr_Success && demuxer)
|
||||
{
|
||||
/* turn control over to the demuxer */
|
||||
ret = demuxer->Run(this, player, secondary_parameters);
|
||||
if (ret == NErr_EndOfFile)
|
||||
{
|
||||
/* TODO: re-implement the individual demuxers so they keep calling set position for a while */
|
||||
player->OnClosed();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (ret == NErr_Interrupted)
|
||||
{
|
||||
player->OnStopped();
|
||||
return 0;
|
||||
}
|
||||
else if (ret == NErr_TimedOut)
|
||||
{
|
||||
player->OnError(ret);
|
||||
return 0;
|
||||
}
|
||||
else if (ret == NErr_Success)
|
||||
{
|
||||
player->OnError(NErr_NoMatchingImplementation);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, "libreplicant", "[http] error: %d, reply code: %d", ret, jnl_http_getreplycode(http));
|
||||
player->OnError(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_Wake(int mask)
|
||||
{
|
||||
return PlaybackBase::Wake(mask);
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_Check(int mask)
|
||||
{
|
||||
return PlaybackBase::Check(mask);
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_Wait(unsigned int milliseconds, int mask)
|
||||
{
|
||||
return PlaybackBase::Wait(milliseconds, mask);
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_Sleep(int milliseconds, int mask)
|
||||
{
|
||||
return PlaybackBase::Sleep(milliseconds, mask);
|
||||
}
|
||||
|
||||
Agave_Seek *HTTPPlayback::HTTP_GetSeek()
|
||||
{
|
||||
return PlaybackBase::GetSeek();
|
||||
}
|
||||
|
||||
void HTTPPlayback::HTTP_FreeSeek(Agave_Seek *seek)
|
||||
{
|
||||
PlaybackBase::FreeSeek(seek);
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_Seek(uint64_t byte_position)
|
||||
{
|
||||
jnl_http_reset_headers(http);
|
||||
SetupHTTP(http);
|
||||
return Internal_Connect(byte_position);
|
||||
}
|
||||
#if defined(_WIN32) && !defined(strcasecmp)
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
int HTTPPlayback::HTTP_Seekable()
|
||||
{
|
||||
const char *accept_ranges = jnl_http_getheader(http, "accept-ranges");
|
||||
if (accept_ranges && !strcasecmp(accept_ranges, "none"))
|
||||
return NErr_False; /* server says it doesn't accept ranges */
|
||||
|
||||
/* note that not having an accept-ranges header doesn't necessary mean it's not seekable. see RFC2616 14.5 */
|
||||
return NErr_True;
|
||||
}
|
||||
|
||||
int HTTPPlayback::HTTP_AudioOpen(const ifc_audioout::Parameters *format, ifc_audioout **out_output)
|
||||
{
|
||||
__android_log_print(ANDROID_LOG_INFO, "libreplicant", "[http] output_service=%x", output_service);
|
||||
return output_service->AudioOpen(format, player, secondary_parameters, out_output);
|
||||
}
|
37
Src/replicant/http/HTTPPlayback.h
Normal file
37
Src/replicant/http/HTTPPlayback.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include "nx/nxonce.h"
|
||||
#include "jnetlib/jnetlib.h"
|
||||
#include "http/ifc_http_demuxer.h"
|
||||
#include "http/ifc_http.h"
|
||||
#include "nswasabi/PlaybackBase.h"
|
||||
|
||||
class HTTPPlayback : public PlaybackBase, public ifc_http
|
||||
{
|
||||
public:
|
||||
HTTPPlayback();
|
||||
~HTTPPlayback();
|
||||
|
||||
int Initialize(nx_uri_t url, ifc_player *player);
|
||||
/* ifc_http implementation */
|
||||
int WASABICALL HTTP_Wake(int mask);
|
||||
int WASABICALL HTTP_Check(int mask);
|
||||
int WASABICALL HTTP_Wait(unsigned int milliseconds, int mask);
|
||||
int WASABICALL HTTP_Sleep(int milliseconds, int mask);
|
||||
Agave_Seek *WASABICALL HTTP_GetSeek();
|
||||
void WASABICALL HTTP_FreeSeek(Agave_Seek *seek);
|
||||
int WASABICALL HTTP_Seek(uint64_t byte_position);
|
||||
int WASABICALL HTTP_Seekable();
|
||||
int WASABICALL HTTP_AudioOpen(const ifc_audioout::Parameters *format, ifc_audioout **out_output);
|
||||
private:
|
||||
int Internal_Connect(uint64_t byte_position);
|
||||
ifc_http_demuxer *demuxer;
|
||||
|
||||
volatile int paused;
|
||||
volatile int stopped;
|
||||
jnl_http_t http;
|
||||
|
||||
int Init();
|
||||
|
||||
nx_thread_return_t NXTHREADCALL DecodeLoop();
|
||||
static nx_thread_return_t NXTHREADCALL HTTPPlayerThreadFunction(nx_thread_parameter_t param);
|
||||
};
|
28
Src/replicant/http/HTTPPlaybackService.cpp
Normal file
28
Src/replicant/http/HTTPPlaybackService.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "HTTPPlaybackService.h"
|
||||
#include "player/ifc_player.h"
|
||||
#include "player/ifc_playback.h"
|
||||
#include "HTTPPlayback.h"
|
||||
#include "nx/nxpath.h"
|
||||
#include "nswasabi/ReferenceCounted.h"
|
||||
|
||||
int HTTPPlaybackService::PlaybackService_CreatePlayback(unsigned int pass, nx_uri_t filename, ifc_player *player, ifc_playback **out_playback_object)
|
||||
{
|
||||
if (NXPathProtocol(filename, "http") == NErr_Success)
|
||||
{
|
||||
HTTPPlayback *http_playback = new ReferenceCounted<HTTPPlayback>;
|
||||
if (!http_playback)
|
||||
return NErr_OutOfMemory;
|
||||
|
||||
int ret = http_playback->Initialize(filename, player);
|
||||
if (ret != NErr_Success)
|
||||
{
|
||||
http_playback->ifc_playback::Release();
|
||||
return ret;
|
||||
}
|
||||
|
||||
*out_playback_object = http_playback;
|
||||
return NErr_Success;
|
||||
}
|
||||
return NErr_False;
|
||||
}
|
||||
|
16
Src/replicant/http/HTTPPlaybackService.h
Normal file
16
Src/replicant/http/HTTPPlaybackService.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include "player/svc_playback.h"
|
||||
#include "nx/nxstring.h"
|
||||
#include "nswasabi/ServiceName.h"
|
||||
|
||||
// {672AF800-F239-40e5-8C87-3B4D305B72B2}
|
||||
static const GUID http_playback_guid =
|
||||
{ 0x672af800, 0xf239, 0x40e5, { 0x8c, 0x87, 0x3b, 0x4d, 0x30, 0x5b, 0x72, 0xb2 } };
|
||||
|
||||
class HTTPPlaybackService : public svc_playback
|
||||
{
|
||||
public:
|
||||
WASABI_SERVICE_NAME("HTTP Playback Service");
|
||||
static GUID GetServiceGUID() { return http_playback_guid; }
|
||||
int WASABICALL PlaybackService_CreatePlayback(unsigned int pass, nx_uri_t filename, ifc_player *player, ifc_playback **out_playback_object);
|
||||
};
|
8
Src/replicant/http/api.h
Normal file
8
Src/replicant/http/api.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include "service/api_service.h"
|
||||
extern api_service *serviceApi;
|
||||
#define WASABI2_API_SVC serviceApi
|
||||
|
||||
#include "application/api_application.h"
|
||||
extern api_application *applicationApi;
|
||||
#define WASABI2_API_APP applicationApi
|
156
Src/replicant/http/http.vcxproj
Normal file
156
Src/replicant/http/http.vcxproj
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B6B8BAE5-BC2C-4A78-97C3-D0A5053F11F2}</ProjectGuid>
|
||||
<RootNamespace>http</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>x86_Debug\</OutDir>
|
||||
<IntDir>x86_Debug\</IntDir>
|
||||
<TargetExt>.w5c</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>x64_Debug\</OutDir>
|
||||
<IntDir>x64_Debug\</IntDir>
|
||||
<TargetExt>.w5c</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>x86_Release\</OutDir>
|
||||
<IntDir>x86_Release\</IntDir>
|
||||
<TargetExt>.w5c</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>x64_Release\</OutDir>
|
||||
<IntDir>x64_Release\</IntDir>
|
||||
<TargetExt>.w5c</TargetExt>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTP_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>copy "$(TargetPath)" "$(ProgramFiles)\Replicant\$(TargetName)$(TargetExt)"</Command>
|
||||
<Outputs>$(ProgramFiles)\Replicant\$(TargetName)$(TargetExt)</Outputs>
|
||||
<Inputs>$(TargetPath);%(Inputs)</Inputs>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTP_EXPORTS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>copy "$(TargetPath)" "$(ProgramFiles)\Replicant\$(TargetName)$(TargetExt)"</Command>
|
||||
<Outputs>$(ProgramFiles)\Replicant\$(TargetName)$(TargetExt)</Outputs>
|
||||
<Inputs>$(TargetPath);%(Inputs)</Inputs>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="HTTPPlayback.cpp" />
|
||||
<ClCompile Include="HTTPPlaybackService.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="HTTPPlayback.h" />
|
||||
<ClInclude Include="HTTPPlaybackService.h" />
|
||||
<ClInclude Include="ifc_http.h" />
|
||||
<ClInclude Include="ifc_http_demuxer.h" />
|
||||
<ClInclude Include="svc_http_demuxer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\jnetlib\jnetlib.vcxproj">
|
||||
<Project>{e105a0a2-7391-47c5-86ac-718003524c3d}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\nswasabi\nswasabi.vcxproj">
|
||||
<Project>{480502a0-71da-4bf0-bf99-2720d69a526b}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\nu\nu.vcxproj">
|
||||
<Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\nx\nx.vcxproj">
|
||||
<Project>{2851cf33-337d-44d9-ba6d-30547b1cdef0}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
68
Src/replicant/http/ifc_http.h
Normal file
68
Src/replicant/http/ifc_http.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
#include "foundation/dispatch.h"
|
||||
#include "player/ifc_playback.h"
|
||||
#include "foundation/types.h"
|
||||
// TODO: benski> not sure that this is the best name for it, but it works for now
|
||||
|
||||
class ifc_http : public Wasabi2::Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_http() : Dispatchable(DISPATCHABLE_VERSION) {}
|
||||
~ifc_http() {}
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
WAKE_KILL=(1<<0),
|
||||
WAKE_PLAY=(1<<1),
|
||||
WAKE_PAUSE=(1<<2),
|
||||
WAKE_STOP=(1<<3),
|
||||
WAKE_INTERRUPT=(1<<4),
|
||||
WAKE_UNPAUSE=(1<<5), // this is actually unused in wake_flags, just used as a return value from Wake/WakeReason
|
||||
WAKE_RESUME=(1<<6), // this is actually unused in wake_flags, just used as a return value from Wake/WakeReason
|
||||
WAKE_START_MASK = WAKE_PLAY|WAKE_STOP,
|
||||
WAKE_KILL_MASK = WAKE_KILL|WAKE_STOP,
|
||||
WAKE_ALL_MASK = WAKE_KILL|WAKE_PLAY|WAKE_PAUSE|WAKE_STOP|WAKE_INTERRUPT,
|
||||
};
|
||||
|
||||
// these aren't the best names, either
|
||||
|
||||
// if playback flag isn't ready, sleeps until a flag changes and returns changed flag
|
||||
int Wake(int mask) { return HTTP_Wake(mask); }
|
||||
|
||||
// checks for pending flags and updates them
|
||||
int Check(int mask) { return HTTP_Check(mask); }
|
||||
|
||||
// like wake, but only wait a specified amount of time. will return 0 if flags didn't change
|
||||
int Wait(unsigned int milliseconds, int mask) { return HTTP_Wait(milliseconds, mask); }
|
||||
|
||||
int Sleep(unsigned int milliseconds, int mask) { return HTTP_Sleep(milliseconds, mask); }
|
||||
|
||||
Agave_Seek *GetSeek() { return HTTP_GetSeek(); }
|
||||
void FreeSeek(Agave_Seek *seek) { HTTP_FreeSeek(seek); }
|
||||
|
||||
int Seek(uint64_t byte_position) { return HTTP_Seek(byte_position); }
|
||||
|
||||
/* returns NErr_True / NErr_False, returns whether or not it's seekable by Range headers.
|
||||
NErr_True doesn't mean 100% certainity that the stream is seekable.
|
||||
Note that some protocols (e.g. RTSP) might still be seekable by other means than Range headers. */
|
||||
int Seekable() { return HTTP_Seekable(); }
|
||||
|
||||
int AudioOpen(const ifc_audioout::Parameters *format, ifc_audioout **out_output) { return HTTP_AudioOpen(format, out_output); }
|
||||
|
||||
enum
|
||||
{
|
||||
DISPATCHABLE_VERSION,
|
||||
};
|
||||
protected:
|
||||
virtual int WASABICALL HTTP_Wake(int mask)=0;
|
||||
virtual int WASABICALL HTTP_Check(int mask)=0;
|
||||
virtual int WASABICALL HTTP_Wait(unsigned int milliseconds, int mask)=0;
|
||||
virtual int WASABICALL HTTP_Sleep(int milliseconds, int mask)=0;
|
||||
virtual Agave_Seek *WASABICALL HTTP_GetSeek()=0;
|
||||
virtual void WASABICALL HTTP_FreeSeek(Agave_Seek *seek)=0;
|
||||
virtual int WASABICALL HTTP_Seek(uint64_t byte_position)=0;
|
||||
virtual int WASABICALL HTTP_Seekable()=0;
|
||||
virtual int WASABICALL HTTP_AudioOpen(const ifc_audioout::Parameters *format, ifc_audioout **out_output)=0;
|
||||
|
||||
};
|
25
Src/replicant/http/ifc_http_demuxer.h
Normal file
25
Src/replicant/http/ifc_http_demuxer.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "jnetlib/jnetlib_defines.h"
|
||||
#include "foundation/dispatch.h"
|
||||
#include "foundation/error.h"
|
||||
#include "player/svc_output.h"
|
||||
#include "player/ifc_player.h"
|
||||
#include "http/ifc_http.h"
|
||||
#include "player/ifc_playback_parameters.h"
|
||||
|
||||
class ifc_http_demuxer: public Wasabi2::Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_http_demuxer() : Dispatchable(DISPATCHABLE_VERSION) {}
|
||||
~ifc_http_demuxer() {}
|
||||
public:
|
||||
enum
|
||||
{
|
||||
DISPATCHABLE_VERSION,
|
||||
};
|
||||
|
||||
int Run(ifc_http *http_parent, ifc_player *player, ifc_playback_parameters *secondary_parameters) { return HTTPDemuxer_Run(http_parent, player, secondary_parameters); }
|
||||
|
||||
protected:
|
||||
virtual int WASABICALL HTTPDemuxer_Run(ifc_http *http_parent, ifc_player *player, ifc_playback_parameters *secondary_parameters)=0;
|
||||
};
|
68
Src/replicant/http/main.cpp
Normal file
68
Src/replicant/http/main.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "api.h"
|
||||
#include "jnetlib/jnetlib.h"
|
||||
#include "component/ifc_component.h"
|
||||
#include "service/ifc_servicefactory.h"
|
||||
#include "foundation/export.h"
|
||||
#include "nswasabi/singleton.h"
|
||||
#include "HTTPPlaybackService.h"
|
||||
|
||||
static SingletonService<HTTPPlaybackService, svc_playback> playback_factory;
|
||||
|
||||
// {446BFBF6-8CE9-4697-844E-8386B5037685}
|
||||
static const GUID http_component_guid =
|
||||
{ 0x446bfbf6, 0x8ce9, 0x4697, { 0x84, 0x4e, 0x83, 0x86, 0xb5, 0x3, 0x76, 0x85 } };
|
||||
|
||||
|
||||
class HTTPComponent : public ifc_component
|
||||
{
|
||||
public:
|
||||
HTTPComponent() : ifc_component(http_component_guid) {}
|
||||
int WASABICALL Component_Initialize(api_service *service);
|
||||
int WASABICALL Component_RegisterServices(api_service *service);
|
||||
|
||||
void WASABICALL Component_DeregisterServices(api_service *service);
|
||||
int WASABICALL Component_Quit(api_service *_service_manager);
|
||||
};
|
||||
|
||||
static HTTPComponent http_component;
|
||||
api_service *WASABI2_API_SVC=0;
|
||||
api_application *WASABI2_API_APP=0;
|
||||
|
||||
int HTTPComponent::Component_Initialize(api_service *service)
|
||||
{
|
||||
int ret = jnl_init();
|
||||
if (ret != NErr_Success)
|
||||
return ret;
|
||||
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
int HTTPComponent::Component_RegisterServices(api_service *service)
|
||||
{
|
||||
WASABI2_API_SVC = service;
|
||||
|
||||
// get application API
|
||||
WASABI2_API_SVC->GetService(&WASABI2_API_APP);
|
||||
|
||||
playback_factory.Register(WASABI2_API_SVC);
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
void HTTPComponent::Component_DeregisterServices(api_service *service)
|
||||
{
|
||||
playback_factory.Deregister(WASABI2_API_SVC);
|
||||
|
||||
if (WASABI2_API_APP)
|
||||
WASABI2_API_APP->Release();
|
||||
}
|
||||
|
||||
int HTTPComponent::Component_Quit(api_service *_service_manager)
|
||||
{
|
||||
jnl_quit();
|
||||
return NErr_Success;
|
||||
}
|
||||
|
||||
extern "C" DLLEXPORT ifc_component *GetWasabi2Component()
|
||||
{
|
||||
return &http_component;
|
||||
}
|
38
Src/replicant/http/svc_http_demuxer.h
Normal file
38
Src/replicant/http/svc_http_demuxer.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
#include "jnetlib/jnetlib_defines.h"
|
||||
#include "foundation/dispatch.h"
|
||||
#include "foundation/error.h"
|
||||
#include "http/ifc_http_demuxer.h"
|
||||
|
||||
// {5E3551B0-B0FF-4997-89E4-958545C3EC19}
|
||||
static const GUID demuxer_service_type_guid =
|
||||
{ 0x5E3551B0, 0xB0FF, 0x4997, { 0x89, 0xE4, 0x95, 0x85, 0x45, 0xC3, 0xEC, 0x19 } };
|
||||
|
||||
class svc_http_demuxer: public Wasabi2::Dispatchable
|
||||
{
|
||||
protected:
|
||||
svc_http_demuxer() : Dispatchable(DISPATCHABLE_VERSION) {}
|
||||
~svc_http_demuxer() {}
|
||||
public:
|
||||
static GUID GetServiceType() { return demuxer_service_type_guid; }
|
||||
/* returns types to be added to "Accept" HTTP header */
|
||||
const char *EnumerateAcceptedTypes(size_t i) { return HTTPDemuxerService_EnumerateAcceptedTypes(i); }
|
||||
/* returns a string to be added to the user-agent (e.g. Ultravox/2.1) */
|
||||
const char *GetUserAgent() { return HTTPDemuxerService_GetUserAgent(); }
|
||||
/* allows service to do any necessary customization (mainly for adding headers) */
|
||||
void CustomizeHTTP(jnl_http_t http) { HTTPDemuxerService_CustomizeHTTP(http); }
|
||||
|
||||
/* if you create a demuxer, you now own http and are expected to call jnl_http_release on it when you are done */
|
||||
/* you can return NErr_TryAgain to let everyone else go first, you'll be called again with pass=1 */
|
||||
NError CreateDemuxer(nx_uri_t uri, jnl_http_t http, ifc_http_demuxer **demuxer, int pass) { return HTTPDemuxerService_CreateDemuxer(uri, http, demuxer, pass); }
|
||||
enum
|
||||
{
|
||||
DISPATCHABLE_VERSION,
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual const char *WASABICALL HTTPDemuxerService_EnumerateAcceptedTypes(size_t i) = 0;
|
||||
virtual const char *WASABICALL HTTPDemuxerService_GetUserAgent() = 0;
|
||||
virtual void WASABICALL HTTPDemuxerService_CustomizeHTTP(jnl_http_t http) = 0;
|
||||
virtual NError WASABICALL HTTPDemuxerService_CreateDemuxer(nx_uri_t uri, jnl_http_t http, ifc_http_demuxer **demuxer, int pass) = 0;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue