598 lines
13 KiB
C++
598 lines
13 KiB
C++
|
//#define PLUGIN_NAME "Nullsoft CD Plug-in"
|
||
|
#define PLUGIN_VERSION L"4.7"
|
||
|
|
||
|
#include "main.h"
|
||
|
#include "cddb.h"
|
||
|
|
||
|
#include "CDPlay.h"
|
||
|
#include "DAEPlay.h"
|
||
|
#include "MCIPlay.h"
|
||
|
#include "WindacPlay.h"
|
||
|
|
||
|
#include "PlayStatus.h"
|
||
|
#include "../nu/AutoWide.h"
|
||
|
#include "../nu/AutoChar.h"
|
||
|
#include "../Winamp/strutil.h"
|
||
|
#include "../winamp/wa_ipc.h"
|
||
|
#include <shlwapi.h>
|
||
|
#include "api__in_cdda.h"
|
||
|
#include "workorder.h"
|
||
|
#include <strsafe.h>
|
||
|
using namespace Nullsoft::Utility;
|
||
|
Nullsoft::Utility::LockGuard *playDeviceGuard = 0;
|
||
|
char * s_last_error = NULL;
|
||
|
|
||
|
static wchar_t playDriveLetter;
|
||
|
//extern int config_maxextractspeed;
|
||
|
api_config *AGAVE_API_CONFIG=0;
|
||
|
|
||
|
#ifndef _DEBUG
|
||
|
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||
|
{
|
||
|
DisableThreadLibraryCalls(hInst);
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef IGNORE_API_GRACENOTE
|
||
|
static DINFO g_ps;
|
||
|
#endif
|
||
|
int g_ps_inuse = 0;
|
||
|
int g_playtrack, g_playlength;
|
||
|
wchar_t lastfn[1024] = {0};
|
||
|
int paused;
|
||
|
void _setvolume();
|
||
|
DWORD MainThreadId;
|
||
|
|
||
|
extern char INI_FILE[];
|
||
|
extern char app_name[];
|
||
|
|
||
|
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
|
||
|
{
|
||
|
MSGBOXPARAMS msgbx = {sizeof(MSGBOXPARAMS),0};
|
||
|
msgbx.lpszText = message;
|
||
|
msgbx.lpszCaption = title;
|
||
|
msgbx.lpszIcon = MAKEINTRESOURCE(102);
|
||
|
msgbx.hInstance = GetModuleHandle(0);
|
||
|
msgbx.dwStyle = MB_USERICON;
|
||
|
msgbx.hwndOwner = parent;
|
||
|
return MessageBoxIndirect(&msgbx);
|
||
|
}
|
||
|
|
||
|
void about(HWND hwndParent)
|
||
|
{
|
||
|
wchar_t message[1024] = {0}, text[1024] = {0};
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_CD_PLUGIN_OLD,text,1024);
|
||
|
StringCchPrintf(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
|
||
|
line.description, TEXT(__DATE__));
|
||
|
DoAboutMessageBox(hwndParent,text,message);
|
||
|
}
|
||
|
|
||
|
void quit();
|
||
|
int init();
|
||
|
|
||
|
int isourfile(const in_char *fn)
|
||
|
{
|
||
|
if (!_wcsnicmp(fn, L"cda://", 6)) return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
volatile int done = 0;
|
||
|
|
||
|
int g_lastpos = 0;
|
||
|
C_CDPlay *g_cdplay = 0;
|
||
|
|
||
|
const wchar_t *filename(const wchar_t *fn)
|
||
|
{
|
||
|
const wchar_t *s = scanstr_backcW(fn, L"\\/", 0);
|
||
|
if (!s) return fn;
|
||
|
return (s + 1);
|
||
|
}
|
||
|
|
||
|
bool ParseName(const wchar_t *fn, wchar_t &device, int &trackNum)
|
||
|
{
|
||
|
wchar_t track[16] = L"1";
|
||
|
if (!_wcsnicmp(fn, L"cda://", 6))
|
||
|
{
|
||
|
fn += 6;
|
||
|
wchar_t d[16] = {0};
|
||
|
wchar_t *p = d;
|
||
|
while (fn && *fn && *fn != L',' && (p - d < 15)) *p++ = *fn++;
|
||
|
if (p) *p = 0;
|
||
|
device = toupper(d[0]);
|
||
|
if (*fn == L',') fn++;
|
||
|
lstrcpyn(track, fn, ARRAYSIZE(track));
|
||
|
trackNum = _wtoi(track);
|
||
|
return true;
|
||
|
}
|
||
|
else if (!_wcsicmp(extensionW(fn), L"cda"))
|
||
|
{
|
||
|
const wchar_t *f = filename(fn);
|
||
|
if (!_wcsnicmp(f, L"track", 5)) f += 5;
|
||
|
wchar_t t[16] = {0};
|
||
|
wchar_t *p = t;
|
||
|
while (f && *f && *f != L'.' && (p - t < 15)) *p++ = *f++;
|
||
|
lstrcpyn(track, t, ARRAYSIZE(track));
|
||
|
device = toupper(fn[0]);
|
||
|
trackNum = _wtoi(track);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
WindacPlay *windacPlayer = 0;
|
||
|
DAEPlay *daePlayer = 0;
|
||
|
MciPlay *mciPlayer = 0;
|
||
|
|
||
|
int play(const in_char *fn)
|
||
|
{
|
||
|
done = 0;
|
||
|
lstrcpyn(lastfn, fn, 1024);
|
||
|
line.is_seekable = 0;
|
||
|
g_lastpos = 0;
|
||
|
|
||
|
int track = -1;
|
||
|
if (!ParseName(fn, playDriveLetter, track))
|
||
|
return 1;
|
||
|
|
||
|
if (playStatus[playDriveLetter].IsRipping() || (g_cdplay && g_cdplay->IsPlaying(playDriveLetter)))
|
||
|
{
|
||
|
wchar_t title[32] = {0};
|
||
|
MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_CD_CURRENTLY_IN_USE),
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_IN_USE,title,32), MB_OK);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (g_cdplay) delete g_cdplay; g_cdplay = NULL;
|
||
|
|
||
|
//first, try DAE
|
||
|
if (!daePlayer) daePlayer = new DAEPlay;
|
||
|
g_cdplay = daePlayer;
|
||
|
|
||
|
int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
if (g_cdplay) delete g_cdplay; g_cdplay = daePlayer = NULL;
|
||
|
|
||
|
//second, try Windac
|
||
|
if (!windacPlayer) windacPlayer = new WindacPlay;
|
||
|
g_cdplay = windacPlayer;
|
||
|
ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
if (g_cdplay) delete g_cdplay; g_cdplay = windacPlayer = NULL;
|
||
|
|
||
|
//try MCI
|
||
|
if (!mciPlayer) mciPlayer = new MciPlay;
|
||
|
g_cdplay = mciPlayer;
|
||
|
int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 1);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
//no luck
|
||
|
if (g_cdplay) delete g_cdplay; g_cdplay = mciPlayer = NULL;
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
paused = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void pause()
|
||
|
{
|
||
|
if (g_cdplay) g_cdplay->pause();
|
||
|
paused = 1;
|
||
|
}
|
||
|
void unpause()
|
||
|
{
|
||
|
if (g_cdplay) g_cdplay->unpause();
|
||
|
paused = 0;
|
||
|
}
|
||
|
int ispaused()
|
||
|
{
|
||
|
return paused;
|
||
|
}
|
||
|
|
||
|
void stop()
|
||
|
{
|
||
|
if (g_cdplay)
|
||
|
{
|
||
|
g_cdplay->stop();
|
||
|
g_cdplay = NULL;
|
||
|
}
|
||
|
|
||
|
done = 0;
|
||
|
line.SAVSADeInit();
|
||
|
}
|
||
|
|
||
|
int getlength()
|
||
|
{
|
||
|
if (g_cdplay) return g_cdplay->getlength();
|
||
|
return -1000;
|
||
|
}
|
||
|
|
||
|
int getoutputtime()
|
||
|
{
|
||
|
if (g_cdplay) return g_cdplay->getoutputtime();
|
||
|
return 0;
|
||
|
//return audioGetPos();
|
||
|
}
|
||
|
void setoutputtime(int time_in_ms)
|
||
|
{
|
||
|
if (g_cdplay) g_cdplay->setoutputtime(time_in_ms);
|
||
|
}
|
||
|
|
||
|
void setvolume(int volume)
|
||
|
{
|
||
|
if (volume != -666)
|
||
|
{
|
||
|
a_v = volume;
|
||
|
}
|
||
|
if (g_cdplay) g_cdplay->setvolume(a_v, a_p);
|
||
|
}
|
||
|
|
||
|
void setpan(int pan)
|
||
|
{
|
||
|
a_p = pan;
|
||
|
if (g_cdplay) g_cdplay->setvolume(a_v, a_p);
|
||
|
}
|
||
|
|
||
|
int infoDlg(const in_char *fn, HWND hwnd)
|
||
|
{
|
||
|
return 0;
|
||
|
#if 0 // switched to unified file info dialog in 5.53
|
||
|
if (!_stricmp(extension(fn), "cda") || !_strnicmp(fn, "cda://", 6))
|
||
|
{
|
||
|
if (!g_ps_inuse)
|
||
|
{
|
||
|
char device;
|
||
|
int res=1;
|
||
|
MCIDEVICEID d = 0;
|
||
|
g_ps_inuse = 1;
|
||
|
device = fn[_strnicmp(fn, "cda://", 6) ? 0 : 6];
|
||
|
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||
|
|
||
|
CDOpen(&d, device, L"infoDlg");
|
||
|
memset(&g_ps, 0, sizeof(g_ps));
|
||
|
res = GetDiscID(d, &g_ps);
|
||
|
CDClose(&d);
|
||
|
if (!res)
|
||
|
res = GetCDDBInfo(&g_ps, device);
|
||
|
|
||
|
//if (!res) DBEdit(&g_ps, hwnd, 0, device);
|
||
|
//if (!res)
|
||
|
{
|
||
|
if (CDEdit(device, &g_ps, hwnd))
|
||
|
{
|
||
|
g_ps_inuse = 0;
|
||
|
return INFOBOX_EDITED;
|
||
|
}
|
||
|
}
|
||
|
g_ps_inuse = 0;
|
||
|
}
|
||
|
}
|
||
|
return INFOBOX_UNCHANGED;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms)
|
||
|
{
|
||
|
#if 0
|
||
|
int track;
|
||
|
char device;
|
||
|
MCIDEVICEID dev2 = 0;
|
||
|
if (length_in_ms) *length_in_ms = -1000;
|
||
|
|
||
|
if (!filename || !*filename) // currently playing
|
||
|
{
|
||
|
if (!_stricmp(extension(lastfn), "cda") || !_strnicmp(lastfn, "cda://", 6))
|
||
|
{
|
||
|
#ifdef IGNORE_API_GRACENOTE
|
||
|
if (title)
|
||
|
{
|
||
|
lstrcpynA(title, "CD Track", GETFILEINFO_TITLE_LENGTH);
|
||
|
if (!g_ps_inuse)
|
||
|
{
|
||
|
g_ps_inuse = 1;
|
||
|
memset(&g_ps, 0, sizeof(g_ps));
|
||
|
|
||
|
if (CDOpen(&dev2, playDriveLetter, L"getfileinfo"))
|
||
|
{
|
||
|
wchar_t wtitle[256] = {0};
|
||
|
int ret = GetDiscID(dev2, &g_ps);
|
||
|
CDClose(&dev2);
|
||
|
if (!ret && GetCDDBInfo(&g_ps, 0)) // TODO: get device letter
|
||
|
PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247/*IPC_REFRESHPLCACHE*/);
|
||
|
if (wtitle[0])
|
||
|
lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH);
|
||
|
|
||
|
}
|
||
|
g_ps_inuse = 0;
|
||
|
}
|
||
|
}
|
||
|
if (length_in_ms) *length_in_ms = g_playlength;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (title)
|
||
|
{
|
||
|
const char *p = filename + strlen(filename);
|
||
|
while (p >= filename && *p != '\\') p--;
|
||
|
lstrcpynA(title, ++p, GETFILEINFO_TITLE_LENGTH);
|
||
|
}
|
||
|
track = 0;
|
||
|
|
||
|
if (!_strnicmp(filename, "cda://", 6)) // determine length of cd track via MCI
|
||
|
{
|
||
|
track = atoi(filename + 8);
|
||
|
device = filename[6];
|
||
|
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||
|
|
||
|
if (length_in_ms)
|
||
|
{
|
||
|
if (CDOpen(&dev2, device, L"getfileinfo"))
|
||
|
{
|
||
|
MCI_SET_PARMS sMCISet;
|
||
|
sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
|
||
|
MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
|
||
|
*length_in_ms = CDGetTrackLength(dev2, track);
|
||
|
sMCISet.dwTimeFormat = MCI_FORMAT_TMSF;
|
||
|
MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else // determine from RIFF structure of .CDA
|
||
|
{
|
||
|
HMMIO hmmio;
|
||
|
hmmio = mmioOpenA((char *)filename, NULL, MMIO_READ | MMIO_ALLOCBUF);
|
||
|
device = filename[0];
|
||
|
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||
|
if (hmmio)
|
||
|
{
|
||
|
MMCKINFO mmckinfoParent; // parent chunk information
|
||
|
mmckinfoParent.fccType = mmioFOURCC('C', 'D', 'D', 'A');
|
||
|
if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF) == MMSYSERR_NOERROR)
|
||
|
{
|
||
|
MMCKINFO mmckinfoSubchunk; // subchunk information structure
|
||
|
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
||
|
if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) == MMSYSERR_NOERROR)
|
||
|
{
|
||
|
char *format;
|
||
|
DWORD dwFmtSize; // size of "FMT" chunk
|
||
|
dwFmtSize = mmckinfoSubchunk.cksize;
|
||
|
format = (char *) GlobalAlloc(GPTR, dwFmtSize);
|
||
|
if (mmioRead(hmmio, (HPSTR) format, dwFmtSize) == (int)dwFmtSize)
|
||
|
{
|
||
|
mmioAscend(hmmio, &mmckinfoSubchunk, 0);
|
||
|
track = *((short int *)format + 1);
|
||
|
if (length_in_ms)
|
||
|
{
|
||
|
int length = *((int *)format + 3);
|
||
|
int l = length % 75;
|
||
|
length /= 75;
|
||
|
length *= 1000;
|
||
|
length += (l * 1000) / 75;
|
||
|
*length_in_ms = length;
|
||
|
}
|
||
|
}
|
||
|
GlobalFree(format);
|
||
|
}
|
||
|
}
|
||
|
mmioClose(hmmio, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef IGNORE_API_GRACENOTE
|
||
|
if (title && track)
|
||
|
{
|
||
|
if (0 && !g_ps_inuse)
|
||
|
{
|
||
|
g_ps_inuse = 1;
|
||
|
memset(&g_ps, 0, sizeof(g_ps));
|
||
|
if (!dev2)
|
||
|
{
|
||
|
CDOpen(&dev2, device, L"getfileinfo");
|
||
|
}
|
||
|
if (dev2)
|
||
|
{
|
||
|
StringCchPrintfA(title, GETFILEINFO_TITLE_LENGTH, "CD Track %d", track);
|
||
|
wchar_t wtitle[256] = L"";
|
||
|
int ret = GetDiscID(dev2, &g_ps);
|
||
|
CDClose(&dev2);
|
||
|
dev2=0;
|
||
|
if (!ret && GetCDDBInfo(&g_ps, device))
|
||
|
PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247 /*IPC_REFRESHPLCACHE*/);
|
||
|
if (wtitle[0])
|
||
|
lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH);
|
||
|
}
|
||
|
g_ps_inuse = 0;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if (dev2) CDClose(&dev2);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void eq_set(int on, char data[10], int preamp)
|
||
|
{}
|
||
|
|
||
|
In_Module line =
|
||
|
{
|
||
|
IN_VER_RET,
|
||
|
"nullsoft(in_cdda.dll)",
|
||
|
0, // hMainWindow
|
||
|
0, // hDllInstance
|
||
|
0,
|
||
|
0, // is_seekable
|
||
|
1, // uses output plugins
|
||
|
about,//config,
|
||
|
about,
|
||
|
init,
|
||
|
quit,
|
||
|
getfileinfo,
|
||
|
infoDlg,
|
||
|
isourfile,
|
||
|
play,
|
||
|
pause,
|
||
|
unpause,
|
||
|
ispaused,
|
||
|
stop,
|
||
|
getlength,
|
||
|
getoutputtime,
|
||
|
setoutputtime,
|
||
|
setvolume,
|
||
|
setpan,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, // dsp shit
|
||
|
eq_set,
|
||
|
NULL, // setinfo
|
||
|
NULL // out_mod
|
||
|
};
|
||
|
|
||
|
int m_nblock = 0;
|
||
|
|
||
|
extern "C"
|
||
|
{
|
||
|
__declspec(dllexport) In_Module * winampGetInModule2()
|
||
|
{
|
||
|
s_last_error = NULL;
|
||
|
return &line;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if 0 // TODO?
|
||
|
|
||
|
__declspec(dllexport) int winampWriteExtendedFileInfo()
|
||
|
{
|
||
|
s_last_error = NULL;
|
||
|
// write it out
|
||
|
if (m_eiw_lastdrive)
|
||
|
{
|
||
|
AddToDatabase(&setInfo);
|
||
|
m_eiw_lastdrive = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
// wasabi based services for localisation support
|
||
|
api_language *WASABI_API_LNG = 0;
|
||
|
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
api_gracenote *AGAVE_API_GRACENOTE = 0;
|
||
|
#endif
|
||
|
api_application *WASABI_API_APP = 0;
|
||
|
|
||
|
void SetFileExtensions(void)
|
||
|
{
|
||
|
static char fileExtensionsString[1200] = {0}; // "CDA\0CDDA Audio Tracks (*.CDA)\0"
|
||
|
char* end = 0;
|
||
|
StringCchCopyExA(fileExtensionsString, 1200, "CDA", &end, 0, 0);
|
||
|
StringCchCopyExA(end+1, 1200, WASABI_API_LNGSTRING(IDS_CDDA_AUDIO_TRACKS), 0, 0, 0);
|
||
|
line.FileExtensions = fileExtensionsString;
|
||
|
}
|
||
|
|
||
|
int init()
|
||
|
{
|
||
|
if (!IsWindow(line.hMainWindow))
|
||
|
return IN_INIT_FAILURE;
|
||
|
|
||
|
//CoInitialize(0);
|
||
|
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
Cddb_Initialize();
|
||
|
InitializeCddbCache();
|
||
|
#endif
|
||
|
|
||
|
// loader so that we can get the localisation service api for use
|
||
|
waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID);
|
||
|
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
|
||
|
|
||
|
sf = line.service->service_getServiceByGuid(AgaveConfigGUID);
|
||
|
if (sf) AGAVE_API_CONFIG = reinterpret_cast<api_config*>(sf->getInterface());
|
||
|
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
sf = line.service->service_getServiceByGuid(gracenoteApiGUID);
|
||
|
if (sf) AGAVE_API_GRACENOTE = reinterpret_cast<api_gracenote*>(sf->getInterface());
|
||
|
#endif
|
||
|
|
||
|
sf = line.service->service_getServiceByGuid(applicationApiServiceGuid);
|
||
|
if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
|
||
|
|
||
|
// need to have this initialised before we try to do anything with localisation features
|
||
|
WASABI_API_START_LANG(line.hDllInstance,InCDDALangGUID);
|
||
|
|
||
|
static wchar_t szDescription[256];
|
||
|
StringCchPrintfW(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_CD_PLUGIN),PLUGIN_VERSION);
|
||
|
line.description = (char*)szDescription;
|
||
|
|
||
|
SetFileExtensions();
|
||
|
|
||
|
playDeviceGuard = new Nullsoft::Utility::LockGuard;
|
||
|
playStatusGuard = new Nullsoft::Utility::LockGuard;
|
||
|
|
||
|
MainThreadId = GetCurrentThreadId();
|
||
|
config_read();
|
||
|
return IN_INIT_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void quit()
|
||
|
{
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
ShutdownMusicIDWorkOrder();
|
||
|
#endif
|
||
|
|
||
|
if (playStatusGuard)
|
||
|
{
|
||
|
delete playStatusGuard;
|
||
|
playStatusGuard = 0;
|
||
|
}
|
||
|
|
||
|
if (windacPlayer)
|
||
|
{
|
||
|
delete windacPlayer;
|
||
|
windacPlayer = NULL;
|
||
|
}
|
||
|
|
||
|
if (daePlayer)
|
||
|
{
|
||
|
delete daePlayer;
|
||
|
daePlayer = NULL;
|
||
|
}
|
||
|
|
||
|
if (mciPlayer)
|
||
|
{
|
||
|
delete mciPlayer;
|
||
|
mciPlayer = NULL;
|
||
|
}
|
||
|
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
ShutDownCDDB();
|
||
|
#endif
|
||
|
|
||
|
waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID);
|
||
|
if (sf) sf->releaseInterface(WASABI_API_LNG);
|
||
|
|
||
|
sf = line.service->service_getServiceByGuid(AgaveConfigGUID);
|
||
|
if (sf) sf->releaseInterface(AGAVE_API_CONFIG);
|
||
|
|
||
|
#ifndef IGNORE_API_GRACENOTE
|
||
|
sf = line.service->service_getServiceByGuid(gracenoteApiGUID);
|
||
|
if (sf) sf->releaseInterface(AGAVE_API_GRACENOTE);
|
||
|
|
||
|
Cddb_Uninitialize();
|
||
|
UninitializeCddbCache();
|
||
|
#endif
|
||
|
|
||
|
CloseTables();
|
||
|
//CoUninitialize();
|
||
|
}
|