/* * API - service related calls * * Copyright (C) 2013 Adam Sutton * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef __TVH_API_SERVICE_H__ #define __TVH_API_SERVICE_H__ #include "tvheadend.h" #include "service.h" #include "service_mapper.h" #include "access.h" #include "api.h" #include "notify.h" static int api_mapper_start ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { service_mapper_conf_t conf = { 0 }; htsmsg_t *uuids; #define get_u32(x)\ conf.x = htsmsg_get_bool_or_default(args, #x, 0) /* Get config */ uuids = htsmsg_get_list(args, "uuids"); get_u32(check_availability); get_u32(encrypted); get_u32(merge_same_name); get_u32(provider_tags); pthread_mutex_lock(&global_lock); service_mapper_start(&conf, uuids); pthread_mutex_unlock(&global_lock); return 0; } static int api_mapper_stop ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { pthread_mutex_lock(&global_lock); service_mapper_stop(); pthread_mutex_unlock(&global_lock); return 0; } static htsmsg_t * api_mapper_status_msg ( void ) { htsmsg_t *m; service_mapper_status_t stat = service_mapper_status(); m = htsmsg_create_map(); htsmsg_add_u32(m, "total", stat.total); htsmsg_add_u32(m, "ok", stat.ok); htsmsg_add_u32(m, "fail", stat.fail); htsmsg_add_u32(m, "ignore", stat.ignore); if (stat.active) htsmsg_add_str(m, "active", idnode_uuid_as_str(&stat.active->s_id)); return m; } static int api_mapper_status ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { pthread_mutex_lock(&global_lock); *resp = api_mapper_status_msg(); pthread_mutex_unlock(&global_lock); return 0; } void api_service_mapper_notify ( void ) { notify_by_msg("servicemapper", api_mapper_status_msg()); } static htsmsg_t * api_service_streams_get_one ( elementary_stream_t *es, int use_filter ) { htsmsg_t *e = htsmsg_create_map(); htsmsg_add_u32(e, "index", es->es_index); htsmsg_add_u32(e, "pid", es->es_pid); htsmsg_add_str(e, "type", streaming_component_type2txt(es->es_type)); htsmsg_add_str(e, "language", es->es_lang); if (SCT_ISSUBTITLE(es->es_type)) { htsmsg_add_u32(e, "composition_id", es->es_composition_id); htsmsg_add_u32(e, "ancillary_id", es->es_ancillary_id); } else if (SCT_ISAUDIO(es->es_type)) { htsmsg_add_u32(e, "audio_type", es->es_audio_type); } else if (SCT_ISVIDEO(es->es_type)) { htsmsg_add_u32(e, "width", es->es_width); htsmsg_add_u32(e, "height", es->es_height); htsmsg_add_u32(e, "duration", es->es_frame_duration); htsmsg_add_u32(e, "aspect_num", es->es_aspect_num); htsmsg_add_u32(e, "aspect_den", es->es_aspect_den); } else if (es->es_type == SCT_CA) { caid_t *ca; htsmsg_t *e2, *l2 = htsmsg_create_list(); LIST_FOREACH(ca, &es->es_caids, link) { if (use_filter && !ca->use) continue; e2 = htsmsg_create_map(); htsmsg_add_u32(e2, "caid", ca->caid); htsmsg_add_u32(e2, "provider", ca->providerid); htsmsg_add_msg(l2, NULL, e2); } htsmsg_add_msg(e, "caids", l2); } return e; } static int api_service_streams ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { const char *uuid; htsmsg_t *e, *st, *stf; service_t *s; elementary_stream_t *es; /* No UUID */ if (!(uuid = htsmsg_get_str(args, "uuid"))) return EINVAL; pthread_mutex_lock(&global_lock); /* Couldn't find */ if (!(s = service_find(uuid))) { pthread_mutex_unlock(&global_lock); return EINVAL; } /* Build response */ pthread_mutex_lock(&s->s_stream_mutex); st = htsmsg_create_list(); stf = htsmsg_create_list(); if (s->s_pcr_pid) { e = htsmsg_create_map(); htsmsg_add_u32(e, "pid", s->s_pcr_pid); htsmsg_add_str(e, "type", "PCR"); htsmsg_add_msg(st, NULL, e); } if (s->s_pmt_pid) { e = htsmsg_create_map(); htsmsg_add_u32(e, "pid", s->s_pmt_pid); htsmsg_add_str(e, "type", "PMT"); htsmsg_add_msg(st, NULL, e); } TAILQ_FOREACH(es, &s->s_components, es_link) htsmsg_add_msg(st, NULL, api_service_streams_get_one(es, 0)); if (TAILQ_FIRST(&s->s_filt_components) == NULL || s->s_status == SERVICE_IDLE) service_build_filter(s); TAILQ_FOREACH(es, &s->s_filt_components, es_filt_link) htsmsg_add_msg(stf, NULL, api_service_streams_get_one(es, 1)); *resp = htsmsg_create_map(); htsmsg_add_str(*resp, "name", s->s_nicename); htsmsg_add_msg(*resp, "streams", st); htsmsg_add_msg(*resp, "fstreams", stf); pthread_mutex_unlock(&s->s_stream_mutex); /* Done */ pthread_mutex_unlock(&global_lock); return 0; } void api_service_init ( void ) { extern const idclass_t service_class; static api_hook_t ah[] = { { "service/mapper/start", ACCESS_ADMIN, api_mapper_start, NULL }, { "service/mapper/stop", ACCESS_ADMIN, api_mapper_stop, NULL }, { "service/mapper/status", ACCESS_ADMIN, api_mapper_status, NULL }, { "service/list", ACCESS_ANONYMOUS, api_idnode_load_by_class, (void*)&service_class }, { "service/streams", ACCESS_ANONYMOUS, api_service_streams, NULL }, { NULL }, }; api_register_all(ah); } #endif /* __TVH_API_IDNODE_H__ */