]> git.vomp.tv Git - vompclient.git/blob - vaudioselector.cc
Fully working cross compilation
[vompclient.git] / vaudioselector.cc
1 /*
2     Copyright 2006-2020 Chris Tallon, Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <algorithm>
21 #include <sstream>
22 #include <iomanip>
23
24 #include "input.h"
25 #include "colour.h"
26 #include "video.h"
27 #include "audio.h"
28 #include "boxstack.h"
29 #include "i18n.h"
30 #include "message.h"
31 #include "messagequeue.h"
32 #include "recinfo.h"
33 #include "log.h"
34 #include "channel.h"
35
36 #include "vaudioselector.h"
37
38 VAudioSelector::VAudioSelector(void* tparent, bool* availableMpegAudioChannels,
39                                bool* availableAc3AudioChannels, int currentAudioChannel, bool* availableSubtitleChannels, int* ttxtpages,
40                                int currentSubtitleChannel, int currentSubtitleType, RecInfo* recInfo)
41 : parent(tparent), liveMode(false)
42 {
43   Log::getInstance()->log("VAS", Log::DEBUG, "%i", currentAudioChannel);
44
45   int i;
46
47   if (availableSubtitleChannels != NULL)
48   {
49     for (i = 0; i < PES_DVBSUBTITLE_MAXCHANNELS; i++)
50     {
51       if (availableSubtitleChannels[i])
52       {
53         AudioSubtitleChannel sc;
54         sc.type = 0x10; //dvbsubtitle
55         sc.pestype = PES_DVBSUBTITLE_START + i;
56         scl.push_back(std::move(sc));
57       }
58     }
59
60     for (i = 0; i < 10; i++)
61     {
62       if (ttxtpages[i] > 0)
63       {
64         AudioSubtitleChannel sc;
65         sc.type = 0x11; //Teletxt
66         sc.pestype = ttxtpages[i];
67         std::ostringstream oss;
68         oss << tr("TTxt:") << " " << std::hex << std::setw(3) << ttxtpages[i];
69         sc.name = std::move(oss.str());
70         scl.push_back(std::move(sc));
71       }
72     }
73   }
74
75   if (scl.size() > 0)
76   {
77     AudioSubtitleChannel sc;
78     sc.type = 0xFF; //special
79     sc.name = tr("No Subtitles");
80     sc.pestype = 0;
81     scl.insert(scl.begin(), std::move(sc));
82     subtitles = true;
83   }
84
85   if (subtitles)
86     setSize(400, 120);
87   else
88     setSize(200, 120);
89
90   createBuffer();
91
92   asl.setPosition(40, 30);
93   asl.setSize(200 - 45, area.h - 30);
94   add(&asl);
95
96   if (subtitles)
97   {
98     ssl.setPosition(200 + 40, 30);
99     ssl.setSize(200 - 45, area.h - 30);
100     add(&ssl);
101   }
102
103   // Load data from availableAudioChannels, currentAudioChannel and recInfo
104
105   for (i = 0; i < PES_AUDIO_MAXCHANNELS; i++)
106   {
107     if (availableMpegAudioChannels[i])
108     {
109       AudioSubtitleChannel ac;
110       ac.type = 0;
111       ac.pestype = PES_AUDIO_START + i;
112       acl.push_back(std::move(ac));
113     }
114   }
115
116   if (availableAc3AudioChannels != NULL)
117   {
118     for (i = 0; i < PES_AUDIO_AC3_MAXCHANNELS; i++)
119     {
120       if (availableAc3AudioChannels[i])
121       {
122         AudioSubtitleChannel ac;
123         ac.type = 1; //ac3
124         ac.pestype = PES_AUDIO_AC3_START + i;
125         acl.push_back(std::move(ac));
126       }
127     }
128   }
129
130   int numchan_recinfo = recInfo->numComponents;
131   UINT mp_audcounter = 0;
132   UINT ac3_counter = 0;
133   int ac3_offset = 0;
134   UINT dvb_subcounter = 1;
135
136   for (auto& ac : acl)
137   {
138     if (ac.type == 0) ++ac3_offset;
139   }
140
141   unsigned char type;
142   char* lang;
143   char* description;
144   int type_int;
145
146   for (i = 0; i < numchan_recinfo; i++)
147   {
148     type = recInfo->types[i];
149     lang = recInfo->languages[i];
150     description = recInfo->descriptions[i];
151     AudioSubtitleChannel* acp = NULL;
152     type_int = 0;
153
154     if (recInfo->streams[i] == 2)
155     {
156       switch (type)
157       {
158         case 1: //mpaudio mono
159         case 3: //mpaudio stereo
160           if (mp_audcounter < acl.size()) acp = &acl[mp_audcounter];
161
162           type_int = 0;
163           break;
164
165         case 5: //ac3
166           if (ac3_counter + ac3_offset < acl.size()) acp = &acl[ac3_counter + ac3_offset];
167
168           type_int = 1;
169           break;
170       }
171     }
172     else if (recInfo->streams[i] == 3)
173     {
174       /*  switch (type)
175         {
176         case 20:*/
177       if (dvb_subcounter < scl.size()) acp = &scl[dvb_subcounter];
178
179       type_int = 0x10;
180       /*     break;
181        };*/
182     }
183     else continue;   //neither audio nor subtitle
184
185     if (acp)
186     {
187       if (acp->type == type_int)
188       {
189         if (description && (strlen(description) > 0))
190         {
191           acp->name = description;
192         }
193         else if (lang && (strlen(lang) > 0))
194         {
195           acp->name = lang;
196         }
197       }
198     }
199
200     switch (type_int)
201     {
202       case 0: //mpaudio
203         mp_audcounter++;
204         break;
205
206       case 1: //ac3
207         ac3_counter++;
208         break;
209
210       case 0x10:
211         dvb_subcounter++;
212         break;
213     }
214   }
215
216   // Now do display. acl and scl are read only from now on, so pointers always remain valid
217
218   if (acl.size())
219   {
220     for (auto& ac : acl)
221     {
222       if (!ac.name.empty())
223       {
224         asl.addOption(ac.name.c_str(), &ac, (ac.pestype == currentAudioChannel));
225       }
226       else
227       {
228         std::string tempString;
229
230         if      (ac.type == 0) tempString = std::to_string(ac.pestype - PES_AUDIO_START);
231         else if (ac.type == 1) tempString = "ac3 " + std::to_string(ac.pestype - PES_AUDIO_AC3_START);
232         else                   tempString = "unknown";
233
234         asl.addOption(tempString.c_str(), &ac, (ac.pestype == currentAudioChannel));
235       }
236     }
237   }
238   else
239   {
240     asl.addOption(tr("No audio channel data available"), 0, 1);
241   }
242
243   if (subtitles)
244   {
245     ssl.setDarkSelOption(true);
246
247     for (auto& sc : scl)
248     {
249       bool selected = false;
250
251       if (sc.pestype == currentSubtitleChannel && sc.type == currentSubtitleType) selected = true;
252
253       if (!sc.name.empty())
254       {
255         ssl.addOption(sc.name.c_str(), &sc, selected);
256       }
257       else
258       {
259         std::string tempString;
260
261         if (sc.type == 0x10) tempString = std::to_string(sc.pestype - PES_DVBSUBTITLE_START);
262         else                 tempString = "unknown";
263
264         ssl.addOption(tempString.c_str(), &sc, selected);
265       }
266     }
267   }
268 }
269
270 VAudioSelector::VAudioSelector(void* tparent, Channel* channel, int currentAudioChannel, int currentSubtitletype, int currentSubtitleChannel, int* ttxtpages)
271 : parent(tparent), liveMode(true)
272 {
273   UINT i;
274
275   for (i = 0; i < channel->numSPids; i++)
276   {
277     AudioSubtitleChannel sc;
278     sc.type = 0x10;
279     sc.name = channel->spids[i].desc;
280     sc.pestype = channel->spids[i].pid;
281     scl.push_back(std::move(sc));
282   }
283
284   if (ttxtpages)
285   {
286     for (i = 0; i < 10; i++)
287     {
288       if (ttxtpages[i] > 0)
289       {
290         AudioSubtitleChannel sc;
291         sc.type = 0x11; //Teletxt
292         sc.pestype = ttxtpages[i];
293         std::ostringstream oss;
294         oss << tr("TTxt:") << " " << std::hex << std::setw(3) << ttxtpages[i];
295         sc.name = std::move(oss.str());
296         scl.push_back(std::move(sc));
297       }
298     }
299   }
300
301   if (scl.size() > 0)
302   {
303     AudioSubtitleChannel sc;
304     sc.type = 0xFF; //special
305     sc.name = tr("No Subtitles");
306     sc.pestype = 0;
307     scl.insert(scl.begin(), std::move(sc));
308     subtitles = true;
309   }
310
311   if (subtitles)
312     setSize(400, 120);
313   else
314     setSize(200, 120);
315
316   createBuffer();
317
318   asl.setPosition(40, 30);
319   asl.setSize(200 - 45, area.h - 30);
320   add(&asl);
321
322   if (subtitles)
323   {
324     ssl.setPosition(200 + 40, 30);
325     ssl.setSize(200 - 45, area.h - 30);
326     add(&ssl);
327   }
328
329   // Load data from availableAudioChannels, currentAudioChannel and recInfo
330
331   for (i = 0; i < channel->numAPids; i++)
332   {
333     if (Audio::getInstance()->streamTypeSupported(channel->apids[i].type))
334     {
335       AudioSubtitleChannel ac;
336       ac.type = 0;
337       ac.name = channel->apids[i].desc;
338       ac.pestype = channel->apids[i].pid;
339       ac.streamtype = channel->apids[i].type;
340       acl.push_back(std::move(ac));
341     }
342   }
343
344   if (Audio::getInstance()->supportsAc3())
345   {
346     for (i = 0; i < channel->numDPids; i++)
347     {
348       if (Audio::getInstance()->streamTypeSupported(channel->dpids[i].type))
349       {
350         AudioSubtitleChannel ac;
351         ac.type = 1;
352         ac.name = channel->dpids[i].desc;
353         ac.pestype = channel->dpids[i].pid;
354         ac.streamtype = channel->dpids[i].type;
355         acl.push_back(std::move(ac));
356       }
357     }
358   }
359
360   // acl and scl now read only so pointers are always valid
361
362   if (acl.size())
363   {
364     for (auto& ac : acl)
365     {
366       asl.addOption(ac.name.c_str(), &ac, (ac.pestype == currentAudioChannel));
367     }
368   }
369   else
370   {
371     asl.addOption(tr("No audio channel data available"), 0, 1);
372   }
373
374   if (subtitles)
375   {
376     ssl.setDarkSelOption(true);
377
378     for (auto& sc : scl)
379     {
380       bool selected = false;
381       if ((sc.type == currentSubtitletype) && (sc.pestype == currentSubtitleChannel)) selected = true;
382       ssl.addOption(sc.name.c_str(), &sc, selected);
383     }
384   }
385 }
386
387 VAudioSelector::~VAudioSelector()
388 {
389   Message* m = new Message();
390   m->from = this;
391   m->to = parent;
392   m->message = Message::CHILD_CLOSE;
393   MessageQueue::getInstance()->postMessage(m);
394 }
395
396 void VAudioSelector::draw()
397 {
398   TBBoxx::draw();
399
400   // FIXME bad drawing
401
402   rectangle(0, 0, area.w, 30, DrawStyle::TITLEBARBACKGROUND);
403   drawText(tr("Audio"), 45, 5, DrawStyle::LIGHTTEXT);
404
405   if (subtitles)
406   {
407     drawText(tr("Subtitles"), 45 + 200, 5, DrawStyle::LIGHTTEXT);
408
409     ssl.setBackgroundColour(backgroundColour);
410     ssl.draw();
411   }
412
413   asl.setBackgroundColour(backgroundColour);
414   asl.draw();
415 }
416
417 int VAudioSelector::handleCommand(int command)
418 {
419   switch (command)
420   {
421     case Input::BACK:
422     case Input::OK:
423     case Input::GREEN:
424     {
425       return 4;
426     }
427
428     case Input::UP:
429     {
430       if (editsubtitles)
431       {
432         ssl.up();
433         ssl.draw();
434         BoxStack::getInstance()->update(this);
435         Message* m = new Message();
436         m->from = this;
437         m->to = parent;
438         m->message = Message::SUBTITLE_CHANGE_CHANNEL;
439         AudioSubtitleChannel* asc = static_cast<AudioSubtitleChannel*>(ssl.getCurrentOptionData());
440         m->parameter = (asc->pestype & 0xFFFF) | (asc->type & 0xFF) << 16;
441         MessageQueue::getInstance()->postMessage(m);
442       }
443       else
444       {
445         asl.up();
446         asl.draw();
447         BoxStack::getInstance()->update(this);
448         Message* m = new Message();
449         m->from = this;
450         m->to = parent;
451         m->message = Message::AUDIO_CHANGE_CHANNEL;
452         AudioSubtitleChannel* asc = static_cast<AudioSubtitleChannel*>(asl.getCurrentOptionData());
453         m->parameter = (asc->pestype & 0xFFFF) | (asc->type & 0xFF) << 16;
454         MessageQueue::getInstance()->postMessage(m);
455       }
456
457       return 2;
458     }
459
460     case Input::DOWN:
461     {
462       if (editsubtitles)
463       {
464         ssl.down();
465         ssl.draw();
466         BoxStack::getInstance()->update(this);
467         Message* m = new Message();
468         m->from = this;
469         m->to = parent;
470         m->message = Message::SUBTITLE_CHANGE_CHANNEL;
471         AudioSubtitleChannel* subchan = static_cast<AudioSubtitleChannel*>(ssl.getCurrentOptionData());
472         AudioSubtitleChannel* audchan = static_cast<AudioSubtitleChannel*>(asl.getCurrentOptionData());
473         m->parameter =   (subchan->pestype & 0xFFFF)
474                        | (subchan->type & 0xFF) << 16
475                        | (audchan->streamtype & 0xFF) << 24; // FIXME: Is this really supposed to be audio channel here? Old code did audio, looks wrong
476         MessageQueue::getInstance()->postMessage(m);
477       }
478       else
479       {
480         asl.down();
481         asl.draw();
482         BoxStack::getInstance()->update(this);
483         Message* m = new Message();
484         m->from = this;
485         m->to = parent;
486         m->message = Message::AUDIO_CHANGE_CHANNEL;
487         AudioSubtitleChannel* asc = static_cast<AudioSubtitleChannel*>(asl.getCurrentOptionData());
488         m->parameter =   (asc->pestype & 0xFFFF)
489                        | (asc->type & 0xFF) << 16
490                        | (asc->streamtype & 0xFF) << 24;
491         MessageQueue::getInstance()->postMessage(m);
492       }
493
494       return 2;
495     }
496
497     case Input::LEFT:
498     {
499       if (editsubtitles && subtitles)
500       {
501         ssl.setDarkSelOption(true);
502         asl.setDarkSelOption(false);
503         editsubtitles = false;
504         asl.draw();
505         ssl.draw();
506         BoxStack::getInstance()->update(this);
507       }
508
509       return 2;
510     }
511
512     case Input::RIGHT:
513     {
514       if (!editsubtitles && subtitles)
515       {
516         ssl.setDarkSelOption(false);
517         asl.setDarkSelOption(true);
518         editsubtitles = true;
519         asl.draw();
520         ssl.draw();
521         BoxStack::getInstance()->update(this);
522       }
523
524       return 2;
525     }
526   }
527
528   return 1;
529 }
530
531 void VAudioSelector::processMessage(Message* m)
532 {
533   if (m->message == Message::MOUSE_MOVE)
534   {
535     int lastsel = asl.getCurrentOption();
536
537     if ((m->parameter - getScreenX()) < 200 && asl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
538     {
539       editsubtitles = false;
540       ssl.setDarkSelOption(true);
541       asl.setDarkSelOption(false);
542       asl.draw();
543       ssl.draw();
544       BoxStack::getInstance()->update(this);
545
546       if (lastsel != asl.getCurrentOption())
547       {
548         Message* m2 = new Message();
549         m2->from = this;
550         m2->to = parent;
551         m2->message = Message::AUDIO_CHANGE_CHANNEL;
552         AudioSubtitleChannel* asc = static_cast<AudioSubtitleChannel*>(asl.getCurrentOptionData());
553         m2->parameter = (asc->pestype & 0xFFFF) | (asc->type & 0xFF) << 16 ;
554         MessageQueue::getInstance()->postMessage(m2);
555       }
556
557       return;
558     }
559
560     lastsel = ssl.getCurrentOption();
561
562     if (ssl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
563     {
564       editsubtitles = true;
565       ssl.setDarkSelOption(false);
566       asl.setDarkSelOption(true);
567       asl.draw();
568       ssl.draw();
569       BoxStack::getInstance()->update(this);
570
571       if (lastsel != ssl.getCurrentOption())
572       {
573         Message* m2 = new Message();
574         m2->from = this;
575         m2->to = parent;
576         m2->message = Message::SUBTITLE_CHANGE_CHANNEL;
577         AudioSubtitleChannel* asc = static_cast<AudioSubtitleChannel*>(ssl.getCurrentOptionData());
578         m2->parameter = (asc->pestype & 0xFFFF) | (asc->type & 0xFF) << 16 ;
579         MessageQueue::getInstance()->postMessage(m2);
580       }
581
582       return;
583     }
584   }
585   else if (m->message == Message::MOUSE_LBDOWN)
586   {
587     if (asl.mouseLBDOWN(m->parameter - getScreenX(), m->tag - getScreenY()))
588     {
589       editsubtitles = false;
590       ssl.setDarkSelOption(true);
591       asl.setDarkSelOption(false);
592       asl.draw();
593       ssl.draw();
594       BoxStack::getInstance()->handleCommand(Input::OK); //simulate OK press
595     }
596     else if (ssl.mouseLBDOWN(m->parameter - getScreenX(), m->tag - getScreenY()))
597     {
598       editsubtitles = true;
599       ssl.setDarkSelOption(false);
600       asl.setDarkSelOption(true);
601       asl.draw();
602       ssl.draw();
603       BoxStack::getInstance()->handleCommand(Input::OK); //simulate OK press
604     }
605     else
606     {
607       //check if press is outside this view! then simulate cancel
608       int x = m->parameter - getScreenX();
609       int y = m->tag - getScreenY();
610
611       if (x < 0 || y < 0 || x > static_cast<int>(getWidth()) || y > static_cast<int>(getHeight()))
612       {
613         BoxStack::getInstance()->handleCommand(Input::BACK); //simulate cancel press
614       }
615     }
616   }
617 }