This source file includes following definitions.
- HYB_RegisterMimeTypes
- HYB_CanHandleURL
- hybmedia_sanity_check
- HYB_ConnectService
- HYB_CloseService
- HYB_GetServiceDesc
- HYB_ConnectChannel
- HYB_DisconnectChannel
- HYB_ServiceCommand
- HYB_CanHandleURLInService
- HYB_ChannelGetSLP
- HYB_ChannelReleaseSLP
- QueryInterfaces
- LoadInterface
- ShutdownInterface
#include "hyb_in.h"
extern GF_HYBMEDIA master_fm_mmbtools;
extern GF_HYBMEDIA master_fm_fake_pull;
extern GF_HYBMEDIA master_fm_fake_push;
GF_HYBMEDIA* hyb_masters[] = {
&master_fm_fake_pull,
&master_fm_fake_push,
#ifdef GPAC_ANDROID
&master_fm_mmbtools,
#endif
};
typedef struct {
GF_ClientService *service;
GF_HYBMEDIA* master;
} GF_HYB_In;
static u32 HYB_RegisterMimeTypes(const GF_InputService *plug)
{
if (!plug)
return 0;
return 1;
}
static Bool HYB_CanHandleURL(GF_InputService *plug, const char *url)
{
u32 i;
const size_t nb_masters = sizeof(hyb_masters) / sizeof(GF_HYBMEDIA*);
for (i=0; i<nb_masters; i++) {
if (hyb_masters[i]->CanHandleURL(url))
return 1;
}
return 0;
}
static GF_Err hybmedia_sanity_check(GF_HYBMEDIA *master)
{
if (master->data_mode != HYB_PUSH && master->data_mode != HYB_PULL)
return GF_BAD_PARAM;
if (!master->name) goto error_exit;
if (!master->CanHandleURL) goto error_exit;
if (!master->GetOD) goto error_exit;
if (!master->Connect) goto error_exit;
if (!master->Disconnect) goto error_exit;
if (master->data_mode == HYB_PUSH) {
if (!master->SetState) goto error_exit;
}
if (master->data_mode == HYB_PULL) {
if (!master->GetData) goto error_exit;
if (!master->ReleaseData) goto error_exit;
}
return GF_OK;
error_exit:
return GF_SERVICE_ERROR;
}
static GF_Err HYB_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
u32 i;
GF_Err e = GF_OK;
const size_t nb_masters = sizeof(hyb_masters) / sizeof(GF_HYBMEDIA*);
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Received Connection request from service %p for %s\n", serv, url));
if (!hyb_in || !serv || !url) return GF_BAD_PARAM;
hyb_in->service = serv;
for (i=0; i<nb_masters; i++) {
if (hyb_masters[i]->CanHandleURL(url)) {
hyb_in->master = hyb_masters[i];
break;
}
}
assert(hyb_in->master);
e = hybmedia_sanity_check(hyb_in->master);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[HYB_IN] Error - object \"%s\" failed the sanity checks\n", hyb_in->master->name));
gf_service_connect_ack(hyb_in->service, NULL, e);
return e;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Selected master object \"%s\" for URL: %s\n", hyb_in->master->name, url));
e = hyb_in->master->Connect(hyb_in->master, hyb_in->service, url);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[HYB_IN] Error - cannot connect service, wrong URL %s\n", url));
gf_service_connect_ack(hyb_in->service, NULL, GF_BAD_PARAM);
return e;
}
gf_service_connect_ack(hyb_in->service, NULL, GF_OK);
gf_service_declare_media(hyb_in->service, (GF_Descriptor*)hyb_in->master->GetOD(), 0);
return GF_OK;
}
static GF_Err HYB_CloseService(GF_InputService *plug)
{
GF_Err e;
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Received Close Service (%p) request from terminal\n", ((GF_HYB_In*)plug->priv)->service));
hyb_in->master->SetState(hyb_in->master, GF_NET_CHAN_STOP);
e = hyb_in->master->Disconnect(hyb_in->master);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[HYB_IN] Error - cannot disconnect service %p\n", hyb_in->service));
gf_service_connect_ack(hyb_in->service, NULL, GF_BAD_PARAM);
return e;
}
gf_service_disconnect_ack(hyb_in->service, NULL, GF_OK);
return GF_OK;
}
static GF_Descriptor *HYB_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url)
{
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Received Service Description request from terminal for %s\n", sub_url));
return NULL;
}
static GF_Err HYB_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream)
{
GF_HYB_In *hyb_in;
GF_HYBMEDIA *master;
if (!plug || !plug->priv)
return GF_SERVICE_ERROR;
hyb_in = (GF_HYB_In*)plug->priv;
master = (GF_HYBMEDIA*)hyb_in->master;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Received Channel Connection request from service %p for %s\n", channel, url));
master->channel = channel;
gf_service_connect_ack(hyb_in->service, channel, GF_OK);
return GF_OK;
}
static GF_Err HYB_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[HYB_IN] Received Channel Disconnect Service (%p) request from terminal\n", hyb_in->service));
gf_service_disconnect_ack(hyb_in->service, channel, GF_OK);
hyb_in->master->channel = NULL;
return GF_OK;
}
static GF_Err HYB_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com)
{
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
switch (com->command_type) {
case GF_NET_CHAN_SET_SPEED:
assert(hyb_in->master->data_mode == HYB_PULL);
return GF_OK;
case GF_NET_CHAN_INTERACTIVE:
return GF_NOT_SUPPORTED;
case GF_NET_CHAN_BUFFER:
com->buffer.max = com->buffer.min = 0;
return GF_OK;
case GF_NET_CHAN_DURATION:
com->duration.duration = 0;
return GF_OK;
case GF_NET_CHAN_PLAY:
case GF_NET_CHAN_STOP:
case GF_NET_CHAN_PAUSE:
case GF_NET_CHAN_RESUME:
if (hyb_in->master->data_mode == HYB_PUSH)
return hyb_in->master->SetState(hyb_in->master, com->command_type);
return GF_OK;
case GF_NET_CHAN_SET_PULL:
if (hyb_in->master->data_mode == HYB_PULL)
return GF_OK;
else
return GF_NOT_SUPPORTED;
}
return GF_OK;
}
static Bool HYB_CanHandleURLInService(GF_InputService *plug, const char *url)
{
return 0;
}
static GF_Err HYB_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, char **out_data_ptr, u32 *out_data_size, GF_SLHeader *out_sl_hdr, Bool *sl_compressed, GF_Err *out_reception_status, Bool *is_new_data)
{
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
assert(hyb_in->master->data_mode == HYB_PULL && hyb_in->master->GetData && hyb_in->master->ReleaseData);
assert(((GF_HYB_In*)plug->priv)->master->channel == channel);
hyb_in->master->GetData(hyb_in->master, out_data_ptr, out_data_size, out_sl_hdr);
*sl_compressed = 0;
*out_reception_status = GF_OK;
*is_new_data = 1;
return GF_OK;
}
static GF_Err HYB_ChannelReleaseSLP(GF_InputService *plug, LPNETCHANNEL channel)
{
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
assert(((GF_HYB_In*)plug->priv)->master->channel == channel);
return GF_OK;
}
GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
static u32 si [] = {
GF_NET_CLIENT_INTERFACE,
0
};
return si;
}
GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
GF_HYB_In *hyb_in;
GF_InputService *plug;
if (InterfaceType != GF_NET_CLIENT_INTERFACE) return NULL;
GF_SAFEALLOC(plug, GF_InputService);
GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC HYBRID MEDIA Loader", "gpac distribution")
plug->RegisterMimeTypes= HYB_RegisterMimeTypes;
plug->CanHandleURL= HYB_CanHandleURL;
plug->ConnectService= HYB_ConnectService;
plug->CloseService= HYB_CloseService;
plug->GetServiceDescriptor= HYB_GetServiceDesc;
plug->ConnectChannel= HYB_ConnectChannel;
plug->DisconnectChannel= HYB_DisconnectChannel;
plug->ServiceCommand= HYB_ServiceCommand;
plug->CanHandleURLInService=HYB_CanHandleURLInService;
plug->ChannelGetSLP= HYB_ChannelGetSLP;
plug->ChannelReleaseSLP= HYB_ChannelReleaseSLP;
GF_SAFEALLOC(hyb_in, GF_HYB_In);
plug->priv = hyb_in;
return (GF_BaseInterface *)plug;
}
GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *ifce)
{
GF_LOG(GF_LOG_MEDIA, GF_LOG_ERROR, ("DeleteLoaderInterface %p: 1\n", ifce));
if (ifce->InterfaceType == GF_NET_CLIENT_INTERFACE) {
GF_InputService *plug = (GF_InputService*)ifce;
GF_HYB_In *hyb_in = (GF_HYB_In*)plug->priv;
gf_free(hyb_in);
plug->priv = NULL;
gf_free(plug);
GF_LOG(GF_LOG_MEDIA, GF_LOG_ERROR, ("DeleteLoaderInterface %p: 2\n", ifce));
}
}
GPAC_MODULE_STATIC_DECLARATION( hyb_in )