Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/engine/engineshoutcast.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                   engineshoutcast.cpp  -  class to shoutcast the mix
00003                              -------------------
00004     copyright            : (C) 2007 by Wesley Stessens
00005                            (C) 2007 by Albert Santoni
00006                          : (C) 2010 by Tobias Rafreider
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "engineshoutcast.h"
00019 //#include "controllogpotmeter.h"
00020 #include "configobject.h"
00021 #include "dlgprefshoutcast.h"
00022 
00023 
00024 #include "recording/encodervorbis.h"
00025 #include "recording/encodermp3.h"
00026 
00027 #include "playerinfo.h"
00028 #include "trackinfoobject.h"
00029 #ifdef __WINDOWS__
00030     #include <windows.h>
00031     //sleep on linux assumes seconds where as Sleep on Windows assumes milliseconds
00032     #define sleep(x) Sleep(x*1000)
00033 #endif
00034 
00035 #define TIMEOUT 10
00036 
00037 #include <QDebug>
00038 #include <QMutexLocker>
00039 #include <stdio.h> // currently used for writing to stdout
00040 
00041 
00042 /*
00043  * Initialize EngineShoutcast
00044  */
00045 EngineShoutcast::EngineShoutcast(ConfigObject<ConfigValue> *_config)
00046         : m_pMetaData(),
00047           m_pShout(NULL),
00048           m_pShoutMetaData(NULL),
00049           m_pConfig(_config),
00050           m_encoder(NULL),
00051           m_pUpdateShoutcastFromPrefs(NULL),
00052           m_pMasterSamplerate(new ControlObjectThread(
00053               ControlObject::getControl(ConfigKey("[Master]", "samplerate")))),
00054           m_shoutMutex(QMutex::Recursive) {
00055 
00056     m_pShout = 0;
00057     m_iShoutStatus = 0;
00058     m_pShoutcastNeedUpdateFromPrefs = new ControlObject(ConfigKey("[Shoutcast]","update_from_prefs"));
00059     m_pUpdateShoutcastFromPrefs = new ControlObjectThreadMain(m_pShoutcastNeedUpdateFromPrefs);
00060 
00061     m_bQuit = false;
00062 
00063     m_firstCall = false;
00064     // Initialize libshout
00065     shout_init();
00066 
00067     if (!(m_pShout = shout_new())) {
00068         errorDialog(tr("Mixxx encountered a problem"), tr("Could not allocate shout_t"));
00069         return;
00070     }
00071 
00072     if (!(m_pShoutMetaData = shout_metadata_new())) {
00073         errorDialog(tr("Mixxx encountered a problem"), tr("Could not allocate shout_metadata_t"));
00074         return;
00075     }
00076     if (shout_set_nonblocking(m_pShout, 1) != SHOUTERR_SUCCESS) {
00077         errorDialog(tr("Error setting non-blocking mode:"), shout_get_error(m_pShout));
00078         return;
00079     }
00080 }
00081 
00082 /*
00083  * Cleanup EngineShoutcast
00084  */
00085 EngineShoutcast::~EngineShoutcast()
00086 {
00087     QMutexLocker locker(&m_shoutMutex);
00088 
00089     if (m_encoder){
00090         m_encoder->flush();
00091         delete m_encoder;
00092     }
00093 
00094     delete m_pUpdateShoutcastFromPrefs;
00095     delete m_pShoutcastNeedUpdateFromPrefs;
00096     delete m_pMasterSamplerate;
00097 
00098     if (m_pShoutMetaData)
00099         shout_metadata_free(m_pShoutMetaData);
00100     if (m_pShout) {
00101         shout_close(m_pShout);
00102         shout_free(m_pShout);
00103     }
00104     shout_shutdown();
00105 }
00106 
00107 bool EngineShoutcast::serverDisconnect()
00108 {
00109     QMutexLocker locker(&m_shoutMutex);
00110     if (m_encoder){
00111         m_encoder->flush();
00112         delete m_encoder;
00113         m_encoder = NULL;
00114     }
00115 
00116     if (m_pShout) {
00117         shout_close(m_pShout);
00118         return true;
00119     }
00120     return false; //if no connection has been established, nothing can be disconnected
00121 }
00122 
00123 bool EngineShoutcast::isConnected()
00124 {
00125     QMutexLocker locker(&m_shoutMutex);
00126     if (m_pShout) {
00127         m_iShoutStatus = shout_get_connected(m_pShout);
00128         if (m_iShoutStatus == SHOUTERR_CONNECTED)
00129             return true;
00130     }
00131     return false;
00132 }
00133 /*
00134  * Update EngineShoutcast values from the preferences.
00135  */
00136 void EngineShoutcast::updateFromPreferences()
00137 {
00138     QMutexLocker locker(&m_shoutMutex);
00139     qDebug() << "EngineShoutcast: updating from preferences";
00140 
00141     m_pUpdateShoutcastFromPrefs->slotSet(0.0f);
00142 
00143     //Convert a bunch of QStrings to QByteArrays so we can get regular C char* strings to pass to libshout.
00144     QByteArray baHost       = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"host")).toLatin1();
00145     QByteArray baServerType = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"servertype")).toLatin1();
00146     QByteArray baPort       = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"port")).toLatin1();
00147     QByteArray baMountPoint = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"mountpoint")).toLatin1();
00148     QByteArray baLogin      = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"login")).toLatin1();
00149     QByteArray baPassword   = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"password")).toLatin1();
00150     QByteArray baStreamName = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"stream_name")).toLatin1();
00151     QByteArray baStreamWebsite = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"stream_website")).toLatin1();
00152     QByteArray baStreamDesc = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"stream_desc")).toLatin1();
00153     QByteArray baStreamGenre = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"stream_genre")).toLatin1();
00154     QByteArray baStreamPublic = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"stream_public")).toLatin1();
00155     QByteArray baBitrate    = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"bitrate")).toLatin1();
00156 
00157     m_baFormat    = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"format")).toLatin1();
00158 
00159     m_custom_metadata = (bool)m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"enable_metadata")).toInt();
00160     m_baCustom_title = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"custom_title")).toLatin1();
00161     m_baCustom_artist = m_pConfig->getValueString(ConfigKey(SHOUTCAST_PREF_KEY,"custom_artist")).toLatin1();
00162 
00163     int format;
00164     int len;
00165     int protocol;
00166 
00167 
00168     if (shout_set_host(m_pShout, baHost.data()) != SHOUTERR_SUCCESS) {
00169         errorDialog("Error setting hostname!", shout_get_error(m_pShout));
00170         return;
00171     }
00172 
00173     if (shout_set_protocol(m_pShout, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) {
00174         errorDialog("Error setting protocol!", shout_get_error(m_pShout));
00175         return;
00176     }
00177 
00178     if (shout_set_port(m_pShout, baPort.toUInt()) != SHOUTERR_SUCCESS) {
00179         errorDialog("Error setting port!", shout_get_error(m_pShout));
00180         return;
00181     }
00182 
00183     if (shout_set_password(m_pShout, baPassword.data()) != SHOUTERR_SUCCESS) {
00184         errorDialog("Error setting password!", shout_get_error(m_pShout));
00185         return;
00186     }
00187     if (shout_set_mount(m_pShout, baMountPoint.data()) != SHOUTERR_SUCCESS) {
00188         errorDialog("Error setting mount!", shout_get_error(m_pShout));
00189         return;
00190     }
00191 
00192     if (shout_set_user(m_pShout, baLogin.data()) != SHOUTERR_SUCCESS) {
00193         errorDialog("Error setting username!", shout_get_error(m_pShout));
00194         return;
00195     }
00196     if (shout_set_name(m_pShout, baStreamName.data()) != SHOUTERR_SUCCESS) {
00197         errorDialog("Error setting stream name!", shout_get_error(m_pShout));
00198         return;
00199     }
00200     if (shout_set_description(m_pShout, baStreamDesc.data()) != SHOUTERR_SUCCESS) {
00201         errorDialog("Error setting stream description!", shout_get_error(m_pShout));
00202         return;
00203     }
00204     if (shout_set_genre(m_pShout, baStreamGenre.data()) != SHOUTERR_SUCCESS) {
00205           errorDialog("Error setting stream genre!", shout_get_error(m_pShout));
00206         return;
00207     }
00208     if (shout_set_url(m_pShout, baStreamWebsite.data()) != SHOUTERR_SUCCESS) {
00209        errorDialog("Error setting stream url!", shout_get_error(m_pShout));
00210        return;
00211     }
00212 
00213 
00214     if ( !qstrcmp(m_baFormat.data(), "MP3")) {
00215         format = SHOUT_FORMAT_MP3;
00216     }
00217     else if ( !qstrcmp(m_baFormat.data(), "Ogg Vorbis")) {
00218         format = SHOUT_FORMAT_OGG;
00219     }
00220     else {
00221         qDebug() << "Error: unknown format:" << m_baFormat.data();
00222         return;
00223     }
00224 
00225     if (shout_set_format(m_pShout, format) != SHOUTERR_SUCCESS) {
00226         errorDialog("Error setting soutcast format!", shout_get_error(m_pShout));
00227         return;
00228     }
00229 
00230     if ((len = baBitrate.indexOf(' ')) != -1) {
00231         baBitrate.resize(len);
00232     }
00233     int iBitrate = baBitrate.toInt();
00234 
00235     int iMasterSamplerate = m_pMasterSamplerate->get();
00236     if (format == SHOUT_FORMAT_OGG && iMasterSamplerate == 96000) {
00237         errorDialog("Broadcasting at 96kHz with Ogg Vorbis is not currently "
00238                     "supported. Please try a different sample-rate or switch "
00239                     "to a different encoding.",
00240                     "See https://bugs.launchpad.net/mixxx/+bug/686212 for more "
00241                     "information.");
00242         return;
00243     }
00244 
00245     if (shout_set_audio_info(m_pShout, SHOUT_AI_BITRATE, baBitrate.data()) != SHOUTERR_SUCCESS) {
00246         errorDialog("Error setting bitrate", shout_get_error(m_pShout));
00247         return;
00248     }
00249 
00250     if ( ! qstricmp(baServerType.data(), "Icecast 2")) {
00251         protocol = SHOUT_PROTOCOL_HTTP;
00252     } else if ( ! qstricmp(baServerType.data(), "Shoutcast")) {
00253         protocol = SHOUT_PROTOCOL_ICY;
00254     } else if ( ! qstricmp(baServerType.data(), "Icecast 1")) {
00255         protocol = SHOUT_PROTOCOL_XAUDIOCAST;
00256     } else {
00257         errorDialog("Error: unknown server protocol!", shout_get_error(m_pShout));
00258         return;
00259     }
00260 
00261     if (( protocol == SHOUT_PROTOCOL_ICY ) && ( format != SHOUT_FORMAT_MP3)) {
00262         errorDialog("Error: libshout only supports Shoutcast with MP3 format!", shout_get_error(m_pShout));
00263         return;
00264     }
00265 
00266     if (shout_set_protocol(m_pShout, protocol) != SHOUTERR_SUCCESS) {
00267         errorDialog("Error setting protocol!", shout_get_error(m_pShout));
00268         return;
00269     }
00270 
00271     // Initialize m_encoder
00272     if(m_encoder) {
00273         delete m_encoder;        //delete m_encoder if it has been initalized (with maybe) different bitrate
00274     }
00275     if ( ! qstrcmp(m_baFormat, "MP3")) {
00276         m_encoder = new EncoderMp3(this);
00277 
00278     }
00279     else if ( ! qstrcmp(m_baFormat, "Ogg Vorbis")) {
00280         m_encoder = new EncoderVorbis(this);
00281     }
00282     else {
00283         qDebug() << "**** Unknown Encoder Format";
00284         return;
00285     }
00286     if (m_encoder->initEncoder(iBitrate) < 0) {
00287         //e.g., if lame is not found
00288         //init m_encoder itself will display a message box
00289         qDebug() << "**** Encoder init failed";
00290         delete m_encoder;
00291         m_encoder = NULL;
00292     }
00293 
00294 }
00295 
00296 /*
00297  * Reset the Server state and Connect to the Server.
00298  *
00299  */
00300 bool EngineShoutcast::serverConnect()
00301 {
00302     QMutexLocker locker(&m_shoutMutex);
00303     // set to busy in case another thread calls one of the other
00304     // EngineShoutcast calls
00305     m_iShoutStatus = SHOUTERR_BUSY;
00306     // reset the number of failures to zero
00307     m_iShoutFailures = 0;
00308     // set to a high number to automatically update the metadata
00309     // on the first change
00310     m_iMetaDataLife = 31337;
00311     //If static metadata is available, we only need to send metadata one time
00312     m_firstCall = false;
00313 
00314     /*Check if m_encoder is initalized
00315      * Encoder is initalized in updateFromPreferences which is called always before serverConnect()
00316      * If m_encoder is NULL, then we propably want to use MP3 streaming, however, lame could not be found
00317      * It does not make sense to connect
00318      */
00319      if(m_encoder == NULL){
00320         m_pConfig->set(ConfigKey("[Shoutcast]","enabled"),ConfigValue("0"));
00321         return false;
00322     }
00323     const int iMaxTries = 3;
00324     while (!m_bQuit && m_iShoutFailures < iMaxTries) {
00325         if (m_pShout)
00326             shout_close(m_pShout);
00327 
00328         m_iShoutStatus = shout_open(m_pShout);
00329         if (m_iShoutStatus == SHOUTERR_SUCCESS)
00330             m_iShoutStatus = SHOUTERR_CONNECTED;
00331 
00332         if ((m_iShoutStatus == SHOUTERR_BUSY) ||
00333             (m_iShoutStatus == SHOUTERR_CONNECTED) ||
00334             (m_iShoutStatus == SHOUTERR_SUCCESS))
00335             break;
00336 
00337         m_iShoutFailures++;
00338         qDebug() << "Shoutcast failed connect. Failures:" << m_iShoutFailures;
00339         sleep(1);
00340     }
00341     if (m_iShoutFailures == iMaxTries) {
00342         if (m_pShout)
00343             shout_close(m_pShout);
00344         m_pConfig->set(ConfigKey("[Shoutcast]","enabled"),ConfigValue("0"));
00345     }
00346     if (m_bQuit) {
00347         if (m_pShout)
00348             shout_close(m_pShout);
00349         return false;
00350     }
00351 
00352     m_iShoutFailures = 0;
00353     int timeout = 0;
00354     while (m_iShoutStatus == SHOUTERR_BUSY && timeout < TIMEOUT) {
00355         qDebug() << "Connection pending. Sleeping...";
00356         sleep(1);
00357         m_iShoutStatus = shout_get_connected(m_pShout);
00358         ++ timeout;
00359     }
00360     if (m_iShoutStatus == SHOUTERR_CONNECTED) {
00361         qDebug() << "***********Connected to Shoutcast server...";
00362         return true;
00363     }
00364     //otherwise disable shoutcast in preferences
00365     m_pConfig->set(ConfigKey("[Shoutcast]","enabled"),ConfigValue("0"));
00366     if(m_pShout){
00367         shout_close(m_pShout);
00368         //errorDialog(tr("Mixxx could not connect to the server"), tr("Please check your connection to the Internet and verify that your username and password are correct."));
00369     }
00370 
00371     return false;
00372 }
00373 
00374 /*
00375  * Called by the encoder in method 'encodebuffer()' to flush the stream to the server.
00376  */
00377 void EngineShoutcast::write(unsigned char *header, unsigned char *body,
00378                                 int headerLen, int bodyLen)
00379 {
00380     QMutexLocker locker(&m_shoutMutex);
00381     int ret;
00382 
00383     if (!m_pShout)
00384         return;
00385 
00386     if (m_iShoutStatus == SHOUTERR_CONNECTED) {
00387         // Send header if there is one
00388         if ( headerLen > 0 ) {
00389             ret = shout_send(m_pShout, header, headerLen);
00390             if (ret != SHOUTERR_SUCCESS) {
00391                 qDebug() << "DEBUG: Send error: " << shout_get_error(m_pShout);
00392                 if ( m_iShoutFailures > 3 ){
00393                     if(!serverConnect())
00394                         errorDialog(tr("Lost connection to streaming server"), tr("Please check your connection to the Internet and verify that your username and password are correct."));
00395                  }
00396                  else{
00397                     m_iShoutFailures++;
00398                  }
00399 
00400                 return;
00401             } else {
00402                 //qDebug() << "yea I kinda sent header";
00403             }
00404         }
00405 
00406         ret = shout_send(m_pShout, body, bodyLen);
00407         if (ret != SHOUTERR_SUCCESS) {
00408             qDebug() << "DEBUG: Send error: " << shout_get_error(m_pShout);
00409             if ( m_iShoutFailures > 3 ){
00410                     if(!serverConnect())
00411                         errorDialog(tr("Lost connection to streaming server"), tr("Please check your connection to the Internet and verify that your username and password are correct."));
00412              }
00413              else{
00414                 m_iShoutFailures++;
00415              }
00416 
00417             return;
00418         } else {
00419             //qDebug() << "yea I kinda sent footer";
00420         }
00421         if (shout_queuelen(m_pShout) > 0)
00422             printf("DEBUG: queue length: %d\n", (int)shout_queuelen(m_pShout));
00423     } else {
00424         qDebug() << "Error connecting to Shoutcast server:" << shout_get_error(m_pShout);
00425        // errorDialog(tr("Shoutcast aborted connect after 3 tries"), tr("Please check your connection to the Internet and verify that your username and password are correct."));
00426     }
00427 }
00428 
00429 /*
00430  * This is called by the Engine implementation for each sample.
00431  * Encode and send the stream, as well as check for metadata changes.
00432  */
00433 void EngineShoutcast::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize)
00434 {
00435     QMutexLocker locker(&m_shoutMutex);
00436      //Check to see if Shoutcast is enabled, and pass the samples off to be broadcast if necessary.
00437      bool prefEnabled = (m_pConfig->getValueString(ConfigKey("[Shoutcast]","enabled")).toInt() == 1);
00438 
00439     if (prefEnabled) {
00440         if(!isConnected()){
00441             //Initialize the m_pShout structure with the info from Mixxx's m_shoutcast preferences.
00442             updateFromPreferences();
00443 
00444             if(serverConnect()){
00445                 ErrorDialogProperties* props = ErrorDialogHandler::instance()->newDialogProperties();
00446                 props->setType(DLG_INFO);
00447                 props->setTitle(tr("Live broadcasting"));
00448                 props->setText(tr("Mixxx has successfully connected to the shoutcast server"));
00449                 ErrorDialogHandler::instance()->requestErrorDialog(props);
00450             }
00451             else{
00452                 errorDialog(tr("Mixxx could not connect to streaming server"), tr("Please check your connection to the Internet and verify that your username and password are correct."));
00453 
00454             }
00455         }
00456         //send to shoutcast, if connection has been established
00457         if (m_iShoutStatus != SHOUTERR_CONNECTED)
00458             return;
00459 
00460         if (iBufferSize > 0 && m_encoder){
00461             m_encoder->encodeBuffer(pOut, iBufferSize); //encode and send to shoutcast
00462         }
00463         //Check if track has changed and submit its new metadata to shoutcast
00464         if (metaDataHasChanged())
00465             updateMetaData();
00466 
00467         if (m_pUpdateShoutcastFromPrefs->get() > 0.0f){
00468             /*
00469              * You cannot change bitrate, hostname, etc while connected to a stream
00470              */
00471             serverDisconnect();
00472             updateFromPreferences();
00473             serverConnect();
00474         }
00475      }
00476     //if shoutcast is disabled
00477     else{
00478         if(isConnected()){
00479             serverDisconnect();
00480             ErrorDialogProperties* props = ErrorDialogHandler::instance()->newDialogProperties();
00481             props->setType(DLG_INFO);
00482             props->setTitle(tr("Live broadcasting"));
00483             props->setText(tr("Mixxx has successfully disconnected to the shoutcast server"));
00484 
00485             ErrorDialogHandler::instance()->requestErrorDialog(props);
00486         }
00487     }
00488 }
00489 
00490 /*
00491  * Check if the metadata has changed since the previous check.
00492  * We also check when was the last check performed to avoid using
00493  * too much CPU and as well to avoid changing the metadata during
00494  * scratches.
00495  */
00496 bool EngineShoutcast::metaDataHasChanged()
00497 {
00498     QMutexLocker locker(&m_shoutMutex);
00499     TrackPointer pTrack;
00500 
00501 
00502     if ( m_iMetaDataLife < 16 ) {
00503         m_iMetaDataLife++;
00504         return false;
00505     }
00506 
00507     m_iMetaDataLife = 0;
00508 
00509 
00510     pTrack = PlayerInfo::Instance().getCurrentPlayingTrack();
00511     if ( !pTrack )
00512         return false;
00513 
00514     if ( m_pMetaData ) {
00515         if ((pTrack->getId() == -1) || (m_pMetaData->getId() == -1)) {
00516             if ((pTrack->getArtist() == m_pMetaData->getArtist()) &&
00517                 (pTrack->getTitle() == m_pMetaData->getArtist())) {
00518                 return false;
00519             }
00520         }
00521         else if (pTrack->getId() == m_pMetaData->getId()) {
00522             return false;
00523         }
00524     }
00525 
00526     m_pMetaData = pTrack;
00527     return true;
00528 }
00529 
00530 /*
00531  * Update shoutcast metadata.
00532  * This does not work for OGG/Vorbis and Icecast, since the actual
00533  * OGG/Vorbis stream contains the metadata.
00534  */
00535 void EngineShoutcast::updateMetaData()
00536 {
00537     QMutexLocker locker(&m_shoutMutex);
00538     if (!m_pShout || !m_pShoutMetaData)
00539         return;
00540 
00541     QByteArray baSong = "";
00556     //If we use MP3 streaming and want dynamic metadata changes
00557     if(!m_custom_metadata && !qstrcmp(m_baFormat, "MP3")){
00558         if (m_pMetaData != NULL) {
00559             // convert QStrings to char*s
00560             QByteArray baArtist = m_pMetaData->getArtist().toLatin1();
00561             QByteArray baTitle = m_pMetaData->getTitle().toLatin1();
00562 
00563             if (baArtist.isEmpty())
00564                 baSong = baTitle;
00565             else
00566                 baSong = baArtist + " - " + baTitle;
00567 
00569             shout_metadata_add(m_pShoutMetaData, "song",  baSong.data());
00570                 shout_set_metadata(m_pShout, m_pShoutMetaData);
00571         }
00572     }
00573     //Otherwise we might use static metadata
00574     else{
00576         if(m_custom_metadata && !m_firstCall){
00577             baSong = m_baCustom_artist + " - " + m_baCustom_title;
00579             shout_metadata_add(m_pShoutMetaData, "song",  baSong.data());
00580                 shout_set_metadata(m_pShout, m_pShoutMetaData);
00581             m_firstCall = true;
00582         }
00583     }
00584 }
00585 /* -------- ------------------------------------------------------
00586 Purpose: Common error dialog creation code for run-time exceptions
00587          Notify user when connected or disconnected and so on
00588 Input:   Detailed error string
00589 Output:  -
00590 -------- ------------------------------------------------------ */
00591 void EngineShoutcast::errorDialog(QString text, QString detailedError) {
00592     qWarning() << "Shoutcast error: " << detailedError;
00593     ErrorDialogProperties* props = ErrorDialogHandler::instance()->newDialogProperties();
00594     props->setType(DLG_WARNING);
00595     props->setTitle(tr("Live broadcasting"));
00596     props->setText(text);
00597     props->setDetails(detailedError);
00598     props->setKey(detailedError);   // To prevent multiple windows for the same error
00599     props->setDefaultButton(QMessageBox::Close);
00600 
00601     props->setModal(false);
00602 
00603     ErrorDialogHandler::instance()->requestErrorDialog(props);
00604 }
00605 
00606 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines