Updated the resource signature to match the app's signature
Utilize CDDB lookups Use display controls look similar to LED panels on CD players Window is resizable and controls respond appropriately Added support to display elapsed time, both for the CD and the current track Numerous little bugfixes git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13294 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+252
-49
@@ -24,6 +24,9 @@
|
||||
#include "CDButton.h"
|
||||
#include "DrawButton.h"
|
||||
#include <TranslationUtils.h>
|
||||
#include <TranslatorFormats.h>
|
||||
#include <TranslatorRoster.h>
|
||||
#include <BitmapStream.h>
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -42,9 +45,15 @@ enum
|
||||
};
|
||||
|
||||
CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flags)
|
||||
: BView(frame, name, resizeMask, flags)
|
||||
: BView(frame, name, resizeMask, flags | B_FRAME_EVENTS)
|
||||
{
|
||||
// This will eventually one of a few preferences - to stop playing music
|
||||
// when the app is closed
|
||||
fStopOnQuit = false;
|
||||
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// TODO: Support multiple CD drives
|
||||
engine = new CDEngine(CDEngine::FindCDPlayerDevice());
|
||||
|
||||
BuildGUI();
|
||||
@@ -65,34 +74,69 @@ CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flag
|
||||
|
||||
CDButton::~CDButton()
|
||||
{
|
||||
if(fStopOnQuit)
|
||||
engine->Stop();
|
||||
|
||||
delete engine;
|
||||
}
|
||||
|
||||
void CDButton::BuildGUI(void)
|
||||
{
|
||||
fCDTitle = new BTextControl( BRect(5,5,230,30), "CDTitle","","",new BMessage(M_SET_CD_TITLE));
|
||||
AddChild(fCDTitle);
|
||||
fCDTitle->SetDivider(0);
|
||||
fCDTitle->TextView()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
BRect r(5,5,230,25);
|
||||
|
||||
BBox *box = new BBox(BRect(0,0,75,20),"TrackBox");
|
||||
box->MoveTo(fCDTitle->Frame().right + 15, 5);
|
||||
AddChild(box);
|
||||
// Assemble the CD Title box
|
||||
fCDBox = new BBox(r,"TrackBox");
|
||||
AddChild(fCDBox);
|
||||
|
||||
BView *view = new BView( box->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_NONE,B_WILL_DRAW);
|
||||
view->SetViewColor(0,0,0);
|
||||
box->AddChild(view);
|
||||
BView *view = new BView( fCDBox->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_ALL,B_WILL_DRAW);
|
||||
view->SetViewColor(20,20,20);
|
||||
fCDBox->AddChild(view);
|
||||
|
||||
fTrackNumber = new BStringView( view->Bounds(),"TrackNumber","Track: --");
|
||||
view->AddChild(fTrackNumber);
|
||||
fTrackNumber->SetAlignment(B_ALIGN_CENTER);
|
||||
fTrackNumber->SetHighColor(0,255,0);
|
||||
fTrackNumber->SetFont(be_bold_font);
|
||||
fCDTitle = new BStringView(view->Bounds(),"CDTitle","");
|
||||
view->AddChild(fCDTitle);
|
||||
fCDTitle->SetHighColor(200,200,200);
|
||||
fCDTitle->SetFont(be_bold_font);
|
||||
|
||||
fVolume = new BSlider( BRect(0,0,75,30), "VolumeSlider", "Volume", new BMessage(M_SET_VOLUME),0,100);
|
||||
r.Set(fCDTitle->Frame().right + 15,5,Bounds().right - 5,25);
|
||||
fTrackBox = new BBox(r,"TrackBox",B_FOLLOW_TOP);
|
||||
AddChild(fTrackBox);
|
||||
|
||||
view = new BView( fTrackBox->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_ALL,B_WILL_DRAW);
|
||||
view->SetViewColor(0,34,7);
|
||||
fTrackBox->AddChild(view);
|
||||
|
||||
fCurrentTrack = new BStringView( view->Bounds(),"TrackNumber","Track:",B_FOLLOW_ALL);
|
||||
view->AddChild(fCurrentTrack);
|
||||
fCurrentTrack->SetHighColor(40,230,40);
|
||||
fCurrentTrack->SetFont(be_bold_font);
|
||||
|
||||
r.OffsetBy(0, r.Height() + 5);
|
||||
fTimeBox = new BBox(r,"TimeBox",B_FOLLOW_LEFT_RIGHT);
|
||||
AddChild(fTimeBox);
|
||||
|
||||
view = new BView( fTimeBox->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_ALL,B_WILL_DRAW);
|
||||
view->SetViewColor(0,7,34);
|
||||
fTimeBox->AddChild(view);
|
||||
|
||||
r = view->Bounds();
|
||||
r.right /= 2;
|
||||
|
||||
fTrackTime = new BStringView(r,"TrackTime","Track --:-- / --:--",B_FOLLOW_LEFT_RIGHT);
|
||||
view->AddChild(fTrackTime);
|
||||
fTrackTime->SetHighColor(120,120,255);
|
||||
fTrackTime->SetFont(be_bold_font);
|
||||
|
||||
r.right = view->Bounds().right;
|
||||
r.left = fTrackTime->Frame().right + 1;
|
||||
|
||||
fDiscTime = new BStringView(r,"DiscTime","Disc --:-- / --:--",B_FOLLOW_RIGHT);
|
||||
view->AddChild(fDiscTime);
|
||||
fDiscTime->SetHighColor(120,120,255);
|
||||
fDiscTime->SetFont(be_bold_font);
|
||||
|
||||
fVolume = new BSlider( BRect(0,0,75,30), "VolumeSlider", "Volume", new BMessage(M_SET_VOLUME),0,255);
|
||||
fVolume->MoveTo(5, Bounds().bottom - 10 - fVolume->Frame().Height());
|
||||
AddChild(fVolume);
|
||||
fVolume->SetEnabled(false);
|
||||
|
||||
fStop = new DrawButton( BRect(0,0,1,1), "Stop", BTranslationUtils::GetBitmap('PNG ',"stop_up"),
|
||||
BTranslationUtils::GetBitmap('PNG ',"stop_down"), new BMessage(M_STOP),
|
||||
@@ -154,7 +198,7 @@ void CDButton::BuildGUI(void)
|
||||
|
||||
fSave = new DrawButton( BRect(0,0,1,1), "Save", BTranslationUtils::GetBitmap('PNG ',"save_up"),
|
||||
BTranslationUtils::GetBitmap('PNG ',"save_down"), new BMessage(M_SAVE),
|
||||
B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fSave->ResizeToPreferred();
|
||||
fSave->MoveTo(fEject->Frame().right + 20, Bounds().bottom - 5 - fSave->Frame().Height());
|
||||
fSave->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"save_disabled"));
|
||||
@@ -164,7 +208,7 @@ void CDButton::BuildGUI(void)
|
||||
// TODO: Shuffle and Repeat are special buttons. Implement as two-state buttons
|
||||
fShuffle = new DrawButton( BRect(0,0,1,1), "Shuffle", BTranslationUtils::GetBitmap('PNG ',"shuffle_up"),
|
||||
BTranslationUtils::GetBitmap('PNG ',"shuffle_down"), new BMessage(M_SHUFFLE),
|
||||
B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fShuffle->ResizeToPreferred();
|
||||
fShuffle->MoveTo(fSave->Frame().right + 2, Bounds().bottom - 5 - fShuffle->Frame().Height());
|
||||
fShuffle->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"shuffle_disabled"));
|
||||
@@ -173,7 +217,7 @@ void CDButton::BuildGUI(void)
|
||||
|
||||
fRepeat = new DrawButton( BRect(0,0,1,1), "Repeat", BTranslationUtils::GetBitmap('PNG ',"repeat_up"),
|
||||
BTranslationUtils::GetBitmap('PNG ',"repeat_down"), new BMessage(M_REPEAT),
|
||||
B_FOLLOW_BOTTOM, B_WILL_DRAW);
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fRepeat->ResizeToPreferred();
|
||||
fRepeat->MoveTo(fShuffle->Frame().right + 2, Bounds().bottom - 5 - fRepeat->Frame().Height());
|
||||
fRepeat->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"repeat_disabled"));
|
||||
@@ -183,13 +227,72 @@ void CDButton::BuildGUI(void)
|
||||
|
||||
|
||||
void
|
||||
CDButton::MessageReceived(BMessage *message)
|
||||
CDButton::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (message->what)
|
||||
if(msg->WasDropped())
|
||||
{
|
||||
// We'll handle two types of drops: those from Tracker and those from ShowImage
|
||||
if(msg->what==B_SIMPLE_DATA)
|
||||
{
|
||||
int32 actions;
|
||||
if(msg->FindInt32("be:actions",&actions)==B_OK)
|
||||
{
|
||||
// ShowImage drop. This is a negotiated drag&drop, so send a reply
|
||||
BMessage reply(B_COPY_TARGET), response;
|
||||
reply.AddString("be:types","image/jpeg");
|
||||
reply.AddString("be:types","image/png");
|
||||
|
||||
msg->SendReply(&reply,&response);
|
||||
|
||||
// now, we've gotten the response
|
||||
if(response.what==B_MIME_DATA)
|
||||
{
|
||||
// Obtain and translate the received data
|
||||
uint8 *imagedata;
|
||||
ssize_t datasize;
|
||||
|
||||
// Try JPEG first
|
||||
if(response.FindData("image/jpeg",B_MIME_DATA,(const void **)&imagedata,&datasize)!=B_OK)
|
||||
{
|
||||
// Try PNG next and piddle out if unsuccessful
|
||||
if(response.FindData("image/png",B_PNG_FORMAT,(const void **)&imagedata,&datasize)!=B_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up to decode into memory
|
||||
BMemoryIO memio(imagedata,datasize);
|
||||
BTranslatorRoster *roster=BTranslatorRoster::Default();
|
||||
BBitmapStream bstream;
|
||||
|
||||
if(roster->Translate(&memio,NULL,NULL,&bstream, B_TRANSLATOR_BITMAP)==B_OK)
|
||||
{
|
||||
BBitmap *bmp;
|
||||
if(bstream.DetachBitmap(&bmp)!=B_OK)
|
||||
return;
|
||||
|
||||
SetBitmap(bmp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
entry_ref ref;
|
||||
if(msg->FindRef("refs",&ref)==B_OK)
|
||||
{
|
||||
// Tracker drop
|
||||
BBitmap *bmp=BTranslationUtils::GetBitmap(&ref);
|
||||
SetBitmap(bmp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg->what)
|
||||
{
|
||||
case M_SET_VOLUME:
|
||||
{
|
||||
// TODO: Implement
|
||||
engine->SetVolume(fVolume->Value());
|
||||
break;
|
||||
}
|
||||
case M_STOP:
|
||||
@@ -245,10 +348,10 @@ CDButton::MessageReceived(BMessage *message)
|
||||
default:
|
||||
{
|
||||
|
||||
if (!Observer::HandleObservingMessages(message))
|
||||
if (!Observer::HandleObservingMessages(msg))
|
||||
{
|
||||
// just support observing messages
|
||||
BView::MessageReceived(message);
|
||||
BView::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -258,17 +361,17 @@ CDButton::MessageReceived(BMessage *message)
|
||||
void
|
||||
CDButton::NoticeChange(Notifier *notifier)
|
||||
{
|
||||
// debugger("");
|
||||
|
||||
PlayState *ps;
|
||||
TrackState *trs;
|
||||
TimeState *tms;
|
||||
CDContentWatcher *ccw;
|
||||
VolumeState *vs;
|
||||
|
||||
ps = dynamic_cast<PlayState *>(notifier);
|
||||
trs = dynamic_cast<TrackState *>(notifier);
|
||||
tms = dynamic_cast<TimeState *>(notifier);
|
||||
ccw = dynamic_cast<CDContentWatcher *>(notifier);
|
||||
vs = dynamic_cast<VolumeState *>(notifier);
|
||||
|
||||
if(ps)
|
||||
{
|
||||
@@ -286,6 +389,10 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
fRewind->SetEnabled(false);
|
||||
fSave->SetEnabled(false);
|
||||
}
|
||||
fCurrentTrack->SetText("Track: ");
|
||||
fTrackTime->SetText("Track --:-- / --:--");
|
||||
fDiscTime->SetText("Disc --:-- / --:--");
|
||||
printf("Notification: No CD\n");
|
||||
break;
|
||||
}
|
||||
case kStopped:
|
||||
@@ -300,6 +407,10 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
fRewind->SetEnabled(true);
|
||||
fSave->SetEnabled(true);
|
||||
}
|
||||
fCurrentTrack->SetText("Track: ");
|
||||
fTrackTime->SetText("Track --:-- / --:--");
|
||||
fDiscTime->SetText("Disc --:-- / --:--");
|
||||
printf("Notification: CD Stopped\n");
|
||||
break;
|
||||
}
|
||||
case kPaused:
|
||||
@@ -315,7 +426,7 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
fRewind->SetEnabled(true);
|
||||
fSave->SetEnabled(true);
|
||||
}
|
||||
UpdateTrackInfo();
|
||||
printf("Notification: CD Paused\n");
|
||||
break;
|
||||
}
|
||||
case kPlaying:
|
||||
@@ -330,7 +441,7 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
fRewind->SetEnabled(true);
|
||||
fSave->SetEnabled(true);
|
||||
}
|
||||
UpdateTrackInfo();
|
||||
printf("Notification: CD Playing\n");
|
||||
break;
|
||||
}
|
||||
case kSkipping:
|
||||
@@ -345,6 +456,7 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
fRewind->SetEnabled(true);
|
||||
fSave->SetEnabled(true);
|
||||
}
|
||||
printf("Notification: CD Skipping\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -356,34 +468,69 @@ CDButton::NoticeChange(Notifier *notifier)
|
||||
else
|
||||
if(trs)
|
||||
{
|
||||
UpdateTrackInfo();
|
||||
UpdateCDInfo();
|
||||
|
||||
// TODO: Update track count indicator
|
||||
}
|
||||
else
|
||||
if(tms)
|
||||
{
|
||||
UpdateTimeInfo();
|
||||
}
|
||||
else
|
||||
if(ccw)
|
||||
{
|
||||
UpdateCDInfo();
|
||||
}
|
||||
else
|
||||
if(vs)
|
||||
{
|
||||
fVolume->SetValue(engine->VolumeStateWatcher()->GetVolume());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDButton::UpdateTrackInfo(void)
|
||||
CDButton::UpdateCDInfo(void)
|
||||
{
|
||||
|
||||
fCurrentTrack=engine->TrackStateWatcher()->GetTrack();
|
||||
fTrackCount=engine->TrackStateWatcher()->GetNumTracks();
|
||||
BString CDName, currentTrackName;
|
||||
vector<BString> trackNames;
|
||||
|
||||
if(fCurrentTrack < 1)
|
||||
int32 currentTrack = engine->TrackStateWatcher()->GetTrack();
|
||||
engine->ContentWatcher()->GetContent(&CDName,&trackNames);
|
||||
|
||||
fCDTitle->SetText(CDName.String());
|
||||
|
||||
if(currentTrack > 0)
|
||||
{
|
||||
char string[255];
|
||||
sprintf(string,"Track: %ld",fCurrentTrack);
|
||||
fTrackNumber->SetText(string);
|
||||
currentTrackName << "Track " << currentTrack << ": " << trackNames[ currentTrack - 1];
|
||||
fCurrentTrack->SetText(currentTrackName.String());
|
||||
}
|
||||
else
|
||||
fTrackNumber->SetText("Track: --");
|
||||
{
|
||||
fCurrentTrack->SetText("Track:");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
CDButton::UpdateTimeInfo(void)
|
||||
{
|
||||
int32 min,sec;
|
||||
char string[1024];
|
||||
|
||||
engine->TimeStateWatcher()->GetDiscTime(min,sec);
|
||||
if(min >= 0)
|
||||
sprintf(string,"Disc %ld:%.2ld / --:--",min,sec);
|
||||
else
|
||||
sprintf(string,"Disc --:-- / --:--");
|
||||
fDiscTime->SetText(string);
|
||||
|
||||
engine->TimeStateWatcher()->GetTrackTime(min,sec);
|
||||
if(min >= 0)
|
||||
sprintf(string,"Track %ld:%.2ld / --:--",min,sec);
|
||||
else
|
||||
sprintf(string,"Track --:-- / --:--");
|
||||
fTrackTime->SetText(string);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -393,6 +540,9 @@ CDButton::AttachedToWindow()
|
||||
engine->AttachedToLooper(Window());
|
||||
StartObserving(engine->TrackStateWatcher());
|
||||
StartObserving(engine->PlayStateWatcher());
|
||||
StartObserving(engine->ContentWatcher());
|
||||
StartObserving(engine->TimeStateWatcher());
|
||||
StartObserving(engine->VolumeStateWatcher());
|
||||
|
||||
fVolume->SetTarget(this);
|
||||
fStop->SetTarget(this);
|
||||
@@ -407,12 +557,52 @@ CDButton::AttachedToWindow()
|
||||
fRepeat->SetTarget(this);
|
||||
}
|
||||
|
||||
void
|
||||
CDButton::FrameResized(float new_width, float new_height)
|
||||
{
|
||||
// We implement this method because there is no resizing mode to split the window's
|
||||
// width into two and have a box fill each half
|
||||
|
||||
// The boxes are laid out with 5 pixels between the window edge and each box.
|
||||
// Additionally, 15 pixels of padding are between the two boxes themselves
|
||||
|
||||
float half = (new_width / 2);
|
||||
|
||||
fCDBox->ResizeTo( half - 7, fCDBox->Bounds().Height() );
|
||||
|
||||
fTrackBox->MoveTo(half + 8, fTrackBox->Frame().top);
|
||||
fTrackBox->ResizeTo( Bounds().right - (half + 8) - 5, fTrackBox->Bounds().Height() );
|
||||
|
||||
fTimeBox->MoveTo(half + 8, fTimeBox->Frame().top);
|
||||
fTimeBox->ResizeTo( Bounds().right - (half + 8) - 5, fTimeBox->Bounds().Height() );
|
||||
|
||||
fRepeat->MoveTo(new_width - fRepeat->Bounds().right - 5, fRepeat->Frame().top);
|
||||
|
||||
fShuffle->MoveTo(fRepeat->Frame().left - fShuffle->Bounds().Width() - 2, fShuffle->Frame().top);
|
||||
fSave->MoveTo(fShuffle->Frame().left - fSave->Bounds().Width() - 2, fSave->Frame().top);
|
||||
}
|
||||
|
||||
void
|
||||
CDButton::Pulse()
|
||||
{
|
||||
engine->DoPulse();
|
||||
}
|
||||
|
||||
void
|
||||
CDButton::SetBitmap(BBitmap *bitmap)
|
||||
{
|
||||
if(!bitmap)
|
||||
{
|
||||
ClearViewBitmap();
|
||||
return;
|
||||
}
|
||||
|
||||
SetViewBitmap(bitmap);
|
||||
fVolume->SetViewBitmap(bitmap);
|
||||
fVolume->Invalidate();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
class CDButtonWindow : public BWindow
|
||||
{
|
||||
public:
|
||||
@@ -421,8 +611,14 @@ public:
|
||||
};
|
||||
|
||||
CDButtonWindow::CDButtonWindow(void)
|
||||
: BWindow(BRect (100, 100, 610, 400), "CD Player", B_TITLED_WINDOW, 0)
|
||||
: BWindow(BRect (100, 100, 610, 200), "CD Player", B_TITLED_WINDOW, B_NOT_V_RESIZABLE)
|
||||
{
|
||||
float wmin,wmax,hmin,hmax;
|
||||
|
||||
GetSizeLimits(&wmin,&wmax,&hmin,&hmax);
|
||||
wmin=510;
|
||||
hmin=100;
|
||||
SetSizeLimits(wmin,wmax,hmin,hmax);
|
||||
}
|
||||
|
||||
bool CDButtonWindow::QuitRequested(void)
|
||||
@@ -431,16 +627,23 @@ bool CDButtonWindow::QuitRequested(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
CDButtonApplication::CDButtonApplication()
|
||||
: BApplication("application/x-vnd.Be-CDPlayer")
|
||||
{
|
||||
BWindow *window = new CDButtonWindow();
|
||||
|
||||
BView *button = new CDButton(window->Bounds(), "CD");
|
||||
window->AddChild(button);
|
||||
window->Show();
|
||||
}
|
||||
CDButtonWindow *cdbwin;
|
||||
CDButton *cdbutton;
|
||||
|
||||
CDButtonApplication::CDButtonApplication()
|
||||
: BApplication("application/x-vnd.Haiku-CDPlayer")
|
||||
{
|
||||
// BWindow *window = new CDButtonWindow();
|
||||
|
||||
// BView *button = new CDButton(window->Bounds(), "CD");
|
||||
/// window->AddChild(button);
|
||||
// window->Show();
|
||||
cdbwin = new CDButtonWindow();
|
||||
|
||||
cdbutton = new CDButton(cdbwin->Bounds(), "CD");
|
||||
cdbwin->AddChild(cdbutton);
|
||||
cdbwin->Show();
|
||||
}
|
||||
|
||||
int
|
||||
main(int, char **argv)
|
||||
|
||||
@@ -35,6 +35,8 @@ public:
|
||||
virtual void AttachedToWindow();
|
||||
|
||||
virtual void Pulse();
|
||||
|
||||
virtual void FrameResized(float new_width, float new_height);
|
||||
|
||||
virtual void MessageReceived(BMessage *);
|
||||
|
||||
@@ -45,7 +47,11 @@ public:
|
||||
virtual void NoticeChange(Notifier *);
|
||||
|
||||
private:
|
||||
void UpdateTrackInfo(void);
|
||||
void UpdateCDInfo(void);
|
||||
void UpdateTimeInfo(void);
|
||||
void SetBitmap(BBitmap *bitmap);
|
||||
|
||||
bool fStopOnQuit;
|
||||
|
||||
CDEngine *engine;
|
||||
|
||||
@@ -54,11 +60,16 @@ private:
|
||||
|
||||
BSlider *fVolume;
|
||||
|
||||
BTextControl *fCDTitle;
|
||||
BStringView *fTrackNumber;
|
||||
BStringView *fCDTitle;
|
||||
BStringView *fCurrentTrack;
|
||||
BStringView *fTrackTime;
|
||||
BStringView *fDiscTime;
|
||||
|
||||
BBox *fCDBox;
|
||||
BBox *fTrackBox;
|
||||
BBox *fTimeBox;
|
||||
|
||||
CDState fCDState;
|
||||
int32 fTrackCount, fCurrentTrack;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+109
-37
@@ -15,6 +15,8 @@
|
||||
#include "scsi.h"
|
||||
#include "CDEngine.h"
|
||||
|
||||
const bigtime_t kPulseRate = 500000;
|
||||
|
||||
PeriodicWatcher::PeriodicWatcher(int devicefd)
|
||||
: Notifier(),
|
||||
devicefd(devicefd)
|
||||
@@ -168,50 +170,67 @@ TimeState::UpdateState()
|
||||
status_t media_status = B_DEV_NO_MEDIA;
|
||||
ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status));
|
||||
if (media_status != B_NO_ERROR)
|
||||
return CurrentState(-1, -1);
|
||||
|
||||
return CurrentState(-1, -1, -1, -1);
|
||||
|
||||
status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos);
|
||||
|
||||
|
||||
if (result != B_NO_ERROR)
|
||||
return CurrentState(-1, -1);
|
||||
else if ((!pos.position[1]) || (pos.position[1] >= 0x13) ||
|
||||
((pos.position[1] == 0x12) && (!pos.position[6])))
|
||||
return CurrentState(0, 0);
|
||||
return CurrentState(-1, -1, -1, -1);
|
||||
else
|
||||
if ((!pos.position[1]) || (pos.position[1] >= 0x13) ||
|
||||
((pos.position[1] == 0x12) && (!pos.position[6])))
|
||||
{
|
||||
// This indicates that we have a CD, but we are stopped. We *could* simply
|
||||
// return all 0's, but because the GUI expects valid numbers or -1's, we
|
||||
// return -1's.
|
||||
return CurrentState(-1, -1, -1, -1);
|
||||
}
|
||||
else
|
||||
return CurrentState(pos.position[9], pos.position[10]);
|
||||
return CurrentState(pos.position[9], pos.position[10], pos.position[13], pos.position[14]);
|
||||
}
|
||||
|
||||
bool
|
||||
TimeState::CurrentState(int32 minutes, int32 seconds)
|
||||
TimeState::CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec)
|
||||
{
|
||||
if (minutes == oldMinutes && seconds == oldSeconds)
|
||||
if (dmin == fDiscMinutes && dsec == fDiscSeconds)
|
||||
return false;
|
||||
oldMinutes = minutes;
|
||||
oldSeconds = seconds;
|
||||
|
||||
fDiscMinutes = dmin;
|
||||
fDiscSeconds = dsec;
|
||||
fTrackMinutes = tmin;
|
||||
fTrackSeconds = tsec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TimeState::GetTime(int32 &minutes, int32 &seconds) const
|
||||
TimeState::GetDiscTime(int32 &minutes, int32 &seconds) const
|
||||
{
|
||||
minutes = oldMinutes;
|
||||
seconds = oldSeconds;
|
||||
minutes = fDiscMinutes;
|
||||
seconds = fDiscSeconds;
|
||||
}
|
||||
|
||||
void
|
||||
TimeState::GetTrackTime(int32 &minutes, int32 &seconds) const
|
||||
{
|
||||
minutes = fTrackMinutes;
|
||||
seconds = fTrackSeconds;
|
||||
}
|
||||
|
||||
|
||||
CDContentWatcher::CDContentWatcher(int devicefd)
|
||||
: PeriodicWatcher(devicefd),
|
||||
cddbQuery("us.cddb.com", 888, true),
|
||||
cddbQuery("us.freedb.org", 888, true),
|
||||
discID(-1),
|
||||
wasReady(false)
|
||||
fReady(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDContentWatcher::CDContentWatcher(BMessage *message)
|
||||
: PeriodicWatcher(message),
|
||||
cddbQuery("us.cddb.com", 888, true),
|
||||
cddbQuery("us.freedb.org", 888, true),
|
||||
discID(-1),
|
||||
wasReady(false)
|
||||
fReady(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -224,23 +243,61 @@ CDContentWatcher::GetContent(BString *title, vector<BString> *tracks)
|
||||
bool
|
||||
CDContentWatcher::UpdateState()
|
||||
{
|
||||
bool newReady = false;
|
||||
bool newDiscID = -1;
|
||||
if (engine->PlayStateWatcher()->GetState() != kNoCD) {
|
||||
|
||||
// Check the table of contents to see if the new one is different
|
||||
// from the old one whenever there is a CD in the drive
|
||||
if (engine->PlayStateWatcher()->GetState() != kNoCD)
|
||||
{
|
||||
scsi_toc toc;
|
||||
ioctl(devicefd, B_SCSI_GET_TOC, &toc);
|
||||
newDiscID = cddbQuery.GetDiscID(&toc);
|
||||
if (discID != newDiscID)
|
||||
cddbQuery.SetToCD(&toc);
|
||||
|
||||
if (discID == newDiscID)
|
||||
return false;
|
||||
|
||||
// We have changed CDs, so we are not ready until the CDDB lookup finishes
|
||||
cddbQuery.SetToCD(&toc);
|
||||
fReady=false;
|
||||
}
|
||||
|
||||
// If the CD has changed and the CDDB query is ready, we set to true so that
|
||||
// when UpdateState returns, a notification is sent
|
||||
bool result = ( (fReady != cddbQuery.Ready()) && (newDiscID != discID) );
|
||||
|
||||
if(result)
|
||||
{
|
||||
fReady = true;
|
||||
discID = newDiscID;
|
||||
}
|
||||
|
||||
bool result = newReady != cddbQuery.Ready() && newDiscID != discID;
|
||||
newReady = cddbQuery.Ready();
|
||||
newDiscID = discID;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VolumeState::VolumeState(int devicefd)
|
||||
: PeriodicWatcher(devicefd),
|
||||
fVolume(-1)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
VolumeState::UpdateState(void)
|
||||
{
|
||||
scsi_volume vol;
|
||||
ioctl(devicefd, B_SCSI_GET_VOLUME, &vol);
|
||||
if(vol.port0_volume == fVolume)
|
||||
return false;
|
||||
|
||||
fVolume = vol.port0_volume;
|
||||
return true;
|
||||
}
|
||||
|
||||
int32
|
||||
VolumeState::GetVolume(void) const
|
||||
{
|
||||
return fVolume;
|
||||
}
|
||||
|
||||
CDEngine::CDEngine(int devicefd)
|
||||
: BHandler("CDEngine"),
|
||||
devicefd(devicefd),
|
||||
@@ -318,12 +375,13 @@ void
|
||||
CDEngine::Play()
|
||||
{
|
||||
// play the CD
|
||||
if (playState.GetState() == kNoCD) {
|
||||
if (playState.GetState() == kNoCD)
|
||||
{
|
||||
// no CD available, bail out
|
||||
ioctl(devicefd, B_LOAD_MEDIA, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
scsi_play_track track;
|
||||
|
||||
track.start_track = 1;
|
||||
@@ -332,7 +390,8 @@ CDEngine::Play()
|
||||
track.end_index = 1;
|
||||
|
||||
status_t result = ioctl(devicefd, B_SCSI_PLAY_TRACK, &track);
|
||||
if (result != B_NO_ERROR) {
|
||||
if (result != B_NO_ERROR)
|
||||
{
|
||||
PRINT(("error %s playing track\n", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
@@ -343,7 +402,8 @@ CDEngine::PlayContinue()
|
||||
{
|
||||
// continue after a pause
|
||||
status_t result = ioctl(devicefd, B_SCSI_RESUME_AUDIO);
|
||||
if (result != B_NO_ERROR) {
|
||||
if (result != B_NO_ERROR)
|
||||
{
|
||||
PRINT(("error %s resuming\n", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
@@ -354,8 +414,9 @@ CDEngine::Stop()
|
||||
{
|
||||
// stop a playing CD
|
||||
status_t result = ioctl(devicefd, B_SCSI_STOP_AUDIO);
|
||||
if (result != B_NO_ERROR) {
|
||||
PRINT(("error %s stoping\n", strerror(errno)));
|
||||
if (result != B_OK)
|
||||
{
|
||||
PRINT(("error %s stopping\n", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -371,9 +432,10 @@ CDEngine::Eject()
|
||||
|
||||
// if door open, load the media, else eject the CD
|
||||
status_t result = ioctl(devicefd,
|
||||
media_status == B_DEV_DOOR_OPEN ? B_LOAD_MEDIA : B_EJECT_DEVICE);
|
||||
media_status == B_DEV_DOOR_OPEN ? B_LOAD_MEDIA : B_EJECT_DEVICE);
|
||||
|
||||
if (result != B_NO_ERROR) {
|
||||
if (result != B_OK)
|
||||
{
|
||||
PRINT(("error %s ejecting\n", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
@@ -506,12 +568,22 @@ CDEngine::SelectTrack(int32 trackNumber)
|
||||
}
|
||||
}
|
||||
|
||||
const bigtime_t kPulseRate = 500000;
|
||||
void
|
||||
CDEngine::SetVolume(uint8 value)
|
||||
{
|
||||
scsi_volume vol;
|
||||
|
||||
// change only port0's volume
|
||||
vol.flags=2;
|
||||
vol.port0_volume=value;
|
||||
|
||||
ioctl(devicefd,B_SCSI_SET_VOLUME,&vol);
|
||||
}
|
||||
|
||||
void
|
||||
CDEngine::DoPulse()
|
||||
{
|
||||
// this is the CDEngine's hearbeat; Since it is a Notifier, it checks if
|
||||
// this is the CDEngine's heartbeat; Since it is a Notifier, it checks if
|
||||
// any values changed since the last hearbeat and sends notices to observers
|
||||
|
||||
bigtime_t time = system_time();
|
||||
|
||||
@@ -98,13 +98,18 @@ public:
|
||||
: PeriodicWatcher(message)
|
||||
{}
|
||||
|
||||
void GetTime(int32 &minutes, int32 &seconds) const;
|
||||
void GetDiscTime(int32 &minutes, int32 &seconds) const;
|
||||
void GetTrackTime(int32 &minutes, int32 &seconds) const;
|
||||
|
||||
private:
|
||||
bool UpdateState();
|
||||
bool CurrentState(int32 minutes, int32 seconds);
|
||||
int32 oldMinutes;
|
||||
int32 oldSeconds;
|
||||
bool CurrentState(int32 dmin, int32 dsec, int32 tmin, int32 tsec);
|
||||
|
||||
int32 fDiscMinutes;
|
||||
int32 fDiscSeconds;
|
||||
|
||||
int32 fTrackMinutes;
|
||||
int32 fTrackSeconds;
|
||||
};
|
||||
|
||||
class CDContentWatcher : public PeriodicWatcher {
|
||||
@@ -119,24 +124,24 @@ private:
|
||||
|
||||
CDDBQuery cddbQuery;
|
||||
int32 discID;
|
||||
bool wasReady;
|
||||
bool fReady;
|
||||
};
|
||||
|
||||
class VolumeState : public PeriodicWatcher {
|
||||
// this watcher sends notices to observers that are interrested
|
||||
// this watcher sends notices to observers that are interested
|
||||
// about changes in the current volume
|
||||
// currently not used yet
|
||||
public:
|
||||
VolumeState(int devicefd)
|
||||
: PeriodicWatcher(devicefd)
|
||||
{ }
|
||||
VolumeState(int devicefd);
|
||||
VolumeState(BMessage *message)
|
||||
: PeriodicWatcher(message)
|
||||
{}
|
||||
|
||||
bool UpdateState() { return true; }
|
||||
virtual void DoPulse() {}
|
||||
bool UpdateState();
|
||||
int32 GetVolume() const;
|
||||
|
||||
private:
|
||||
int32 fVolume;
|
||||
|
||||
};
|
||||
|
||||
class CDEngine : public BHandler {
|
||||
@@ -168,6 +173,7 @@ public:
|
||||
void StopSkipping();
|
||||
void SelectTrack(int32);
|
||||
|
||||
void SetVolume(uint8 value);
|
||||
|
||||
TrackState *TrackStateWatcher()
|
||||
{ return &trackState; }
|
||||
@@ -186,6 +192,11 @@ public:
|
||||
|
||||
CDContentWatcher *ContentWatcher()
|
||||
{ return &contentWatcher; }
|
||||
|
||||
VolumeState *VolumeStateWatcher()
|
||||
// to find the current location on the CD, you may call the GetVolume function
|
||||
// VolumeState defines
|
||||
{ return &volumeState; }
|
||||
|
||||
static int FindCDPlayerDevice();
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ resource(101, "BEOS:M:STD_ICON") #'MICN' array {
|
||||
$"FFFFFFFFFFFF000000000EFFFFFFFFFF"
|
||||
};
|
||||
|
||||
resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku.CDPlayer";
|
||||
resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-CDPlayer";
|
||||
|
||||
resource(1, "BEOS:FILE_TYPES") message;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user