Files
neutrino/src/driver/radiotext.cpp
[CST] Focus 4b086415d8 driver/radiotext.cpp: rework CRadioText,
thread now persistent, minimal delay for stop at zap,
for testing
2012-10-25 18:48:36 +04:00

2421 lines
72 KiB
C++

/*
$Id: radiotext.cpp,v 1.7 2009/10/31 10:11:02 seife Exp $
Neutrino-GUI - DBoxII-Project
License: GPL
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
ripped from:
*/
/*
* radioaudio.c: A plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* This is a "plugin" for the Video Disk Recorder (VDR).
*
* Written by: Lars Tegeler <email@host.dom>
*
* Project's homepage: www.math.uni-paderborn.de/~tegeler/vdr
*
* Latest version available at: URL
*
* See the file COPYING for license information.
*
* Description:
*
* This Plugin display an background image while the vdr is switcht to radio channels.
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <malloc.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <ctype.h>
#include <config.h>
#if 0
#ifdef HAVE_TRIPLEDRAGON
#include <zapit/td-demux-compat.h>
#include <tddevices.h>
#define DMXDEV "/dev/" DEVICE_NAME_DEMUX "1"
#elif HAVE_DVB_API_VERSION < 3
#include <ost/dmx.h>
#define DMXDEV "/dev/dvb/card0/demux0"
#define DVRDEV "/dev/dvb/card0/dvr0"
#define dmx_pes_filter_params dmxPesFilterParams
#define pes_type pesType
#else
#include <linux/dvb/dmx.h>
#define DMXDEV "/dev/dvb/adapter0/demux0"
#define DVRDEV "/dev/dvb/adapter0/dvr0"
#endif
#endif
#include <global.h>
#include <system/settings.h>
#include <neutrino.h>
#include <gui/color.h>
extern "C" {
#include "ringbuffer.h"
}
#include "radiotext.h"
#include "radiotools.h"
rtp_classes rtp_content;
// RDS rest
bool RDS_PSShow = false;
int RDS_PSIndex = 0;
char RDS_PSText[12][9];
// plugin audiorecorder service
bool ARec_Receive = false, ARec_Record = false;
#if ENABLE_RASS
// ... Gallery (1..999)
#define RASS_GALMAX 999
bool Rass_Gallery[RASS_GALMAX+1];
int Rass_GalStart, Rass_GalEnd, Rass_GalCount, Rass_SlideFoto;
#endif
#define floor
const char *DataDir = "./";
//cRadioAudio *RadioAudio;
//cRadioTextOsd *RadioTextOsd;
//cRDSReceiver *RDSReceiver;
// RDS-Chartranslation: 0x80..0xff
unsigned char rds_addchar[128] = {
0xe1, 0xe0, 0xe9, 0xe8, 0xed, 0xec, 0xf3, 0xf2,
0xfa, 0xf9, 0xd1, 0xc7, 0x8c, 0xdf, 0x8e, 0x8f,
0xe2, 0xe4, 0xea, 0xeb, 0xee, 0xef, 0xf4, 0xf6,
0xfb, 0xfc, 0xf1, 0xe7, 0x9c, 0x9d, 0x9e, 0x9f,
0xaa, 0xa1, 0xa9, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xa3, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xba, 0xb9, 0xb2, 0xb3, 0xb1, 0xa1, 0xb6, 0xb7,
0xb5, 0xbf, 0xf7, 0xb0, 0xbc, 0xbd, 0xbe, 0xa7,
0xc1, 0xc0, 0xc9, 0xc8, 0xcd, 0xcc, 0xd3, 0xd2,
0xda, 0xd9, 0xca, 0xcb, 0xcc, 0xcd, 0xd0, 0xcf,
0xc2, 0xc4, 0xca, 0xcb, 0xce, 0xcf, 0xd4, 0xd6,
0xdb, 0xdc, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xc3, 0xc5, 0xc6, 0xe3, 0xe4, 0xdd, 0xd5, 0xd8,
0xde, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xf0,
0xe3, 0xe5, 0xe6, 0xf3, 0xf4, 0xfd, 0xf5, 0xf8,
0xfe, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
static const char *entitystr[5] = { "&apos;", "&amp;", "&quote;", "&gt", "&lt" };
static const char *entitychar[5] = { "'", "&", "\"", ">", "<" };
char *CRadioText::rds_entitychar(char *text)
{
int i = 0, l, lof, lre, space;
char *temp;
while (i < 5) {
if ((temp = strstr(text, entitystr[i])) != NULL) {
if (S_Verbose >= 2)
printf("RText-Entity: %s\n", text);
l = strlen(entitystr[i]);
lof = (temp-text);
if (strlen(text) < RT_MEL) {
lre = strlen(text) - lof - l;
space = 1;
}
else {
lre = RT_MEL - 1 - lof - l;
space = 0;
}
memmove(text+lof, entitychar[i], 1);
memmove(text+lof+1, temp+l, lre);
if (space != 0)
memmove(text+lof+1+lre, " ", l-1);
}
else i++;
}
return text;
}
char* CRadioText::ptynr2string(int nr)
{
switch (nr) {
// Source: http://www.ebu.ch/trev_255-beale.pdf
case 0: return tr(const_cast<char *>("unknown program type"));
case 1: return tr(const_cast<char *>("News"));
case 2: return tr(const_cast<char *>("Current affairs"));
case 3: return tr(const_cast<char *>("Information"));
case 4: return tr(const_cast<char *>("Sport"));
case 5: return tr(const_cast<char *>("Education"));
case 6: return tr(const_cast<char *>("Drama"));
case 7: return tr(const_cast<char *>("Culture"));
case 8: return tr(const_cast<char *>("Science"));
case 9: return tr(const_cast<char *>("Varied"));
case 10: return tr(const_cast<char *>("Pop music"));
case 11: return tr(const_cast<char *>("Rock music"));
case 12: return tr(const_cast<char *>("M.O.R. music"));
case 13: return tr(const_cast<char *>("Light classical"));
case 14: return tr(const_cast<char *>("Serious classical"));
case 15: return tr(const_cast<char *>("Other music"));
// 16-30 "Spares"
case 31: return tr(const_cast<char *>("Alarm"));
default: return const_cast<char *>("?");
}
}
bool CRadioText::DividePes(unsigned char *data, int length, int *substart, int *subend)
{
int i = *substart;
int found = 0;
while ((i<length-2) && (found < 2))
{
if ((found == 0) && (data[i] == 0xFF) && (data[i+1] == 0xFD)) {
*substart = i;
found++;
}
else if ((found == 1) && (data[i] == 0xFD) && (data[i+1] == 0xFF)) {
*subend = i;
found++;
}
i++;
}
if ((found == 1) && (data[length-1] == 0xFD)) {
*subend = length-1;
found++;
}
if (found == 2) {
return(true);
} else {
return(false);
}
}
int CRadioText::PES_Receive(unsigned char *data, int len)
{
const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
static unsigned char mtext[mframel+1];
static bool rt_start = false, rt_bstuff=false;
static int index;
static int mec = 0;
int offset = 0;
while (true)
{
if (len < offset + 6)
return offset;
int pesl = (data[offset + 4] << 8) + data[offset + 5] + 6;
if (pesl <= 0 || offset + pesl > len)
return offset;
offset += pesl;
/* try to find subpackets in the pes stream */
int substart = 0;
int subend = 0;
while (DividePes(&data[0], pesl, &substart, &subend))
{
int inner_offset = subend + 1;
if (inner_offset < 3) fprintf(stderr, "RT %s: inner_offset < 3 (%d)\n", __FUNCTION__, inner_offset);
int rdsl = data[subend - 1]; // RDS DataFieldLength
// RDS DataSync = 0xfd @ end
if (data[subend] == 0xfd && rdsl > 0) {
// print RawData with RDS-Info
if (S_Verbose >= 3) {
printf("\n\nPES-Data(%d/%d): ", pesl, len);
for (int a=inner_offset -rdsl; a<offset; a++)
printf("%02x ", data[a]);
printf("(End)\n\n");
}
if (subend-2-rdsl < 0) fprintf(stderr, "RT %s: start: %d subend-2-rdsl < 0 (%d-2-%d)\n", __FUNCTION__, substart,subend,rdsl);
for (int i = subend - 2, val; i > subend - 2 - rdsl; i--) { // <-- data reverse, from end to start
if (i < 0) { fprintf(stderr, "RT %s: i < 0 (%d)\n", __FUNCTION__, i); break; }
val = data[i];
if (val == 0xfe) { // Start
index = -1;
rt_start = true;
rt_bstuff = false;
if (S_Verbose >= 2)
printf("RDS-Start: ");
}
if (rt_start) {
if (S_Verbose >= 3)
printf("%02x ", val);
// byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
if (rt_bstuff) {
switch (val) {
case 0x00: mtext[index] = 0xfd; break;
case 0x01: mtext[index] = 0xfe; break;
case 0x02: mtext[index] = 0xff; break;
default: mtext[++index] = val; // should never be
}
rt_bstuff = false;
if (S_Verbose >= 3)
printf("(Bytestuffing -> %02x) ", mtext[index]);
}
else
mtext[++index] = val;
if (val == 0xfd && index > 0) // stuffing found
rt_bstuff = true;
// early check for used MEC
if (index == 5) {
//mec = val;
switch (val) {
case 0x0a: // RT
have_radiotext = true;
case 0x46: // RTplus-Tags
case 0xda: // RASS
case 0x07: // PTY
case 0x3e: // PTYN
case 0x02: // PS
mec = val;
break;
default:
rt_start = false;
if (S_Verbose >= 2)
printf("(RDS-MEC '%02x' not used -> End)\n", val);
}
}
if (index >= mframel) { // max. rdslength, garbage ?
if (S_Verbose >= 1)
printf("RDS-Error: too long, garbage ?\n");
rt_start = false;
}
}
if (rt_start && val == 0xff) { // End
if (S_Verbose >= 2)
printf("(RDS-End)\n");
rt_start = false;
if (index < 9) { // min. rdslength, garbage ?
if (S_Verbose >= 1)
printf("RDS-Error: too short -> garbage ?\n");
}
else {
// crc16-check
unsigned short crc16 = crc16_ccitt(mtext, index-3, true);
if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) {
if (S_Verbose >= 1)
printf("RDS-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]);
} else {
switch (mec) {
case 0x0a:
case 0x46:
if (S_Verbose >= 2)
printf("(RDS-MEC '%02x') -> RadiotextDecode - %d\n", mec, index);
RadiotextDecode(mtext, index); // Radiotext, RT+
break;
case 0x07: RT_PTY = mtext[8]; // PTY
RT_MsgShow = true;
if (S_Verbose >= 1)
printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY));
break;
case 0x3e:
if (S_Verbose >= 2)
printf("(RDS-MEC '%02x') -> RDS_PsPtynDecode - %d\n", mec, index);
RDS_PsPtynDecode(true, mtext, index); // PTYN
break;
case 0x02:
if (S_Verbose >= 2)
printf("(RDS-MEC '%02x') -> RDS_PsPtynDecode - %d\n", mec, index);
RDS_PsPtynDecode(false, mtext, index); // PS
break;
case 0xda:
#if ENABLE_RASS
RassDecode(mtext, index); // Rass
#endif
break;
}
}
}
}
}
}
substart = subend;
}
}
}
void CRadioText::RadiotextDecode(unsigned char *mtext, int len)
{
static bool rtp_itoggle = false;
static int rtp_idiffs = 0;
static cTimeMs rtp_itime;
static char plustext[RT_MEL];
// byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress)
// byte 3 = SQC (Sequence Counter 0x00 = not used)
int leninfo = mtext[4]; // byte 4 = MFL (Message Field Length)
if (len >= leninfo+7) { // check complete length
// byte 5 = MEC (Message Element Code, 0x0a for RT, 0x46 for RTplus)
if (mtext[5] == 0x0a) {
// byte 6+7 = DSN+PSN (DataSetNumber+ProgramServiceNumber,
// ignore here, always 0x00 ?)
// byte 8 = MEL (MessageElementLength, max. 64+1 byte @ RT)
if (mtext[8] == 0 || mtext[8] > RT_MEL || mtext[8] > leninfo-4) {
if (S_Verbose >= 1)
printf("RT-Error: Length = 0 or not correct !");
return;
}
// byte 9 = RT-Status bitcodet (0=AB-flagcontrol, 1-4=Transmission-Number, 5+6=Buffer-Config,
// ingnored, always 0x01 ?)
fprintf(stderr, "MEC=0x%02x DSN=0x%02x PSN=0x%02x MEL=%02d STATUS=0x%02x MFL=%02d\n", mtext[5], mtext[6], mtext[7], mtext[8], mtext[9], mtext[4]);
char temptext[RT_MEL];
memset(temptext, 0x20, RT_MEL-1);
temptext[RT_MEL - 1] = '\0';
for (int i = 1, ii = 0; i < mtext[8]; i++) {
if (mtext[9+i] <= 0xfe)
// additional rds-character, see RBDS-Standard, Annex E
temptext[ii++] = (mtext[9+i] >= 0x80) ? rds_addchar[mtext[9+i]-0x80] : mtext[9+i];
}
memcpy(plustext, temptext, RT_MEL);
rds_entitychar(temptext);
// check repeats
bool repeat = false;
for (int ind = 0; ind < S_RtOsdRows; ind++) {
if (memcmp(RT_Text[ind], temptext, RT_MEL-1) == 0) {
repeat = true;
if (S_Verbose >= 1)
printf("RText-Rep[%d]: %s\n", ind, RT_Text[ind]);
}
}
if (!repeat) {
memcpy(RT_Text[RT_Index], temptext, RT_MEL);
// +Memory
char *temp;
asprintf(&temp, "%s", RT_Text[RT_Index]);
if (++rtp_content.rt_Index >= 2*MAX_RTPC)
rtp_content.rt_Index = 0;
asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", rtrim(temp));
free(temp);
if (S_Verbose >= 1)
printf("Radiotext[%d]: %s\n", RT_Index, RT_Text[RT_Index]);
RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
}
RTP_TToggle = 0x03; // Bit 0/1 = Title/Artist
RT_MsgShow = true;
S_RtOsd = 1;
RT_Info = (RT_Info > 0) ? RT_Info : 1;
RadioStatusMsg();
}
else if (RTP_TToggle > 0 && mtext[5] == 0x46 && S_RtFunc >= 2) { // RTplus tags V2.0, only if RT
if (mtext[6] > leninfo-2 || mtext[6] != 8) { // byte 6 = MEL, only 8 byte for 2 tags
if (S_Verbose >= 1)
printf("RTp-Error: Length not correct !");
return;
}
uint rtp_typ[2], rtp_start[2], rtp_len[2];
// byte 7+8 = ApplicationID, always 0x4bd7
// byte 9 = Applicationgroup Typecode / PTY ?
// bit 10#4 = Item Togglebit
// bit 10#3 = Item Runningbit
// Tag1: bit 10#2..11#5 = Contenttype, 11#4..12#7 = Startmarker, 12#6..12#1 = Length
rtp_typ[0] = (0x38 & mtext[10]<<3) | mtext[11]>>5;
rtp_start[0] = (0x3e & mtext[11]<<1) | mtext[12]>>7;
rtp_len[0] = 0x3f & mtext[12]>>1;
// Tag2: bit 12#0..13#3 = Contenttype, 13#2..14#5 = Startmarker, 14#4..14#0 = Length(5bit)
rtp_typ[1] = (0x20 & mtext[12]<<5) | mtext[13]>>3;
rtp_start[1] = (0x38 & mtext[13]<<3) | mtext[14]>>5;
rtp_len[1] = 0x1f & mtext[14];
if (S_Verbose >= 2)
printf("RTplus (tag=Typ/Start/Len): Toggle/Run = %d/%d, tag#1 = %d/%d/%d, tag#2 = %d/%d/%d\n",
(mtext[10]&0x10)>0, (mtext[10]&0x08)>0, rtp_typ[0], rtp_start[0], rtp_len[0], rtp_typ[1], rtp_start[1], rtp_len[1]);
// save info
for (int i = 0; i < 2; i++) {
if (rtp_start[i]+rtp_len[i]+1 >= RT_MEL) { // length-error
if (S_Verbose >= 1)
printf("RTp-Error (tag#%d = Typ/Start/Len): %d/%d/%d (Start+Length > 'RT-MEL' !)\n",
i+1, rtp_typ[i], rtp_start[i], rtp_len[i]);
} else {
char temptext[RT_MEL];
memset(temptext, 0x20, RT_MEL-1);
memmove(temptext, plustext+rtp_start[i], rtp_len[i]+1);
rds_entitychar(temptext);
// +Memory
memset(rtp_content.temptext, 0x20, RT_MEL-1);
memcpy(rtp_content.temptext, temptext, RT_MEL-1);
switch (rtp_typ[i]) {
case 1: // Item-Title
if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x01) == 0x01) {
RTP_TToggle -= 0x01;
RT_Info = 2;
if (memcmp(RTP_Title, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) {
memcpy(RTP_Title, temptext, RT_MEL-1);
if (RT_PlusShow && rtp_itime.Elapsed() > 1000)
rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
if (!rtp_content.item_New) {
RTP_Starttime = time(NULL);
rtp_itime.Set(0);
sprintf(RTP_Artist, "---");
if (++rtp_content.item_Index >= MAX_RTPC)
rtp_content.item_Index = 0;
rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode
rtp_content.item_Artist[rtp_content.item_Index] = NULL;
}
rtp_content.item_New = (!rtp_content.item_New) ? true : false;
if (rtp_content.item_Index >= 0)
asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext));
RT_PlusShow = RT_MsgShow = rtp_itoggle = true;
}
}
break;
case 4: // Item-Artist
if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x02) == 0x02) {
RTP_TToggle -= 0x02;
RT_Info = 2;
if (memcmp(RTP_Artist, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) {
memcpy(RTP_Artist, temptext, RT_MEL-1);
if (RT_PlusShow && rtp_itime.Elapsed() > 1000)
rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
if (!rtp_content.item_New) {
RTP_Starttime = time(NULL);
rtp_itime.Set(0);
sprintf(RTP_Title, "---");
if (++rtp_content.item_Index >= MAX_RTPC)
rtp_content.item_Index = 0;
rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode
rtp_content.item_Title[rtp_content.item_Index] = NULL;
}
rtp_content.item_New = (!rtp_content.item_New) ? true : false;
if (rtp_content.item_Index >= 0)
asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext));
RT_PlusShow = RT_MsgShow = rtp_itoggle = true;
}
}
break;
case 12: // Info_News
asprintf(&rtp_content.info_News, "%s", rtrim(rtp_content.temptext));
break;
case 13: // Info_NewsLocal
asprintf(&rtp_content.info_NewsLocal, "%s", rtrim(rtp_content.temptext));
break;
case 14: // Info_Stockmarket
if (++rtp_content.info_StockIndex >= MAX_RTPC)
rtp_content.info_StockIndex = 0;
asprintf(&rtp_content.info_Stock[rtp_content.info_StockIndex], "%s", rtrim(rtp_content.temptext));
break;
case 15: // Info_Sport
if (++rtp_content.info_SportIndex >= MAX_RTPC)
rtp_content.info_SportIndex = 0;
asprintf(&rtp_content.info_Sport[rtp_content.info_SportIndex], "%s", rtrim(rtp_content.temptext));
break;
case 16: // Info_Lottery
if (++rtp_content.info_LotteryIndex >= MAX_RTPC)
rtp_content.info_LotteryIndex = 0;
asprintf(&rtp_content.info_Lottery[rtp_content.info_LotteryIndex], "%s", rtrim(rtp_content.temptext));
break;
case 24: // Info_DateTime
asprintf(&rtp_content.info_DateTime, "%s", rtrim(rtp_content.temptext));
break;
case 25: // Info_Weather
if (++rtp_content.info_WeatherIndex >= MAX_RTPC)
rtp_content.info_WeatherIndex = 0;
asprintf(&rtp_content.info_Weather[rtp_content.info_WeatherIndex], "%s", rtrim(rtp_content.temptext));
break;
case 26: // Info_Traffic
asprintf(&rtp_content.info_Traffic, "%s", rtrim(rtp_content.temptext));
break;
case 27: // Info_Alarm
asprintf(&rtp_content.info_Alarm, "%s", rtrim(rtp_content.temptext));
break;
case 28: // Info_Advert
asprintf(&rtp_content.info_Advert, "%s", rtrim(rtp_content.temptext));
break;
case 29: // Info_Url
asprintf(&rtp_content.info_Url, "%s", rtrim(rtp_content.temptext));
break;
case 30: // Info_Other
if (++rtp_content.info_OtherIndex >= MAX_RTPC)
rtp_content.info_OtherIndex = 0;
asprintf(&rtp_content.info_Other[rtp_content.info_OtherIndex], "%s", rtrim(rtp_content.temptext));
break;
case 31: // Programme_Stationname.Long
asprintf(&rtp_content.prog_Station, "%s", rtrim(rtp_content.temptext));
break;
case 32: // Programme_Now
asprintf(&rtp_content.prog_Now, "%s", rtrim(rtp_content.temptext));
break;
case 33: // Programme_Next
asprintf(&rtp_content.prog_Next, "%s", rtrim(rtp_content.temptext));
break;
case 34: // Programme_Part
asprintf(&rtp_content.prog_Part, "%s", rtrim(rtp_content.temptext));
break;
case 35: // Programme_Host
asprintf(&rtp_content.prog_Host, "%s", rtrim(rtp_content.temptext));
break;
case 36: // Programme_EditorialStaff
asprintf(&rtp_content.prog_EditStaff, "%s", rtrim(rtp_content.temptext));
break;
case 38: // Programme_Homepage
asprintf(&rtp_content.prog_Homepage, "%s", rtrim(rtp_content.temptext));
break;
case 39: // Phone_Hotline
asprintf(&rtp_content.phone_Hotline, "%s", rtrim(rtp_content.temptext));
break;
case 40: // Phone_Studio
asprintf(&rtp_content.phone_Studio, "%s", rtrim(rtp_content.temptext));
break;
case 44: // Email_Hotline
asprintf(&rtp_content.email_Hotline, "%s", rtrim(rtp_content.temptext));
break;
case 45: // Email_Studio
asprintf(&rtp_content.email_Studio, "%s", rtrim(rtp_content.temptext));
break;
}
}
}
// Title-end @ no Item-Running'
if ((mtext[10] & 0x08) == 0) {
sprintf(RTP_Title, "---");
sprintf(RTP_Artist, "---");
if (RT_PlusShow) {
RT_PlusShow = false;
rtp_itoggle = true;
rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
RTP_Starttime = time(NULL);
}
RT_MsgShow = (RT_Info > 0);
rtp_content.item_New = false;
}
if (rtp_itoggle) {
if (S_Verbose >= 1) {
struct tm tm_store;
struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
if (rtp_idiffs > 0)
printf(" StartTime : %02d:%02d:%02d (last Title elapsed = %d s)\n",
ts->tm_hour, ts->tm_min, ts->tm_sec, rtp_idiffs);
else
printf(" StartTime : %02d:%02d:%02d\n", ts->tm_hour, ts->tm_min, ts->tm_sec);
printf(" RTp-Title : %s\n RTp-Artist: %s\n", RTP_Title, RTP_Artist);
}
RTP_ItemToggle = mtext[10] & 0x10;
rtp_itoggle = false;
rtp_idiffs = 0;
RadioStatusMsg();
// AudioRecorderService();
}
RTP_TToggle = 0;
}
}
else {
if (S_Verbose >= 1)
printf("RDS-Error: [RTDecode] Length not correct !\n");
}
}
void CRadioText::RDS_PsPtynDecode(bool ptyn, unsigned char *mtext, int len)
{
if (len < 16) return;
// decode Text
for (int i = 8; i <= 15; i++) {
if (mtext[i] <= 0xfe) {
// additional rds-character, see RBDS-Standard, Annex E
if (!ptyn)
RDS_PSText[RDS_PSIndex][i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i];
else
RDS_PTYN[i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i];
}
}
if (S_Verbose >= 1) {
if (!ptyn)
printf("RDS-PS No= %d, Content[%d]= '%s'\n", mtext[7], RDS_PSIndex, RDS_PSText[RDS_PSIndex]);
else
printf("RDS-PTYN No= %d, Content= '%s'\n", mtext[7], RDS_PTYN);
}
if (!ptyn) {
RDS_PSIndex += 1; if (RDS_PSIndex >= 12) RDS_PSIndex = 0;
RT_MsgShow = RDS_PSShow = true;
}
}
void CRadioText::RadioStatusMsg(void)
{
/* announce text/items for lcdproc & other */
if (!RT_MsgShow || S_RtMsgItems <= 0)
return;
if (S_RtMsgItems >= 2) {
char temp[100];
int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
strcpy(temp, RT_Text[ind]);
printf("RadioStatusMsg = %s\n", temp);
// cStatus::MsgOsdTextItem(rtrim(temp), false);
}
if ((S_RtMsgItems == 1 || S_RtMsgItems >= 3) && ((S_RtOsdTags == 1 && RT_PlusShow) || S_RtOsdTags >= 2)) {
// struct tm tm_store;
// struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
// cStatus::MsgOsdProgramme(mktime(ts), RTP_Title, RTP_Artist, 0, NULL, NULL);
printf("RTP_Title = %s, RTP_Artist = %s\n", RTP_Title, RTP_Artist);
}
}
#if ENABLE_RASS
// add <names> of DVB Radio Slides Specification 1.0, 20061228
void CRadioText::RassDecode(unsigned char *mtext, int len)
{
static uint splfd = 0, spmax = 0, index = 0;
static uint afiles, slidenumr, slideelem, filemax, fileoffp;
static int filetype, fileoffb;
static bool slideshow = false, slidesave = false, slidecan = false, slidedel = false, start = false;
static uchar daten[65536]; // mpegs-stills defined <= 50kB
FILE *fd;
// byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress)
// byte 3 = SQC (Sequence Counter 0x00 = not used)
// byte 4 = MFL (Message Field Length),
if (len >= mtext[4]+7) { // check complete length
// byte 5 = MEC (0xda for Rass)
// byte 6 = MEL
if (mtext[6] == 0 || mtext[6] > mtext[4]-2) {
if ((S_Verbose && 0x0f) >= 1)
printf("Rass-Error: Length = 0 or not correct !\n");
return;
}
// byte 7+8 = Service-ID zugehöriger Datenkanal
// byte 9-11 = Nummer aktuelles Paket, <PNR>
uint plfd = mtext[11] + mtext[10]*256 + mtext[9]*65536;
// byte 12-14 = Anzahl Pakete, <NOP>
uint pmax = mtext[14] + mtext[13]*256 + mtext[12]*65536;
// byte 15+16 = Rass-Kennung = Header, <Rass-STA>
if (mtext[15] == 0x40 && mtext[16] == 0xda) { // first
// byte 17+18 = Anzahl Dateien im Archiv, <NOI>
afiles = mtext[18] + mtext[17]*256;
// byte 19+20 = Slide-Nummer, <Rass-ID>
slidenumr = mtext[20] + mtext[19]*256;
// byte 21+22 = Element-Nummer im Slide, <INR>
slideelem = mtext[22] + mtext[21]*256;
// byte 23 = Slide-Steuerbyte, <Cntrl-Byte>: bit0 = Anzeige, bit1 = Speichern, bit2 = DarfAnzeige bei Senderwechsel, bit3 = Löschen
slideshow = mtext[23] & 0x01;
slidesave = mtext[23] & 0x02;
slidecan = mtext[23] & 0x04;
slidedel = mtext[23] & 0x08;
// byte 24 = Dateiart, <Item-Type>: 0=unbekannt/1=MPEG-Still/2=Definition
filetype = mtext[24];
if (filetype != 1 && filetype != 2) {
if ((S_Verbose && 0x0f) >= 1)
printf("Rass-Error: Filetype unknown !\n");
return;
}
// byte 25-28 = Dateilänge, <Item-Length>
filemax = mtext[28] + mtext[27]*256 + mtext[26]*65536 + mtext[25]*65536*256;
if (filemax >= 65536) {
if ((S_Verbose && 0x0f) >= 1)
printf("Rass-Error: Filesize will be too big !\n");
return;
}
// byte 29-31 = Dateioffset Paketnr, <Rfu>
fileoffp = mtext[31] + mtext[30]*256 + mtext[29]*65536;
// byte 32 = Dateioffset Bytenr, <Rfu>
fileoffb = mtext[32];
if (S_Verbose >= 2)
printf("Rass-Header: afiles= %d\n slidenumr= %d, slideelem= %d\n slideshow= %d, -save= %d, -canschow= %d, -delete= %d\n filetype= %d, filemax= %d\n fileoffp= %d, fileoffb= %d\n",
afiles, slidenumr, slideelem, slideshow, slidesave, slidecan, slidedel, filetype, filemax, fileoffp, fileoffb);
if (fileoffp == 0) { // First
if (S_Verbose >= 2)
printf("Rass-Start@0 ...\n");
start = true;
index = 0;
for (int i=fileoffb; i < len-2; i++) {
if (index < filemax)
daten[index++] = mtext[i];
else
start = false;
}
}
splfd = plfd;
}
else if (plfd < pmax && plfd == splfd+1) { // Between
splfd = plfd;
if (!start && fileoffp == plfd) { // Data start, <with Rfu no more necesssary>
if (S_Verbose >= 2)
printf("Rass-Start@%d ...\n", fileoffp);
start = true;
index = 0;
}
else
fileoffb = 15;
if (start) {
for (int i=fileoffb; i < len-2; i++) {
if (index < filemax)
daten[index++] = mtext[i];
else
start = false;
}
}
}
else if (plfd == pmax && plfd == splfd+1) { // Last
fileoffb = 15;
if (start) {
for (int i=fileoffb; i < len-4; i++) {
if (index <= filemax)
daten[index++] = mtext[i];
else {
start = false;
return;
}
}
if (S_Verbose >= 2)
printf("... Rass-End (%d bytes)\n", index);
}
if (filemax > 0) { // nothing todo, if 0 byte file
// crc-check with bytes 'len-4/3'
unsigned short crc16 = crc16_ccitt(daten, filemax, false);
if (crc16 != (mtext[len-4]<<8)+mtext[len-3]) {
if ((S_Verbose && 0x0f) >= 1)
printf("Rass-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[len-4], mtext[len-3]);
start = false;
return;
}
}
// show & save file ?
if (index == filemax) {
if (slideshow || (slidecan && Rass_Show == -1)) {
if (filetype == 1) { // show only mpeg-still
char *filepath;
asprintf(&filepath, "%s/%s", DataDir, "Rass_show.mpg");
if ((fd = fopen(filepath, "wb")) != NULL) {
fwrite(daten, 1, filemax, fd);
//fflush(fd); // for test in replaymode
fclose(fd);
Rass_Show = 1;
if (S_Verbose >= 2)
printf("Rass-File: ready for displaying :-)\n");
}
else
printf("ERROR vdr-radio: writing imagefile failed '%s'", filepath);
free(filepath);
}
}
if (slidesave || slidedel || slidenumr < RASS_GALMAX) {
// lfd. Fotogallery 100.. ???
if (slidenumr >= 100 && slidenumr < RASS_GALMAX) {
(Rass_SlideFoto < RASS_GALMAX) ? Rass_SlideFoto++ : Rass_SlideFoto = 100;
slidenumr = Rass_SlideFoto;
}
//
char *filepath;
(filetype == 2) ? asprintf(&filepath, "%s/Rass_%d.def", DataDir, slidenumr)
: asprintf(&filepath, "%s/Rass_%d.mpg", DataDir, slidenumr);
if ((fd = fopen(filepath, "wb")) != NULL) {
fwrite(daten, 1, filemax, fd);
fclose(fd);
if (S_Verbose >= 1)
printf("Rass-File: saving '%s'\n", filepath);
// archivemarker mpeg-stills
if (filetype == 1) {
// 0, 1000/1100/1110/1111..9000/9900/9990/9999
if (slidenumr == 0 || slidenumr > RASS_GALMAX) {
if (slidenumr == 0) {
Rass_Flags[0][0] = !slidedel;
(RT_Info > 0) ? : RT_Info = 0; // open RadioTextOsd for ArchivTip
}
else {
int islide = (int) floor(slidenumr/1000);
for (int i = 3; i >= 0; i--) {
if ((slidenumr % (i==3 ? 1000 : i==2 ? 100 : i==1 ? 10 : 1)) == 0) {
Rass_Flags[islide][3-i] = !slidedel; //true;
break;
}
}
}
}
// gallery
else {
Rass_Gallery[slidenumr] = !slidedel;
if (!slidedel && (int)slidenumr > Rass_GalEnd)
Rass_GalEnd = slidenumr;
if (!slidedel && (Rass_GalStart == 0 || (int)slidenumr < Rass_GalStart))
Rass_GalStart = slidenumr;
// counter
Rass_GalCount = 0;
for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) {
if (Rass_Gallery[i])
Rass_GalCount++;
}
Rass_Flags[10][0] = (Rass_GalCount > 0);
}
}
}
else
printf("ERROR vdr-radio: writing image/data-file failed '%s'", filepath);
free(filepath);
}
}
start = false;
splfd = spmax = 0;
}
else {
start = false;
splfd = spmax = 0;
}
}
else {
start = false;
splfd = spmax = 0;
if (S_Verbose >= 1)
printf("RDS-Error: [Rass] Length not correct !\n");
}
}
#endif
#if 0
void cRadioAudio::EnableRadioTextProcessing(const char *Titel, bool replay)
{
asprintf(&RT_Titel, "%s", Titel);
RT_Replay = replay;
ARec_Receive = ARec_Record = false;
first_packets = 0;
enabled = true;
imagedelay = 0;
// Radiotext init
if (S_RtFunc >= 1) {
RT_MsgShow = RT_PlusShow = false;
RT_ReOpen = true;
RT_OsdTO = false;
RT_Index = RT_PTY = RTP_TToggle = 0;
RTP_ItemToggle = 1;
for (int i = 0; i < 5; i++)
memset(RT_Text[i], 0x20, RT_MEL-1);
sprintf(RTP_Title, "---");
sprintf(RTP_Artist, "---");
RTP_Starttime = time(NULL);
//
RDS_PSShow = false;
RDS_PSIndex = 0;
for (int i = 0; i < 12; i++)
memset(RDS_PSText[i], 0x20, 8);
}
// ...Memory
rtp_content.start = time(NULL);
rtp_content.item_New = false;
rtp_content.rt_Index = -1;
rtp_content.item_Index = -1;
rtp_content.info_StockIndex = -1;
rtp_content.info_SportIndex = -1;
rtp_content.info_LotteryIndex = -1;
rtp_content.info_WeatherIndex = -1;
rtp_content.info_OtherIndex = -1;
for (int i = 0; i < MAX_RTPC; i++) {
rtp_content.radiotext[i] = NULL;
rtp_content.radiotext[MAX_RTPC+i] = NULL;
rtp_content.item_Title[i] = NULL;
rtp_content.item_Artist[i] = NULL;
rtp_content.info_Stock[i] = NULL;
rtp_content.info_Sport[i] = NULL;
rtp_content.info_Lottery[i] = NULL;
rtp_content.info_Weather[i] = NULL;
rtp_content.info_Other[i] = NULL;
}
rtp_content.info_News = NULL;
rtp_content.info_NewsLocal = NULL;
rtp_content.info_DateTime = NULL;
rtp_content.info_Traffic = NULL;
rtp_content.info_Alarm = NULL;
rtp_content.info_Advert = NULL;
rtp_content.info_Url = NULL;
rtp_content.prog_Station = NULL;
rtp_content.prog_Now = NULL;
rtp_content.prog_Next = NULL;
rtp_content.prog_Part = NULL;
rtp_content.prog_Host = NULL;
rtp_content.prog_EditStaff = NULL;
rtp_content.prog_Homepage = NULL;
rtp_content.phone_Hotline = NULL;
rtp_content.phone_Studio = NULL;
rtp_content.email_Hotline = NULL;
rtp_content.email_Studio = NULL;
// Rass init
Rass_Show = Rass_Archiv = -1;
for (int i = 0; i <= 10; i++) {
for (int ii = 0; ii < 4; ii++)
Rass_Flags[i][ii] = false;
}
Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0;
for (int i = 0; i < RASS_GALMAX; i++)
Rass_Gallery[i] = false;
Rass_SlideFoto = 99;
if (S_RtFunc < 1) return;
// RDS-Receiver for seperate Data-PIDs, only Livemode, hardcoded Astra_19E + Hotbird 13E
int pid = 0;
if (!replay) {
switch (chan->Tid()) {
case 1113:
switch (pid = chan->Apid(0)) { // Astra_19.2E - 12633 GHz
/* case 0x161: pid = 0x229; // radio top40
break; */
case 0x400: // Hitradio FFH
case 0x406: // planet radio
case 0x40c: pid += 1; // harmony.ffm
break;
default: return;
}
break;
case 1115:
switch (pid = chan->Apid(0)) { // Astra_19.2E - 12663 GHz
case 0x1bA: pid = 0x21e; // TruckRadio, only NaviData(0xbf) seen
break;
default: return;
}
break;
case 5300:
switch (pid = chan->Apid(0)) { // Hotbird_13E - 11747 GHz, no Radiotext @ moment, only TMC + MECs 25/26
case 0xdc3: // Radio 1
case 0xdd3: // Radio 3
case 0xddb: // Radio 5
case 0xde3: // Radio Exterior
case 0xdeb: pid += 1; // Radio 4
break;
default: return;
}
break;
default: return;
}
RDSReceiver = new cRDSReceiver(pid);
rdsdevice = cDevice::ActualDevice();
rdsdevice->AttachReceiver(RDSReceiver);
}
}
void cRadioAudio::DisableRadioTextProcessing()
{
RT_Replay = enabled = false;
// Radiotext & Rass
RT_Info = -1;
RT_ReOpen = false;
Rass_Show = Rass_Archiv = -1;
Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0;
if (RadioTextOsd != NULL)
RadioTextOsd->Hide();
if (RDSReceiver != NULL) {
rdsdevice->Detach(RDSReceiver);
delete RDSReceiver;
RDSReceiver = NULL;
rdsdevice = NULL;
}
}
// --- cRadioTextOsd ------------------------------------------------------
cBitmap cRadioTextOsd::rds(rds_xpm);
cBitmap cRadioTextOsd::arec(arec_xpm);
cBitmap cRadioTextOsd::rass(rass_xpm);
cBitmap cRadioTextOsd::index(index_xpm);
cBitmap cRadioTextOsd::marker(marker_xpm);
cBitmap cRadioTextOsd::page1(page1_xpm);
cBitmap cRadioTextOsd::pages2(pages2_xpm);
cBitmap cRadioTextOsd::pages3(pages3_xpm);
cBitmap cRadioTextOsd::pages4(pages4_xpm);
cBitmap cRadioTextOsd::no0(no0_xpm);
cBitmap cRadioTextOsd::no1(no1_xpm);
cBitmap cRadioTextOsd::no2(no2_xpm);
cBitmap cRadioTextOsd::no3(no3_xpm);
cBitmap cRadioTextOsd::no4(no4_xpm);
cBitmap cRadioTextOsd::no5(no5_xpm);
cBitmap cRadioTextOsd::no6(no6_xpm);
cBitmap cRadioTextOsd::no7(no7_xpm);
cBitmap cRadioTextOsd::no8(no8_xpm);
cBitmap cRadioTextOsd::no9(no9_xpm);
cBitmap cRadioTextOsd::bok(bok_xpm);
cBitmap cRadioTextOsd::pageE(pageE_xpm);
cRadioTextOsd::cRadioTextOsd()
{
RadioTextOsd = this;
osd = NULL;
qosd = NULL;
rtclosed = rassclosed = false;
RT_ReOpen = false;
}
cRadioTextOsd::~cRadioTextOsd()
{
if (Rass_Archiv >= 0) {
if (!RT_Replay)
Rass_Archiv = RassImage(-1, -1, false);
else {
Rass_Archiv = -1;
RadioAudio->SetBackgroundImage(ReplayFile);
}
}
if (osd != NULL)
delete osd;
if (qosd != NULL)
delete qosd;
RadioTextOsd = NULL;
RT_ReOpen = !RT_OsdTO;
cRemote::Put(LastKey);
}
void cRadioTextOsd::Show(void)
{
LastKey = kNone;
RT_OsdTO = false;
#ifndef VDRP_CLOSEMENU
osdtimer.Set();
#endif
ftitel = cFont::GetFont(fontOsd);
ftext = cFont::GetFont(fontSml);
fheight = ftext->Height() + 4;
int rowoffset = (S_RtOsdTitle == 1) ? 1 : 0;
bheight = (S_RtOsdTags >=1 ) ? fheight * (S_RtOsdRows+rowoffset+2) : fheight * (S_RtOsdRows+rowoffset);
(S_RtOsdTitle == 1) ? bheight += 20 : bheight += 12;
asprintf(&RTp_Titel, "%s - %s", tr("RTplus"), RT_Titel);
if (S_RtDispl >= 1 && (Rass_Show == -1 || S_RassText >= 2)) {
RT_MsgShow = (RT_Info >= 1);
ShowText();
}
}
void cRadioTextOsd::Hide(void)
{
RTOsdClose();
RassOsdClose();
}
void cRadioTextOsd::RTOsdClose(void)
{
if (osd != NULL) {
delete osd;
osd = NULL;
}
}
#endif
#if ENABLE_RASS
int CRadioText::RassImage(int QArchiv, int QKey, bool DirUp)
{
int i;
if (QKey >= 0 && QKey <= 9) {
if (QArchiv == 0)
(Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0;
else if (QArchiv > 0) {
if (floor(QArchiv/1000) == QKey) {
for (i = 3; i >= 0; i--) {
// if (fmod(QArchiv, pow(10, i)) == 0)
if ((QArchiv % (i==3 ? 1000 : i==2 ? 100 : i==1 ? 10 : 1)) == 0)
break;
}
if (i > 0) {
--i;
QArchiv += QKey * (int) (i==3 ? 1000 : i==2 ? 100 : i==1 ? 10 : 1);
}
else
QArchiv = QKey * 1000;
(Rass_Flags[QKey][3-i]) ? : QArchiv = QKey * 1000;
}
else
(Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0;
}
}
// Gallery
else if (QKey > 9 && Rass_GalCount >= 0) {
if (QArchiv < Rass_GalStart || QArchiv > Rass_GalEnd)
QArchiv = Rass_GalStart - 1;
if (DirUp) {
for (i = QArchiv+1; i <= Rass_GalEnd; i++) {
if (Rass_Gallery[i])
break;
}
QArchiv = (i <= Rass_GalEnd) ? i : Rass_GalStart;
}
else {
for (i = QArchiv-1; i >= Rass_GalStart; i--) {
if (Rass_Gallery[i])
break;
}
QArchiv = (i >= Rass_GalStart) ? i : Rass_GalEnd;
}
}
// show mpeg-still
char *image;
if (QArchiv >= 0)
asprintf(&image, "%s/Rass_%d.mpg", DataDir, QArchiv);
else
asprintf(&image, "%s/Rass_show.mpg", DataDir);
// Houdini: SetBackgroundImage() does not accept mpg stills
// frameBuffer->useBackground(frameBuffer->loadBackground(image));// set useBackground true or false
// frameBuffer->paintBackground();
// RadioAudio->SetBackgroundImage(image);
free(image);
return QArchiv;
}
#endif
#if 0
void cRadioTextOsd::RassOsd(void)
{
int fh = ftext->Height();
if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) {
qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+264-6+36));
tArea Area = {0, 0, 97, 29+264+5, 4};
qosd->SetAreas(&Area, 1);
}
if (qosd) {
uint32_t bcolor, fcolor;
int skin = theme_skin();
// Logo
bcolor = radioSkin[skin].clrTitleBack;
fcolor = radioSkin[skin].clrTitleText;
qosd->DrawRectangle(0, 1, 97, 29, bcolor);
qosd->DrawBitmap(25, 5, rass, bcolor, fcolor);
// Body
bcolor = radioSkin[skin].clrBack;
fcolor = radioSkin[skin].clrText;
int offs = 29 + 2;
qosd->DrawRectangle(0, offs, 97, 29+264+5, bcolor);
// Keys+Index
offs += 4;
qosd->DrawBitmap(4, offs, no0, bcolor, fcolor);
qosd->DrawBitmap(44, offs, index, bcolor, fcolor);
qosd->DrawBitmap(4, 24+offs, no1, bcolor, fcolor);
qosd->DrawBitmap(4, 48+offs, no2, bcolor, fcolor);
qosd->DrawBitmap(4, 72+offs, no3, bcolor, fcolor);
qosd->DrawBitmap(4, 96+offs, no4, bcolor, fcolor);
qosd->DrawBitmap(4, 120+offs, no5, bcolor, fcolor);
qosd->DrawBitmap(4, 144+offs, no6, bcolor, fcolor);
qosd->DrawBitmap(4, 168+offs, no7, bcolor, fcolor);
qosd->DrawBitmap(4, 192+offs, no8, bcolor, fcolor);
qosd->DrawBitmap(4, 216+offs, no9, bcolor, fcolor);
qosd->DrawBitmap(4, 240+offs, bok, bcolor, fcolor);
// Content
bool mark = false;
for (int i = 1; i <= 9; i++) {
// Pages
if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2] && Rass_Flags[i][3])
qosd->DrawBitmap(48, (i*24)+offs, pages4, bcolor, fcolor);
else if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2])
qosd->DrawBitmap(48, (i*24)+offs, pages3, bcolor, fcolor);
else if (Rass_Flags[i][0] && Rass_Flags[i][1])
qosd->DrawBitmap(48, (i*24)+offs, pages2, bcolor, fcolor);
else if (Rass_Flags[i][0])
qosd->DrawBitmap(48, (i*24)+offs, page1, bcolor, fcolor);
// Marker
if (floor(Rass_Archiv/1000) == i) {
qosd->DrawBitmap(28, (i*24)+offs, marker, bcolor, fcolor);
mark = true;
}
}
// Gallery
if (Rass_GalCount > 0) {
char *temp;
qosd->DrawBitmap(48, 240+offs, pageE, bcolor, fcolor);
asprintf(&temp, "%d", Rass_GalCount);
qosd->DrawText(67, 240+offs-2, temp, fcolor, clrTransparent, ftext, 97, fh);
free(temp);
}
// Marker gallery/index
if (!mark) {
if (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX)
qosd->DrawBitmap(30, 240+offs, marker, bcolor, fcolor);
else
qosd->DrawBitmap(28, offs, marker, bcolor, fcolor);
}
qosd->Flush();
}
}
void cRadioTextOsd::RassOsdTip(void)
{
int fh = ftext->Height();
if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) {
qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+(2*fh)-6+36));
tArea Area = {0, 0, 97, 29+(2*fh)+5, 4};
qosd->SetAreas(&Area, 1);
}
if (qosd) {
uint32_t bcolor, fcolor;
int skin = theme_skin();
// Title
bcolor = radioSkin[skin].clrTitleBack;
fcolor = radioSkin[skin].clrTitleText;
qosd->DrawRectangle(0, 0, 97, 29, bcolor);
qosd->DrawBitmap(25, 5, rass, bcolor, fcolor);
// Body
bcolor = radioSkin[skin].clrBack;
fcolor = radioSkin[skin].clrText;
qosd->DrawRectangle(0, 29+2, 97, 29+(2*fh)+5, bcolor);
qosd->DrawText(5, 29+4, tr("Records"), fcolor, clrTransparent, ftext, 97, fh);
qosd->DrawText(5, 29+fh+4, tr("with <0>"), fcolor, clrTransparent, ftext, 97, fh);
qosd->Flush();
}
}
void cRadioTextOsd::RassOsdClose(void)
{
if (qosd != NULL) {
delete qosd;
qosd = NULL;
}
}
void cRadioTextOsd::RassImgSave(char *size, int pos)
{
char *infile, *outfile, *cmd;
int filenr = 0, error = 0;
struct tm *ts, tm_store;
time_t t = time(NULL);
ts = localtime_r(&t, &tm_store);
switch (pos) {
// all from 1-9
case 1 ... 9:
for (int i = 3; i >= 0; i--) {
filenr += (int) (pos * pow(10, i));
if (Rass_Flags[pos][3-i]) {
asprintf(&infile, "%s/Rass_%d.mpg", DataDir, filenr);
asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, filenr,
ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
asprintf(&cmd, "ffmpeg -i %s -s %s -f mjpeg -y %s", infile, size, outfile);
if ((error = system(cmd)))
i = -1;
}
}
asprintf(&cmd, "%s '%d'", tr("Rass-Image(s) saved from Archiv "), pos);
break;
// all from gallery
case 10:
for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) {
if (Rass_Gallery[i]) {
asprintf(&infile, "%s/Rass_%d.mpg", DataDir, i);
asprintf(&outfile, "%s/Rass_%s-Gallery%04d_%02d%02d.jpg", DataDir, RT_Titel, i,
ts->tm_mon+1, ts->tm_mday);
asprintf(&cmd, "ffmpeg -i %s -s %s -f mjpeg -y %s", infile, size, outfile);
if ((error = system(cmd)))
i = Rass_GalEnd + 1;
}
}
asprintf(&cmd, "%s", tr("Rass-Image(s) saved from Gallery"));
break;
// single
default:
asprintf(&infile, "%s/Rass_%d.mpg", DataDir, Rass_Archiv);
asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, Rass_Archiv,
ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
asprintf(&cmd, "ffmpeg -i %s -s %s -f mjpeg -y %s", infile, size, outfile);
error = system(cmd);
asprintf(&cmd, "%s: %s", tr("Rass-Image saved"), outfile);
}
free(infile);
// Info
RassOsdClose();
if (error) {
asprintf(&cmd, "%s: %s", tr("Rass-Image failed"), outfile);
Skins.Message(mtError, cmd, Setup.OSDMessageTime);
}
else
Skins.Message(mtInfo, cmd, Setup.OSDMessageTime);
free(outfile);
free(cmd);
}
void cRadioTextOsd::rtp_print(void)
{
struct tm tm_store;
time_t t = time(NULL);
printf("\n>>> RTplus-Memoryclasses @ %s", asctime(localtime_r(&t, &tm_store)));
printf(" on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store)));
printf("--- Programme ---\n");
if (rtp_content.prog_Station != NULL) printf(" Station: %s\n", rtp_content.prog_Station);
if (rtp_content.prog_Now != NULL) printf(" Now: %s\n", rtp_content.prog_Now);
if (rtp_content.prog_Next != NULL) printf(" Next: %s\n", rtp_content.prog_Next);
if (rtp_content.prog_Part != NULL) printf(" Part: %s\n", rtp_content.prog_Part);
if (rtp_content.prog_Host != NULL) printf(" Host: %s\n", rtp_content.prog_Host);
if (rtp_content.prog_EditStaff != NULL) printf(" Ed.Staff: %s\n", rtp_content.prog_EditStaff);
if (rtp_content.prog_Homepage != NULL) printf(" Homepage: %s\n", rtp_content.prog_Homepage);
printf("--- Interactivity ---\n");
if (rtp_content.phone_Hotline != NULL) printf(" Phone-Hotline: %s\n", rtp_content.phone_Hotline);
if (rtp_content.phone_Studio != NULL) printf(" Phone-Studio: %s\n", rtp_content.phone_Studio);
if (rtp_content.email_Hotline != NULL) printf(" Email-Hotline: %s\n", rtp_content.email_Hotline);
if (rtp_content.email_Studio != NULL) printf(" Email-Studio: %s\n", rtp_content.email_Studio);
printf("--- Info ---\n");
if (rtp_content.info_News != NULL) printf(" News: %s\n", rtp_content.info_News);
if (rtp_content.info_NewsLocal != NULL) printf(" NewsLocal: %s\n", rtp_content.info_NewsLocal);
if (rtp_content.info_DateTime != NULL) printf(" DateTime: %s\n", rtp_content.info_DateTime);
if (rtp_content.info_Traffic != NULL) printf(" Traffic: %s\n", rtp_content.info_Traffic);
if (rtp_content.info_Alarm != NULL) printf(" Alarm: %s\n", rtp_content.info_Alarm);
if (rtp_content.info_Advert != NULL) printf(" Advertisg: %s\n", rtp_content.info_Advert);
if (rtp_content.info_Url != NULL) printf(" Url: %s\n", rtp_content.info_Url);
// no sorting
for (int i = 0; i < MAX_RTPC; i++)
if (rtp_content.info_Stock[i] != NULL) printf(" Stock[%02d]: %s\n", i, rtp_content.info_Stock[i]);
for (int i = 0; i < MAX_RTPC; i++)
if (rtp_content.info_Sport[i] != NULL) printf(" Sport[%02d]: %s\n", i, rtp_content.info_Sport[i]);
for (int i = 0; i < MAX_RTPC; i++)
if (rtp_content.info_Lottery[i] != NULL) printf(" Lottery[%02d]: %s\n", i, rtp_content.info_Lottery[i]);
for (int i = 0; i < MAX_RTPC; i++)
if (rtp_content.info_Weather[i] != NULL) printf(" Weather[%02d]: %s\n", i, rtp_content.info_Weather[i]);
for (int i = 0; i < MAX_RTPC; i++)
if (rtp_content.info_Other[i] != NULL) printf(" Other[%02d]: %s\n", i, rtp_content.info_Other[i]);
/*
printf("--- Item-Playlist ---\n");
// no sorting
if (rtp_content.item_Index >= 0) {
for (int i = 0; i < MAX_RTPC; i++) {
if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
struct tm tm_store;
struct tm *ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
printf(" [%02d] %02d:%02d Title: %s | Artist: %s\n",
i, ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
}
}
}
printf("--- Last seen Radiotext ---\n");
// no sorting
if (rtp_content.rt_Index >= 0) {
for (int i = 0; i < 2*MAX_RTPC; i++)
if (rtp_content.radiotext[i] != NULL) printf(" [%03d] %s\n", i, rtp_content.radiotext[i]);
}
*/
printf("<<<\n");
}
#define rtplog 0
eOSState cRadioTextOsd::ProcessKey(eKeys Key)
{
// RTplus Infolog
if (rtplog == 1 && S_Verbose >= 1) {
static int ct = 0;
if (++ct >= 60) {
ct = 0;
rtp_print();
}
}
// check end @ replay
if (RT_Replay) {
int rplayCur, rplayTot;
cControl::Control()->GetIndex(rplayCur, rplayTot, false);
if (rplayCur >= rplayTot-1) {
Hide();
return osEnd;
}
}
// Timeout or no Info/Rass
if (RT_OsdTO || (RT_OsdTOTemp > 0) || (RT_Info < 0)) {
Hide();
return osEnd;
}
eOSState state = cOsdObject::ProcessKey(Key);
if (state != osUnknown) return state;
// Key pressed ...
if (Key != kNone && Key < k_Release) {
if (osd) { // Radiotext, -plus Osd
switch (Key) {
case kBack: RTOsdClose();
rtclosed = true;
//rassclosed = false;
break;
case k0: RTOsdClose();
RTplus_Osd = true;
cRemote::CallPlugin("radio");
return osEnd;
default: Hide();
LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
return osEnd;
}
}
else if (qosd && Rass_Archiv >= 0) { // Rass-Archiv Osd
int i, pos;
pos = (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX) ? 10 : (int) floor(Rass_Archiv/1000);
switch (Key) {
// back to Slideshow
case kBlue:
case kBack:
if (!RT_Replay)
Rass_Archiv = RassImage(-1, 0, false);
else {
Rass_Archiv = -1;
RadioAudio->SetBackgroundImage(ReplayFile);
}
RassOsdClose();
rassclosed = rtclosed = false;
break;
// Archiv-Sides
case k0 ... k9:
Rass_Archiv = RassImage(Rass_Archiv, Key-k0, false);
RassOsd();
break;
case kOk:
if (Rass_Flags[10][0]) {
Rass_Archiv = RassImage(Rass_Archiv, 10, true);
RassOsd();
}
break;
case kLeft:
case kRight:
Rass_Archiv = RassImage(Rass_Archiv, pos, (Key == kRight) ? true : false);
RassOsd();
break;
case kDown:
(pos == 10) ? i = 0 : i = pos + 1;
while (i != pos) {
if (Rass_Flags[i][0]) {
Rass_Archiv = RassImage(Rass_Archiv, i, true);
RassOsd();
return osContinue;
}
if (++i > 10) i = 0;
}
break;
case kUp:
(pos == 0) ? i = 10 : i = pos - 1;
while (i != pos) {
if (Rass_Flags[i][0]) {
Rass_Archiv = RassImage(Rass_Archiv, i, true);
RassOsd();
return osContinue;
}
if (--i < 0) i = 10;
}
break;
case kRed:
RassImgSave("1024x576", 0);
break;
case kGreen:
RassImgSave("1024x576", pos);
break;
case kYellow:
break; // todo, what ?
default:
Hide();
LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
return osEnd;
}
}
else if (qosd && Rass_Archiv == -1) { // Rass-Slideshow Osd
switch (Key) {
// close
case kBack:
RassOsdClose();
rassclosed = true;
//rtclosed = false;
break;
// Archiv-Index
case k0:
if (Rass_Flags[0][0]) {
RassOsdClose();
Rass_Archiv = RassImage(0, 0, false);
RassOsd();
}
break;
default:
Hide();
LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
return osEnd;
}
}
else { // no RT && no Rass
Hide();
LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
return osEnd;
}
}
// no Key pressed ...
#ifndef VDRP_CLOSEMENU
else if (S_RtOsdTO > 0 && osdtimer.Elapsed()/1000/60 >= (uint)S_RtOsdTO) {
RT_OsdTO = true;
Hide();
return osEnd;
}
#endif
else if (Rass_Archiv >= 0)
RassOsd();
else if (RT_MsgShow && !rtclosed && (Rass_Show == -1 || S_RassText >= 2 || rassclosed)) {
RassOsdClose();
ShowText();
}
else if (Rass_Flags[0][0] && !rassclosed && (S_RassText < 2 || rtclosed)) {
RTOsdClose();
RassOsdTip();
}
return osContinue;
}
// --- cRTplusOsd ------------------------------------------------------
cRTplusOsd::cRTplusOsd(void)
:cOsdMenu(RTp_Titel, 3, 12)
{
RTplus_Osd = false;
bcount = helpmode = 0;
listtyp[0] = tr("Radiotext");
listtyp[1] = tr("Playlist");
listtyp[2] = tr("Sports");
listtyp[3] = tr("Lottery");
listtyp[4] = tr("Weather");
listtyp[5] = tr("Stockmarket");
listtyp[6] = tr("Other");
Load();
Display();
}
cRTplusOsd::~cRTplusOsd()
{
}
void cRTplusOsd::Load(void)
{
char text[80];
struct tm tm_store;
struct tm *ts = localtime_r(&rtp_content.start, &tm_store);
snprintf(text, sizeof(text), "%s %02d:%02d", tr("RTplus Memory since"), ts->tm_hour, ts->tm_min);
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "-- %s --", tr("Programme"));
Add(new cOsdItem(hk(text)));
if (rtp_content.prog_Station != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Station"), rtp_content.prog_Station);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_Now != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Now"), rtp_content.prog_Now);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_Part != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("...Part"), rtp_content.prog_Part);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_Next != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Next"), rtp_content.prog_Next);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_Host != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Host"), rtp_content.prog_Host);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_EditStaff != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Edit.Staff"), rtp_content.prog_EditStaff);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.prog_Homepage != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Homepage"), rtp_content.prog_Homepage);
Add(new cOsdItem(hk(text)));
}
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "-- %s --", tr("Interactivity"));
Add(new cOsdItem(hk(text)));
if (rtp_content.phone_Hotline != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Hotline"), rtp_content.phone_Hotline);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.phone_Studio != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Studio"), rtp_content.phone_Studio);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.email_Hotline != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Hotline"), rtp_content.email_Hotline);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.email_Studio != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Studio"), rtp_content.email_Studio);
Add(new cOsdItem(hk(text)));
}
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "-- %s --", tr("Info"));
Add(new cOsdItem(hk(text)));
if (rtp_content.info_News != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("News"), rtp_content.info_News);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_NewsLocal != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("NewsLocal"), rtp_content.info_NewsLocal);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_DateTime != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("DateTime"), rtp_content.info_DateTime);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_Traffic != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Traffic"), rtp_content.info_Traffic);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_Alarm != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Alarm"), rtp_content.info_Alarm);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_Advert != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Advertising"), rtp_content.info_Advert);
Add(new cOsdItem(hk(text)));
}
if (rtp_content.info_Url != NULL) {
snprintf(text, sizeof(text), "\t%s:\t%s", tr("Url"), rtp_content.info_Url);
Add(new cOsdItem(hk(text)));
}
for (int i = 0; i <= 6; i++)
btext[i] = NULL;
bcount = 0;
asprintf(&btext[bcount++], "%s", listtyp[0]);
if (rtp_content.item_Index >= 0)
asprintf(&btext[bcount++], "%s", listtyp[1]);
if (rtp_content.info_SportIndex >= 0)
asprintf(&btext[bcount++], "%s", listtyp[2]);
if (rtp_content.info_LotteryIndex >= 0)
asprintf(&btext[bcount++], "%s", listtyp[3]);
if (rtp_content.info_WeatherIndex >= 0)
asprintf(&btext[bcount++], "%s", listtyp[4]);
if (rtp_content.info_StockIndex >= 0)
asprintf(&btext[bcount++], "%s", listtyp[5]);
if (rtp_content.info_OtherIndex >= 0)
asprintf(&btext[bcount++], "%s", listtyp[6]);
switch (bcount) {
case 4: if (helpmode == 0)
SetHelp(btext[0], btext[1], btext[2], ">>");
else if (helpmode == 1)
SetHelp("<<", btext[3], NULL, tr("Exit"));
break;
case 5: if (helpmode == 0)
SetHelp(btext[0], btext[1], btext[2], ">>");
else if (helpmode == 1)
SetHelp("<<", btext[3], btext[4], tr("Exit"));
break;
case 6: if (helpmode == 0)
SetHelp(btext[0], btext[1], btext[2], ">>");
else if (helpmode == 1)
SetHelp("<<", btext[3], btext[4], ">>");
else if (helpmode == 2)
SetHelp("<<", btext[5], NULL, tr("Exit"));
break;
case 7: if (helpmode == 0)
SetHelp(btext[0], btext[1], btext[2], ">>");
else if (helpmode == 1)
SetHelp("<<", btext[3], btext[4], ">>");
else if (helpmode == 2)
SetHelp("<<", btext[5], btext[6], tr("Exit"));
break;
default: helpmode = 0;
SetHelp(btext[0], btext[1], btext[2], tr("Exit"));
}
}
void cRTplusOsd::Update(void)
{
Clear();
Load();
Display();
}
int cRTplusOsd::rtptyp(char *btext)
{
for (int i = 0; i <= 6; i++) {
if (strcmp(btext, listtyp[i]) == 0)
return i;
}
return -1;
}
void cRTplusOsd::rtp_fileprint(void)
{
struct tm *ts, tm_store;
char *fname, *fpath;
FILE *fd;
int ind, lfd = 0;
time_t t = time(NULL);
ts = localtime_r(&t, &tm_store);
asprintf(&fname, "RTplus_%s_%04d-%02d-%02d.%02d.%02d", RT_Titel, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
asprintf(&fpath, "%s/%s", DataDir, fname);
if ((fd = fopen(fpath, "w")) != NULL) {
fprintf(fd, ">>> RTplus-Memoryclasses @ %s", asctime(localtime_r(&t, &tm_store)));
fprintf(fd, " on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store)));
fprintf(fd, "--- Programme ---\n");
if (rtp_content.prog_Station != NULL) fprintf(fd, " Station: %s\n", rtp_content.prog_Station);
if (rtp_content.prog_Now != NULL) fprintf(fd, " Now: %s\n", rtp_content.prog_Now);
if (rtp_content.prog_Part != NULL) fprintf(fd, " Part: %s\n", rtp_content.prog_Part);
if (rtp_content.prog_Next != NULL) fprintf(fd, " Next: %s\n", rtp_content.prog_Next);
if (rtp_content.prog_Host != NULL) fprintf(fd, " Host: %s\n", rtp_content.prog_Host);
if (rtp_content.prog_EditStaff != NULL) fprintf(fd, " Ed.Staff: %s\n", rtp_content.prog_EditStaff);
if (rtp_content.prog_Homepage != NULL) fprintf(fd, " Homepage: %s\n", rtp_content.prog_Homepage);
fprintf(fd, "--- Interactivity ---\n");
if (rtp_content.phone_Hotline != NULL) fprintf(fd, " Phone-Hotline: %s\n", rtp_content.phone_Hotline);
if (rtp_content.phone_Studio != NULL) fprintf(fd, " Phone-Studio: %s\n", rtp_content.phone_Studio);
if (rtp_content.email_Hotline != NULL) fprintf(fd, " Email-Hotline: %s\n", rtp_content.email_Hotline);
if (rtp_content.email_Studio != NULL) fprintf(fd, " Email-Studio: %s\n", rtp_content.email_Studio);
fprintf(fd, "--- Info ---\n");
if (rtp_content.info_News != NULL) fprintf(fd, " News: %s\n", rtp_content.info_News);
if (rtp_content.info_NewsLocal != NULL) fprintf(fd, " NewsLocal: %s\n", rtp_content.info_NewsLocal);
if (rtp_content.info_DateTime != NULL) fprintf(fd, " DateTime: %s\n", rtp_content.info_DateTime);
if (rtp_content.info_Traffic != NULL) fprintf(fd, " Traffic: %s\n", rtp_content.info_Traffic);
if (rtp_content.info_Alarm != NULL) fprintf(fd, " Alarm: %s\n", rtp_content.info_Alarm);
if (rtp_content.info_Advert != NULL) fprintf(fd, " Advertisg: %s\n", rtp_content.info_Advert);
if (rtp_content.info_Url != NULL) fprintf(fd, " Url: %s\n", rtp_content.info_Url);
if (rtp_content.item_Index >= 0) {
fprintf(fd, "--- Item-Playlist ---\n");
ind = rtp_content.item_Index;
if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
}
}
}
if (rtp_content.info_SportIndex >= 0) {
fprintf(fd, "--- Sports ---\n");
ind = rtp_content.info_SportIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Sport[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Sport[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]);
}
}
if (rtp_content.info_LotteryIndex >= 0) {
fprintf(fd, "--- Lottery ---\n");
ind = rtp_content.info_LotteryIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Lottery[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Lottery[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]);
}
}
if (rtp_content.info_WeatherIndex >= 0) {
fprintf(fd, "--- Weather ---\n");
ind = rtp_content.info_WeatherIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Weather[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Weather[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]);
}
}
if (rtp_content.info_StockIndex >= 0) {
fprintf(fd, "--- Stockmarket ---\n");
ind = rtp_content.info_StockIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Stock[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Stock[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]);
}
}
if (rtp_content.info_OtherIndex >= 0) {
fprintf(fd, "--- Other ---\n");
ind = rtp_content.info_OtherIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Other[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Other[i] != NULL)
fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]);
}
}
fprintf(fd, "--- Last seen Radiotext ---\n");
ind = rtp_content.rt_Index;
if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) {
for (int i = ind+1; i < 2*MAX_RTPC; i++) {
if (rtp_content.radiotext[i] != NULL)
fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]);
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.radiotext[i] != NULL)
fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]);
}
fprintf(fd, "<<<\n");
fclose(fd);
char *infotext;
asprintf(&infotext, "%s: %s", tr("RTplus-File saved"), fname);
Skins.Message(mtInfo, infotext, Setup.OSDMessageTime);
free(infotext);
}
else
printfesyslog("ERROR vdr-radio: writing RTplus-File failed '%s'", fpath);
free(fpath);
free(fname);
}
eOSState cRTplusOsd::ProcessKey(eKeys Key)
{
int typ, ind;
eOSState state = cOsdMenu::ProcessKey(Key);
if (HasSubMenu())
return osContinue;
if (state == osUnknown) {
switch (Key) {
case kBack:
case kOk:
return osEnd;
case kBlue:
if (bcount >= 4 && helpmode == 0) {
helpmode += 1;
Update();
}
else if (bcount >= 6 && helpmode == 1) {
helpmode += 1;
Update();
}
else
return osEnd;
break;
case k0:
Update();
break;
case k8:
rtp_fileprint();
break;
case kRed:
if (helpmode == 0) {
if (btext[0] != NULL)
if ((typ = rtptyp(btext[0])) >= 0)
AddSubMenu(new cRTplusList(typ));
}
else {
helpmode -= 1;
Update();
}
break;
case kGreen:
ind = (helpmode*2) + 1;
if (btext[ind] != NULL) {
if ((typ = rtptyp(btext[ind])) >= 0)
AddSubMenu(new cRTplusList(typ));
}
break;
case kYellow:
ind = (helpmode*2) + 2;
if (btext[ind] != NULL) {
if ((typ = rtptyp(btext[ind])) >= 0)
AddSubMenu(new cRTplusList(typ));
}
break;
default:
state = osContinue;
}
}
static int ct;
if (++ct >= 60) {
ct = 0;
Update();
}
return state;
}
// --- cRTplusList ------------------------------------------------------
cRTplusList::cRTplusList(int Typ)
:cOsdMenu(RTp_Titel, 4)
{
typ = Typ;
refresh = false;
Load();
Display();
}
cRTplusList::~cRTplusList()
{
typ = 0;
}
void cRTplusList::Load(void)
{
char text[80];
struct tm *ts, tm_store;
int ind, lfd = 0;
ts = localtime_r(&rtp_content.start, &tm_store);
switch (typ) {
case 0:
snprintf(text, sizeof(text), "-- %s (max. %d) --", tr("last seen Radiotext"), 2*MAX_RTPC);
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.rt_Index;
if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) {
for (int i = ind+1; i < 2*MAX_RTPC; i++) {
if (rtp_content.radiotext[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.radiotext[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.radiotext[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.radiotext[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 1:
SetCols(6, 19, 1);
snprintf(text, sizeof(text), "-- %s --", tr("Playlist"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s\t%s\t\t%s", tr("Time"), tr("Title"), tr("Artist"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.item_Index;
if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 2:
snprintf(text, sizeof(text), "-- %s --", tr("Sports"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.info_SportIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Sport[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Sport[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Sport[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Sport[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 3:
snprintf(text, sizeof(text), "-- %s --", tr("Lottery"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.info_LotteryIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Lottery[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Lottery[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Lottery[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Lottery[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 4: snprintf(text, sizeof(text), "-- %s --", tr("Weather"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.info_WeatherIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Weather[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Weather[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Weather[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Weather[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 5:
snprintf(text, sizeof(text), "-- %s --", tr("Stockmarket"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.info_StockIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Stock[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Stock[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Stock[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Stock[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
case 6:
snprintf(text, sizeof(text), "-- %s --", tr("Other"));
Add(new cOsdItem(hk(text)));
snprintf(text, sizeof(text), "%s", " ");
Add(new cOsdItem(hk(text)));
ind = rtp_content.info_OtherIndex;
if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) {
for (int i = ind+1; i < MAX_RTPC; i++) {
if (rtp_content.info_Other[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Other[i]);
Add(new cOsdItem(hk(text)));
}
}
}
for (int i = 0; i <= ind; i++) {
if (rtp_content.info_Other[i] != NULL) {
snprintf(text, sizeof(text), "%d.\t%s", ++lfd, rtp_content.info_Other[i]);
Add(new cOsdItem(hk(text)), refresh);
}
}
break;
}
SetHelp(NULL, NULL , refresh ? tr("Refresh Off") : tr("Refresh On"), tr("Back"));
}
void cRTplusList::Update(void)
{
Clear();
Load();
Display();
}
eOSState cRTplusList::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case k0:
Update();
break;
case kYellow:
refresh = (refresh) ? false : true;
Update();
break;
case kBack:
case kOk:
case kBlue:
return osBack;
default:
state = osContinue;
}
}
static int ct;
if (refresh) {
if (++ct >= 20) {
ct = 0;
Update();
}
}
return state;
}
//--------------- End -----------------------------------------------------------------
#endif
CRadioText::CRadioText(void)
{
pid = 0;
audioDemux = NULL;
init();
running = true;
start();
}
CRadioText::~CRadioText(void)
{
printf("CRadioText::~CRadioText\n");
running = false;
radiotext_stop();
cond.broadcast();
OpenThreads::Thread::join();
printf("CRadioText::~CRadioText done\n");
}
void CRadioText::init()
{
S_Verbose = 0;
S_RtFunc = 1;
S_RtOsd = 0;
S_RtOsdTitle = 1;
S_RtOsdTags = 2;
S_RtOsdPos = 2;
S_RtOsdRows = 3;
S_RtOsdLoop = 1;
S_RtOsdTO = 60;
S_RtSkinColor = false;
S_RtBgCol = 0;
S_RtBgTra = 0xA0;
S_RtFgCol = 1;
S_RtDispl = 1;
S_RtMsgItems = 0;
RT_Index = 0;
RT_PTY = 0;
// Radiotext
RTP_ItemToggle = 1;
RTP_TToggle = 0;
RT_PlusShow = false;
RT_Replay = false;
RT_ReOpen = false;
for (int i = 0; i < 5; i++)
RT_Text[i][0] = 0;
RDS_PTYN[0] = 0;
#if ENABLE_RASS
// Rass ...
Rass_Show = -1; // -1=No, 0=Yes, 1=display
Rass_Archiv = -1; // -1=Off, 0=Index, 1000-9990=Slidenr.
#endif
RT_MsgShow = false; // clear entries from old channel
have_radiotext = false;
}
void CRadioText::radiotext_stop(void)
{
printf("CRadioText::radiotext_stop: ###################### pid 0x%x ######################\n", getPid());
if (getPid() != 0) {
mutex.lock();
pid = 0;
have_radiotext = false;
S_RtOsd = 0;
mutex.unlock();
}
}
void CRadioText::setPid(uint inPid)
{
printf("CRadioText::setPid: ###################### old pid 0x%x new pid 0x%x ######################\n", pid, inPid);
if (pid != inPid) {
mutex.lock();
pid = inPid;
init();
mutex.unlock();
cond.broadcast();
}
}
void CRadioText::run()
{
uint current_pid = 0;
printf("CRadioText::run: ###################### Starting thread ######################\n");
audioDemux = new cDemux(1);
audioDemux->Open(DMX_PES_CHANNEL,0,128*1024);
while(running) {
mutex.lock();
if (pid == 0) {
mutex.unlock();
audioDemux->Stop();
pidmutex.lock();
printf("CRadioText::run: ###################### waiting for pid.. ######################\n");
cond.wait(&pidmutex);
pidmutex.unlock();
mutex.lock();
}
if (pid && (current_pid != pid)) {
current_pid = pid;
printf("CRadioText::run: ###################### Setting PID 0x%x ######################\n", getPid());
audioDemux->Stop();
if (!audioDemux->pesFilter(getPid()) || !audioDemux->Start()) {
pid = 0;
printf("CRadioText::run: ###################### failed to start PES filter ######################\n");
}
}
mutex.unlock();
if (pid) {
int n;
unsigned char buf[0x1FFFF];
n = audioDemux->Read(buf, sizeof(buf), 500 /*5000*/);
if (n > 0) {
//printf("."); fflush(stdout);
mutex.lock();
PES_Receive(buf, n);
mutex.unlock();
}
}
}
delete audioDemux;
audioDemux = NULL;
printf("CRadioText::run: ###################### exit ######################\n");
}