📄 player.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Portions Copyright (C) 1998-2000 EMusic.com
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.
$Id: player.cpp,v 1.259 2001/03/02 04:16:57 ijr Exp $
____________________________________________________________________________*/
// The debugger can't handle symbols more than 255 characters long.
// STL often creates symbols longer than that.
// When symbols are longer than 255 characters, the warning is disabled.
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include <iostream>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#include <direct.h>
#define MKDIR(z) mkdir(z)
#else
#define MKDIR(z) mkdir(z, 0755)
#endif
#ifdef __QNX__
#include <strings.h>
#endif
#include <set>
#include "config.h"
#include "event.h"
#include "lmc.h"
#include "player.h"
#include "thread.h"
#include "debug.h"
#include "ui.h"
#include "queue.h"
#include "semaphore.h"
#include "eventdata.h"
#include "registrar.h"
#include "preferences.h"
#include "properties.h"
#include "facontext.h"
#include "log.h"
#include "pmo.h"
#include "utility.h"
#include "downloadmanager.h"
#include "timer.h"
#define DB Debug_v("%s:%d\n", __FILE__, __LINE__);
Player *Player::m_thePlayer = NULL;
const char *szPlaylistExt = ".M3U";
const char *themeExtension = "fat";
#define SEND_NORMAL_EVENT(e) { Event *ev = new Event(e); GetUIManipLock(); \
SendToUI(ev); ReleaseUIManipLock(); delete ev; \
}
Player *
Player::
GetPlayer(FAContext *context)
{
if (m_thePlayer == NULL)
m_thePlayer = new Player(context);
return m_thePlayer;
}
Player::
Player(FAContext *context) : EventQueue()
{
m_context = context;
m_context->player = this;
m_APSInterface = new APSInterface(context);
m_context->aps = m_APSInterface;
bool useProxy = false;
m_context->prefs->GetPrefBoolean(kUseProxyPref, &useProxy);
if (useProxy)
{
uint32 size = 1024;
char *buffer = (char *)malloc(size);
if (kError_BufferTooSmall == m_context->prefs->GetPrefString(
kProxyHostPref, buffer, &size))
{
buffer = (char *)realloc(buffer, size);
m_context->prefs->GetPrefString(kProxyHostPref, buffer, &size);
}
char *port = strrchr(buffer, ':');
if (port) {
*port = '\0';
port++;
}
string proxyAddr = string(buffer, strlen(buffer) + 1);
int nPort = 80;
if (port && *port)
nPort = atoi(port);
free(buffer);
m_APSInterface->SetProxy(proxyAddr.c_str(), nPort);
}
else
m_APSInterface->SetProxy("", 0);
m_signatureThread = NULL;
m_bKillSignature = false;
// cout << "Creating player..." << endl;
m_eventSem = new Semaphore();
m_eventQueue = new Queue < Event * >();
// cout << "Created queue" << endl;
m_eventServiceThread = NULL;
// cout << "Started event thread" << endl;
m_uiList = new vector < UserInterface * >;
// cout << "Created Lists" << endl;
m_uiManipLock = new Mutex();
m_lmcMutex = new Mutex();
m_pmiMutex = new Mutex();
m_pmoMutex = new Mutex();
m_uiMutex = new Mutex();
m_sigStopMutex = new Mutex();
// cout << "Created mutex" << endl;
m_imQuitting = 0;
m_quitWaitingFor = 0;
m_plm = new PlaylistManager(m_context);
m_playerState = PlayerState_Stopped;
m_lmcRegistry = NULL;
m_pmiRegistry = NULL;
m_pmoRegistry = NULL;
m_uiRegistry = NULL;
m_lmcExtensions = NULL;
m_pmiProtocols = NULL;
m_browserUI = NULL;
m_downloadUI = NULL;
m_sigspmo = NULL;
m_pmo = NULL;
m_lmc = NULL;
m_ui = NULL;
m_argUIList = new vector < char *>();
m_argc = 0;
m_argv = NULL;
m_pTermSem = NULL;
m_didUsage = false;
m_autoplay = true;
m_props.RegisterPropertyWatcher("pcm_volume", (PropertyWatcher *) this);
m_context->plm = m_plm;
m_context->props = &m_props;
m_context->target = (EventQueue *) this;
m_context->timerManager = new TimerManager();
// add timer for checking CDs
// this should be used only if there is no way to get notifications
// from the OS since polling is inefficient
#ifndef WIN32
m_cdTimer = NULL;
bool pollCD = false;
m_context->prefs->GetPrefBoolean(kCheckCDAutomaticallyPref, &pollCD);
if (pollCD)
m_context->timerManager->StartTimer(&m_cdTimer, cd_timer, 5, this);
m_cdTimerActive = pollCD;
#endif
// make sure the db dir exists so we have a place to store our
// stuff
char* tempDir = new char[_MAX_PATH];
uint32 length = _MAX_PATH;
struct stat st;
m_context->prefs->GetPrefString(kDatabaseDirPref, tempDir, &length);
if(-1 == stat(tempDir, &st))
{
MKDIR(tempDir);
}
m_musicCatalog = new MusicCatalog(m_context);
m_context->catalog = m_musicCatalog;
string freeampdir = tempDir;
freeampdir += DIR_MARKER_STR;
freeampdir += "metadatabase";
m_musicCatalog->SetDatabase(freeampdir.c_str());
// make sure the music dir exists so we have a place to store our
// stuff
length = _MAX_PATH;
m_context->prefs->GetPrefString(kSaveMusicDirPref, tempDir, &length);
if(-1 == stat(tempDir, &st))
{
MKDIR(tempDir);
}
delete [] tempDir;
m_dlm = new DownloadManager(m_context);
m_context->downloadManager = m_dlm;
m_eqEnabled = false;
memset(m_eqValues, 0, sizeof(m_eqValues));
// Add timer for sync-ing the log to the relatable servers
// only works if a profile is currently active
m_context->timerManager->StartTimer(&m_syncTimer, synclog_timer, 180, this);
}
#define TYPICAL_DELETE(x) /*printf("deleting...\n");*/ if (x) { delete x; x = NULL; }
Player::
~Player()
{
#ifndef WIN32
m_context->timerManager->StopTimer(m_cdTimer);
#endif
m_context->timerManager->StopTimer(m_syncTimer);
TYPICAL_DELETE(m_dlm);
TYPICAL_DELETE(m_pTermSem);
if(m_argUIList)
{
vector<char*>::iterator i = m_argUIList->begin();
for (; i != m_argUIList->end(); i++)
delete [] *i;
delete m_argUIList;
m_argUIList = NULL;
}
if(m_eventServiceThread)
{
m_eventServiceThread->Join();
delete m_eventServiceThread;
m_eventServiceThread = NULL;
}
KillSigThread(NULL);
if(m_pmo)
{
m_pmo->Pause();
delete m_pmo;
m_pmo = NULL;
}
TYPICAL_DELETE(m_eventSem);
TYPICAL_DELETE(m_eventQueue);
// Delete CIOs
if(m_uiList)
{
vector<UserInterface *>::iterator i = m_uiList->begin();
for (; i != m_uiList->end(); i++)
delete *i;
delete m_uiList;
m_uiList = NULL;
}
TYPICAL_DELETE(m_musicCatalog);
TYPICAL_DELETE(m_APSInterface);
TYPICAL_DELETE(m_uiManipLock);
TYPICAL_DELETE(m_lmcMutex);
TYPICAL_DELETE(m_pmiMutex);
TYPICAL_DELETE(m_pmoMutex);
TYPICAL_DELETE(m_uiMutex);
TYPICAL_DELETE(m_lmcRegistry);
TYPICAL_DELETE(m_pmiRegistry);
TYPICAL_DELETE(m_pmoRegistry);
TYPICAL_DELETE(m_uiRegistry);
map<string, RegistryItem *>::iterator i = m_lmcExtensions->begin();
for (; i != m_lmcExtensions->end(); i++)
delete (*i).second;
TYPICAL_DELETE(m_lmcExtensions);
map<string, RegistryItem *>::iterator j = m_pmiProtocols->begin();
for (; j != m_pmiProtocols->end(); j++)
delete (*j).second;
TYPICAL_DELETE(m_pmiProtocols);
TYPICAL_DELETE(m_context->timerManager);
TYPICAL_DELETE(m_sigStopMutex);
TYPICAL_DELETE(m_plm);
}
void
Player::
SetTerminationSemaphore(Semaphore * pSem)
{
m_pTermSem = pSem;
}
/*
return true if parsing was successful, false otherwise.
*/
typedef char *pchar;
bool
Player::
SetArgs(int32 argc, char **argv)
{
bool autoplay = false;
// remember these guys so we can use them later and elsewhere
m_argc = argc;
m_argv = argv;
m_context->argv = m_argv;
m_context->argc = m_argc;
// now parse them and pull out any args we know about
for (int32 i = 1; i < argc; i++)
{
char* arg = argv[i];
// is this an option?
if(arg[0] == '-'
#ifdef WIN32
|| arg[0] == '/'
#endif
)
{
switch(arg[1])
{
// print help
case 'h':
case 'H':
case '-':
if(!strcasecmp(arg + 1, "help") || !strcasecmp(arg + 2, "help"))
{
Usage(argv[0]);
AcceptEvent(new Event(CMD_QuitPlayer));
return true;
}
break;
// autoplay
case 'p':
case 'P':
if(!strcasecmp(arg + 1, "play"))
autoplay = true;
// save streams
// shuffle
case 's':
case 'S':
if(!strcasecmp(arg + 1, "save"))
m_context->argFlags |= FAC_ARGFLAGS_SAVE_STREAMS;
else if(!strcasecmp(arg + 1, "shuffle"))
m_plm->SetShuffleMode(true);
break;
case 'i':
case 'I':
if(!strcasecmp(arg + 1, "import"))
{
uint32 length = _MAX_PATH;
char url[_MAX_PATH];
i++;
FilePathToURL(argv[i], url, &length);
m_context->catalog->AddSong(url);
m_plm->AddItem(url);
}
break;
// set UIs
case 'u':
case 'U':
{
if(arg[2] == 'i' || arg[2] == 'I')
{
char* argUI = NULL;
i++;
if(i >= argc)
{
Usage(argv[0]);
AcceptEvent(new Event(CMD_QuitPlayer));
return false;
}
arg = argv[i];
argUI = new char[strlen(arg) + 1];
strcpy(argUI, arg);
m_argUIList->push_back(argUI);
}
break;
}
default:
break;
}
}
else
{
HandleSingleArg(arg);
}
}
if(m_autoplay)
{
AcceptEvent(new Event(CMD_Play));
}
return true;
}
void Player::HandleSingleArg(char *arg)
{
char* path = new char[_MAX_PATH];
char* url = new char[_MAX_PATH];
char *proto = NULL;
// is this a URL we know how to handle
proto = GetProtocol(arg);
if(IsSupportedProtocol(proto))
{
m_plm->AddItem(arg);
delete proto;
}
else
{
#ifdef WIN32
strcpy(path, arg);
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(arg, &data);
// find long filename for item and
// expand wildcards...
if(handle != INVALID_HANDLE_VALUE)
{
do
{
char* cp = NULL;
cp = strrchr(path, '\\');
if(cp)
cp++;
else
cp = path;
strcpy(cp, data.cFileName);
// make sure we have an absolute path
ResolvePath(&path);
// format this path as a URL
uint32 length = _MAX_PATH;
FilePathToURL(path, url, &length);
// who needs to get this, plm or dlm?
bool giveToDLM = false;
bool giveToTheme = false;
char* extension = NULL;
extension = strrchr(url, '.');
if(extension)
{
DownloadFormatInfo dlfi;
uint32 i = 0;
extension++;
while(IsntError(m_dlm->GetSupportedDownloadFormats(&dlfi, i++)))
{
if(!strcasecmp(extension, dlfi.GetExtension()))
{
giveToDLM = true;
break;
}
}
if (!strcasecmp(extension, themeExtension))
giveToTheme = true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -