Ticket #1458: patch.freebox.v1.diff

File patch.freebox.v1.diff, 39.5 KB (added by laurent@…, 14 years ago)

The patch

  • mythtv/configure

    diff -ru --new-file --exclude=.svn myth-org/mythtv/configure myth-patch/mythtv/configure
    old new  
    22#
    33# ffmpeg configure script (c) 2000, 2001, 2002 Fabrice Bellard
    44#
    5 
     5 
    66x86_mmx_cpus="pentium-mmx,pentium2,pentium3,pentium3m,pentium-m"
    77x86_mmx_cpus="$x86_mmx_cpus,pentium4,pentium4m,prescott"
    88x86_mmx_cpus="$x86_mmx_cpus,athlon,athlon-xp,athlon-tbird,athlon-4,athlon-mp,"
     
    5555lirc="yes"
    5656joystick_menu="yes"
    5757firewire_cable_box="yes"
     58freebox_box="yes"
    5859dbox2_dvb_box="yes"
    5960x11_include_path="/usr/X11R6/include"
    6061x11="yes"
     
    173174echo "  --disable-lirc           disable lirc support (Infrared Remotes)"
    174175echo "  --disable-joystick-menu  disable joystick menu"
    175176echo "  --disable-firewire       disable support for FireWire cable boxes"
     177echo "  --disable-freebox        disable support for Freebox"
    176178echo "  --disable-dbox2          disable support for Nokia DBOX2 DVB boxes (or compatibles)"
    177179echo "  --disable-v4l            disable Video4Linux support"
    178180echo "  --disable-ivtv           disable ivtv support (PVR-x50) req. v4l support"
     
    792794  ;;
    793795  --disable-dbox2) dbox2_dvb_box="no"
    794796  ;;
     797  --enable-freebox) freebox_box="yes"
     798  ;;
     799  --disable-freebox) freebox_box="no"
     800  ;;
    795801  --enable-dvb) dvb="yes"
    796802  ;;
    797803  --disable-dvb) dvb="no"
     
    20522058    fi
    20532059fi
    20542060
     2061if test x"$dvd" = x"yes" ; then
     2062    if has_library libdvdnav ; then
     2063        if has_header dvdnav/dvdnav.h ; then
     2064            dvd="yes"
     2065        fi
     2066    fi
     2067fi
     2068
     2069
    20552070VENDOR_XVMC_LIBS=""
    20562071if test x"$xvmc" = x"yes"; then
    20572072    xvmc="no"
     
    22012216  echo "FireWire support $firewire_cable_box"
    22022217  echo "DVB support      $dvb [$dvb_path]"
    22032218  echo "DBox2 support    $dbox2_dvb_box"
     2219  echo "freebox support    $freebox_box"
     2220
    22042221fi
    22052222
    22062223if test x"$frontend" = x"yes" ; then
     
    28332850  CONFIG_DEFINES="$CONFIG_DEFINES USING_DBOX2"
    28342851fi
    28352852
     2853if test x"$freebox_box" = x"yes" ; then
     2854  CCONFIG="$CCONFIG using_freebox"
     2855  CONFIG_DEFINES="$CONFIG_DEFINES USING_FREEBOX"
     2856fi
     2857
     2858
    28362859if test x"$lirc" = x"yes" ; then
    28372860  CCONFIG="$CCONFIG using_lirc"
    28382861  echo "CONFIG_LIRC_LIBS=-llirc_client" >> $MYTH_CONFIG_MAK
  • mythtv/libs/libmythtv/dbcheck.cpp

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/dbcheck.cpp myth-patch/mythtv/libs/libmythtv/dbcheck.cpp
    old new  
    1010#include "mythdbcon.h"
    1111
    1212/// This is the DB schema version expected by the running MythTV instance.
    13 const QString currentDatabaseVersion = "1128";
     13const QString currentDatabaseVersion = "1129";
    1414
    1515static bool UpdateDBVersionNumber(const QString &newnumber);
    1616static bool performActualUpdate(const QString updates[], QString version,
     
    20052005            return false;
    20062006    }
    20072007
     2008
    20082009    if (dbver == "1123")
    20092010    {
    20102011        const QString updates[] = {
     
    20612062//"ALTER TABLE capturecard DROP COLUMN dvb_recordts;" in 0.21
    20622063//"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21
    20632064
     2065  if (dbver == "1128")
     2066    {
     2067        const QString updates[] = {
     2068"INSERT INTO profilegroups SET name = 'Freebox Input', cardtype = 'Freebox', is_default = 1;",
     2069"ALTER TABLE capturecard ADD COLUMN freebox_host varchar(64) DEFAULT 'mafreebox.freebox.fr';",
     2070""
     2071};
     2072
     2073        if (!performActualUpdate(updates, "1124", dbver))
     2074            return false;
     2075    }
     2076
     2077
    20642078    return true;
    20652079}
    20662080
     
    21212135"  `dbox2_port` int(10) unsigned NOT NULL default '31338',"
    21222136"  `dbox2_httpport` int(10) unsigned NOT NULL default '80',"
    21232137"  `dbox2_host` varchar(32) default NULL,"
     2138"  `freebox_host varchar(64) DEFAULT 'mafreebox.freebox.fr',"
    21242139"  `signal_timeout` int(11) NOT NULL default '1000',"
    21252140"  `channel_timeout` int(11) NOT NULL default '3000',"
    21262141"  PRIMARY KEY  (`cardid`)"
     
    26862701"INSERT INTO `profilegroups` VALUES (8,"
    26872702" 'USB Mpeg-4 Encoder (Plextor ConvertX, etc)','GO7007',1,NULL);",
    26882703"INSERT INTO `profilegroups` VALUES (9,'DBOX2 Input','DBOX2',1,NULL);",
     2704"INSERT INTO `profilegroups` VALUES (10,'Freebox Input','Freebox',1,NULL);",
    26892705"INSERT INTO `recordingprofiles` VALUES (1,'Default',NULL,NULL,1);",
    26902706"INSERT INTO `recordingprofiles` VALUES (2,'Live TV',NULL,NULL,1);",
    26912707"INSERT INTO `recordingprofiles` VALUES (3,'High Quality',NULL,NULL,1);",
  • mythtv/libs/libmythtv/freeboxchannel.cpp

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/freeboxchannel.cpp myth-patch/mythtv/libs/libmythtv/freeboxchannel.cpp
    old new  
     1/**
     2 *  FreeboxChannel
     3 *  Copyright (c) 2005 by Levent Gündogdu
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7
     8
     9#include <iostream>
     10#include <qsqldatabase.h>
     11#include "mythdbcon.h"
     12#include "mythcontext.h"
     13#include "freeboxchannel.h"
     14
     15#define FREEBOX_CHANNEL_DEBUG
     16
     17FreeboxChannel::FreeboxChannel(TVRec *parent, FreeboxDBOptions *freebox_options, int cardid):
     18                                QObject(NULL, "FreeboxChannel"),
     19                                ChannelBase(parent),
     20                                http(new QHttp()),
     21                                m_freeboxoptions(freebox_options),
     22                                m_freeboxchannelcount(0),
     23                                m_channelListReady(false),
     24                                m_requestChannel(""),
     25                                m_lastChannel("1")
     26
     27{
     28        Log(QString("new FreeboxChannel::FreeboxChannel"));
     29       
     30        connect(http,        SIGNAL(           done(bool)),
     31            this,        SLOT(  HttpRequestDone(bool)));
     32 
     33        LoadChannels();
     34}
     35
     36bool FreeboxChannel::SwitchToInput(const QString &inputname, const QString &chan)
     37{
     38        Log(QString("FreeboxChannel::Switch to input %1 %2").arg(inputname, chan));
     39
     40        int inputNum = GetInputByName(inputname);
     41        Log(QString("FreeboxChannel:inputNum %1").arg(inputNum));
     42        if (inputNum < 0)
     43         return false;
     44               
     45   return SetChannelByString(chan);
     46}
     47
     48bool FreeboxChannel::SetChannelByString(const QString &newChan)
     49{
     50        Log(QString("FreeboxChannel::SetChannelByString %1").arg(newChan));
     51       
     52         // Delay set channel when list has not yet been retrieved
     53    if (!m_channelListReady)
     54    {
     55        Log(QString("Channel list not received yet. Will switch to channel %1 later...").arg(newChan));
     56                m_requestChannel = newChan;
     57                return true;
     58    }
     59   
     60    QString chan = newChan;
     61    if (chan == "")
     62    {
     63        Log(QString("Empty channel name has been provided. Getting default name."));
     64                //chan = GetDefaultChannel();
     65    }
     66   
     67    Log(QString("Changing to %1.").arg(chan));
     68    if (m_lastChannel != curchannelname)
     69        m_lastChannel = curchannelname;
     70
     71    curchannelname = chan;
     72    QString channelName = "france2";            //GetChannelNameFromNumber(chan);
     73    if (channelName == "")
     74    {
     75        Log(QString("Changing to %1 failed. Channel not found!").arg(chan));
     76                QString defaultChannel = "france2"; //GetDefaultChannel();
     77                if (defaultChannel != chan)
     78                { 
     79                    Log(QString("Trying default channel %1").arg(defaultChannel));
     80                    return SetChannelByString(defaultChannel);
     81                }
     82                return false;
     83    }
     84
     85
     86    return true;
     87}
     88
     89bool FreeboxChannel::IsOpen(void) const
     90{
     91        VERBOSE(VB_IMPORTANT,QString("FreeboxChannel::IsOpen"));
     92        return true;
     93}
     94
     95bool FreeboxChannel::Open(void)
     96{
     97        Log(QString("FreeboxChannel::Open"));
     98
     99    if (!InitializeInputs())
     100        return false;
     101       
     102        return true;
     103}
     104
     105void FreeboxChannel::Close(void)
     106{
     107        Log(QString("FreeboxChannel::Close"));
     108}
     109
     110
     111void FreeboxChannel::Log(QString string)
     112{
     113    VERBOSE(VB_IMPORTANT,QString("Freebox#%1").arg(string));
     114}
     115
     116
     117// =====================================================================================
     118//
     119//      C H A N N E L     L O A D I N G
     120// =====================================================================================
     121
     122
     123void FreeboxChannel::LoadChannels()
     124{
     125    Log(QString("Loading channels..."));
     126
     127    Log(QString("Reading channel list from %1").arg(m_freeboxoptions->host));
     128
     129    // Request Channel list via http. Signal will be emmitted when list is ready.
     130    QHttpRequestHeader header("GET", "/freeboxtv/playlist.m3u");
     131    header.setValue("Host", m_freeboxoptions->host);
     132    http->setHost(m_freeboxoptions->host, 80);
     133    http->request(header);
     134}
     135
     136void FreeboxChannel::HttpRequestDone(bool error)
     137{
     138    if (error)
     139    {
     140        Log(QString("Reading channel list failed!"));
     141        return;
     142    }
     143
     144    QString buffer=http->readAll();
     145    Log(QString("Reading channel list succeeded."));
     146    m_freeboxchannelcount = 0;
     147
     148    int sepCount = 0;
     149   
     150    QString header = buffer.section("\n", sepCount, sepCount);
     151    sepCount++;
     152
     153        #ifdef FREEBOX_CHANNEL_DEBUG
     154        Log(QString("Found Header %1.").arg(header));
     155        #endif
     156       
     157        if (header != "#EXTM3U")
     158        {
     159                Log(QString("Invalid header while retrieve channel list."));
     160                return;
     161        }
     162   
     163    while (true)
     164    {
     165        QString line1 = buffer.section("\n", sepCount, sepCount);
     166                if (line1 == "")
     167                break;
     168           
     169            sepCount++;
     170
     171        QString line2 = buffer.section("\n", sepCount, sepCount);
     172                if (line2 == "")
     173                break;
     174
     175            sepCount++;
     176
     177                QString lineHead;
     178                QString extension;
     179                QString channelNum;
     180                QString channelName;
     181       
     182                int pos = 0;
     183                int oldPos = 0;
     184               
     185                pos = line1.find(":", oldPos);
     186                if (pos<0)
     187                {
     188                        Log(QString("Invalid header while retrieve channel list."));
     189                        return;
     190                }
     191                lineHead = line1.mid(0, pos);
     192               
     193                if (lineHead != "#EXTINF")
     194                {
     195                        Log(QString("Invalid header while retrieve channel list."));
     196                        return;
     197                }
     198               
     199                oldPos = pos + 1;
     200                pos = line1.find(",", oldPos);
     201                if (pos<0)
     202                {
     203                        Log(QString("Invalid header while retrieve channel list."));
     204                        return;
     205                }
     206                extension = line1.mid(oldPos, pos - oldPos);
     207               
     208
     209                oldPos = pos + 1;
     210                pos = line1.find(" ", oldPos);
     211                if (pos<0)
     212                {
     213                        Log(QString("Invalid header while retrieve channel list."));
     214                        return;
     215                }
     216                channelNum = line1.mid(oldPos, pos - oldPos);
     217               
     218               
     219                oldPos = pos + 1;
     220                pos = line1.find("- ", oldPos);
     221                if (pos<0)
     222                {
     223                        Log(QString("Invalid header while retrieve channel list."));
     224                        return;
     225                }
     226                channelName = line1.mid(pos + 2, line1.length());
     227               
     228               
     229
     230                QString channelUrl = line2;
     231               
     232                m_freeboxchannelUrl[m_freeboxchannelcount] = channelUrl;
     233                m_freeboxchannelNum[m_freeboxchannelcount] = channelNum;
     234                m_freeboxchannelNames[m_freeboxchannelcount] = channelName;
     235               
     236                #ifdef FREEBOX_CHANNEL_DEBUG
     237                Log(QString("Found Channel %1:%2:%3").arg(channelNum).arg(channelName).arg(channelUrl));
     238                #endif
     239                m_freeboxchannelcount++;
     240    }
     241   
     242    Log(QString("Read %1 channels.").arg(m_freeboxchannelcount));
     243
     244    // Initialize EPG
     245    //m_epg->Init(m_dbox2options, m_cardid, this);
     246   
     247    // Channel list is ready.
     248    m_channelListReady = true;
     249   
     250    // Change channel if request available
     251    if (m_requestChannel != "")
     252    {
     253                SetChannelByString(m_requestChannel);
     254                m_requestChannel = "";
     255    }
     256}
  • mythtv/libs/libmythtv/freeboxchannel.h

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/freeboxchannel.h myth-patch/mythtv/libs/libmythtv/freeboxchannel.h
    old new  
     1#ifndef FREEBOXCHANNEL_H
     2#define FREEBOXCHANNEL_H
     3
     4#include <qstring.h>
     5#include <qmap.h>
     6#include <qhttp.h>
     7#include <qobject.h>
     8#include <qthread.h>
     9
     10#ifdef HAVE_STDINT_H
     11#include <stdint.h>
     12#endif
     13
     14#include "tv_rec.h"
     15#include "channelbase.h"
     16#include "sitypes.h"
     17
     18
     19class FreeboxChannel : public QObject, public ChannelBase
     20{
     21    Q_OBJECT
     22        public:
     23        FreeboxChannel(TVRec *parent, FreeboxDBOptions *freebox_options, int cardid);
     24        ~FreeboxChannel(void)
     25        { 
     26                }
     27
     28
     29        bool Open();
     30        void Close();
     31        bool SwitchToInput(const QString &inputname, const QString &chan);
     32        bool SetChannelByString(const QString &chan);
     33        bool IsOpen(void) const;
     34 
     35            bool SwitchToInput(int newcapchannel, bool setstarting)
     36        {
     37                (void)newcapchannel;
     38                (void)setstarting;
     39                return false;
     40        }
     41
     42   
     43        public slots:
     44        void HttpRequestDone(bool error);
     45   
     46        private:
     47        void LoadChannels();
     48
     49                void Log(QString string);
     50 
     51                QHttp                   *http;
     52                FreeboxDBOptions        *m_freeboxoptions;
     53               
     54
     55                bool                    m_channelListReady;
     56                QString                 m_requestChannel;
     57                QString                 m_lastChannel;
     58               
     59                int                     m_freeboxchannelcount;
     60        QMap<int,QString>       m_freeboxchannelUrl;
     61        QMap<int,QString>       m_freeboxchannelNum;
     62        QMap<int,QString>       m_freeboxchannelNames;
     63};
     64
     65#endif
  • mythtv/libs/libmythtv/freeboxrecorder.cpp

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/freeboxrecorder.cpp myth-patch/mythtv/libs/libmythtv/freeboxrecorder.cpp
    old new  
     1/**
     2 *  FreeboxRecorder
     3 *  Copyright (c) 2005 by Levent G?u (mythtv@feature-it.com)
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#include <iostream>
     8using namespace std;
     9
     10
     11
     12#include <pthread.h>
     13#include "RingBuffer.h"
     14#include "mythcontext.h"
     15#include "freeboxrecorder.h"
     16#include "freeboxchannel.h"
     17#include <qhttp.h>
     18#include <qobject.h>
     19#include <sys/select.h>
     20#include <sys/types.h>
     21#include <sys/socket.h>
     22#include <netdb.h>
     23#include <fcntl.h>
     24#include <unistd.h>
     25#include <netinet/in.h>    // For sockaddr_in on OS X
     26
     27void subsessionAfterPlaying(void *clientData);
     28void subsessionByeHandler(void *clientData);
     29
     30
     31
     32
     33
     34FreeboxRecorder::FreeboxRecorder(TVRec *rec, FreeboxChannel *channel):DTVRecorder(rec, "FreeboxRecorder"),
     35                                        m_patPacket(new uint8_t[TSPacket::SIZE]),
     36                                        pat_cc(0),
     37                                        pkts_until_pat(0),
     38                                m_pidPAT(0x0),
     39                                m_pidCount(0),
     40                                m_pmtPID(-1),
     41                                m_ac3PID(-1),
     42                                m_sectionID(-1)
     43                                       
     44{
     45        Log(QString("FreeboxRecorder::new FreeboxRecorder"));
     46
     47        watchVariable = new char();
     48}
     49
     50
     51bool FreeboxRecorder::Open()
     52{
     53        Log(QString("FreeboxRecorder::Open"));
     54
     55    return true;
     56}
     57
     58void FreeboxRecorder::StartRecording()
     59{
     60        Log(QString("FreeboxRecorder::StartRecording"));
     61       
     62        TSPacket *packet = new TSPacket();
     63        BufferedWrite(*packet);
     64       
     65        CreatePAT(m_patPacket);
     66       
     67        Play("rtsp://mafreebox.freebox.fr/freeboxtv/201");
     68}
     69
     70void FreeboxRecorder::StopRecording(void)
     71{
     72        Log(QString("FreeboxRecorder::StopRecording"));
     73       
     74        *watchVariable = 1;
     75        DTVRecorder::StopRecording();
     76}
     77
     78void FreeboxRecorder::SetOptionsFromProfile(RecordingProfile *profile,
     79                                                                                           const QString &videodev,
     80                                                                                           const QString &audiodev,
     81                                                                                           const QString &vbidev)
     82{
     83        Log(QString("FreeboxRecorder::SetOptionsFromProfile"));
     84       
     85}
     86
     87void FreeboxRecorder::Log(QString string)
     88{
     89    VERBOSE(VB_IMPORTANT,QString("Freebox#%1").arg(string));
     90}
     91
     92void FreeboxRecorder::Play(char* url)
     93{
     94  // Begin by setting up our usage environment:
     95  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
     96  env = BasicUsageEnvironment::createNew(*scheduler);
     97
     98 
     99  // Create our client object:
     100  rtspClient = RTSPClient::createNew(*env, 0, "myRTSP", 0);
     101  if (rtspClient == NULL)
     102  {
     103    *env << "Failed to create RTSP client: " << env->getResultMsg() << "\n";
     104    shutdown();
     105  }
     106 
     107  char* sdpDescription = rtspClient->describeURL(url);
     108  rtspClient->describeStatus();
     109
     110  if (sdpDescription == NULL)
     111  {
     112    *env << "Failed to get a SDP description from URL \"" << url << "\": " << env->getResultMsg() << "\n";
     113    shutdown();
     114  }
     115 
     116  *env << "Opened URL \"" << url << "\", returning a SDP description:\n" << sdpDescription << "\n";
     117
     118  // Create a media session object from this SDP description:
     119  session = MediaSession::createNew(*env, sdpDescription);
     120  delete[] sdpDescription;
     121  if (session == NULL)
     122  {
     123    *env << "Failed to create a MediaSession object from the SDP description: " << env->getResultMsg() << "\n";
     124    shutdown();
     125  }
     126  else if (!session->hasSubsessions())
     127  {
     128    *env << "This session has no media subsessions (i.e., \"m=\" lines)\n";
     129    shutdown();
     130  }
     131 
     132    // Then, setup the "RTPSource"s for the session:
     133  MediaSubsessionIterator iter(*session);
     134  MediaSubsession *subsession;
     135  Boolean madeProgress = False;
     136  while ((subsession = iter.next()) != NULL)
     137  {
     138      if (!subsession->initiate(-1))
     139      {
     140                *env << "Unable to create receiver for \"" << subsession->mediumName()  << "/" << subsession->codecName()       << "\" subsession: " << env->getResultMsg() << "\n";
     141      }
     142      else
     143      {
     144                *env << "Created receiver for \"" << subsession->mediumName() << "/" << subsession->codecName() << "\" subsession (client ports " << subsession->clientPortNum()
     145                                << "-" << subsession->clientPortNum()+1 << ")\n";
     146               
     147                madeProgress = True;
     148
     149                if (subsession->rtpSource() != NULL)
     150                {
     151                  unsigned const thresh = 1000000; // 1 second
     152                  subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
     153                }
     154      }
     155  }
     156
     157
     158  if (!madeProgress) shutdown();
     159
     160
     161  // Perform additional 'setup' on each subsession, before playing them:
     162  madeProgress = false;
     163  iter.reset();
     164  while ((subsession = iter.next()) != NULL)
     165  {
     166    if (subsession->clientPortNum() == 0) continue; // port # was not set
     167
     168
     169    if (rtspClient->setupMediaSubsession(*subsession, False, false))
     170    {
     171      *env << "Setup \"" << subsession->mediumName() << "/" << subsession->codecName() << "\" subsession (client ports " << subsession->clientPortNum() << "-" << subsession->clientPortNum()+1 << ")\n";
     172       madeProgress = True;
     173        }
     174        else
     175        {       
     176      *env << "Failed to setup \"" << subsession->mediumName() << "/" << subsession->codecName() << "\" subsession: " << env->getResultMsg() << "\n";
     177    }
     178  }
     179 
     180 
     181  if (!madeProgress) shutdown();
     182 
     183 
     184  // Create and start "FileSink"s for each subsession:
     185  madeProgress = False;
     186  iter.reset();
     187  while ((subsession = iter.next()) != NULL)
     188  {
     189                if (subsession->readSource() == NULL) continue; // was not initiated
     190                char outFileName[1000];
     191                sprintf(outFileName, "out");
     192               
     193                MySink* mySink = MySink::createNew(*env, this);
     194           
     195        subsession->sink = mySink;
     196                if (subsession->sink == NULL)
     197                {
     198                         *env << "Failed to create FileSink for \"" << outFileName << "\": " << env->getResultMsg() << "\n";
     199                }
     200                else {
     201                          *env << "Created output file: \"" << outFileName << "\"\n";
     202                }
     203               
     204            subsession->sink->startPlaying(*(subsession->readSource()),  subsessionAfterPlaying, new MyClientData(this, subsession));
     205           
     206            if (subsession->rtcpInstance() != NULL) {
     207                        subsession->rtcpInstance()->setByeHandler(subsessionByeHandler, new MyClientData(this, subsession));
     208                }
     209
     210            madeProgress = True;
     211  }
     212
     213  if (!madeProgress) shutdown();
     214
     215  if (rtspClient->playMediaSession(*session))
     216  {
     217    *env << "Started playing session\n";
     218  }
     219  else
     220  {
     221         *env << "Failed to start playing session: " << env->getResultMsg() << "\n";
     222         shutdown();
     223  }
     224
     225    _request_recording = true;
     226    _recording = true;
     227
     228  *watchVariable = 0;
     229  env->taskScheduler().doEventLoop(watchVariable); // does not return
     230
     231  Log(QString("RecordStop"));
     232
     233
     234}
     235
     236int FreeboxRecorder::findTSHeader(unsigned char *data, unsigned dataSize)
     237{
     238    unsigned int pos = 0;
     239   
     240    while (pos < dataSize)
     241    {
     242        if (data[pos] == 0x47)
     243                return pos;
     244                pos++;
     245    }
     246    return -1;
     247}
     248
     249
     250void FreeboxRecorder::addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime)
     251
     252    unsigned int readIndex = 0;
     253    while (readIndex < dataSize)
     254    {
     255        // Try to find next TS
     256        int tsPos = findTSHeader(data + readIndex, dataSize);
     257        if (tsPos == -1)
     258        {
     259                VERBOSE(VB_IMPORTANT, QString("FREEBOX: No TS header."));
     260                break;
     261                }
     262     
     263                if (tsPos > 0)
     264                {
     265                VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1, not in sync.").arg(tsPos));
     266            }
     267
     268                if ((dataSize - tsPos) < 188)
     269                {
     270                VERBOSE(VB_IMPORTANT, QString("FREEBOX: TS header at %1 but packet not yet complete.").arg(tsPos));
     271                        break;
     272            }
     273       
     274                // Inject PAT every 2000 TS packets.
     275                if (pkts_until_pat == 0)
     276                {
     277                    BufferedWrite(*(reinterpret_cast<const TSPacket*>(m_patPacket)));
     278                    pkts_until_pat = 2000;
     279                }
     280                else
     281                    pkts_until_pat--;
     282
     283               
     284                       
     285            const void     *newData     = data + tsPos + readIndex;
     286            const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(newData);
     287
     288                _buffer_packets = !FindKeyframes(tspacket);
     289
     290                BufferedWrite(*tspacket);
     291               
     292                readIndex += tsPos + TSPacket::SIZE;
     293               
     294        }
     295}
     296
     297
     298
     299
     300void FreeboxRecorder::shutdown(int exitCode)
     301{
     302  if (session == NULL) return;
     303  MediaSubsessionIterator iter(*session);
     304  MediaSubsession* subsession;
     305  while ((subsession = iter.next()) != NULL)
     306  {
     307    Medium::close(subsession->sink);
     308    subsession->sink = NULL;
     309  }
     310 
     311  if (session == NULL) return;
     312 
     313  rtspClient->teardownMediaSession(*session);
     314 
     315 
     316  Medium::close(session);
     317  Medium::close(rtspClient);
     318
     319  exit(exitCode);
     320}
     321
     322
     323
     324
     325void subsessionAfterPlaying(void *clientData)
     326{
     327        MyClientData *myData = (MyClientData*)clientData;
     328        myData->freeboxRecorder->SubsessionAfterPlaying(myData->mediaSubSession);
     329}
     330
     331void subsessionByeHandler(void *clientData)
     332{
     333        MyClientData *myData = (MyClientData*)clientData;
     334        myData->freeboxRecorder->SubsessionByeHandler(myData->mediaSubSession);
     335}
     336
     337void FreeboxRecorder::SubsessionAfterPlaying(MediaSubsession* subsession)
     338{
     339  Medium::close(subsession->sink);
     340  subsession->sink = NULL;
     341
     342  MediaSession& session = subsession->parentSession();
     343  MediaSubsessionIterator iter(session);
     344  while ((subsession = iter.next()) != NULL)
     345  {
     346    if (subsession->sink != NULL) return;
     347  }
     348
     349  shutdown(0);
     350
     351}
     352
     353
     354void FreeboxRecorder::SubsessionByeHandler(MediaSubsession* subsession)
     355{
     356  *env << "Received RTCP \"BYE\" on \"" << subsession->mediumName() << "/" << subsession->codecName() << "\n";
     357
     358  subsessionAfterPlaying(subsession);
     359}
     360
     361
     362
     363MySink::MySink(UsageEnvironment& pEnv, FreeboxRecorder *pRecorder) : MediaSink(pEnv)
     364{
     365        recorder = pRecorder;
     366        env = &pEnv;
     367        fBufferSize = 20000;
     368        fBuffer = new unsigned char[fBufferSize];
     369}
     370
     371MySink::~MySink()
     372{
     373         delete[] fBuffer;
     374}
     375
     376MySink* MySink::createNew(UsageEnvironment& env, FreeboxRecorder *pRecorder)
     377{
     378               
     379
     380  MySink* newSink = new MySink(env, pRecorder);
     381  return newSink;
     382}
     383
     384Boolean MySink::continuePlaying()
     385{
     386
     387  if (fSource == NULL) return False;
     388
     389  fSource->getNextFrame(fBuffer, fBufferSize, afterGettingFrame, this, onSourceClosure, this);
     390
     391  return True;
     392}
     393
     394void MySink::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/,struct timeval presentationTime, unsigned /*durationInMicroseconds*/)
     395{
     396
     397  MySink* sink = (MySink*)clientData;
     398  sink->afterGettingFrame1(frameSize, presentationTime);
     399
     400
     401void MySink::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime)
     402{
     403
     404        addData(fBuffer, frameSize, presentationTime);
     405    continuePlaying();
     406}
     407
     408void MySink::addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime)
     409
     410        recorder->addData(data, dataSize, presentationTime);
     411}
     412
     413
     414extern unsigned int mpegts_crc32(const uint8_t *data, int len);
     415
     416
     417void FreeboxRecorder::CreatePAT(uint8_t *ts_packet)
     418{
     419    VERBOSE(VB_IMPORTANT, QString("Freebox: Creating PAT for PMT pid."));
     420
     421    memset(ts_packet, 0xFF, 188);
     422
     423    ts_packet[0] = 0x47;                            // sync byte
     424    ts_packet[1] = 0x40 | ((m_pidPAT >> 8) & 0x1F);  // payload start & PID
     425    ts_packet[2] = m_pidPAT & 0xFF;                  // PID
     426    ts_packet[3] = 0x10 | pat_cc;                   // scrambling, adaptation & continuity counter
     427    ts_packet[4] = 0x00;                            // pointer field
     428
     429    ++pat_cc &= 0x0F;   // inc. continuity counter
     430    uint8_t *pat = ts_packet + 5;
     431    int p = 0;
     432
     433    pat[p++] = PAT_TID; // table ID
     434    pat[p++] = 0xB0;    // section syntax indicator
     435    p++;                // section length (set later)
     436    pat[p++] = 0;       // TSID
     437    pat[p++] = 1;       // TSID
     438    pat[p++] = 0xC3;    // Version + Current/Next
     439    pat[p++] = 0;       // Current Section
     440    pat[p++] = 0;       // Last Section
     441    pat[p++] = (m_sectionID >> 8) & 0xFF;
     442    pat[p++] = m_sectionID & 0xFF;
     443    pat[p++] = (m_pmtPID >> 8) & 0x1F;
     444    pat[p++] = m_pmtPID & 0xFF;
     445
     446    pat[2] = p + 4 - 3; // section length
     447
     448    unsigned int crc = mpegts_crc32(pat, p);
     449    pat[p++] = (crc >> 24) & 0xFF;
     450    pat[p++] = (crc >> 16) & 0xFF;
     451    pat[p++] = (crc >> 8) & 0xFF;
     452    pat[p++] = crc & 0xFF;
     453}
     454
     455
  • mythtv/libs/libmythtv/freeboxrecorder.h

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/freeboxrecorder.h myth-patch/mythtv/libs/libmythtv/freeboxrecorder.h
    old new  
     1/**
     2 *  DBOX2Recorder
     3 *  Copyright (c) 2005 by Levent Gündogdu
     4 *  Distributed as part of MythTV under GPL v2 and later.
     5 */
     6
     7#ifndef FREEBOXRECORDER_H_
     8#define FREEBOXRECORDER_H_
     9
     10#include "dtvrecorder.h"
     11#include <time.h>
     12#include "freeboxchannel.h"
     13#include "sitypes.h"
     14#include "qhttp.h"
     15#include "mpeg/tspacket.h"
     16
     17
     18#include "BasicUsageEnvironment.hh"
     19#include "GroupsockHelper.hh"
     20#include "liveMedia.hh"
     21
     22/**
     23
     24 *
     25 *  Constructs a FreeboxRecorder
     26 *
     27 */
     28
     29#if defined(__WIN32__) || defined(_WIN32)
     30#define snprintf _snprintf
     31#else
     32#include <signal.h>
     33#define USE_SIGNALS 1
     34#endif
     35
     36#define PAT_TID   0x00
     37#define DBOX_MAX_PID_COUNT 32
     38
     39
     40class FreeboxRecorder : public DTVRecorder
     41{
     42    Q_OBJECT
     43    public:
     44        FreeboxRecorder(TVRec *rec, FreeboxChannel *channel);
     45        ~FreeboxRecorder() {  }
     46
     47
     48        void StartRecording(void);
     49        void StopRecording(void);
     50        bool Open(void);
     51        void SetOptionsFromProfile(RecordingProfile *profile,
     52                                   const QString &videodev,
     53                                   const QString &audiodev,
     54                                   const QString &vbidev);
     55
     56           void SubsessionAfterPlaying(MediaSubsession* subsession);
     57           void SubsessionByeHandler(MediaSubsession* subsession);
     58           
     59           void addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime);
     60           int findTSHeader(unsigned char *data, unsigned dataSize);
     61
     62        void CreatePAT(uint8_t *ts_packet);
     63
     64        private:
     65           UsageEnvironment* env;
     66           RTSPClient* rtspClient;
     67           MediaSession* session;
     68           char* watchVariable;
     69           
     70           void FreeboxRecorder::Play(char* url);
     71           void Log(QString string);
     72           void shutdown(int exitCode = 1);
     73           
     74           int pkts_until_pat;
     75          uint8_t *m_patPacket;
     76          int m_pidPAT;
     77          int m_pids[DBOX_MAX_PID_COUNT];
     78          int m_pidCount;
     79          int pat_cc;
     80          int m_pmtPID;
     81          int m_ac3PID;
     82          int m_sectionID;
     83};
     84
     85class MyClientData
     86{
     87        public:
     88                MyClientData(FreeboxRecorder *pFreeboxRecorder, MediaSubsession *pMediaSubSession)
     89                {
     90                        freeboxRecorder = pFreeboxRecorder;
     91                        mediaSubSession = pMediaSubSession;
     92                }
     93       
     94        FreeboxRecorder *freeboxRecorder;
     95        MediaSubsession *mediaSubSession;
     96};
     97
     98
     99
     100class MySink: public MediaSink {
     101        public:
     102          static MySink* createNew(UsageEnvironment& env, FreeboxRecorder *pRecorder);
     103       
     104          void addData(unsigned char* data, unsigned dataSize, struct timeval presentationTime);
     105       
     106        protected:
     107          MySink(UsageEnvironment& env, FreeboxRecorder *pRecorder);
     108          virtual ~MySink();
     109       
     110          static void afterGettingFrame(void* clientData, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds);
     111          virtual void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime);
     112       
     113        private:
     114          virtual Boolean continuePlaying();
     115         
     116          unsigned char* fBuffer;
     117          unsigned fBufferSize;
     118          UsageEnvironment *env;
     119          FreeboxRecorder *recorder;
     120          int bufferIndex;
     121         
     122};
     123#endif
  • mythtv/libs/libmythtv/libmythtv.pro

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/libmythtv.pro myth-patch/mythtv/libs/libmythtv/libmythtv.pro
    old new  
    289289    # Support for set top boxes (Nokia DBox2 etc.)
    290290    using_dbox2:SOURCES += dbox2recorder.cpp dbox2channel.cpp dbox2epg.cpp
    291291    using_dbox2:HEADERS += dbox2recorder.h dbox2channel.h dbox2epg.h
     292   
     293    using_freebox:SOURCES += freeboxrecorder.cpp freeboxchannel.cpp
     294    using_freebox:HEADERS += freeboxrecorder.h freeboxchannel.h
    292295
    293296    # Support for PVR-150/250/350/500, etc. on Linux
    294297    using_ivtv:HEADERS += mpegrecorder.h
  • mythtv/libs/libmythtv/tv_rec.cpp

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/tv_rec.cpp myth-patch/mythtv/libs/libmythtv/tv_rec.cpp
    old new  
    6868#include "dbox2channel.h"
    6969#endif
    7070
     71#ifdef USING_FREEBOX
     72#include "freeboxrecorder.h"
     73#include "freeboxchannel.h"
     74#endif
     75
    7176#define DEBUG_CHANNEL_PREFIX 0 /**< set to 1 to channel prefixing */
    7277
    7378#define LOC QString("TVRec(%1): ").arg(cardid)
     
    174179        init_run = true;
    175180#endif
    176181    }
     182    else if (genOpt.cardtype == "FREEBOX")
     183    {
     184#ifdef USING_FREEBOX
     185        channel = new FreeboxChannel(this, &freeboxOpt, cardid);
     186        channel->Open();
     187        InitChannel(genOpt.defaultinput, startchannel);
     188        init_run = true;
     189#endif
     190    }
    177191    else if (genOpt.cardtype == "MPEG" &&
    178192             genOpt.videodev.lower().left(5) == "file:")
    179193    {
     
    221235{
    222236    QMutexLocker lock(&stateChangeLock);
    223237
    224     if (!GetDevices(cardid, genOpt, dvbOpt, fwOpt, dboxOpt))
     238    if (!GetDevices(cardid, genOpt, dvbOpt, fwOpt, dboxOpt, freeboxOpt))
    225239        return false;
    226240
    227241    QString startchannel = GetStartChannel(cardid, genOpt.defaultinput);
     
    288302        GetDBox2Channel()->deleteLater();
    289303    else
    290304#endif // USING_DBOX2
     305#ifdef USING_FREEBOX
     306        if (GetFreeboxChannel())
     307        GetFreeboxChannel()->deleteLater();
     308    else
     309#endif // USING_FREEBOX
    291310    if (channel)
    292311        delete channel;
    293312    channel = NULL;
     
    845864        recorder->SetOption("httpport", dboxOpt.httpport);
    846865#endif // USING_DBOX2
    847866    }
     867    else if (genOpt.cardtype == "FREEBOX")
     868    {
     869#ifdef USING_FREEBOX
     870        recorder = new FreeboxRecorder(this, GetFreeboxChannel());
     871        recorder->SetOption("host",     freeboxOpt.host);
     872#endif // USING_FREEBOX
     873    }
    848874    else if (genOpt.cardtype == "DVB")
    849875    {
    850876#ifdef USING_DVB
     
    10521078#endif // USING_DBOX2
    10531079}
    10541080
     1081FreeboxChannel *TVRec::GetFreeboxChannel(void)
     1082{
     1083#ifdef USING_FREEBOX
     1084    return dynamic_cast<FreeboxChannel*>(channel);
     1085#else
     1086    return NULL;
     1087#endif // USING_FREEBOX
     1088}
     1089
     1090
    10551091DVBChannel *TVRec::GetDVBChannel(void)
    10561092{
    10571093#ifdef USING_DVB
     
    13871423                       GeneralDBOptions  &gen_opts,
    13881424                       DVBDBOptions      &dvb_opts,
    13891425                       FireWireDBOptions &firewire_opts,
    1390                        DBox2DBOptions    &dbox2_opts)
     1426                       DBox2DBOptions    &dbox2_opts,
     1427                       FreeboxDBOptions  &freebox_opts)
    13911428{
    13921429    int testnum = 0;
    13931430    QString test;
     
    14011438        "       firewire_port,    firewire_node,       firewire_speed, "
    14021439        "       firewire_model,   firewire_connection,                 "
    14031440        "       dbox2_port,       dbox2_host,          dbox2_httpport, "
    1404         "       signal_timeout,   channel_timeout                      "
     1441        "       signal_timeout,   channel_timeout,                     "
     1442        "               freebox_host                                                                                       "
    14051443        "FROM capturecard "
    14061444        "WHERE cardid = :CARDID");
    14071445    query.bindValue(":CARDID", cardid);
     
    14551493        if (test != QString::null)
    14561494           dbox2_opts.host = QString::fromUtf8(test);
    14571495        dbox2_opts.httpport = query.value(16).toInt();
     1496       
     1497        test = query.value(21).toString();
     1498        if (test != QString::null)
     1499                freebox_opts.host = QString::fromUtf8(test);
    14581500
    14591501        gen_opts.signal_timeout  = (uint) max(query.value(17).toInt(), 0);
    14601502        gen_opts.channel_timeout = (uint) max(query.value(18).toInt(), 0);
     
    21672209        return retval;
    21682210
    21692211    QString channelinput = chan->GetCurrentInput();
    2170    
     2212      
    21712213    query.prepare(
    21722214        QString(
    21732215            "SELECT channel.%1 "
     
    22522294                             int cardid, QString channelorder,
    22532295                             int channeldirection, QString &chanid)
    22542296{
    2255     bool isNum = true;
     2297   bool isNum = true;
    22562298    channum.toULong(&isNum);
    22572299
    22582300    if (!isNum && channelorder == "channum + 0")
     
    34113453        delete channel;
    34123454        channel = NULL;
    34133455
    3414         GetDevices(newCardID, genOpt, dvbOpt, fwOpt, dboxOpt);
     3456        GetDevices(newCardID, genOpt, dvbOpt, fwOpt, dboxOpt, freeboxOpt);
    34153457        genOpt.defaultinput = inputname;
    34163458        CreateChannel(channum);
    34173459        if (!(request.flags & kFlagNoRec))
     
    40264068        return false;
    40274069
    40284070    QString channum = channel->GetCurrentName();
     4071        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("parm1: %1").arg(channum));
    40294072    int chanid = GetChannelValue("chanid", channel, channum);
    40304073
    40314074    if (chanid < 0)
  • mythtv/libs/libmythtv/tv_rec.h

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/tv_rec.h myth-patch/mythtv/libs/libmythtv/tv_rec.h
    old new  
    3434class DBox2Channel;
    3535class DVBChannel;
    3636class Channel;
     37class FreeboxChannel;
    3738
    3839class ProgramMapTable;
    3940
     
    100101    QString host;
    101102};
    102103
     104class FreeboxDBOptions
     105{
     106        public:
     107            FreeboxDBOptions() : host("mafreebox.freebox.fr") {;}
     108
     109        QString host;
     110};
     111
     112
    103113class TuningRequest
    104114{
    105115  public:
     
    235245                           GeneralDBOptions   &general_opts,
    236246                           DVBDBOptions       &dvb_opts,
    237247                           FireWireDBOptions  &firewire_opts,
    238                            DBox2DBOptions     &dbox2_opts);
     248                           DBox2DBOptions     &dbox2_opts,
     249                           FreeboxDBOptions       &free_opts);
    239250
    240251
    241252    static QString GetStartChannel(int cardid, const QString &defaultinput);
     
    248259    bool CreateChannel(const QString &startChanNum);
    249260    void InitChannel(const QString &inputname, const QString &startchannel);
    250261    void CloseChannel(void);
     262    FreeboxChannel *GetFreeboxChannel(void);
    251263    DBox2Channel *GetDBox2Channel(void);
    252264    DVBChannel   *GetDVBChannel(void);
    253265    Channel      *GetV4LChannel(void);
     
    331343    DVBDBOptions      dvbOpt;
    332344    FireWireDBOptions fwOpt;
    333345    DBox2DBOptions    dboxOpt;
     346    FreeboxDBOptions  freeboxOpt;
    334347
    335348    // State variables
    336349    QMutex         stateChangeLock;
  • mythtv/libs/libmythtv/videosource.cpp

    diff -ru --new-file --exclude=.svn myth-org/mythtv/libs/libmythtv/videosource.cpp myth-patch/mythtv/libs/libmythtv/videosource.cpp
    old new  
    894894 };
    895895
    896896
     897class FreeboxHost : public LineEditSetting, public CCSetting {
     898        public:
     899           FreeboxHost(const CaptureCard &parent):
     900           CCSetting(parent, "freebox_host") {
     901                        setValue("mafreebox.freebox.fr");
     902                        setLabel(QObject::tr("Freebox Host"));
     903            setHelpText(QObject::tr("The freebox host."));
     904        }
     905};
     906
     907class FreeboxConfigurationGroup: public VerticalConfigurationGroup {
     908public:
     909   FreeboxConfigurationGroup(CaptureCard& a_parent):
     910       parent(a_parent) {
     911       setUseLabel(false);
     912       addChild(new FreeboxHost(parent));
     913   };
     914  private:
     915     CaptureCard& parent;
     916 };
     917                     
    897918
    898919
    899920class V4LConfigurationGroup: public VerticalConfigurationGroup
     
    9881009    addTarget("MPEG", new MPEGConfigurationGroup(parent));
    9891010    addTarget("FIREWIRE", new FirewireConfigurationGroup(parent));
    9901011    addTarget("DBOX2", new DBOX2ConfigurationGroup(parent));
     1012    addTarget("FREEBOX", new FreeboxConfigurationGroup(parent));
    9911013}
    9921014
    9931015void CaptureCardGroup::triggerChanged(const QString& value)
     
    10221044    QString qstr =
    10231045        "SELECT cardtype, videodevice, cardid, "
    10241046        "       firewire_port, firewire_node, "
    1025         "       dbox2_port, dbox2_host, dbox2_httpport "
     1047        "       dbox2_port, dbox2_host, dbox2_httpport, freebox_host "
    10261048        "FROM capturecard "
    10271049        "WHERE hostname = :HOSTNAME";
    10281050    if (no_children)
     
    10521074                    "Streaming-Port: " + query.value(5).toString() + ", " +
    10531075                    "Http-Port: " + query.value(7).toString() +
    10541076                    "] ", query.value(2).toString());
    1055             }
     1077                        }
     1078            else if (query.value(0).toString() == "FREEBOX")
     1079            {
     1080                setting->addSelection(
     1081                    "[ " + query.value(0).toString() + " " +
     1082                    "HOST: " + query.value(8).toString() +  " " +
     1083                    "] ", query.value(2).toString());
     1084                        }
    10561085            else
    10571086            {
    10581087                setting->addSelection(
     
    10981127        "GO7007");
    10991128    setting->addSelection(
    11001129        QObject::tr("DBox2 TCP/IP cable box"), "DBOX2");
     1130    setting->addSelection(
     1131        QObject::tr("Freebox"), "FREEBOX");
    11011132}
    11021133
    11031134class CardID: public SelectLabelSetting, public CISetting {
     
    18471878    // SelectSetting provided a facility to edit the labels, we
    18481879    // could use CaptureCard::fillSelections
    18491880
     1881
    18501882    MSqlQuery query(MSqlQuery::InitCon());
    18511883    query.prepare(
    18521884        "SELECT cardid, videodevice, cardtype "
  • mythtv/settings.pro

    diff -ru --new-file --exclude=.svn myth-org/mythtv/settings.pro myth-patch/mythtv/settings.pro
    old new  
    2020
    2121INCLUDEPATH += $${PREFIX}/include
    2222INCLUDEPATH += $$CONFIG_INCLUDEPATH
     23INCLUDEPATH += /usr/lib/live/liveMedia/include
     24INCLUDEPATH += /usr/lib/live/UsageEnvironment/include
     25INCLUDEPATH += /usr/lib/live/BasicUsageEnvironment/include
     26INCLUDEPATH += /usr/lib/live/groupsock/include
    2327
    2428# figure out compile flags based on qmake info
    2529
     
    7276}
    7377QMAKE_LIBDIR_OPENGL =
    7478
    75 EXTRA_LIBS = -lfreetype -lmp3lame
     79EXTRA_LIBS = -lfreetype -lmp3lame -L /usr/lib/live/liveMedia -lliveMedia -L/usr/lib/live/UsageEnvironment -lUsageEnvironment -L/usr/lib/live/groupsock -lgroupsock -L/usr/lib/live/BasicUsageEnvironment -lBasicUsageEnvironment
    7680EXTRA_LIBS += $$CONFIG_AUDIO_OSS_LIBS
    7781EXTRA_LIBS += $$CONFIG_AUDIO_ALSA_LIBS
    7882EXTRA_LIBS += $$CONFIG_AUDIO_ARTS_LIBS