/* Execute the given command. In fact, it just will ask MPD to do it.
 * You will have to check the next "status" or "playlist" update (using the corresponding slot)
 * to know if the command has really been executed.
 */
void Player::executeCmd(EMSPlayerCmd cmd)
{
    bool waitResponse = true; /* Wait the responase by default */
    bool error = false;

    if (conn == NULL)
    {
        return;
    }

    /* Dispatch execution depending on the action */
    switch (cmd.action)
    {
        case ACTION_ADD:
        {
            if(searchTrackInPlaylist(cmd.track) >= 0)
            {
                qDebug() << "Do not add track in the playlist as it already exist";
                return;
            }
            QString filename = getMPDFilename(cmd.track);
            mpd_send_add(conn, filename.toStdString().c_str());
            break;
        }
        case ACTION_DEL:
        {
            int pos = searchTrackInPlaylist(cmd.track);
            if (pos >= 0)
            {
                mpd_send_delete(conn, pos);
            }
            break;
        }
        case ACTION_DEL_ALL:
        {
            mpd_send_clear(conn);
            break;
        }
        case ACTION_PLAY_POS:
        {
            mutex.lock();
            int size = playlist.tracks.size();
            mutex.unlock();
            if (size <= 0 || cmd.uintValue >= (unsigned int)size)
            {
                qDebug() << "Asked to play a track after the end of the current playlist";
                error = true;
                break;
            }
            mpd_send_play_pos(conn, cmd.uintValue);
            break;
        }
        case ACTION_PLAY_TRACK:
        {
            int position = searchTrackInPlaylist(cmd.track);
            if (position < 0)
            {
                qDebug() << "Asked to play a track which is not in the current playlist";
                error = true;
                break;
            }
            mpd_send_play_pos(conn, position);
            break;
        }
        case ACTION_PLAY:
        {
            mpd_send_play(conn);
            break;
        }
        case ACTION_SEEK:
        {
            /* Get current position */
            int songId = getCurrentPos();
            if (songId >= 0)
            {
                mpd_send_seek_pos(conn, songId, cmd.uintValue);
            }
            break;
        }
        case ACTION_PAUSE:
        {
            mpd_send_pause(conn, true);
            break;
        }
        case ACTION_TOGGLE:
        {
            mpd_send_toggle_pause(conn);
            break;
        }
        case ACTION_STOP:
        {
            mpd_send_stop(conn);
            break;
        }
        case ACTION_NEXT:
        {
            mpd_send_next(conn);
            break;
        }
        case ACTION_PREV:
        {
            mpd_send_previous(conn);
            break;
        }
        case ACTION_REPEAT:
        {
            mutex.lock();
            bool repeatTmp = status.repeat;
            mutex.unlock();
            if (cmd.boolValue != repeatTmp)
            {
                mpd_send_repeat(conn, cmd.boolValue);
            }
            break;
        }
        case ACTION_RANDOM:
        {
            mutex.lock();
            bool randomTmp = status.random;
            mutex.unlock();
            if (cmd.boolValue != randomTmp)
            {
                mpd_send_random(conn, cmd.boolValue);
            }
            break;
        }
        case ACTION_ENABLE_OUTPUT:
        {
            if (cmd.uintValue >= 1)
            {
                mpd_send_enable_output(conn, cmd.uintValue-1);
            }
            break;
        }
        case ACTION_DISABLE_OUTPUT:
        {
            if (cmd.uintValue >= 1)
            {
                mpd_send_disable_output(conn, cmd.uintValue-1);
            }
            break;
        }
        default:
        {
            qCritical() << "Unhandled action in the current command.";
            waitResponse = false;
            break;
        }
    }

    if (waitResponse && !mpd_response_finish(conn))
    {
        error = true;
        qCritical() << "MPD could not execute the current command.";
        enum mpd_error errorMpd = mpd_connection_get_error(conn);
        if (errorMpd == MPD_ERROR_SERVER ||
            errorMpd == MPD_ERROR_ARGUMENT) /* Problem with the command */
        {
            QString errorMessage = QString::fromUtf8(mpd_connection_get_error_message(conn));
            qCritical() << "Command error : " << errorMessage;
            if (!mpd_connection_clear_error(conn))
            {
                qCritical() << "This error cannot be cleared, reconnecting...";
                connectToMpd();
            }

        }
        else if (errorMpd == MPD_ERROR_TIMEOUT ||
                 errorMpd == MPD_ERROR_RESOLVER ||
                 errorMpd == MPD_ERROR_MALFORMED ||
                 errorMpd == MPD_ERROR_CLOSED ) /* Assume there is a connection problem, try to reconnect... */
        {
            QString errorMessage = QString::fromUtf8(mpd_connection_get_error_message(conn));
            qCritical() << "Connexion error : " << errorMessage;
            qCritical() << "Reconnecting...";
            connectToMpd();
            mutex.lock();
            queue.push_front(cmd);
            mutex.unlock();
            cmdAvailable.release(1);
        }
    }

    /* Post-action depending on the command
     * Do the minimum here as the whole status will be
     * retrieve here. But for playlist ADD/DEL, we need to
     * store the EMSTrack structure.
     */
    if(!error)
    {
        switch (cmd.action)
        {
            case ACTION_ADD:
            {
                EMSPlaylist newPlaylist;
                mutex.lock();
                playlist.tracks.append(cmd.track);
                newPlaylist = playlist;
                mutex.unlock();
                emit playlistChanged(newPlaylist);
                break;
            }
            case ACTION_DEL:
            {
                int pos = searchTrackInPlaylist(cmd.track);
                if (pos >= 0)
                {
                    EMSPlaylist newPlaylist;
                    mutex.lock();
                    playlist.tracks.removeAt(pos);
                    newPlaylist = playlist;
                    mutex.unlock();
                    emit playlistChanged(newPlaylist);
                }
                break;
            }
            case ACTION_DEL_ALL:
            {
                EMSPlaylist newPlaylist;
                mutex.lock();
                playlist.tracks.clear();
                newPlaylist = playlist;
                mutex.unlock();
                emit playlistChanged(newPlaylist);
                break;
            }
            case ACTION_ENABLE_OUTPUT:
            {
                mutex.lock();
                for(int i=0; i<outputs.size(); i++)
                {
                    if (outputs.at(i).id_mpd == cmd.uintValue)
                    {
                        EMSSndCard card = outputs.at(i);
                        card.enabled = true;
                        outputs.replace(i, card);
                    }
                }
                emit outputsChanged(outputs);
                mutex.unlock();
                break;
            }
            case ACTION_DISABLE_OUTPUT:
            {
                mutex.lock();
                for(int i=0; i<outputs.size(); i++)
                {
                    if (outputs.at(i).id_mpd == cmd.uintValue)
                    {
                        EMSSndCard card = outputs.at(i);
                        card.enabled = false;
                        outputs.replace(i, card);
                    }
                }
                emit outputsChanged(outputs);
                mutex.unlock();
                break;
            }
            default:
                break;
        }
    }
}
Example #2
0
bool
mpd_run_previous(struct mpd_connection *connection)
{
	return mpd_run_check(connection) && mpd_send_previous(connection) &&
		mpd_response_finish(connection);
}