/*
Neutrino-GUI - DBoxII-Project - AudioPlayer by Dirch, Zwen
Copyright (C) 2001 Steffen Hehn 'McClean'
Copyright (C) 2002-2008 the tuxbox project contributors
Copyright (C) 2008 Novell, Inc. Author: Stefan Seyfried
Copyright (C) 2011-2013,2015,2017 Stefan Seyfried
Copyright (C) 2017 Sven Hoefer
License: GPL
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef ENABLE_GUI_MOUNT
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "gui/pictureviewer.h"
extern CPictureViewer * g_PicViewer;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if LIBCURL_VERSION_NUM < 0x071507
#include
#endif
#include
#include
extern cVideo * videoDecoder;
#define AUDIOPLAYERGUI_SMSKEY_TIMEOUT 1000
#define SHOW_FILE_LOAD_LIMIT 50
#define AUDIOPLAYER_TIME_DEBUG
// check if files to be added are already in the playlist
#define AUDIOPLAYER_CHECK_FOR_DUPLICATES
#define AUDIOPLAYER_START_SCRIPT "audioplayer.start"
#define AUDIOPLAYER_END_SCRIPT "audioplayer.end"
#define DEFAULT_RADIOSTATIONS_XMLFILE CONFIGDIR "/radio-stations.xml"
#define DEFAULT_RADIOFAVORITES_XMLFILE CONFIGDIR "/radio-favorites.xml"
const char RADIO_STATION_XML_FILE[] = {DEFAULT_RADIOSTATIONS_XMLFILE};
const char RADIO_FAVORITES_XML_FILE[] = {DEFAULT_RADIOFAVORITES_XMLFILE};
CAudiofileExt::CAudiofileExt() : CAudiofile(), firstChar('\0')
{
}
CAudiofileExt::CAudiofileExt(std::string name, CFile::FileType type) : CAudiofile(name, type), firstChar('\0')
{
}
CAudiofileExt::CAudiofileExt(const CAudiofileExt& src) : CAudiofile(src), firstChar(src.firstChar)
{
}
void CAudiofileExt::operator=(const CAudiofileExt& src)
{
if (&src == this)
return;
CAudiofile::operator=(src);
firstChar = src.firstChar;
}
CAudioPlayerGui::CAudioPlayerGui(bool inetmode)
{
m_frameBuffer = CFrameBuffer::getInstance();
m_visible = false;
m_inetmode = inetmode;
m_detailsline = NULL;
m_infobox = NULL;
m_titlebox = NULL;
Init();
}
void CAudioPlayerGui::Init(void)
{
m_selected = 0;
m_metainfo.clear();
pictureviewer = false;
m_select_title_by_name = g_settings.audioplayer_select_title_by_name==1;
if (!g_settings.network_nfs_audioplayerdir.empty())
m_Path = g_settings.network_nfs_audioplayerdir.c_str();
else
m_Path = "/";
audiofilefilter.Clear();
if (m_inetmode)
{
audiofilefilter.addFilter("url");
audiofilefilter.addFilter("xml");
audiofilefilter.addFilter("m3u");
audiofilefilter.addFilter("pls");
}
else
{
audiofilefilter.addFilter("cdr");
audiofilefilter.addFilter("mp3");
audiofilefilter.addFilter("m2a");
audiofilefilter.addFilter("mpa");
audiofilefilter.addFilter("mp2");
audiofilefilter.addFilter("m3u");
audiofilefilter.addFilter("ogg");
audiofilefilter.addFilter("wav");
audiofilefilter.addFilter("flac");
audiofilefilter.addFilter("flv");
#ifdef ENABLE_FFMPEGDEC
audiofilefilter.addFilter("aac");
audiofilefilter.addFilter("dts");
audiofilefilter.addFilter("m4a");
#endif
}
m_SMSKeyInput.setTimeout(AUDIOPLAYERGUI_SMSKEY_TIMEOUT);
}
CAudioPlayerGui::~CAudioPlayerGui()
{
m_playlist.clear();
m_radiolist.clear();
m_filelist.clear();
m_title2Pos.clear();
delete m_detailsline;
delete m_infobox;
delete m_titlebox;
}
/*const*/ struct button_label AudioPlayerButtons[][4] =
{
{
{ NEUTRINO_ICON_BUTTON_STOP , LOCALE_AUDIOPLAYER_STOP },
{ NEUTRINO_ICON_BUTTON_BACKWARD , LOCALE_AUDIOPLAYER_REWIND },
{ NEUTRINO_ICON_BUTTON_PAUSE , LOCALE_AUDIOPLAYER_PAUSE },
{ NEUTRINO_ICON_BUTTON_FORWARD , LOCALE_AUDIOPLAYER_FASTFORWARD },
},
{
{ NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE },
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD },
{ NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_DELETEALL },
{ NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_SHUFFLE },
},
{
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS },
{ NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS },
},
{
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS },
{ NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS },
},
{
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST },
{ NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_ID },
},
{
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST },
{ NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_NAME},
},
{
{ NEUTRINO_ICON_BUTTON_STOP , LOCALE_AUDIOPLAYER_STOP },
{ NEUTRINO_ICON_BUTTON_PAUSE , LOCALE_AUDIOPLAYER_PAUSE },
{ NEUTRINO_ICON_BUTTON_RECORD_ACTIVE, LOCALE_AUDIOPLAYER_STREAMRIPPER_START },
},
{
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD },
{ NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME },
},
{
{ NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE },
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD },
{ NEUTRINO_ICON_BUTTON_YELLOW , LOCALE_AUDIOPLAYER_DELETEALL },
{ NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME },
},
};
int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &actionKey)
{
if (actionKey == "init")
Init();
CNeutrinoApp::getInstance()->StopSubtitles();
CAudioPlayer::getInstance()->init();
m_state = CAudioPlayerGui::STOP;
m_show_playlist = g_settings.audioplayer_show_playlist==1;
if (m_select_title_by_name != (g_settings.audioplayer_select_title_by_name==1))
{
if ((g_settings.audioplayer_select_title_by_name == 1) && m_playlistHasChanged)
{
buildSearchTree();
}
m_select_title_by_name = g_settings.audioplayer_select_title_by_name;
}
//auto-load favorites
if ((m_inetmode) && (m_playlist.empty()))
{
if (access(RADIO_FAVORITES_XML_FILE, F_OK) == 0)
scanXmlFile(RADIO_FAVORITES_XML_FILE);
}
if (m_playlist.empty())
m_current = -1;
else
m_current = 0;
m_selected = 0;
m_width = m_frameBuffer->getWindowWidth();
m_height = m_frameBuffer->getWindowHeight();
m_header_height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight();
m_item_height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight();
m_meta_height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight();
m_title_height = 3*OFFSET_INNER_SMALL + 2*m_item_height + m_meta_height;
m_cover_width = 0;
m_info_height = 2*OFFSET_INNER_SMALL + 2*g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight();
m_button_height = ::paintButtons(AudioPlayerButtons[0], 4, 0, 0, 0, 0, 0, false, NULL, NULL);
m_listmaxshow = (m_height - m_title_height - OFFSET_SHADOW - OFFSET_INTER - m_header_height - 2*m_button_height - OFFSET_SHADOW - OFFSET_INTER - m_info_height - OFFSET_SHADOW) / (m_item_height);
m_height = m_title_height + OFFSET_SHADOW + OFFSET_INTER + m_header_height + m_listmaxshow*m_item_height + 2*m_button_height + OFFSET_SHADOW + OFFSET_INTER + m_info_height + OFFSET_SHADOW; // recalc height
m_x = getScreenStartX(m_width);
if (m_x < DETAILSLINE_WIDTH)
m_x = DETAILSLINE_WIDTH;
m_y = getScreenStartY(m_height);
m_cover.clear();
m_stationlogo = false;
m_streamripper_available = !find_executable("streamripper").empty() && !find_executable("streamripper.sh").empty();
m_streamripper_active = false;
if (parent)
parent->hide();
bool usedBackground = m_frameBuffer->getuseBackground();
if (usedBackground)
m_frameBuffer->saveBackgroundImage();
// set zapit in lock mode
CNeutrinoApp::getInstance()->stopPlayBack(true);
m_frameBuffer->showFrame("mp3.jpg");
// tell neutrino we're in audio mode
m_LastMode = CNeutrinoApp::getInstance()->getMode();
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , NeutrinoModes::mode_audio);
// wake up hdd
printf("[audioplayer.cpp] wakeup_hdd(%s)\n", g_settings.network_nfs_audioplayerdir.c_str());
wakeup_hdd(g_settings.network_nfs_audioplayerdir.c_str()/*,true*/);
exec_controlscript(AUDIOPLAYER_START_SCRIPT);
int res = show();
// Restore previous background
if (usedBackground)
m_frameBuffer->restoreBackgroundImage();
m_frameBuffer->useBackground(usedBackground);
m_frameBuffer->paintBackground();
exec_controlscript(AUDIOPLAYER_END_SCRIPT);
//g_Zapit->unlockPlayBack();
CZapit::getInstance()->EnablePlayback(true);
m_frameBuffer->stopFrame();
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , m_LastMode);
g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0);
CNeutrinoApp::getInstance()->StartSubtitles();
return res;
}
int CAudioPlayerGui::show()
{
neutrino_msg_t msg;
neutrino_msg_data_t data;
int ret = menu_return::RETURN_REPAINT;
// clear whole screen
m_frameBuffer->paintBackground();
CInfoClock::getInstance()->block();
CScreenSaver::getInstance()->OnAfterStop.connect(sigc::mem_fun(CInfoClock::getInstance(), &CInfoClock::block));
CScreenSaver::getInstance()->resetIdleTime();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
bool loop = true;
bool update = true;
bool clear_before_update = false;
m_key_level = 0;
// auto-play first entry from favorites
if (g_settings.inetradio_autostart)
{
if ((m_inetmode) && (!m_playlist.empty()))
{
m_current = 0;
m_selected = 0;
play(m_selected);
}
}
while (loop)
{
if (msg <= CRCInput::RC_MaxRC)
CScreenSaver::getInstance()->resetIdleTime();
updateMetaData();
updateTimes();
// stop if mode was changed in another thread
if (CNeutrinoApp::getInstance()->getMode() != NeutrinoModes::mode_audio)
loop = false;
if (
(m_state != CAudioPlayerGui::STOP) &&
(CAudioPlayer::getInstance()->getState() == CBaseDec::STOP) &&
(!m_playlist.empty())
)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
playNext();
}
if (m_streamripper_active && !getpidof("streamripper"))
{
printf("streamripper should but doesn't work.\n");
m_streamripper_active = false;
update = true;
}
if (update)
{
if (clear_before_update)
{
hide();
clear_before_update = false;
}
update = false;
paint();
}
g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display
if (msg == CRCInput::RC_playpause)
{
// manipulate msg
if (m_state == CAudioPlayerGui::PAUSE)
msg = CRCInput::RC_play;
else
msg = CRCInput::RC_pause;
}
if (msg == CRCInput::RC_timeout || msg == NeutrinoMessages::EVT_TIMER)
{
if (CScreenSaver::getInstance()->canStart() && !CScreenSaver::getInstance()->isActive())
{
CScreenSaver::getInstance()->Start();
}
}
else if (!CScreenSaver::getInstance()->ignoredMsg(msg))
{
if (CScreenSaver::getInstance()->isActive())
{
printf("[audioplayer.cpp] CScreenSaver stop; msg: %lX\n", msg);
CScreenSaver::getInstance()->Stop();
m_frameBuffer->stopFrame();
m_frameBuffer->showFrame("mp3.jpg");
paint();
if (msg <= CRCInput::RC_MaxRC)
{
// ignore first keypress - just quit the screensaver
g_RCInput->clearRCMsg();
continue;
}
}
}
if (msg == CRCInput::RC_home)
{
if (m_state == CAudioPlayerGui::STOP)
loop=false;
}
else if (msg == CRCInput::RC_stop)
{
if (m_state != CAudioPlayerGui::STOP)
stop();
}
//add key_favorites for internetradio
else if ((msg == (neutrino_msg_t) g_settings.key_favorites) && (m_inetmode))
{
if (m_key_level == 0)
{
// clear playlist and load RADIO_FAVORITES_XML_FILE
if (access(RADIO_FAVORITES_XML_FILE, F_OK) == 0)
{
if (!m_playlist.empty())
clearPlaylist();
scanXmlFile(RADIO_FAVORITES_XML_FILE);
clear_before_update = true;
update = true;
}
}
}
else if (msg == CRCInput::RC_left || msg == CRCInput::RC_previoussong)
{
if (m_key_level == 1)
{
playPrev();
}
else
{
if (!m_show_playlist)
{
m_current--;
if (m_current < 0)
m_current = m_playlist.size()-1;
update = true;
}
else if (!m_playlist.empty())
{
if (m_selected < m_listmaxshow)
m_selected = m_playlist.size()-1;
else
m_selected -= m_listmaxshow;
m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow;
update = true;
}
}
}
else if (msg == CRCInput::RC_right || msg == CRCInput::RC_nextsong)
{
if (m_key_level == 1)
{
playNext();
}
else
{
if (!m_show_playlist)
{
m_current++;
if (m_current >= (int)m_playlist.size())
m_current = 0;
update = true;
}
else if (!m_playlist.empty())
{
m_selected += m_listmaxshow;
if (m_selected >= m_playlist.size())
{
if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow)
m_selected = 0;
else
m_selected = m_selected < (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow) ? (m_playlist.size()-1) : 0;
}
m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow;
update = true;
}
}
}
else if ((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_up || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_up)
{
if (m_show_playlist && !m_playlist.empty())
{
int prevselected = m_selected;
int step = msg == CRCInput::RC_page_up ? m_listmaxshow : 1;
m_selected -= step;
if ((prevselected-step) < 0)
m_selected = m_playlist.size()-1;
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow;
if (oldliststart != m_liststart)
{
update = true;
}
else
{
paintItem(prevselected - m_liststart);
paintItem(m_selected - m_liststart);
}
}
}
else if ((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_down || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_down)
{
if (m_show_playlist && !m_playlist.empty())
{
int prevselected = m_selected;
unsigned int step = msg == CRCInput::RC_page_down ? m_listmaxshow : 1;
m_selected += step;
if (m_selected >= m_playlist.size())
{
if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow) // last page has full entries
m_selected = 0;
else
m_selected = ((step == m_listmaxshow) && (m_selected < (((m_playlist.size() / m_listmaxshow)+1) * m_listmaxshow))) ? (m_playlist.size() - 1) : 0;
}
//m_selected = (m_selected + 1) % m_playlist.size();
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow;
if (oldliststart != m_liststart)
{
update = true;
}
else
{
paintItem(prevselected - m_liststart);
paintItem(m_selected - m_liststart);
}
}
}
else if (msg == CRCInput::RC_ok || msg == CRCInput::RC_play)
{
if (!m_playlist.empty())
{
if (!m_show_playlist)
play(m_current);
else
play(m_selected);
}
}
else if (msg == CRCInput::RC_red)
{
if (m_key_level == 0)
{
if (!m_playlist.empty())
{
removeFromPlaylist(m_selected);
if ((int)m_selected == m_current)
m_current--;
if (m_selected >= m_playlist.size())
m_selected = m_playlist.empty() ? m_playlist.size() : m_playlist.size() - 1;
update = true;
}
}
else if (m_key_level == 1)
{
stop();
}
else
{
// key_level==2
}
}
else if (msg == CRCInput::RC_stop)
{
if (m_key_level == 1)
stop();
}
else if ((msg == CRCInput::RC_rewind) || (msg == CRCInput::RC_green))
{
if (m_key_level == 0)
{
openFilebrowser();
update=true;
}
else if (m_key_level == 1)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
rev();
}
else
{ // key_level == 2
if (m_state == CAudioPlayerGui::STOP)
{
if (!m_playlist.empty())
{
savePlaylist();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
update = true;
}
}
else
{
// keylevel 2 can only be reached if the currently played file
// is no stream, so we do not have to test for this case
int seconds=0;
CIntInput secondsInput( LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE,
&seconds,
5,
LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1,
LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2);
int res = secondsInput.exec(NULL,"");
if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL)
rev(seconds);
update=true;
}
}
}
else if ((msg == CRCInput::RC_pause) || (msg == CRCInput::RC_yellow))
{
if (m_key_level == 0)
{
if (!m_playlist.empty())
{
//stop();
clearPlaylist();
clear_before_update = true;
update = true;
}
}
else if (m_key_level == 1)
{
pause();
}
else
{ // key_level==2
m_select_title_by_name =! m_select_title_by_name;
if (m_select_title_by_name && m_playlistHasChanged)
buildSearchTree();
paint();
}
}
else if ((msg == CRCInput::RC_forward) || (msg == CRCInput::RC_blue))
{
if (m_key_level == 0)
{
if (m_inetmode)
{
static int old_select = 0;
char cnt[5];
CMenuWidget InputSelector(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS, NEUTRINO_ICON_AUDIO);
int count = 0;
int select = -1;
CMenuSelectorTarget *InetRadioInputChanger = new CMenuSelectorTarget(&select);
// -- setup menue for inetradio input
sprintf(cnt, "%d", count);
InputSelector.addItem(new CMenuForwarder(
LOCALE_AUDIOPLAYER_ADD_FAV, true, NULL, InetRadioInputChanger,
cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count);
sprintf(cnt, "%d", ++count);
InputSelector.addItem(new CMenuForwarder(
LOCALE_AUDIOPLAYER_ADD_LOC, true, NULL, InetRadioInputChanger,
cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count);
sprintf(cnt, "%d", ++count);
InputSelector.addItem(new CMenuForwarder(
LOCALE_AUDIOPLAYER_ADD_IC, true, NULL, InetRadioInputChanger,
cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count);
sprintf(cnt, "%d", ++count);
InputSelector.addItem(new CMenuForwarder(
LOCALE_AUDIOPLAYER_ADD_SC, g_settings.shoutcast_enabled, NULL, InetRadioInputChanger,
cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count);
//InputSelector.addItem(GenericMenuSeparator);
hide();
InputSelector.exec(NULL, "");
delete InetRadioInputChanger;
if (!m_playlist.empty())
clearPlaylist();
if (select >= 0)
old_select = select;
switch (select)
{
case 0:
scanXmlFile(RADIO_FAVORITES_XML_FILE);
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
break;
case 1:
scanXmlFile(RADIO_STATION_XML_FILE);
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
break;
case 2:
readDir_ic();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
break;
case 3:
openSCbrowser();
break;
default:
break;
}
m_current = 0;
m_selected = 0;
update=true;
}
else if (shufflePlaylist())
{
update = true;
}
}
else if (m_key_level == 1)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
ff();
}
else // key_level == 2
{
if (m_state != CAudioPlayerGui::STOP)
{
// keylevel 2 can only be reached if the currently played file
// is no stream, so we do not have to test for this case
int seconds=0;
CIntInput secondsInput( LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE,
&seconds,
5,
LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1,
LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2);
int res = secondsInput.exec(NULL,"");
if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL)
ff(seconds);
update = true;
}
}
}
#if 0
// FIXME; this seems totally broken
else if (msg == CRCInput::RC_info && !m_playlist.empty())
{
pictureviewer = true;
m_frameBuffer->Clear();
m_frameBuffer->stopFrame();
CPictureViewerGui * picture = new CPictureViewerGui();
picture->m_audioPlayer = this;
picture->exec(this, "audio");
delete picture;
pictureviewer = false;
CScreenSaver::getInstance()->resetIdleTime();
videoDecoder->setBlank(true);
m_frameBuffer->showFrame("mp3.jpg");
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
update = true;
}
#endif
else if (msg == CRCInput::RC_help)
{
if (m_key_level == 2)
m_key_level = 0;
else
m_key_level++;
if (m_state != CAudioPlayerGui::STOP)
{
// jumping in streams not supported
if (m_key_level == 2 && m_curr_audiofile.FileType == CFile::STREAM_AUDIO)
{
m_key_level = 0;
}
}
// there are only two keylevels in the "STOP"-case
else if (m_key_level == 1)
{
m_key_level = 2;
}
paintFoot();
}
else if (msg == CRCInput::RC_0)
{
if (m_current >= 0)
{
m_selected = m_current;
update = true;
}
}
else if (msg == (neutrino_msg_t) g_settings.key_record)
{
if (m_key_level == 1)
{
if (m_curr_audiofile.FileType == CFile::STREAM_AUDIO && m_streamripper_available)
{
if (m_streamripper_active)
{
ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP, HINTBOX_MIN_WIDTH, 2);
my_system(2, "streamripper.sh", "stop");
m_streamripper_active = false;
}
else
{
ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_START, HINTBOX_MIN_WIDTH, 2);
printf("streamripper.sh start \"%s\"\n", m_playlist[m_current].MetaData.url.c_str());
puts("[audioplayer.cpp] executing streamripper");
if (my_system(3, "streamripper.sh", "start", m_playlist[m_current].MetaData.url.c_str()) != 0)
perror("[audioplayer.cpp]: streamripper.sh failed\n");
else
m_streamripper_active = true;
}
update = true;
}
}
}
else if (CRCInput::isNumeric(msg) && !(m_playlist.empty()))
{ //numeric zap or SMS zap
if (m_select_title_by_name)
{
//printf("select by name\n");
unsigned char smsKey = 0;
int w = 0;
do
{
//FIXME - remove fixed values
smsKey = m_SMSKeyInput.handleMsg(msg);
//printf(" new key: %c", smsKey);
/* show a hint box with current char (too slow at the moment?)*/
char selectedKey[2];
sprintf(selectedKey,"%c",smsKey);
int x1=(g_settings.screen_EndX- g_settings.screen_StartX)/2 + g_settings.screen_StartX-50;
int y1=(g_settings.screen_EndY- g_settings.screen_StartY)/2 + g_settings.screen_StartY;
int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight();
w = std::max(w, g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(selectedKey));
m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_FRAME_PLUS_0, RADIUS_SMALL);
m_frameBuffer->paintBoxRel(x1 - 6, y1 - h - 4, w + 12, h + 8, COL_MENUCONTENTSELECTED_PLUS_0, RADIUS_SMALL);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1,y1,w+1,selectedKey,COL_MENUCONTENTSELECTED_TEXT);
g_RCInput->getMsg_ms(&msg, &data, AUDIOPLAYERGUI_SMSKEY_TIMEOUT - 200);
} while (CRCInput::isNumeric(msg) && !(m_playlist.empty()));
if (msg == CRCInput::RC_timeout || msg == CRCInput::RC_nokey)
{
//printf("selected key: %c\n",smsKey);
selectTitle(smsKey);
}
update = true;
m_SMSKeyInput.resetOldKey();
}
else
{
//printf("numeric zap\n");
int val = 0;
if (getNumericInput(msg,val))
m_selected = std::min((int)m_playlist.size(), val) - 1;
update = true;
}
}
#ifdef ENABLE_GUI_MOUNT
else if ((msg == CRCInput::RC_setup) && !m_inetmode)
{
CNFSSmallMenu nfsMenu;
nfsMenu.exec(this, "");
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
update = true;
}
#endif
else if (msg == NeutrinoMessages::CHANGEMODE)
{
if ((data & NeutrinoModes::mode_mask) != NeutrinoModes::mode_audio)
{
loop = false;
m_LastMode=data;
}
}
else if (
msg == NeutrinoMessages::RECORD_START ||
msg == NeutrinoMessages::ZAPTO ||
msg == NeutrinoMessages::STANDBY_ON ||
msg == NeutrinoMessages::LEAVE_ALL ||
msg == NeutrinoMessages::SHUTDOWN ||
(msg == NeutrinoMessages::SLEEPTIMER && !data)
)
{
if (msg != NeutrinoMessages::RECORD_START)
ret = menu_return::RETURN_EXIT_ALL;
// Exit for Record/Zapto Timers
loop = false;
g_RCInput->postMsg(msg, data);
}
else if (msg == NeutrinoMessages::EVT_TIMER)
{
CNeutrinoApp::getInstance()->handleMsg(msg, data);
}
else
{
if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all)
{
ret = menu_return::RETURN_EXIT_ALL;
loop = false;
}
//paintLCD();
}
}
hide();
if (m_state != CAudioPlayerGui::STOP)
stop();
CInfoClock::getInstance()->enableInfoClock(CInfoClock::getInstance()->isRun());
CScreenSaver::getInstance()->OnAfterStop.clear();
return ret;
}
bool CAudioPlayerGui::playNext(bool allow_rotate)
{
bool result = false;
if (!(m_playlist.empty()))
{
int next = getNext();
if (next >= 0)
play(next);
else if (allow_rotate)
play(0);
else
stop();
result = true;
}
return(result);
}
void CAudioPlayerGui::wantNextPlay()
{
if (
(m_state != CAudioPlayerGui::STOP) &&
(CAudioPlayer::getInstance()->getState() == CBaseDec::STOP) &&
(!m_playlist.empty())
)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
playNext();
}
}
bool CAudioPlayerGui::playPrev(bool allow_rotate)
{
bool result = false;
if (!(m_playlist.empty()))
{
if (m_current == -1)
stop();
else if (m_current-1 > 0)
play(m_current-1);
else if (allow_rotate)
play(m_playlist.size()-1);
else
play(0);
result = true;
}
return(result);
}
bool CAudioPlayerGui::clearPlaylist(void)
{
bool result = false;
CAudioPlayList::const_iterator it;
#if 0
for (it = m_playlist.begin(); it!=m_playlist.end(); ++it) {
unlink(it->MetaData.cover.c_str());
}
#endif
if (!(m_playlist.empty()))
{
m_playlist.clear();
m_current = -1;
m_selected = 0;
m_title2Pos.clear();
result = true;
}
return(result);
}
bool CAudioPlayerGui::shufflePlaylist(void)
{
RandomNumber rnd;
bool result = false;
if (!(m_playlist.empty()))
{
if (m_current > 0)
{
std::swap(m_playlist[0], m_playlist[m_current]);
m_current = 0;
}
std::random_shuffle((m_current != 0) ? m_playlist.begin() : m_playlist.begin() + 1, m_playlist.end(), rnd);
if (m_select_title_by_name)
buildSearchTree();
m_playlistHasChanged = true;
m_selected = 0;
result = true;
}
return(result);
}
void CAudioPlayerGui::addUrl2Playlist(const char *url, const char *name, const char *logo, const time_t bitrate)
{
CAudiofileExt mp3(url, CFile::STREAM_AUDIO);
//tmp = tmp.substr(0,tmp.length()-4); //remove .url
//printf("[addUrl2Playlist], name = %s, url = %s\n", name, url);
if (name != NULL)
{
mp3.MetaData.title = name;
}
else
{
std::string filename = mp3.Filename.substr(mp3.Filename.rfind('/') + 1);
mp3.MetaData.title = filename;
}
if (logo != NULL)
mp3.MetaData.logo = logo;
else
mp3.MetaData.logo.clear();
if (bitrate)
mp3.MetaData.total_time = bitrate;
else
mp3.MetaData.total_time = 0;
mp3.MetaData.url = url;
if (url[0] != '#')
addToPlaylist(mp3);
}
void CAudioPlayerGui::processPlaylistUrl(const char *url, const char *name, const char *logo, const time_t tim)
{
CURL *curl_handle;
struct MemoryStruct chunk;
const long int GET_PLAYLIST_TIMEOUT = 2;
printf("CAudioPlayerGui::processPlaylistUrl (%s, %s)\n", url, name);
chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
chunk.size = 0; /* no data at this point */
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
/* don't use signal for timeout */
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, (long)1);
/* set timeout to 10 seconds */
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_PLAYLIST_TIMEOUT);
/* get it! */
curl_easy_perform(curl_handle);
/*
Now, our chunk.memory points to a memory block that is chunk.size
bytes big and contains the remote file.
Do something nice with it!
You should be aware of the fact that at this point we might have an
allocated data block, and nothing has yet deallocated that data. So when
you're done with it, you should free() it as a nice application.
*/
long res_code;
if (curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE/*CURLINFO_RESPONSE_CODE*/, &res_code) == CURLE_OK)
{
if (200 == res_code)
{
//printf("\nchunk = %s\n", chunk.memory);
std::istringstream iss;
iss.str (std::string(chunk.memory, chunk.size));
char line[512];
char *ptr;
while (iss.rdstate() == std::ifstream::goodbit)
{
iss.getline(line, 512);
if (line[0] != '#')
{
//printf("chunk: line = %s\n", line);
const char *schemes[] = {"http://", "https://", NULL };
const char **scheme = schemes;
while (*scheme) {
ptr = strstr(line, *scheme);
scheme++;
if (ptr == NULL)
continue;
char *tmp;
// strip \n and \r characters from url
tmp = strchr(line, '\r');
if (tmp != NULL)
*tmp = '\0';
tmp = strchr(line, '\n');
if (tmp != NULL)
*tmp = '\0';
addUrl2Playlist(ptr, name, logo, tim);
break;
}
}
}
}
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
if (chunk.memory)
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
}
void CAudioPlayerGui::readDir_ic(void)
{
const std::string icecasturl = "http://dir.xiph.org/yp.xml";
const long int GET_ICECAST_TIMEOUT = 90; // list is about 500kB!
std::string answer="";
std::cout << "[readDir_ic] IC URL: " << icecasturl << std::endl;
CURL *curl_handle;
CURLcode httpres;
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, icecasturl.c_str());
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer);
/* Generate error if http error >= 400 occurs */
curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
/* set timeout to 30 seconds */
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_ICECAST_TIMEOUT);
/* error handling */
char error[CURL_ERROR_SIZE];
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error);
/* get it! */
CHintBox *scanBox = new CHintBox(LOCALE_AUDIOPLAYER_ADD_IC, g_Locale->getText(LOCALE_AUDIOPLAYER_RECEIVING_LIST)); // UTF-8
scanBox->paint();
httpres = curl_easy_perform(curl_handle);
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
//std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl;
if (!answer.empty() && httpres == 0)
{
xmlDocPtr answer_parser = parseXml(answer.c_str());
scanBox->hide();
scanXmlData(answer_parser, "listen_url", "server_name", "", "bitrate", true);
}
else
scanBox->hide();
delete scanBox;
}
void CAudioPlayerGui::scanXmlFile(std::string filename)
{
xmlDocPtr answer_parser = parseXmlFile(filename.c_str());
scanXmlData(answer_parser, "url", "name", "logo");
}
void CAudioPlayerGui::scanXmlData(xmlDocPtr answer_parser, const char *urltag, const char *nametag, const char *logotag, const char *bitratetag, bool usechild)
{
#define IC_typetag "server_type"
if (answer_parser != NULL)
{
xmlNodePtr element = xmlDocGetRootElement(answer_parser);
element = xmlChildrenNode(element);
xmlNodePtr element_tmp = element;
if (element == NULL)
{
printf("[openFilebrowser] No valid XML File.\n");
}
else
{
CProgressWindow progress;
long maxProgress = 1;
// count # of entries
while (element)
{
maxProgress++;
element = xmlNextNode(element);
}
element = element_tmp;
long listPos = -1;
progress.setTitle(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS);
progress.exec(this, "");
neutrino_msg_t msg;
neutrino_msg_data_t data;
g_RCInput->getMsg(&msg, &data, 0);
while (element && msg != CRCInput::RC_home)
{
const char *ptr = NULL;
const char *name = NULL;
const char *url = NULL;
const char *logo = NULL;
time_t bitrate = 0;
bool skip = true;
listPos++;
// show status
int global = 100*listPos / maxProgress;
progress.showStatus(global);
#ifdef LCD_UPDATE
CVFD::getInstance()->showProgressBar(global, "read xmldata...");
CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR);
#endif // LCD_UPDATE
if (usechild)
{
const char *type = NULL;
xmlNodePtr child = xmlChildrenNode(element);
while (child)
{
if (strcmp(xmlGetName(child), urltag) == 0)
url = xmlGetData(child);
else if (strcmp(xmlGetName(child), nametag) == 0)
name = xmlGetData(child);
else if (strcmp(xmlGetName(child), logotag) == 0)
logo = xmlGetData(child);
else if (strcmp(xmlGetName(child), IC_typetag) == 0)
type = xmlGetData(child);
else if (bitratetag && strcmp(xmlGetName(child), bitratetag) == 0)
{
ptr = xmlGetData(child);
if (ptr)
bitrate = atoi(ptr);
}
child = xmlNextNode(child);
}
if (type)
{
if (strcmp("audio/mpeg", type) == 0) skip = false;
else if (strcmp("application/ogg", type) == 0) skip = false;
else if (strcmp("mp3", type) == 0) skip = false;
else if (strcmp("application/mp3", type) == 0) skip = false;
}
}
else
{
url = xmlGetAttribute(element, urltag);
name = xmlGetAttribute(element, nametag);
logo = xmlGetAttribute(element, logotag);
if (bitratetag)
{
ptr = xmlGetAttribute(element, bitratetag);
if (ptr)
bitrate = atoi(ptr);
}
skip = false;
}
if ((url != NULL) && !skip)
{
progress.showStatusMessageUTF(url);
//printf("Processing %s, %s\n", url, name);
if (strstr(url, ".m3u") || strstr(url, ".pls"))
processPlaylistUrl(url, name, logo);
else
addUrl2Playlist(url, name, logo, bitrate);
}
element = xmlNextNode(element);
g_RCInput->getMsg(&msg, &data, 0);
if( ( msg>= CRCInput::RC_WithData ) && ( msg< CRCInput::RC_WithData+ 0x10000000 ) )
delete[] (unsigned char*) data;
}
progress.hide();
}
xmlFreeDoc(answer_parser);
}
else
printf("[scanXmlData] answer_parser == NULL");
}
bool CAudioPlayerGui::openFilebrowser(void)
{
bool result = false;
CFileBrowser filebrowser((g_settings.filebrowser_denydirectoryleave) ? g_settings.network_nfs_audioplayerdir.c_str() : "");
filebrowser.Multi_Select = true;
filebrowser.Dirs_Selectable = true;
filebrowser.Filter = &audiofilefilter;
hide();
if (filebrowser.exec(m_Path.c_str()))
{
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval start;
gettimeofday(&start,NULL);
#endif
CProgressWindow progress;
long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1 : 1;
long currentProgress = -1;
if (maxProgress > SHOW_FILE_LOAD_LIMIT)
{
progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES);
progress.exec(this,"");
}
m_Path = filebrowser.getCurrentDir();
CFileList::const_iterator files = filebrowser.getSelectedFiles().begin();
for (; files != filebrowser.getSelectedFiles().end(); ++files)
{
if (maxProgress > SHOW_FILE_LOAD_LIMIT)
{
currentProgress++;
// show status
int global = 100*currentProgress/maxProgress;
progress.showStatus(global);
progress.showStatusMessageUTF(files->Name);
#ifdef LCD_UPDATE
CVFD::getInstance()->showProgressBar(global, "read metadata...");
CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR);
#endif // LCD_UPDATE
}
if (
(files->getType() == CFile::FILE_CDR)
|| (files->getType() == CFile::FILE_OGG)
|| (files->getType() == CFile::FILE_MP3)
|| (files->getType() == CFile::FILE_WAV)
#ifdef ENABLE_FFMPEGDEC
|| (files->getType() == CFile::FILE_AAC)
#endif
|| (files->getType() == CFile::FILE_FLAC)
|| (files->getType() == CFile::FILE_FLV)
)
{
CAudiofileExt audiofile(files->Name,
files->getType());
addToPlaylist(audiofile);
}
if (files->getType() == CFile::STREAM_AUDIO)
{
std::string filename = files->Name;
FILE *fd = fopen(filename.c_str(), "r");
if (fd)
{
char buf[512];
unsigned int len = fread(buf, sizeof(char), 512, fd);
fclose(fd);
if (len && (strstr(buf, ".m3u") || strstr(buf, ".pls")))
{
printf("m3u/pls Playlist found: %s\n", buf);
filename = buf;
processPlaylistUrl(buf);
}
else
{
addUrl2Playlist(filename.c_str());
}
}
}
else if (files->getType() == CFile::FILE_PLAYLIST)
{
std::string sPath = files->Name.substr(0, files->Name.rfind('/'));
std::ifstream infile;
char cLine[256];
char name[255] = { 0 };
infile.open(files->Name.c_str(), std::ifstream::in);
while (infile.good())
{
infile.getline(cLine, 255);
int duration;
sscanf(cLine, "#EXTINF:%d,%[^\n]\n", &duration, name);
if (strlen(cLine) > 0 && cLine[0]!='#')
{
// remove CR
if (cLine[strlen(cLine)-1]=='\r')
cLine[strlen(cLine)-1]=0;
char *url = strstr(cLine, "http://");
if (url != NULL)
{
if (strstr(url, ".m3u") || strstr(url, ".pls"))
processPlaylistUrl(url);
else
addUrl2Playlist(url, name, NULL, duration);
}
else if ((url = strstr(cLine, "icy://")) != NULL)
{
addUrl2Playlist(url);
}
else if ((url = strstr(cLine, "scast:://")) != NULL)
{
addUrl2Playlist(url);
}
else
{
std::string filename = sPath + '/' + cLine;
std::string::size_type pos;
while ((pos=filename.find('\\'))!=std::string::npos)
filename[pos]='/';
std::ifstream testfile;
testfile.open(filename.c_str(), std::ifstream::in);
if (testfile.good())
{
#ifdef AUDIOPLAYER_CHECK_FOR_DUPLICATES
// Check for duplicates and remove (new entry has higher prio)
// this really needs some time :(
for (unsigned long i=0; igetType() == CFile::FILE_XML)
{
if (!files->Name.empty())
scanXmlFile(files->Name);
}
}
if (m_select_title_by_name)
buildSearchTree();
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval end;
gettimeofday(&end,NULL);
printf("adding %ld files took: ",maxProgress+1);
printTimevalDiff(start,end);
#endif
//store last dir
if (g_settings.network_nfs_audioplayerdir.size() > m_Path.size() && g_settings.network_nfs_audioplayerdir != m_Path.c_str())
g_settings.network_nfs_audioplayerdir = m_Path;
result = true;
}
CScreenSaver::getInstance()->resetIdleTime();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
// if playlist is turned off -> start playing immediately
if (!m_show_playlist && !m_playlist.empty())
play(m_selected);
return result;
}
bool CAudioPlayerGui::openSCbrowser(void)
{
bool result = false;
//shoutcast
const char *sc_base_dir = "http://api.shoutcast.com";
CFileBrowser filebrowser(sc_base_dir, CFileBrowser::ModeSC);
filebrowser.Multi_Select = true;
filebrowser.Dirs_Selectable = true;
filebrowser.Filter = NULL;//&audiofilefilter;
hide();
if (filebrowser.exec(filebrowser.sc_init_dir.c_str()))
{
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval start;
gettimeofday(&start,NULL);
#endif
CProgressWindow progress;
long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1: 1;
long currentProgress = -1;
//if (maxProgress > SHOW_FILE_LOAD_LIMIT)
{
progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES);
progress.exec(this,"");
}
m_Path = filebrowser.getCurrentDir();
CFileList::const_iterator files = filebrowser.getSelectedFiles().begin();
neutrino_msg_t msg;
neutrino_msg_data_t data;
g_RCInput->getMsg(&msg, &data, 0);
for (; (files != filebrowser.getSelectedFiles().end()) && (msg != CRCInput::RC_home); ++files)
{
//if (maxProgress > SHOW_FILE_LOAD_LIMIT)
{
currentProgress++;
// show progress
int global = 100*currentProgress/maxProgress;
progress.showStatus(global);
progress.showStatusMessageUTF(files->Name);
#ifdef LCD_UPDATE
CVFD::getInstance()->showProgressBar(global, "read metadata...");
CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR);
#endif // LCD_UPDATE
}
//printf("processPlaylistUrl(%s, %s)\n", files->Url.c_str(), files->Name.c_str());
processPlaylistUrl(files->Url.c_str(), files->Name.c_str(), NULL, files->Time);
g_RCInput->getMsg(&msg, &data, 0);
if( ( msg>= CRCInput::RC_WithData ) && ( msg< CRCInput::RC_WithData+ 0x10000000 ) )
delete[] (unsigned char*) data;
}
if (m_select_title_by_name)
buildSearchTree();
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval end;
gettimeofday(&end,NULL);
printf("adding %ld files took: ",maxProgress+1);
printTimevalDiff(start,end);
#endif
result = true;
}
CScreenSaver::getInstance()->resetIdleTime();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
// if playlist is turned off -> start playing immediately
if (!m_show_playlist && !m_playlist.empty())
play(m_selected);
return result;
}
void CAudioPlayerGui::hide()
{
// printf("hide(){\n");
if (m_visible)
{
clearDetailsLine();
m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width + OFFSET_SHADOW, m_height + OFFSET_SHADOW);
m_visible = false;
}
}
void CAudioPlayerGui::paintItem(int pos)
{
if (!m_show_playlist)
return;
int ypos = m_y + m_title_height + OFFSET_SHADOW + OFFSET_INTER + m_header_height + pos*m_item_height;
unsigned int currpos = m_liststart + pos;
bool i_selected = currpos == m_selected;
bool i_marked = currpos == (unsigned) m_current;
bool i_switch = false; //(currpos < m_playlist.size()) && (pos & 1);
int i_radius = RADIUS_NONE;
fb_pixel_t color;
fb_pixel_t bgcolor;
getItemColors(color, bgcolor, i_selected, i_marked, i_switch);
if (i_selected || i_marked)
i_radius = RADIUS_LARGE;
if (i_selected)
paintDetailsLine(pos);
if (i_radius)
m_frameBuffer->paintBoxRel(m_x, ypos, m_width - SCROLLBAR_WIDTH, m_item_height, COL_MENUCONTENT_PLUS_0);
m_frameBuffer->paintBoxRel(m_x, ypos, m_width - SCROLLBAR_WIDTH, m_item_height, bgcolor, i_radius);
if (currpos < m_playlist.size())
{
char sNr[20];
sprintf(sNr, (currpos + 1) < 10 ? "%02d: " : "%d: ", currpos + 1);
std::string tmp = sNr;
getFileInfoToDisplay(tmp, m_playlist[currpos]);
char dura[14] = {0};
if (m_inetmode)
{
if (m_playlist[currpos].MetaData.total_time != 0)
snprintf(dura, sizeof(dura), "%ldk", m_playlist[currpos].MetaData.total_time);
}
else
snprintf(dura, sizeof(dura), "%ld:%02ld", m_playlist[currpos].MetaData.total_time / 60, m_playlist[currpos].MetaData.total_time % 60);
int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(dura);
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + OFFSET_INNER_MID, ypos + m_item_height, m_width - SCROLLBAR_WIDTH - 3*OFFSET_INNER_MID - w, tmp, color, m_item_height);
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - SCROLLBAR_WIDTH - OFFSET_INNER_MID - w, ypos + m_item_height, w, dura, color, m_item_height);
if (currpos == m_selected)
{
if (m_state == CAudioPlayerGui::STOP)
CVFD::getInstance()->showAudioTrack(m_playlist[currpos].MetaData.artist, m_playlist[currpos].MetaData.title, m_playlist[currpos].MetaData.album);
}
}
}
void CAudioPlayerGui::paintHead()
{
if (!m_show_playlist || CScreenSaver::getInstance()->isActive())
return;
CComponentsHeader header(m_x, m_y + m_title_height + OFFSET_SHADOW + OFFSET_INTER, m_width, m_header_height, LOCALE_AUDIOPLAYER_HEAD, NEUTRINO_ICON_AUDIO);
header.enableShadow( CC_SHADOW_RIGHT | CC_SHADOW_CORNER_TOP_RIGHT | CC_SHADOW_CORNER_BOTTOM_RIGHT, -1, true);
if (m_inetmode)
header.setCaption(LOCALE_INETRADIO_NAME);
#ifdef ENABLE_GUI_MOUNT
if (!m_inetmode)
header.setContextButton(NEUTRINO_ICON_BUTTON_MENU);
#endif
header.paint(CC_SAVE_SCREEN_NO);
}
#if 0
#define BUTTON_LABEL_COUNT 3
const struct button_label SecondLineButtons[BUTTON_LABEL_COUNT] =
{
{ NEUTRINO_ICON_BUTTON_OKAY, LOCALE_AUDIOPLAYER_PLAY },
{ NEUTRINO_ICON_BUTTON_HELP, LOCALE_AUDIOPLAYER_KEYLEVEL },
{ NEUTRINO_ICON_BUTTON_INFO, LOCALE_PICTUREVIEWER_HEAD }
};
#else
#define BUTTON_LABEL_COUNT 2
const struct button_label SecondLineButtons[BUTTON_LABEL_COUNT] =
{
{ NEUTRINO_ICON_BUTTON_OKAY, LOCALE_AUDIOPLAYER_PLAY },
{ NEUTRINO_ICON_BUTTON_HELP, LOCALE_AUDIOPLAYER_KEYLEVEL }
};
#endif
void CAudioPlayerGui::paintFoot()
{
if (CScreenSaver::getInstance()->isActive())
return;
int radius = RADIUS_LARGE;
int button_y = m_y + m_height - OFFSET_SHADOW - m_info_height - OFFSET_INTER - OFFSET_SHADOW - 2*m_button_height;
int button_x = m_x;
int button_width = m_width;
// ensure to get round corners in footer
if (!m_show_playlist && radius)
{
button_x += radius;
button_width -= 2*radius;
}
// shadow
m_frameBuffer->paintBoxRel(m_x + OFFSET_SHADOW, button_y + OFFSET_SHADOW, m_width, 2*m_button_height, COL_SHADOW_PLUS_0, radius, (m_show_playlist ? CORNER_BOTTOM : CORNER_ALL));
m_frameBuffer->paintBoxRel(m_x, button_y, m_width, 2*m_button_height, COL_MENUFOOT_PLUS_0, radius, (m_show_playlist ? CORNER_BOTTOM : CORNER_ALL));
if (!m_playlist.empty())
::paintButtons(button_x, button_y + m_button_height, button_width, BUTTON_LABEL_COUNT, SecondLineButtons, button_width, m_button_height);
if (m_key_level == 0)
{
if (m_playlist.empty())
{
if (m_inetmode)
::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[7], button_width, m_button_height);
else
::paintButtons(button_x, button_y, button_width, 1, &(AudioPlayerButtons[7][0]), button_width, m_button_height);
}
else if (m_inetmode)
::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[8], button_width, m_button_height);
else
::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[1], button_width, m_button_height);
}
else if (m_key_level == 1)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
::paintButtons(button_x, button_y, button_width, 4, AudioPlayerButtons[0], button_width, m_button_height);
else
{
int b = 2;
if (m_streamripper_available)
{
b = 3;
if (m_streamripper_active)
AudioPlayerButtons[6][2].locale = LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP;
else
AudioPlayerButtons[6][2].locale = LOCALE_AUDIOPLAYER_STREAMRIPPER_START;
}
::paintButtons(button_x, button_y, button_width, b, AudioPlayerButtons[6], button_width, m_button_height);
}
}
else // key_level == 2
{
if (m_state == CAudioPlayerGui::STOP)
{
if (m_select_title_by_name)
::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[5], button_width, m_button_height);
else
::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[4], button_width, m_button_height);
}
else
{
if (m_select_title_by_name)
::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[3], button_width, m_button_height);
else
::paintButtons(button_x, button_y, button_width, 2, AudioPlayerButtons[2], button_width, m_button_height);
}
}
}
void CAudioPlayerGui::paintCover()
{
const CAudioMetaData meta = CAudioPlayer::getInstance()->getMetaData();
// try folder.jpg first
m_cover = m_curr_audiofile.Filename.substr(0, m_curr_audiofile.Filename.rfind('/')) + "/folder.jpg";
m_stationlogo = false;
// try cover from tag
if (!meta.cover.empty())
m_cover = meta.cover;
// try station logo
else if (!meta.logo.empty())
{
std::size_t found_url = meta.logo.find("://");
if (found_url != std::string::npos)
{
mkdir(COVERDIR_TMP, 0755);
std::string filename(meta.logo);
const size_t last_slash_idx = filename.find_last_of("/");
if (last_slash_idx != std::string::npos)
filename.erase(0, last_slash_idx + 1);
std::string fullname(COVERDIR_TMP);
fullname += "/" + filename;
CHTTPTool httptool;
if (httptool.downloadFile(meta.logo, fullname.c_str()))
{
m_cover = fullname;
m_stationlogo = true;
}
else
m_cover.clear();
}
}
if (access(m_cover.c_str(), F_OK) == 0)
{
int cover_x = m_x + OFFSET_INNER_MID;
int cover_y = m_y + OFFSET_INNER_SMALL;
m_cover_width = 0;
CComponentsPicture *cover_object = new CComponentsPicture(cover_x, cover_y, m_cover);
if (cover_object)
{
cover_object->doPaintBg(false);
// cover_object->SetTransparent(CFrameBuffer::TM_BLACK);
cover_object->setHeight(m_title_height - 2*OFFSET_INNER_SMALL, true);
cover_object->paint();
m_cover_width = cover_object->getWidth() + OFFSET_INNER_MID;
delete cover_object;
}
}
}
void CAudioPlayerGui::paintTitleBox()
{
if (CScreenSaver::getInstance()->isActive())
return;
if (m_state == CAudioPlayerGui::STOP && m_show_playlist)
{
if (m_titlebox)
{
m_titlebox->kill();
delete m_titlebox; m_titlebox = NULL;
}
}
else
{
// title box
if (!m_titlebox)
{
m_titlebox = new CComponentsShapeSquare(m_x, m_y, m_width, m_title_height, NULL, CC_SHADOW_ON);
m_titlebox->enableFrame(true, FRAME_WIDTH_MIN);
m_titlebox->setCorner(RADIUS_LARGE);
}
m_titlebox->paint(false);
paintCover();
// first line (Track number)
std::string tmp;
if (m_inetmode)
{
tmp = m_curr_audiofile.MetaData.album;
}
else
{
char sNr[20];
sprintf(sNr, ": %2d", m_current + 1);
tmp = g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYING);
tmp += sNr ;
}
int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp);
int xstart = (m_width - w)/2;
if (xstart < OFFSET_INNER_MID + m_cover_width)
xstart = OFFSET_INNER_MID + m_cover_width;
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 1*m_item_height, m_width - OFFSET_INNER_MID - xstart, tmp, COL_MENUHEAD_TEXT); //caption "current track"
// second line (Artist/Title...)
GetMetaData(m_curr_audiofile);
if (m_curr_audiofile.MetaData.title.empty())
tmp = m_curr_audiofile.MetaData.artist;
else if (m_curr_audiofile.MetaData.artist.empty())
tmp = m_curr_audiofile.MetaData.title;
else if (g_settings.audioplayer_display == TITLE_ARTIST)
{
tmp = m_curr_audiofile.MetaData.title;
tmp += " - ";
tmp += m_curr_audiofile.MetaData.artist;
}
else //if (g_settings.audioplayer_display == ARTIST_TITLE)
{
tmp = m_curr_audiofile.MetaData.artist;
tmp += " - ";
tmp += m_curr_audiofile.MetaData.title;
}
w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp);
xstart = (m_width - w)/2;
if (xstart < OFFSET_INNER_MID + m_cover_width)
xstart = OFFSET_INNER_MID + m_cover_width;
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 2*m_item_height, m_width - OFFSET_INNER_MID - xstart, tmp, COL_MENUHEAD_TEXT); //artist - title
// reset so fields get painted always
m_metainfo.clear();
m_time_total = 0;
m_time_played = 0;
updateMetaData();
updateTimes(true);
}
}
void CAudioPlayerGui::paint()
{
if (m_show_playlist)
{
unsigned int tmp_max = m_listmaxshow;
if (!tmp_max)
tmp_max = 1;
m_liststart = (m_selected / tmp_max) * m_listmaxshow;
paintHead();
for (unsigned int count=0; countkill();
delete m_detailsline;
m_detailsline = NULL;
}
// paint Line if detail info (and not valid list pos) and info box
if (!m_playlist.empty() && (pos >= 0))
{
//details line
if (m_detailsline == NULL)
m_detailsline = new CComponentsDetailsLine(xpos, ypos1a, ypos2a, m_item_height/2, m_info_height - RADIUS_LARGE*2);
m_detailsline->paint(false);
// paint id3 infobox
if (m_infobox == NULL)
{
m_infobox = new CComponentsInfoBox(m_x, ypos2, m_width, m_info_height);
m_infobox->setFrameThickness(FRAME_WIDTH_MIN);
m_infobox->setCorner(RADIUS_LARGE);
m_infobox->setColorFrame(COL_FRAME_PLUS_0);
m_infobox->setColorBody(COL_MENUCONTENTDARK_PLUS_0);
m_infobox->enableShadow(CC_SHADOW_ON, -1, true);
m_infobox->forceTextPaint(false);
}
// first line
std::string text_info("");
getFileInfoToDisplay(text_info, m_playlist[m_selected]);
text_info += "\n";
// second line; url or date and genre
if (m_inetmode)
{
if (!m_playlist[m_selected].MetaData.url.empty())
{
text_info += m_playlist[m_selected].MetaData.url;
}
else
text_info += " ";
}
else
{
bool got_date = false;
if (!m_playlist[m_selected].MetaData.date.empty())
{
got_date = true;
text_info += m_playlist[m_selected].MetaData.date;
}
bool got_genre = false;
if (!m_playlist[m_selected].MetaData.genre.empty())
{
got_genre = true;
if (got_date)
text_info += " / ";
text_info += m_playlist[m_selected].MetaData.genre;
}
if (!got_date && !got_genre)
text_info += " ";
}
m_infobox->setText(text_info, CTextBox::AUTO_WIDTH, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO], COL_MENUCONTENTDARK_TEXT);
m_infobox->paint(false);
}
else
{
if (m_detailsline != NULL)
m_detailsline->kill();
if (m_infobox != NULL)
m_infobox->kill();
}
}
void CAudioPlayerGui::stop()
{
m_state = CAudioPlayerGui::STOP;
m_current = 0;
if (!pictureviewer)
{
//LCD
paintLCD();
//Display
paintTitleBox();
m_key_level = 0;
paintFoot();
}
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
cleanupCovers();
if (m_streamripper_active)
{
ShowHint(LOCALE_MESSAGEBOX_INFO, LOCALE_AUDIOPLAYER_STREAMRIPPER_STOP, HINTBOX_MIN_WIDTH, 2);
my_system(2, "streamripper.sh", "stop");
m_streamripper_active = false;
}
}
void CAudioPlayerGui::pause()
{
if (
m_state == CAudioPlayerGui::PLAY
|| m_state == CAudioPlayerGui::FF
|| m_state == CAudioPlayerGui::REV
)
{
m_state = CAudioPlayerGui::PAUSE;
CAudioPlayer::getInstance()->pause();
}
else if (m_state == CAudioPlayerGui::PAUSE)
{
m_state = CAudioPlayerGui::PLAY;
CAudioPlayer::getInstance()->pause();
}
paintLCD();
}
void CAudioPlayerGui::ff(unsigned int seconds)
{
if (m_state == CAudioPlayerGui::FF)
{
m_state = CAudioPlayerGui::PLAY;
CAudioPlayer::getInstance()->ff(seconds);
}
else if (
m_state == CAudioPlayerGui::PLAY
|| m_state == CAudioPlayerGui::PAUSE
|| m_state == CAudioPlayerGui::REV
)
{
m_state = CAudioPlayerGui::FF;
CAudioPlayer::getInstance()->ff(seconds);
}
paintLCD();
}
void CAudioPlayerGui::rev(unsigned int seconds)
{
if (m_state == CAudioPlayerGui::REV)
{
m_state = CAudioPlayerGui::PLAY;
CAudioPlayer::getInstance()->rev(seconds);
}
else if (
m_state == CAudioPlayerGui::PLAY
|| m_state == CAudioPlayerGui::PAUSE
|| m_state == CAudioPlayerGui::FF
)
{
m_state = CAudioPlayerGui::REV;
CAudioPlayer::getInstance()->rev(seconds);
}
paintLCD();
}
void CAudioPlayerGui::play(unsigned int pos)
{
//printf("AudioPlaylist: play %d/%d\n",pos,playlist.size());
unsigned int old_current = m_current;
unsigned int old_selected = m_selected;
cleanupCovers();
m_current = pos;
if (g_settings.audioplayer_follow)
m_selected = pos;
if (m_selected - m_liststart >= m_listmaxshow && g_settings.audioplayer_follow)
{
m_liststart = m_selected;
if (!CScreenSaver::getInstance()->isActive() && !pictureviewer)
paint();
}
else if (m_liststart < m_selected && g_settings.audioplayer_follow)
{
m_liststart = m_selected - m_listmaxshow + 1;
if (!CScreenSaver::getInstance()->isActive() && !pictureviewer)
paint();
}
else
{
if (old_current >= m_liststart && old_current - m_liststart < m_listmaxshow)
{
if (!CScreenSaver::getInstance()->isActive() && !pictureviewer)
paintItem(old_current - m_liststart);
}
if (pos >= m_liststart && pos - m_liststart < m_listmaxshow)
{
if (!CScreenSaver::getInstance()->isActive() && !pictureviewer)
paintItem(pos - m_liststart);
}
if (g_settings.audioplayer_follow)
{
if (old_selected >= m_liststart && old_selected - m_liststart < m_listmaxshow)
if (!CScreenSaver::getInstance()->isActive() && !pictureviewer)
paintItem(old_selected - m_liststart);
}
}
GetMetaData(m_playlist[pos]);
m_metainfo.clear();
m_time_played = 0;
m_time_total = m_playlist[m_current].MetaData.total_time;
m_state = CAudioPlayerGui::PLAY;
m_curr_audiofile = m_playlist[m_current];
if (CScreenSaver::getInstance()->isActive() && g_settings.audioplayer_cover_as_screensaver)
CScreenSaver::getInstance()->forceRefresh();
// Play
CAudioPlayer::getInstance()->play(&m_curr_audiofile, g_settings.audioplayer_highprio == 1);
if (!pictureviewer)
{
//LCD
paintLCD();
// Display
paintTitleBox();
m_key_level = 1;
paintFoot();
}
}
int CAudioPlayerGui::getNext()
{
int ret= m_current + 1;
if (m_playlist.empty())
return -1;
if ((unsigned)ret >= m_playlist.size())
{
if (g_settings.audioplayer_repeat_on == 1)
ret = 0;
else
ret = -1;
}
return ret;
}
void CAudioPlayerGui::updateMetaData()
{
bool updateMeta = false;
bool updateLcd = false;
bool updateScreen = false;
if (m_state == CAudioPlayerGui::STOP)
return;
if (CAudioPlayer::getInstance()->hasMetaDataChanged() || m_metainfo.empty())
{
const CAudioMetaData meta = CAudioPlayer::getInstance()->getMetaData();
std::stringstream info;
info.precision(3);
if (meta.bitrate > 0)
{
info << " / ";
if (meta.vbr)
info << "VBR ";
info << meta.bitrate/1000 << "kbps";
}
if (meta.samplerate > 0)
info << " / " << meta.samplerate/1000 << "." << (meta.samplerate/100)%10 <<"kHz";
m_metainfo = meta.type_info + info.str();
updateMeta = !CScreenSaver::getInstance()->isActive();
if (!meta.artist.empty() && meta.artist != m_curr_audiofile.MetaData.artist)
{
m_curr_audiofile.MetaData.artist = meta.artist;
if (!CScreenSaver::getInstance()->isActive())
updateScreen = true;
updateLcd = true;
}
if (!meta.title.empty() && meta.title != m_curr_audiofile.MetaData.title)
{
m_curr_audiofile.MetaData.title = meta.title;
if (!CScreenSaver::getInstance()->isActive())
updateScreen = true;
updateLcd = true;
}
if (!meta.sc_station.empty() && meta.sc_station != m_curr_audiofile.MetaData.album)
{
m_curr_audiofile.MetaData.album = meta.sc_station;
updateLcd = true;
}
if (!CScreenSaver::getInstance()->isActive())
paintCover();
}
if (CAudioPlayer::getInstance()->hasMetaDataChanged() != 0)
updateLcd = true;
//printf("CAudioPlayerGui::updateMetaData: updateLcd %d\n", updateLcd);
if (updateLcd)
paintLCD();
if (updateScreen)
paintTitleBox();
if (updateMeta || updateScreen)
{
m_frameBuffer->paintBoxRel(m_x + OFFSET_INNER_MID + m_cover_width, m_y + OFFSET_INNER_SMALL + 2*m_item_height + OFFSET_INNER_SMALL, m_width - 2*OFFSET_INNER_MID - m_cover_width, m_meta_height, m_titlebox->getColorBody());
int w = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(m_metainfo);
int xstart = (m_width - w)/2;
if (xstart < OFFSET_INNER_MID)
xstart = OFFSET_INNER_MID;
g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + xstart, m_y + OFFSET_INNER_SMALL + 2*m_item_height + OFFSET_INNER_SMALL + m_meta_height, m_width - 2*xstart, m_metainfo, COL_MENUHEAD_TEXT);
}
}
void CAudioPlayerGui::updateTimes(const bool force)
{
if (m_state != CAudioPlayerGui::STOP)
{
bool updateTotal = force;
bool updatePlayed = force;
if (m_time_total != CAudioPlayer::getInstance()->getTimeTotal())
{
m_time_total = CAudioPlayer::getInstance()->getTimeTotal();
if (m_curr_audiofile.MetaData.total_time != CAudioPlayer::getInstance()->getTimeTotal())
{
m_curr_audiofile.MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal();
if (m_current >= 0)
m_playlist[m_current].MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal();
}
updateTotal = true;
}
if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed()))
{
m_time_played = CAudioPlayer::getInstance()->getTimePlayed();
updatePlayed = true;
}
if (!CScreenSaver::getInstance()->isActive())
{
char total_time[17];
snprintf(total_time, sizeof(total_time), " / %ld:%02ld", m_time_total / 60, m_time_total % 60);
char played_time[14];
snprintf(played_time, sizeof(played_time), "%ld:%02ld", m_time_played / 60, m_time_played % 60);
int w_total_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(total_time);
int w_faked_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth("000:00");
int w_played_time = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(played_time);
// in inetmode we havn't a total_time
if (m_inetmode)
w_total_time = 0;
int x_total_time = m_x + m_width - OFFSET_INNER_MID - w_total_time - 2*m_titlebox->getFrameThickness();
// played time offset to align this value on the right side
int o_played_time = std::max(w_faked_time - w_played_time, 0);
int x_faked_time = x_total_time - w_faked_time;
int x_played_time = x_faked_time + o_played_time;
int y_times = m_y + OFFSET_INNER_SMALL;
if (updateTotal && !m_inetmode)
{
m_frameBuffer->paintBoxRel(x_total_time, y_times, w_total_time, m_item_height, m_titlebox->getColorBody());
if (m_time_total > 0)
{
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x_total_time, y_times + m_item_height, w_total_time, total_time, COL_MENUHEAD_TEXT); //total time
}
}
if (updatePlayed || (m_state == CAudioPlayerGui::PAUSE))
{
m_frameBuffer->paintBoxRel(x_faked_time, y_times, w_faked_time, m_item_height, m_titlebox->getColorBody());
struct timeval tv;
gettimeofday(&tv, NULL);
if ((m_state != CAudioPlayerGui::PAUSE) || (tv.tv_sec & 1))
{
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x_played_time, y_times + m_item_height, w_played_time, played_time, COL_MENUHEAD_TEXT); //elapsed time
}
}
}
if ((updatePlayed || updateTotal) && m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0)
{
CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total));
}
}
}
void CAudioPlayerGui::paintLCD()
{
switch (m_state)
{
case CAudioPlayerGui::STOP:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_STOP);
CVFD::getInstance()->showAudioProgress(0);
break;
case CAudioPlayerGui::PLAY:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PLAY);
CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album);
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0)
CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total));
break;
case CAudioPlayerGui::PAUSE:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PAUSE);
CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album);
break;
case CAudioPlayerGui::FF:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_FF);
CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album);
break;
case CAudioPlayerGui::REV:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_REV);
CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album);
break;
}
}
void CAudioPlayerGui::GetMetaData(CAudiofileExt &File)
{
bool ret = 1;
if (File.FileType != CFile::STREAM_AUDIO && !File.MetaData.bitrate)
ret = CAudioPlayer::getInstance()->readMetaData(&File, m_state != CAudioPlayerGui::STOP && !g_settings.audioplayer_highprio);
if (!ret || (File.MetaData.artist.empty() && File.MetaData.title.empty()))
{
//Set from Filename
std::string tmp = File.Filename.substr(File.Filename.rfind('/') + 1);
tmp = tmp.substr(0,tmp.length() - 4); //remove extension (.mp3)
std::string::size_type i = tmp.rfind(" - ");
if (i != std::string::npos)
{ // Trennzeichen " - " gefunden
File.MetaData.artist = tmp.substr(0, i);
File.MetaData.title = tmp.substr(i + 3);
}
else
{
i = tmp.rfind('-');
if (i != std::string::npos)
{ //Trennzeichen "-"
File.MetaData.artist = tmp.substr(0, i);
File.MetaData.title = tmp.substr(i + 1);
}
else
File.MetaData.title = tmp;
}
File.MetaData.artist = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.artist);
File.MetaData.title = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.title);
}
}
bool CAudioPlayerGui::getNumericInput(neutrino_msg_t& msg, int& val)
{
//FIXME - remove fixed values
neutrino_msg_data_t data;
int x1 = (g_settings.screen_EndX - g_settings.screen_StartX) / 2 + g_settings.screen_StartX - 50;
int y1 = (g_settings.screen_EndY - g_settings.screen_StartY) / 2 + g_settings.screen_StartY;
char str[11];
do
{
val = val * 10 + CRCInput::getNumericValue(msg);
sprintf(str, "%d", val);
int w = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(str);
int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight();
m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_FRAME_PLUS_0);
m_frameBuffer->paintBoxRel(x1 - 6, y1 - h - 4, w + 12, h + 8, COL_MENUCONTENTSELECTED_PLUS_0);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1, y1, w + 1, str, COL_MENUCONTENTSELECTED_TEXT);
while (true)
{
g_RCInput->getMsg(&msg, &data, 100);
if (msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout)
{ // not a key event
CNeutrinoApp::getInstance()->handleMsg(msg, data);
continue;
}
if (msg & (CRCInput::RC_Repeat|CRCInput::RC_Release)) // repeat / release
continue;
break;
}
} while (g_RCInput->isNumeric(msg) && val < 1000000);
return (msg == CRCInput::RC_ok);
}
void CAudioPlayerGui::getFileInfoToDisplay(std::string &fileInfo, CAudiofileExt &file)
{
//std::string fileInfo;
std::string artist;
std::string title;
if (!m_inetmode)
{
artist ="Artist?";
title = "Title?";
}
GetMetaData(file);
if (!file.MetaData.artist.empty())
artist = file.MetaData.artist;
if (!file.MetaData.title.empty())
title = file.MetaData.title;
if (g_settings.audioplayer_display == TITLE_ARTIST)
{
fileInfo += title;
if (!title.empty() && !artist.empty())
fileInfo += " - ";
fileInfo += artist;
}
else //if (g_settings.audioplayer_display == ARTIST_TITLE)
{
fileInfo += artist;
if (!title.empty() && !artist.empty())
fileInfo += " - ";
fileInfo += title;
}
if (!file.MetaData.album.empty())
{
fileInfo += " - ";
fileInfo += file.MetaData.album;
}
if (fileInfo.empty())
{
fileInfo += "Unknown";
}
file.firstChar = (char)tolower(fileInfo[0]);
//info += fileInfo;
}
void CAudioPlayerGui::addToPlaylist(CAudiofileExt &file)
{
//printf("add2Playlist: %s\n", file.Filename.c_str());
if (m_select_title_by_name)
{
std::string t("");
getFileInfoToDisplay(t,file);
}
else
GetMetaData(file);
m_playlist.push_back(file);
m_playlistHasChanged = true;
}
void CAudioPlayerGui::removeFromPlaylist(long pos)
{
unsigned char firstChar = ' ';
// must be called before m_playlist.erase()
if (m_select_title_by_name)
firstChar = getFirstChar(m_playlist[pos]);
//unlink(m_playlist[pos].MetaData.cover.c_str());
m_playlist.erase(m_playlist.begin() + pos);
m_playlistHasChanged = true;
if (m_select_title_by_name)
{
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval start;
gettimeofday(&start,NULL);
#endif
//printf("searching for key: %c val: %ld\n",firstChar,pos);
CTitle2Pos::iterator item = m_title2Pos.find(firstChar);
if (item != m_title2Pos.end())
{
item->second.erase(pos);
// delete empty entries
if (item->second.empty())
m_title2Pos.erase(item);
}
else
{
printf("could not find key: %c pos: %ld\n",firstChar,pos);
}
// decrease position information for all titles with a position
// behind item to delete
long p = 0;
for (CTitle2Pos::iterator title=m_title2Pos.begin(); title!=m_title2Pos.end(); ++title)
{
CPosList newList;
for (CPosList::iterator posIt=title->second.begin(); posIt!=title->second.end(); ++posIt)
{
p = *(posIt);
if (*posIt > pos)
p--;
// old list is sorted so we can give a hint to insert at the end
newList.insert(newList.end(), p);
}
title->second = newList;
}
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval end;
gettimeofday(&end,NULL);
printf("delete took: ");
printTimevalDiff(start,end);
#endif
}
}
void CAudioPlayerGui::selectTitle(unsigned char selectionChar)
{
unsigned long i;
//printf("fastLookup: key %c\n",selectionChar);
CTitle2Pos::iterator it = m_title2Pos.find(selectionChar);
if (it!=m_title2Pos.end())
{
// search for the next greater id
// if nothing found take the first
CPosList::iterator posIt = it->second.upper_bound(m_selected);
if (posIt != it->second.end())
{
i = *posIt;
//printf("upper bound i: %ld\n",i);
}
else
{
if (!it->second.empty())
{
i = *(it->second.begin());
//printf("using begin i: %ld\n",i);
}
else
{
//printf("no title with that key\n");
return;
}
}
}
else
{
//printf("no title with that key\n");
return;
}
int prevselected = m_selected;
m_selected = i;
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected / m_listmaxshow)*m_listmaxshow;
//printf("before paint\n");
if (oldliststart != m_liststart)
{
paint();
}
else
{
paintItem(prevselected - m_liststart);
paintItem(m_selected - m_liststart);
}
}
void CAudioPlayerGui::printSearchTree()
{
for (CTitle2Pos::iterator it=m_title2Pos.begin(); it!=m_title2Pos.end(); ++it)
{
printf("key: %c\n",it->first);
long pos=-1;
for (CPosList::iterator it2=it->second.begin(); it2!=it->second.end(); ++it2)
{
pos++;
printf(" val: %ld ",*it2);
if (pos % 5 == 4)
printf("\n");
}
printf("\n");
}
}
void CAudioPlayerGui::buildSearchTree()
{
//printf("before\n");
//printSearchTree();
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval start;
gettimeofday(&start,NULL);
#endif
CProgressWindow progress;
progress.setTitle(LOCALE_AUDIOPLAYER_BUILDING_SEARCH_INDEX);
progress.exec(this, "");
long maxProgress = (m_playlist.size() > 1) ? m_playlist.size() - 1 : 1;
m_title2Pos.clear();
long listPos = -1;
for (CAudioPlayList::iterator it=m_playlist.begin(); it!=m_playlist.end(); ++it)
{
listPos++;
progress.showStatus(100*listPos / maxProgress);
progress.showStatusMessageUTF(it->Filename);
unsigned char firstChar = getFirstChar(*it);
const std::pair item = m_title2Pos.insert(CTitle2PosItem(firstChar,CPosList()));
item.first->second.insert(listPos);
}
progress.hide();
m_playlistHasChanged = false;
#ifdef AUDIOPLAYER_TIME_DEBUG
timeval end;
gettimeofday(&end,NULL);
printf("searchtree took: ");
printTimevalDiff(start,end);
#endif
//printf("after:\n");
//printSearchTree();
}
unsigned char CAudioPlayerGui::getFirstChar(CAudiofileExt &file)
{
if (file.firstChar == '\0')
{
std::string info("");
getFileInfoToDisplay(info, file);
}
//printf("getFirstChar: %c\n",file.firstChar);
return file.firstChar;
}
#ifdef AUDIOPLAYER_TIME_DEBUG
void CAudioPlayerGui::printTimevalDiff(timeval &start, timeval &end)
{
long secs = end.tv_sec - start.tv_sec;
long usecs = end.tv_usec -start.tv_usec;
if (usecs < 0)
{
usecs = 1000000 + usecs;
secs--;
}
printf("%ld:%ld\n",secs,usecs);
}
#endif
void CAudioPlayerGui::savePlaylist()
{
const char *path;
// .m3u playlist
// http://hanna.pyxidis.org/tech/m3u.html
CFileBrowser browser;
browser.Multi_Select = false;
browser.Dir_Mode = true;
CFileFilter dirFilter;
dirFilter.addFilter("m3u");
browser.Filter = &dirFilter;
// select preferred directory if exists
if (!g_settings.network_nfs_audioplayerdir.empty())
path = g_settings.network_nfs_audioplayerdir.c_str();
else
path = "/";
// let user select target directory
this->hide();
if (browser.exec(path))
{
// refresh view
this->paint();
CFile *file = browser.getSelectedFile();
std::string absPlaylistDir = file->getPath();
// add a trailing slash if necessary
if ((absPlaylistDir.empty()) || ((*(absPlaylistDir.rbegin()) != '/')))
absPlaylistDir += '/';
absPlaylistDir += file->getFileName();
const int filenamesize = 30;
std::string filename = "playlist";
if (file->getType() == CFile::FILE_PLAYLIST)
{
// file is playlist so we should ask if we can overwrite it
std::string name = file->getPath();
name += '/';
name += file->getFileName();
bool overwrite = askToOverwriteFile(name);
if (!overwrite)
return;
filename = name;
}
else if (file->getType() == CFile::FILE_DIR)
{
// query for filename
this->hide();
CKeyboardInput filenameInput(LOCALE_AUDIOPLAYER_PLAYLIST_NAME, &filename, filenamesize - 1, NULL, NULL, LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT1, LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT2);
filenameInput.exec(NULL, "");
// refresh view
this->paint();
std::string name = absPlaylistDir;
name += '/';
name += filename;
name += ".m3u";
std::ifstream input(name.c_str());
// test if file exists and query for overwriting it or not
if (input.is_open())
{
bool overwrite = askToOverwriteFile(name);
if (!overwrite)
return;
}
input.close();
}
else
{
std::cout << "CAudioPlayerGui: neither .m3u nor directory selected, abort" << std::endl;
return;
}
std::string absPlaylistFilename = absPlaylistDir;
absPlaylistFilename += '/';
absPlaylistFilename += filename;
absPlaylistFilename += ".m3u";
std::ofstream playlistFile(absPlaylistFilename.c_str());
std::cout << "CAudioPlayerGui: writing playlist to " << absPlaylistFilename << std::endl;
if (!playlistFile)
{
// an error occured
const int msgsize = 255;
char msg[msgsize] = "";
snprintf(msg, msgsize,
"%s\n%s",
g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEERROR_MSG),
absPlaylistFilename.c_str());
DisplayErrorMessage(msg);
// refresh view
this->paint();
std::cout << "CAudioPlayerGui: could not create play list file " << absPlaylistFilename << std::endl;
return;
}
// writing .m3u file
playlistFile << "#EXTM3U" << std::endl;
CAudioPlayList::const_iterator it;
for (it = m_playlist.begin(); it!=m_playlist.end(); ++it)
{
playlistFile << "#EXTINF:" << it->MetaData.total_time << "," << it->MetaData.artist << " - " << it->MetaData.title << std::endl;
if (m_inetmode)
playlistFile << it->Filename << std::endl;
else
playlistFile << absPath2Rel(absPlaylistDir, it->Filename) << std::endl;
}
playlistFile.close();
}
this->paint();
}
bool CAudioPlayerGui::askToOverwriteFile(const std::string& filename)
{
char msg[filename.length() + 127];
snprintf(msg, filename.length() + 126,
"%s\n%s",
g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_MSG),
filename.c_str());
bool res = (ShowMsg(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_TITLE, msg, CMsgBox::mbrYes, CMsgBox::mbYes | CMsgBox::mbNo) == CMsgBox::mbrYes);
this->paint();
return res;
}
std::string CAudioPlayerGui::absPath2Rel(const std::string& fromDir, const std::string& absFilename)
{
std::string res = "";
int length = fromDir.length() < absFilename.length() ? fromDir.length() : absFilename.length();
int lastSlash = 0;
// find common prefix for both paths
// fromDir: /foo/bar/angle/1 (length: 16)
// absFilename: /foo/bar/devil/2/fire.mp3 (length: 19)
// -> /foo/bar/ is prefix, lastSlash will be 8
for (int i=0; i -1)
{
while (n--)
{
const char *coverfile = coverlist[n]->d_name;
if (strcmp(coverfile, ".") != 0 && strcmp(coverfile, "..") != 0)
{
printf("[audioplayer] removing cover %s/%s\n", COVERDIR_TMP, coverfile);
unlink(((std::string)COVERDIR_TMP + "/" + coverfile).c_str());
}
free(coverlist[n]);
}
free(coverlist);
}
}
m_cover.clear();
m_stationlogo = false;
}