Files
recycled-ni-neutrino/src/gui/audioplayer.cpp
[CST] Focus a03f1b05be Wav play added - not ok, have bugs; Fixes for webif radio streaming bouquets/channels lists; Mute after standby fix; Hack to read 2x sdp on cable, for testing; Restore analog audio stereo/mono mode on zap
git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@238 e54a6e83-5905-42d5-8d5c-058d10e6a962


Origin commit data
------------------
Branch: ni/coolstream
Commit: 529b5dce7c
Author: [CST] Focus <focus.cst@gmail.com>
Date: 2010-01-31 (Sun, 31 Jan 2010)



------------------
This commit was generated by Migit
2010-01-31 16:27:23 +00:00

2887 lines
80 KiB
C++

/*
$Id: audioplayer.cpp,v 1.80 2009/10/18 14:38:03 dbt Exp $
Neutrino-GUI - DBoxII-Project
AudioPlayer by Dirch,Zwen
(C) 2002-2008 the tuxbox project contributors
(C) 2008 Novell, Inc. Author: Stefan Seyfried
Homepage: http://dbox.cyberphoria.org/
Kommentar:
Diese GUI wurde von Grund auf neu programmiert und sollte nun vom
Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert
auf der Client-Server Idee, diese GUI ist also von der direkten DBox-
Steuerung getrennt. Diese wird dann von Daemons uebernommen.
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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gui/audioplayer.h>
#include <global.h>
#include <neutrino.h>
#include <driver/encoding.h>
#include <driver/fontrenderer.h>
#include <driver/rcinput.h>
#include <driver/audioplay.h>
#include <driver/audiometadata.h>
#include <daemonc/remotecontrol.h>
#include <gui/eventlist.h>
#include <gui/color.h>
#include <gui/infoviewer.h>
#ifdef ENABLE_GUI_MOUNT
#include <gui/nfs.h>
#endif
#include <gui/widget/buttons.h>
#include <gui/widget/icons.h>
#include <gui/widget/menue.h>
#include <gui/widget/messagebox.h>
#include <gui/widget/hintbox.h>
#include <gui/widget/stringinput.h>
#include <gui/widget/stringinput_ext.h>
#include <system/settings.h>
#include <xmltree/xmlinterface.h>
#include <driver/screen_max.h>
#include <algorithm>
#include <sys/time.h>
#include <fstream>
#include <iostream>
#include <sstream>
#if 0
#ifdef ENABLE_LIRC
#include <irsend/irsend.h>
#endif
#if HAVE_DVB_API_VERSION >= 3
#include <linux/dvb/audio.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/video.h>
#define ADAP "/dev/dvb/adapter0"
#define ADEC ADAP "/audio0"
#define VDEC ADAP "/video0"
#define DMX ADAP "/demux0"
#define DVR ADAP "/dvr0"
#endif
#endif
#include <video_cs.h>
extern cVideo * videoDecoder;
#ifdef ConnectLineBox_Width
#undef ConnectLineBox_Width
#endif
#define ConnectLineBox_Width 16
#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 CONFIGDIR "/audioplayer.start"
#define AUDIOPLAYER_END_SCRIPT CONFIGDIR "/audioplayer.end"
#define DEFAULT_RADIOSTATIONS_XMLFILE CONFIGDIR "/radio-stations.xml"
const long int GET_PLAYLIST_TIMEOUT = 10;
const char RADIO_STATION_XML_FILE[] = {DEFAULT_RADIOSTATIONS_XMLFILE};
const std::string icecasturl = "http://dir.xiph.org/yp.xml";
const long int GET_ICECAST_TIMEOUT = 90; // list is about 500kB!
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;
}
//------------------------------------------------------------------------
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static void *myrealloc(void *ptr, size_t size)
{
/* There might be a realloc() out there that doesn't like reallocing
NULL pointers, so we take care of it here */
if (ptr)
return realloc(ptr, size);
else
return malloc(size);
}
static size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
if (mem->memory) {
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
// we borrow this from filebrowser
extern size_t CurlWriteToString(void *ptr, size_t size, size_t nmemb, void *data);
CAudioPlayerGui::CAudioPlayerGui(bool /*inetmode*/)
{
m_frameBuffer = CFrameBuffer::getInstance();
m_visible = false;
m_inetmode = false; //inetmode;//FIXME
Init();
}
void CAudioPlayerGui::Init(void)
{
stimer = 0;
m_selected = 0;
m_metainfo.clear();
m_select_title_by_name = g_settings.audioplayer_select_title_by_name==1;
if (strlen(g_settings.network_nfs_audioplayerdir)!=0)
m_Path = g_settings.network_nfs_audioplayerdir;
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");
#ifdef ENABLE_FLAC
audiofilefilter.addFilter("flac");
#endif
}
m_SMSKeyInput.setTimeout(AUDIOPLAYERGUI_SMSKEY_TIMEOUT);
}
//------------------------------------------------------------------------
CAudioPlayerGui::~CAudioPlayerGui()
{
m_playlist.clear();
m_radiolist.clear();
m_filelist.clear();
m_title2Pos.clear();
g_Zapit->setStandby (false);
g_Sectionsd->setPauseScanning (false);
}
//------------------------------------------------------------------------
int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &)
{
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;
}
if (m_playlist.empty())
m_current = -1;
else
m_current = 0;
m_selected = 0;
//m_width = 710;
//if((g_settings.screen_EndX - g_settings.screen_StartX) < m_width+ConnectLineBox_Width)
m_width=(g_settings.screen_EndX - g_settings.screen_StartX) - ConnectLineBox_Width - 5;
//m_height = 570;
//if((g_settings.screen_EndY - g_settings.screen_StartY) < m_height)
m_height = (g_settings.screen_EndY - g_settings.screen_StartY - 5);
m_sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight();
m_buttonHeight = std::min(25, m_sheight);
m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight();
m_fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight();
m_title_height = m_fheight*2 + 20 + m_sheight + 4;
m_info_height = m_fheight*2;
m_listmaxshow = (m_height - m_info_height - m_title_height - m_theight - 2*m_buttonHeight) / (m_fheight);
m_height = m_theight + m_info_height + m_title_height + 2*m_buttonHeight + m_listmaxshow * m_fheight; // recalc height
m_x = getScreenStartX( m_width + ConnectLineBox_Width ) + ConnectLineBox_Width;
m_y = getScreenStartY( m_height );
m_idletime=time(NULL);
m_screensaver=false;
if (parent)
{
parent->hide();
}
#if 0
if (g_settings.video_Format != g_settings.video_backgroundFormat)
g_Controld->setVideoFormat(g_settings.video_backgroundFormat);
#endif
bool usedBackground = m_frameBuffer->getuseBackground();
if (usedBackground)
m_frameBuffer->saveBackgroundImage();
// set zapit in standby mode
g_Zapit->stopPlayBack();
videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg");
// tell neutrino we're in audio mode
CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio );
#if 0
// remember last mode
CZapitClient::responseGetLastChannel firstchannel;
g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode);
if ((firstchannel.mode == 'r') ?
(CNeutrinoApp::getInstance()->zapto_radio_on_init_done) :
(CNeutrinoApp::getInstance()->zapto_tv_on_init_done))
m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap);
else
m_LastMode=(CNeutrinoApp::getInstance()->getLastMode());
#endif
m_LastMode=(CNeutrinoApp::getInstance()->getLastMode());
// Stop sectionsd
g_Sectionsd->setPauseScanning(true);
puts("[audioplayer.cpp] executing " AUDIOPLAYER_START_SCRIPT ".");
if (system(AUDIOPLAYER_START_SCRIPT) != 0)
perror("Datei " AUDIOPLAYER_START_SCRIPT " fehlt.Bitte erstellen, wenn gebraucht.\nFile " AUDIOPLAYER_START_SCRIPT " not found. Please create if needed.\n");
show();
// Restore previous background
if (usedBackground)
m_frameBuffer->restoreBackgroundImage();
m_frameBuffer->useBackground(usedBackground);
m_frameBuffer->paintBackground();
// Restore last mode
//t_channel_id channel_id=CNeutrinoApp::getInstance()->channelList->getActiveChannel_ChannelID();
//g_Zapit->zapTo_serviceID(channel_id);
//g_Zapit->setStandby(false);
puts("[audioplayer.cpp] executing " AUDIOPLAYER_END_SCRIPT ".");
if (system(AUDIOPLAYER_END_SCRIPT) != 0)
perror("Datei " AUDIOPLAYER_END_SCRIPT " fehlt. Bitte erstellen, wenn gebraucht.\nFile " AUDIOPLAYER_END_SCRIPT " not found. Please create if needed.\n");
// Start Sectionsd
g_Sectionsd->setPauseScanning(false);
videoDecoder->StopPicture();
CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode );
g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 );
// always exit all
return menu_return::RETURN_EXIT_ALL;
}
//------------------------------------------------------------------------
int CAudioPlayerGui::show()
{
neutrino_msg_t msg;
neutrino_msg_data_t data;
int pic_index = 0;
int ret = -1;
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
bool loop = true;
bool update = true;
bool clear_before_update = false;
m_key_level = 0;
while (loop)
{
if (!m_screensaver)
{
updateMetaData();
}
updateTimes();
if (CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_audio)
{
// stop if mode was changed in another thread
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 (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_timeout || msg == NeutrinoMessages::EVT_TIMER)
{
int timeout = time(NULL) - m_idletime;
int screensaver_timeout = atoi(g_settings.audioplayer_screensaver);
if (screensaver_timeout !=0 && timeout > screensaver_timeout*60 && !m_screensaver)
screensaver(true);
if (msg == NeutrinoMessages::EVT_TIMER && data == stimer) {
if (m_screensaver) {
char fname[255];
sprintf(fname, "%s/mp3-%d.jpg", DATADIR "/neutrino/icons", pic_index);
int lret = access(fname, F_OK);
printf("CAudioPlayerGui::show: new pic %s: %s\n", fname, lret ? "not found" : "found");
if (lret == 0) {
pic_index++;
videoDecoder->StopPicture();
videoDecoder->ShowPicture(fname);
} else if (pic_index) {
pic_index = 0;
videoDecoder->StopPicture();
videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg");
}
} else
pic_index = 0;
}
}
else
{
m_idletime = time(NULL);
if (m_screensaver)
{
screensaver(false);
}
}
if ( msg == CRCInput::RC_tv)
{
if (m_inetmode) {
m_inetmode = false;
m_radiolist = m_playlist;
m_playlist = m_filelist;
} else {
m_inetmode = true;
m_filelist = m_playlist;
m_playlist = m_radiolist;
}
Init();
clear_before_update = true;
update = true;
}
else if (msg == CRCInput::RC_home || msg == CRCInput::RC_stop)
{
if (m_state != CAudioPlayerGui::STOP)
stop();
else
loop=false;
}
else if (msg == CRCInput::RC_left)
{
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)
{
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 step = 0;
int prevselected = m_selected;
step = msg == CRCInput::RC_page_up ? m_listmaxshow : 1;
m_selected -= step;
if ((prevselected-step) < 0)
m_selected = m_playlist.size()-1;
#if 0
if (m_selected == 0)
{
m_selected = m_playlist.size()-1;
}
else
{
m_selected--;
}
#endif
paintItem(prevselected - m_liststart);
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow;
if (oldliststart != m_liststart)
{
update = true;
}
else
{
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();
paintItem(prevselected - m_liststart);
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow;
if (oldliststart != m_liststart)
{
update = true;
}
else
{
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())
{
//xx CPlayList::iterator p = m_playlist.begin()+selected;
removeFromPlaylist(m_selected);
if ((int)m_selected == m_current)
{
m_current--;
//stop(); // Stop if song is deleted, next song will be startet automat.
}
if (m_selected >= m_playlist.size())
m_selected = m_playlist.size() == 0 ? 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_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_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_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, 400);
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_LOC, true, NULL, InetRadioInputChanger,
cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count);
sprintf(cnt, "%d", ++count);
InputSelector.addItem(new CMenuForwarder(
LOCALE_AUDIOPLAYER_ADD_SC, 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);
//InputSelector.addItem(GenericMenuSeparator);
hide();
InputSelector.exec(NULL, "");
if (select >= 0)
old_select = select;
switch (select) {
case 0:
scanXmlFile(RADIO_STATION_XML_FILE);
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
break;
case 1:
openSCbrowser();
break;
case 2:
readDir_ic();
CVFD::getInstance()->setMode(CVFD::MODE_AUDIO);
paintLCD();
break;
default:
break;
}
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;
}
}
}
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 (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;
do
{
smsKey = m_SMSKeyInput.handleMsg(msg);
//printf(" new key: %c", smsKey);
g_RCInput->getMsg_ms(&msg, &data, AUDIOPLAYERGUI_SMSKEY_TIMEOUT - 200);
/* show a hint box with current char (too slow at the moment?)*/
#if 1
char selectedKey[1];
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();
int w = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(selectedKey);
m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_MENUCONTENT_PLUS_6);
m_frameBuffer->paintBoxRel(x1 - 4, y1 - h - 3, w + 8, h + 6, COL_MENUCONTENTSELECTED_PLUS_0);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]
->RenderString(x1,y1,w+1,selectedKey,COL_MENUCONTENTSELECTED,0);
#endif
} 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;
//pushback key if...
//g_RCInput->postMsg( msg, data );
//loop = false;
}
#endif
else if (msg == NeutrinoMessages::CHANGEMODE)
{
if ((data & NeutrinoMessages::mode_mask) != NeutrinoMessages::mode_audio)
{
loop = false;
m_LastMode=data;
}
}
else if (msg == NeutrinoMessages::RECORD_START ||
msg == NeutrinoMessages::ZAPTO ||
msg == NeutrinoMessages::STANDBY_ON ||
msg == NeutrinoMessages::SHUTDOWN ||
msg == NeutrinoMessages::SLEEPTIMER)
{
// 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 )
{
loop = false;
}
// update mute icon
//paintHead();
//paintLCD();
}
}
hide();
if (m_state != CAudioPlayerGui::STOP)
stop();
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);
}
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;
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 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 tmp = mp3.Filename.substr(mp3.Filename.rfind('/')+1);
mp3.MetaData.title = tmp;
}
if (bitrate)
mp3.MetaData.total_time = bitrate;
else
mp3.MetaData.total_time = 0;
if (url[0] != '#') {
addToPlaylist(mp3);
}
}
void CAudioPlayerGui::processPlaylistUrl(const char *url, const char *name, const time_t tim) {
CURL *curl_handle;
struct MemoryStruct chunk;
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);
/* cleanup curl stuff */
curl_easy_cleanup(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);
ptr = strstr(line, "http://");
if (ptr != NULL) {
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, tim);
}
}
}
}
}
if (chunk.memory)
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
}
void CAudioPlayerGui::readDir_ic(void)
{
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, "server_name", "listen_url", "bitrate", true);
}
else
scanBox->hide();
delete scanBox;
}
void CAudioPlayerGui::scanXmlFile(std::string filename)
{
xmlDocPtr answer_parser = parseXmlFile(filename.c_str());
scanXmlData(answer_parser, "name", "url");
}
void CAudioPlayerGui::scanXmlData(xmlDocPtr answer_parser, const char *nametag, const char *urltag,
const char *bitratetag, bool usechild)
{
#define IC_typetag "server_type"
if (answer_parser != NULL) {
xmlNodePtr element = xmlDocGetRootElement(answer_parser);
element = element->xmlChildrenNode;
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 = element->xmlNextNode;
}
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) {
char *ptr = NULL;
char *name = NULL;
char *url = NULL;
char *type = NULL;
time_t bitrate = 0;
bool skip = true;
listPos++;
// show status
int global = 100*listPos / maxProgress;
progress.showGlobalStatus(global);
#ifdef LCD_UPDATE
CVFD::getInstance()->showProgressBar(global, "read xmldata...");
CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR);
#endif // LCD_UPDATE
if (usechild) {
xmlNodePtr child = element->xmlChildrenNode;
while (child) {
if (strcmp(xmlGetName(child), nametag) == 0)
name = xmlGetData(child);
else if (strcmp(xmlGetName(child), urltag) == 0)
url = 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 = child->xmlNextNode;
}
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);
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);
else
addUrl2Playlist(url, name, bitrate);
}
element = element->xmlNextNode;
g_RCInput->getMsg(&msg, &data, 0);
}
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 : "");
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.showGlobalStatus(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_FLAC
|| (files->getType() == CFile::FILE_FLAC)
#endif
)
{
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];
infile.open(files->Name.c_str(), std::ifstream::in);
while (infile.good())
{
infile.getline(cLine, 255);
// remove CR
if (cLine[strlen(cLine)-1]=='\r')
cLine[strlen(cLine)-1]=0;
if (strlen(cLine) > 0 && cLine[0]!='#')
{
char *url = strstr(cLine, "http://");
if (url != NULL) {
if (strstr(url, ".m3u") || strstr(url, ".pls"))
processPlaylistUrl(url);
} 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; i<m_playlist.size(); i++)
{
if (m_playlist[i].Filename == filename)
removeFromPlaylist(i);
}
#endif
if (strcasecmp(filename.substr(filename.length()-3,3).c_str(), "url")==0)
{
addUrl2Playlist(filename.c_str());
}
else
{
CFile playlistItem;
playlistItem.Name = filename;
CFile::FileType fileType = playlistItem.getType();
if (fileType == CFile::FILE_CDR
|| fileType == CFile::FILE_MP3
|| fileType == CFile::FILE_OGG
|| fileType == CFile::FILE_WAV
#ifdef ENABLE_FLAC
|| fileType == CFile::FILE_FLAC
#endif
)
{
CAudiofileExt audioFile(filename,fileType);
addToPlaylist(audioFile);
} else
{
printf("Audioplayer: file type (%d) is *not* supported in playlists\n(%s)\n",
fileType, filename.c_str());
}
}
}
testfile.close();
}
}
}
infile.close();
}
else if (files->getType() == 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
result = true;
}
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);
}
//------------------------------------------------------------------------
#define SC_BASE_DIR "http://www.shoutcast.com"
#define SC_INIT_DIR "/sbin/newxml.phtml"
bool CAudioPlayerGui::openSCbrowser(void)
{
bool result = false;
CFileBrowser filebrowser(SC_BASE_DIR, CFileBrowser::ModeSC);
filebrowser.Multi_Select = true;
filebrowser.Dirs_Selectable = true;
filebrowser.Filter = NULL;//&audiofilefilter;
hide();
if (filebrowser.exec(SC_INIT_DIR))
{
#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.showGlobalStatus(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(), files->Time);
g_RCInput->getMsg(&msg, &data, 0);
}
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;
}
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)
{
m_frameBuffer->paintBackgroundBoxRel(m_x - ConnectLineBox_Width-1, m_y + m_title_height - 1,
m_width + ConnectLineBox_Width+2, m_height + 2 - m_title_height);
clearItemID3DetailsLine();
m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width, m_title_height);
m_visible = false;
}
}
//------------------------------------------------------------------------
void CAudioPlayerGui::paintItem(int pos)
{
if (!m_show_playlist)
return;
int ypos = m_y + m_title_height + m_theight + pos*m_fheight;
int c_rad_small;
uint8_t color;
fb_pixel_t bgcolor;
if ((pos + m_liststart) == m_selected)
{
if ((pos + m_liststart) == (unsigned)m_current)
{
color = COL_MENUCONTENTSELECTED + 2;
bgcolor = COL_MENUCONTENTSELECTED_PLUS_2;
}
else
{
color = COL_MENUCONTENTSELECTED;
bgcolor = COL_MENUCONTENTSELECTED_PLUS_0;
}
paintItemID3DetailsLine(pos);
c_rad_small = RADIUS_SMALL;
}
else
{
if (((pos + m_liststart) < m_playlist.size()) && (pos & 1))
{
if ((pos + m_liststart) == (unsigned)m_current)
{
color = COL_MENUCONTENTDARK + 2;
bgcolor = COL_MENUCONTENTDARK_PLUS_2;
}
else
{
color = COL_MENUCONTENTDARK;
bgcolor = COL_MENUCONTENTDARK_PLUS_0;
}
}
else
{
if ((pos + m_liststart) == (unsigned)m_current)
{
color = COL_MENUCONTENT + 2;
bgcolor = COL_MENUCONTENT_PLUS_2;
}
else
{
color = COL_MENUCONTENT;
bgcolor = COL_MENUCONTENT_PLUS_0;
}
}
c_rad_small = 0;
}
m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor, c_rad_small);
if ((pos + m_liststart) < m_playlist.size())
{
if (m_playlist[pos + m_liststart].FileType != CFile::STREAM_AUDIO &&
!m_playlist[pos + m_liststart].MetaData.bitrate)
{
// id3tag noch nicht geholt
GetMetaData(m_playlist[pos + m_liststart]);
if (m_state != CAudioPlayerGui::STOP && !g_settings.audioplayer_highprio)
usleep(100*1000);
}
char sNr[20];
sprintf(sNr, "%2d : ", pos + m_liststart + 1);
std::string tmp = sNr;
getFileInfoToDisplay(tmp, m_playlist[pos + m_liststart]);
char dura[9];
if (m_inetmode)
snprintf(dura, 8, "%ldk", m_playlist[pos + m_liststart].MetaData.total_time);
else
snprintf(dura, 8, "%ld:%02ld", m_playlist[pos + m_liststart].MetaData.total_time / 60,
m_playlist[pos + m_liststart].MetaData.total_time % 60);
int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(dura) + 5;
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos + m_fheight, m_width - 30 - w,
tmp, color, m_fheight, true); // UTF-8
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight,
w, dura, color, m_fheight);
if ((pos + m_liststart) == m_selected)
{
if (m_state == CAudioPlayerGui::STOP)
{
CVFD::getInstance()->showAudioTrack(m_playlist[pos + m_liststart].MetaData.artist,
m_playlist[pos + m_liststart].MetaData.title,
m_playlist[pos + m_liststart].MetaData.album);
}
}
}
}
//--------------playlist----------------------------------------------------------
void CAudioPlayerGui::paintHead()
{
if (!m_show_playlist)
return;
int c_rad_mid = RADIUS_MID;
std::string strCaption;
if (m_inetmode)
strCaption = g_Locale->getText(LOCALE_INETRADIO_NAME);
else
strCaption = g_Locale->getText(LOCALE_AUDIOPLAYER_HEAD);
m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_TOP);
m_frameBuffer->paintIcon(NEUTRINO_ICON_MP3,m_x + 7, m_y + m_title_height + 10);
g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0,
m_width - 45, strCaption, COL_MENUHEAD, 0, true); // UTF-8
int ypos = m_y + m_title_height;
if (m_theight > 26)
ypos = (m_theight - 26) / 2 + m_y + m_title_height;
#ifdef ENABLE_GUI_MOUNT
if (!m_inetmode)
m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos);
#endif
#if 1
if ( CNeutrinoApp::getInstance()->isMuted() )
{
int xpos = m_x + m_width - 75;
ypos = m_y + m_title_height;
if (m_theight > 32)
ypos = (m_theight - 32) / 2 + m_y + m_title_height;
m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos);
}
#endif
}
//------------------------------------------------------------------------
const struct button_label AudioPlayerButtons[][4] =
{
{
{ NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_STOP },
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_REWIND },
{ NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_PAUSE },
{ NEUTRINO_ICON_BUTTON_BLUE , 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_RED , LOCALE_AUDIOPLAYER_STOP },
{ NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_PAUSE },
},
{
{ 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 },
},
};
//------------------------------------------------------------------------
void CAudioPlayerGui::paintFoot()
{
// printf("paintFoot{\n");
int top;
int c_rad_mid = RADIUS_MID;
if (m_show_playlist)
top = m_y + (m_height - m_info_height - 2 * m_buttonHeight);
else
top = m_y + (m_height - 2 * m_buttonHeight);
int ButtonWidth = (m_width - 20) / 4;
int ButtonWidth2 = (m_width - 50) / 2;
m_frameBuffer->paintBoxRel(m_x, top, m_width, 2 * m_buttonHeight, COL_INFOBAR_SHADOW_PLUS_1, c_rad_mid, CORNER_BOTTOM);
m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_1);
if (!m_playlist.empty())
{
// play
m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, m_x + 1 * ButtonWidth2 + 25, top + m_buttonHeight - 3);
g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]
->RenderString(m_x + 1 * ButtonWidth2 + 53, top + m_buttonHeight + 24 - 4, ButtonWidth2 - 28,
g_Locale->getText(LOCALE_AUDIOPLAYER_PLAY), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8
// keylevel switch
m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, m_x + 0 * ButtonWidth + 25, top + m_buttonHeight - 3);
g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]
->RenderString(m_x + 0 * ButtonWidth + 53 , top + m_buttonHeight + 24 - 4, ButtonWidth2 - 28,
g_Locale->getText(LOCALE_AUDIOPLAYER_KEYLEVEL), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8
}
if (m_key_level == 0)
{
if (m_playlist.empty()) {
if (m_inetmode)
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[7]);
else
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + 10, top + 4, ButtonWidth, 1, &(AudioPlayerButtons[7][0]));
} else if (m_inetmode)
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[8]);
else
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[1]);
}
else if (m_key_level == 1)
{
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO)
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[0]);
}
else
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[6]);
}
}
else
{ // key_level == 2
if (m_state == CAudioPlayerGui::STOP)
{
if (m_select_title_by_name)
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + ButtonWidth + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[5]);
}
else
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + ButtonWidth + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[4]);
}
}
else
{
if (m_select_title_by_name)
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + ButtonWidth + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[3]);
}
else
{
::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale,
m_x + ButtonWidth + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[2]);
}
}
}
}
//------------------------------------------------------------------------
void CAudioPlayerGui::paintInfo()
{
int c_rad_mid = RADIUS_MID;
if (m_state == CAudioPlayerGui::STOP && m_show_playlist)
m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width, m_title_height);
else
{
if (!m_show_playlist)
{
// no playlist -> smaller Info-Box
m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10 - m_fheight, COL_MENUCONTENT_PLUS_6, c_rad_mid);
m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2 , m_width - 4, m_title_height - 14 - m_fheight, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid);
}
else
{
m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, c_rad_mid);
m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2 , m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid);
}
// 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, true); // UTF-8
int xstart = (m_width - w) / 2;
if (xstart < 10)
xstart = 10;
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_fheight, m_width - 20,
tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8
// second line (Artist/Title...)
if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO &&
!m_curr_audiofile.MetaData.bitrate)
{
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, true); // UTF-8
xstart=(m_width-w)/2;
if (xstart < 10)
xstart=10;
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x+xstart, m_y +4+ 2*m_fheight, m_width- 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8
// 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)
{
m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow;
paintHead();
for (unsigned int count=0; count<m_listmaxshow; count++)
{
paintItem(count);
}
int ypos = m_y + m_title_height + m_theight;
int sb = m_fheight * m_listmaxshow;
m_frameBuffer->paintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1);
int sbc = ((m_playlist.size() - 1) / m_listmaxshow) + 1;
int sbs = (m_selected / m_listmaxshow);
m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc , 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3, RADIUS_SMALL);
}
paintFoot();
paintInfo();
m_visible = true;
}
//------------------------------------------------------------------------
void CAudioPlayerGui::clearItemID3DetailsLine ()
{
paintItemID3DetailsLine(-1);
}
//------------------------------------------------------------------------
void CAudioPlayerGui::paintItemID3DetailsLine (int pos)
{
int xpos = m_x - ConnectLineBox_Width;
int ypos1 = m_y + m_title_height + m_theight+ 0 + pos*m_fheight;
int ypos2 = m_y + (m_height - m_info_height);
int ypos1a = ypos1 + (m_fheight / 2) - 2;
int ypos2a = ypos2 + (m_info_height / 2) - 2;
fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6;
fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1;
int c_rad_small = RADIUS_SMALL;
// Clear
m_frameBuffer->paintBackgroundBoxRel(xpos - 1, m_y + m_title_height, ConnectLineBox_Width + 1,
m_height - m_title_height);
// paint Line if detail info (and not valid list pos)
if (!m_playlist.empty() && (pos >= 0))
{
// 1. col thick line
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos1, 4, m_fheight, col2, c_rad_small, CORNER_LEFT);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 3, ypos1, 8, m_fheight, col1, c_rad_small, CORNER_LEFT); // item marker
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos2, 4, m_info_height, col1);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 4, ypos2a - ypos1a, col1);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 12, 4, col1);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos2a, 12, 4, col1);
// 2. col small line
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos2, 1, m_info_height, col2);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 1, ypos2a - ypos1a + 4, col2);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 12, 1, col2);
m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 12, ypos2a, 8, 1, col2);
// -- small Frame around infobox
m_frameBuffer->paintBoxRel(m_x, ypos2 , 2 , m_info_height , col1);
m_frameBuffer->paintBoxRel(m_x + m_width - 2, ypos2 , 2 , m_info_height , col1);
m_frameBuffer->paintBoxRel(m_x, ypos2 , m_width -2 , 2 , col1);
m_frameBuffer->paintBoxRel(m_x, ypos2 + m_info_height -2, m_width -2 , 2 , col1);
// m_frameBuffer->paintBoxRel(m_x, ypos2, m_width, m_info_height, col1);
// paint id3 infobox
m_frameBuffer->paintBoxRel(m_x + 2, ypos2 + 2 , m_width - 4, m_info_height - 4, COL_MENUCONTENTDARK_PLUS_0);
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos2 + 2 + 1*m_fheight, m_width- 80,
m_playlist[m_selected].MetaData.title, COL_MENUCONTENTDARK, 0, true); // UTF-8
std::string tmp;
if (m_playlist[m_selected].MetaData.genre.empty())
tmp = m_playlist[m_selected].MetaData.date;
else if (m_playlist[m_selected].MetaData.date.empty())
tmp = m_playlist[m_selected].MetaData.genre;
else
{
tmp = m_playlist[m_selected].MetaData.genre;
tmp += " / ";
tmp += m_playlist[m_selected].MetaData.date;
}
int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true) + 10; // UTF-8
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w - 5, ypos2 + 2 + 1*m_fheight,
w, tmp, COL_MENUCONTENTDARK, 0, true); // UTF-8
tmp = m_playlist[m_selected].MetaData.artist;
if (!(m_playlist[m_selected].MetaData.album.empty()))
{
tmp += " (";
tmp += m_playlist[m_selected].MetaData.album;
tmp += ')';
}
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos2 + 2*m_fheight - 2, m_width - 20,
tmp, COL_MENUCONTENTDARK, 0, true); // UTF-8
}
else
{
m_frameBuffer->paintBackgroundBoxRel(m_x, ypos2, m_width, m_info_height);
}
}
//------------------------------------------------------------------------
void CAudioPlayerGui::stop()
{
m_state = CAudioPlayerGui::STOP;
m_current = 0;
//LCD
paintLCD();
//Display
paintInfo();
m_key_level = 0;
paintFoot();
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
}
//------------------------------------------------------------------------
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;
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 (!m_screensaver)
paint();
}
else if (m_liststart < m_selected && g_settings.audioplayer_follow)
{
m_liststart = m_selected - m_listmaxshow + 1;
if (!m_screensaver)
paint();
}
else
{
if (old_current >= m_liststart && old_current - m_liststart < m_listmaxshow)
{
if (!m_screensaver)
paintItem(old_current - m_liststart);
}
if (pos >= m_liststart && pos - m_liststart < m_listmaxshow)
{
if (!m_screensaver)
paintItem(pos - m_liststart);
}
if (g_settings.audioplayer_follow)
{
if (old_selected >= m_liststart && old_selected - m_liststart < m_listmaxshow)
if (!m_screensaver)
paintItem(old_selected - m_liststart);
}
}
if (m_playlist[pos].FileType != CFile::STREAM_AUDIO &&
!m_playlist[pos].MetaData.bitrate)
{
// id3tag noch nicht geholt
//printf("play: need getMetaData\n");
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];
// Play
CAudioPlayer::getInstance()->play(&m_curr_audiofile, g_settings.audioplayer_highprio == 1);
//LCD
paintLCD();
// Display
if (!m_screensaver)
paintInfo();
m_key_level = 1;
if (!m_screensaver)
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 || !m_show_playlist)
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 = true;
if (!meta.artist.empty() &&
meta.artist != m_curr_audiofile.MetaData.artist)
{
m_curr_audiofile.MetaData.artist = meta.artist;
updateScreen = true;
updateLcd = true;
}
if (!meta.title.empty() &&
meta.title != m_curr_audiofile.MetaData.title)
{
m_curr_audiofile.MetaData.title = meta.title;
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 (CAudioPlayer::getInstance()->getScBuffered() != 0)
if (CAudioPlayer::getInstance()->hasMetaDataChanged() != 0)
{
updateLcd = true;
}
//printf("CAudioPlayerGui::updateMetaData: updateLcd %d\n", updateLcd);
if (updateLcd)
paintLCD();
if (updateScreen)
paintInfo();
if (updateMeta || updateScreen)
{
m_frameBuffer->paintBoxRel(m_x + 10, m_y + 4 + 2*m_fheight, m_width - 20,
m_sheight, COL_MENUCONTENTSELECTED_PLUS_0);
int xstart = ((m_width - 20 - g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(m_metainfo))/2)+10;
g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]
->RenderString(m_x + xstart, m_y + 4 + 2*m_fheight + m_sheight,
m_width- 2*xstart, m_metainfo, COL_MENUCONTENTSELECTED);
}
}
//------------------------------------------------------------------------
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 (!m_screensaver)
{
char tot_time[11];
snprintf(tot_time, 10, " / %ld:%02ld", m_time_total / 60, m_time_total % 60);
char tmp_time[8];
snprintf(tmp_time, 7, "%ld:00", m_time_total / 60);
char play_time[8];
snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60);
int w1 = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tot_time);
int w2 = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp_time);
if (updateTotal)
{
m_frameBuffer->paintBoxRel(m_x + m_width - w1 - 10, m_y + 4, w1 + 4,
m_fheight, COL_MENUCONTENTSELECTED_PLUS_0);
if (m_time_total > 0)
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w1 - 10, m_y + 4 + m_fheight,
w1, tot_time, COL_MENUCONTENTSELECTED);
}
if (updatePlayed || (m_state == CAudioPlayerGui::PAUSE))
{
//m_frameBuffer->paintBoxRel(m_x + m_width - w1 - w2 - 15, m_y + 4, w2 + 4, m_fheight,
m_frameBuffer->paintBoxRel(m_x + m_width - w1 - w2 - 16, m_y + 4, w2 + 5, m_fheight,
COL_MENUCONTENTSELECTED_PLUS_0);
struct timeval tv;
gettimeofday(&tv, NULL);
if ((m_state != CAudioPlayerGui::PAUSE) || (tv.tv_sec & 1))
{
g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w1 - w2 - 11, m_y + 4 + m_fheight,
w2+4, play_time, COL_MENUCONTENTSELECTED);
}
}
}
if ((updatePlayed || updateTotal) && m_time_total != 0)
{
CVFD::getInstance()->showAudioProgress(100 * m_time_played / m_time_total, CNeutrinoApp::getInstance()->isMuted());
}
}
}
//------------------------------------------------------------------------
void CAudioPlayerGui::paintLCD()
{
switch (m_state)
{
case CAudioPlayerGui::STOP:
CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_STOP);
CVFD::getInstance()->showAudioProgress(0, CNeutrinoApp::getInstance()->isMuted());
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(100 * m_time_played / m_time_total, CNeutrinoApp::getInstance()->isMuted());
#ifdef INCLUDE_UNUSED_STUFF
else
CVFD::getInstance()->showAudioProgress(100 * CAudioPlayer::getInstance()->getScBuffered() / 65536, CNeutrinoApp::getInstance()->isMuted());
#endif /* INCLUDE_UNUSED_STUFF */
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::screensaver(bool on)
{
if (on)
{
m_screensaver = true;
m_frameBuffer->ClearFrameBuffer();
stimer = g_RCInput->addTimer(10*1000*1000, false);
}
else
{
if (stimer)
g_RCInput->killTimer(stimer);
stimer = 0;
m_screensaver = false;
#if 0
m_frameBuffer->loadPal("radiomode.pal", 18, COL_MAXFREE);
m_frameBuffer->useBackground(m_frameBuffer->loadBackground(NEUTRINO_ICON_RADIOMODE));// set useBackground true or false
m_frameBuffer->paintBackground();
#endif
paint();
m_idletime = time(NULL);
}
}
//------------------------------------------------------------------------
void CAudioPlayerGui::GetMetaData(CAudiofileExt &File)
{
// printf("GetMetaData\n");
bool ret = 1;
if (CFile::STREAM_AUDIO != File.FileType)
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) {
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_MENUCONTENT_PLUS_6);
m_frameBuffer->paintBoxRel(x1 - 4, y1 - h - 3, w + 8, h + 6, COL_MENUCONTENTSELECTED_PLUS_0);
g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1, y1, w + 1, str, COL_MENUCONTENTSELECTED, 0);
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 &info, CAudiofileExt &file)
{
std::string fileInfo;
std::string artist;
std::string title;
if (!m_inetmode) {
artist ="Artist?";
title = "Title?";
}
if (!file.MetaData.bitrate)
{
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;
fileInfo += ')';
}
if (fileInfo.empty())
{
fileInfo += "Unknown";
}
file.firstChar = tolower(fileInfo[0]);
info += fileInfo;
}
//------------------------------------------------------------------------
void CAudioPlayerGui::addToPlaylist(CAudiofileExt &file)
{
//printf("add2Playlist: %s\n", file.Filename.c_str());
if (m_select_title_by_name)
{
if (!file.MetaData.bitrate)
{
std::string t = "";
getFileInfoToDisplay(t,file);
}
}
m_playlist.push_back(file);
m_playlistHasChanged = true;
}
//------------------------------------------------------------------------
void CAudioPlayerGui::removeFromPlaylist(long pos)
{
unsigned char firstChar = ' ';
if (m_select_title_by_name)
{
// must be called before m_playlist.erase()
firstChar = getFirstChar(m_playlist[pos]);
}
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())
{
//const CPosList::size_type del =
item->second.erase(pos);
// delete empty entries
if (item->second.size() == 0)
{
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.clear();
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.size() > 0)
{
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;
paintItem(prevselected - m_liststart);
unsigned int oldliststart = m_liststart;
m_liststart = (m_selected / m_listmaxshow)*m_listmaxshow;
//printf("before paint\n");
if (oldliststart != m_liststart)
{
paint();
}
else
{
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++)
{
// if (m_state == CAudioPlayerGui::PLAY)
// usleep(10*1000);
listPos++;
progress.showGlobalStatus(100*listPos / maxProgress);
//std::string info;
progress.showStatusMessageUTF(it->Filename);
unsigned char firstChar = getFirstChar(*it);
const std::pair<CTitle2Pos::iterator,bool> 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 (strlen(g_settings.network_nfs_audioplayerdir) != 0)
path = g_settings.network_nfs_audioplayerdir;
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;
char filename[filenamesize + 1] = "";
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;
}
snprintf(filename, name.size(), "%s", name.c_str());
}
else if (file->getType() == CFile::FILE_DIR)
{
// query for filename
this->hide();
CStringInputSMS filenameInput(LOCALE_AUDIOPLAYER_PLAYLIST_NAME,
filename,
filenamesize - 1,
LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT1,
LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT2,
"abcdefghijklmnopqrstuvwxyz0123456789-.,:!?/ ");
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 = (ShowMsgUTF(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_TITLE,
msg,CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo)
== CMessageBox::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<length; i++)
{
if (fromDir[i] == absFilename[i])
{
if (fromDir[i] == '/')
{
lastSlash = i;
}
}
else
{
break;
}
}
// cut common prefix
std::string relFilepath = absFilename.substr(lastSlash + 1, absFilename.length() - lastSlash + 1);
// relFilepath is now devil/2/fire.mp3
// First slash is not removed because we have to go up each directory.
// Since the slashes are counted later we make sure for each directory one slash is present
std::string relFromDir = fromDir.substr(lastSlash, fromDir.length() - lastSlash);
// relFromDir is now /angle/1
// go up as many directories as neccessary
for (unsigned int i=0; i<relFromDir.size(); i++)
{
if (relFromDir[i] == '/')
{
res = res + "../";
}
}
res = res + relFilepath;
return res;
}