- abplayer.zip
- abPlayer.sln
- abPlayer.suo
- abPlayer
- DLLs
- ComLib.dll
- ComLib.PocketPC.asmmeta.dll
- OcxControls.dll
- OcxControls.PocketPC.asmmeta.dll
- OpenNETCF.Windows.Forms.AxHost.dll
- OpenNETCF.Windows.Forms.AxHost.PocketPC.asmmeta.dll
- WMPLib.dll
- Graphics
- book.bmp
- bookshelf.jpg
- check.png
- dirclosed.bmp
- diropen.bmp
- uncheck.png
- up.jpg
- Skins
- Color
- battery.jpg
- cancel.jpg
- clock.jpg
- dark.jpg
- exit.jpg
- library.jpg
- light.jpg
- media.jpg
- menu.jpg
- next.jpg
- ok.jpg
- play.jpg
- prev.jpg
- props.jpg
- remove.jpg
- sleep.jpg
- stop.jpg
- switch.jpg
- vol.jpg
- Grayscale
- battery.jpg
- cancel.jpg
- clock.bmp
- dark.jpg
- exit.jpg
- library.jpg
- light.jpg
- media.jpg
- menu.jpg
- next.jpg
- ok.jpg
- play.jpg
- prev.jpg
- Props.jpg
- remove.bmp
- sleep.jpg
- stop.jpg
- switch.jpg
- vol.jpg
- Submission_Form.zip
|
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Configuration;
using Microsoft.Win32;
using System.Collections;
using AxWMPLib;
using System.IO;
using System.Threading;
public class cPlayer : cBasePlayer
{
// tag name constants used
private String[] sTagNames = {"album",
"title",
"author",
"comment",
"filename"};
private String[] sPlayerStatus = {
"UNDEFINED",
"STOPPED",
"PAUSED",
"PLAYING",
"SCAN-FORWARD",
"SCAN-REVERSE",
"BUFFERING",
"WAITING",
"MEDIA-ENDED",
"TRANSITIONING",
"READY",
"RECONNECTING"};
// the event handler place holder
public event PlayItemChangedEventHandler PlayItemChanged = null;
public event StatusChangedEventHandler StatusChanged = null;
// windows media player object
private AxWindowsMediaPlayer WMP = null;
// internal playlist holder
private ArrayList pPlaylistFiles = null;
// files duration population objects
private ArrayList pDurations = null;
// total duration thread
private Thread tMP3 = null;
// player status
private ePlayerStatus pStatus = ePlayerStatus.STOPPED;
// flag indicating playlist is beeing loaded to the player
// at this time intermediate status change events are suppressed
// and any attempt to manipulate media (play/pause/stop/next/previous)
// is ignored
private bool LoadingPlaylist = false;
public cPlayer()
{
// windows media player object
WMP = new AxWindowsMediaPlayer();
// internal playlist holder
pPlaylistFiles = new ArrayList();
pDurations = new ArrayList();
// initial player settings
WMP.uiMode = "invisible";
WMP.enableContextMenu = false;
WMP.settings.autoStart = false;
// windows media player volume control affects the media player
// only. we prefer to control volume via the wave out master volume
// we set the player internal volume to max.
WMP.settings.volume = 100;
// create a dummy playlist - this will be managed and manipulated
// when user loads/plays playlists
WMP.newPlaylist("dummy_name", "dummy_file.mp3");
// add internal event handlers
WMP.PlayStateChange += new _WMPOCXEvents_PlayStateChangeEventHandler(wmp_PlayStateChange);
WMP.NewStream += new EventHandler(WMP_NewStream);
WMP.CurrentItemChange += new _WMPOCXEvents_CurrentItemChangeEventHandler(WMP_CurrentItemChange);
}
// pseudo destructor
public override void Dispose()
{
try { WMP.Dispose(); }
catch { }
}
// get the file name of the indexed
// media file path
public override String PlaylistFile(int i)
{
return ((i >= pPlaylistFiles.Count) ||(i < 0)) ?
"" : (String)pPlaylistFiles[i];
}
// the player item changed event is passed on with the index
// of the media in the playlist
void WMP_NewStream(object sender, EventArgs e)
{
SignalNewMediaEvent();
}
void WMP_CurrentItemChange(object sender, _WMPOCXEvents_CurrentItemChangeEvent e)
{
SignalNewMediaEvent();
}
public override int FileDuration(int i)
{
if((i >= pPlaylistFiles.Count) ||
(i < 0) ||
(Duration == -1) ||
(pDurations.Count - pPlaylistFiles.Count != 1))
return -1;
return (int)pDurations[i + 1] - (int)pDurations[i];
}
public override int TotalDuration
{
get
{
return (Duration == -1)? 0:
(pDurations.Count - pPlaylistFiles.Count == 1) ?
(int)pDurations[pPlaylistFiles.Count]:
0;
}
}
public override String TotalDurationString
{
get { return TrimTimeString(TimeToString(TotalDuration)); }
}
public override int TotalDurationSoFar
{
get
{
if ((Location == -1) ||
(pDurations.Count - pPlaylistFiles.Count != 1))
return 0;
return (int)pDurations[PlayingIndex] + Location;
}
}
public override String TotalDurationSoFarString
{
get { return TrimTimeString(TimeToString(TotalDurationSoFar)); }
}
public override int TotalDurationRemain
{
get
{
if ((Location == -1) ||
(pDurations.Count - pPlaylistFiles.Count != 1))
return 0;
return TotalDuration - TotalDurationSoFar;
}
}
public override String TotalDurationRemainString
{
get { return TrimTimeString(TimeToString(TotalDurationRemain)); }
}
private void SignalNewMediaEvent()
{
if ((PlayItemChanged != null) &&
(!LoadingPlaylist))
{
PlayItemChangedEventArgs ea = new PlayItemChangedEventArgs(PlayingIndex);
PlayItemChanged(this, ea);
}
}
// the player state chnanged is passed on with the new state
// (alphabetized and capitalized)
private void wmp_PlayStateChange(object sender, _WMPOCXEvents_PlayStateChangeEvent e)
{
pStatus = (ePlayerStatus)e.newState;
if ((StatusChanged != null) &&
(!LoadingPlaylist))
{
StatusChangedEventArgs ea = new StatusChangedEventArgs(pStatus, sPlayerStatus[(int)pStatus]);
StatusChanged(this, ea);
}
}
// playlist count is a get only property
public override int PlaylistCount
{
get { return pPlaylistFiles.Count; }
}
// playing item path is a get only property derived from the
// sourceurl property of the media being played
public override String PlayingPath
{
get
{
try
{
return WMP.currentMedia.sourceURL;
}
catch { return ""; }
}
}
// plying index is a get property derived at by using indexof
// of the file paths
public override int PlayingIndex
{
get
{
try
{
return pPlaylistFiles.IndexOf(PlayingPath);
}
catch { return -1; }
}
set
{
if ((value >= pPlaylistFiles.Count) ||
(value < 0))
return;
try
{
WMP.Ctlcontrols.playItem(WMP.currentPlaylist.get_Item(value));
WaitForStatusWithTimeout(ePlayerStatus.PLAYING, 2);
// pause again
WMP.Ctlcontrols.pause();
}
catch { }
}
}
// playing name is a get only property. file name is extracted from
// the playingpath property
public override String PlayingName
{
get
{
return new FileInfo(PlayingPath).Name;
}
}
// delete a playlist entry
public override int RemoveAt(int ix)
{
if ((ix < 0) || (ix > (pPlaylistFiles.Count - 1))) return ix;
TerminateDurationThread();
pDurations.Clear();
pPlaylistFiles.RemoveAt(ix);
int nix = (ix > (pPlaylistFiles.Count - 1)) ? ix - 1 : ix;
try { Playlist((String[])pPlaylistFiles.ToArray(typeof(String)), nix, 0, Shuffle); }
catch { }
return nix;
}
// status is a get only property. state returned is the last reported
// in the statechanged event
public override ePlayerStatus Status
{
get { return pStatus; }
}
public override String StatusString
{
get { return sPlayerStatus[(int)pStatus]; }
}
// set/reset the shuffle attribute in the player.
public override bool Shuffle
{
get
{
try { return WMP.settings.getMode("shuffle"); }
catch { return false; }
}
set
{
try { WMP.settings.setMode("shuffle", value); }
catch{}
}
}
// duration is a get only property (returns the currently playing
// media duration
public override int Duration
{
get
{
try { return (int)WMP.currentMedia.duration; }
catch { return -1; }
}
}
// same as duration but converted to a string
public override String DurationString
{
get
{
return (Duration == -1) ? "No Media" :
TrimTimeString(TimeToString(Duration));
}
}
// location is a get/set property of the currently playing media
// timeline
public override int Location
{
get
{
try { return (int)WMP.Ctlcontrols.currentPosition; }
catch { return -1; }
}
set
{
try { WMP.Ctlcontrols.currentPosition = value; }
catch { }
}
}
// same as duration but as string. obviously only a get property
public override String LocationString
{
get
{
return (Location == -1) ? "No Media" :
TrimTimeString(TimeToString(Location));
}
}
// get ID3 media tag.
// some tags can be accessed using getiteminfo (using the standard
// tag names) others (which have no standard names) have indexers and
// can be accessed using getiteminfobyatom
public override String GetMediaTAG(eTagNames tag)
{
try
{
switch (tag)
{
case eTagNames.ALBUM:
case eTagNames.TITLE:
case eTagNames.AUTHOR:
return WMP.currentMedia.getItemInfo(sTagNames[(int)tag]);
case eTagNames.COMMENT:
return WMP.currentMedia.getItemInfoByAtom(24);
case eTagNames.FILE_NAME:
return WMP.currentMedia.getItemInfoByAtom(2);
default:
return "";
}
}
catch { return ""; }
}
// as described above - player actions are suppressed while loading a
// a playlist
// call player 'play' function
public override bool Play()
{
if (LoadingPlaylist) return false;
try { WMP.Ctlcontrols.play(); }
catch { return false; }
return true;
}
// call 'pause'
public override bool Pause()
{
if (LoadingPlaylist) return false;
try { WMP.Ctlcontrols.pause(); }
catch { return false; }
return true;
}
// call 'next'
public override bool Next()
{
if (LoadingPlaylist) return false;
try { WMP.Ctlcontrols.next(); }
catch { return false; }
return true;
}
// call 'previous'
public override bool Previous()
{
if (LoadingPlaylist) return false;
try { WMP.Ctlcontrols.previous(); }
catch { return false; }
return true;
}
// call 'stop'
public override bool Stop()
{
if (LoadingPlaylist) return false;
try { WMP.Ctlcontrols.stop(); }
catch { return false; }
return true;
}
// stop playing and clear playlist
public override bool StopAndClear()
{
// clear internal playlist
TerminateDurationThread();
pPlaylistFiles.Clear();
pDurations.Clear();
try
{
// try to stop
if (pStatus == ePlayerStatus.PLAYING)
{
WMP.Ctlcontrols.stop();
WaitForStatusWithTimeout(ePlayerStatus.STOPPED, 2);
}
}
catch {}
// clear the media's playlist
try {WMP.currentPlaylist.clear();}
catch { return false; }
return true;
}
// loading a playlist (and also setting various properties) is a
// multi step procedure. when each step is done the player status
// changes to reflect it.
// on ocations the procedure fails (beats me), moreover, the length of time
// it takes to complete each step varies.
// we use a function called 'WaitForStatusWithTimeout' to wait for
// the completion of each step. i use 2 seconds as the max wait time
// before an exception is raised. if we fail - we stop and clear the
// playlist so we can just start over.
public override bool Playlist(String[] files, int Entry, int Location,
bool Shuffle)
{
// flag indicating player actions should be ignored as well as
// intermedia status change events
LoadingPlaylist = true;
try
{
TerminateDurationThread();
// we might activate a previously loaded playlist or load a new
if (files != null)
{
// add files to internal play list
pPlaylistFiles.Clear();
pPlaylistFiles.AddRange(files);
// clear any previously loaded playlists
WMP.currentPlaylist.clear();
foreach (String file in files)
{
// for each file in the playlist -
// create a media object and load into player
WMP.currentPlaylist.appendItem((WMPLib.IWMPMedia)WMP.newMedia(file));
}
// we force garbage collection here to dispose of the media
// objects.
// if we let garbage collection to work automatically it
// would kick in when the player is playing and since it might
// have a large number of objects to dispose, the device (and
// the playing) freezes for a few seconds.
GC.Collect();
}
// start playing - this would initialize various properties
// in the player that we need access to.
// (lame !!) - but i couldn't find any other way to do it
if (pPlaylistFiles.Count > 0)
{
WMP.Ctlcontrols.play();
// wait for it to achieve play state and immediately pause
WaitForStatusWithTimeout(ePlayerStatus.PLAYING, 2);
WMP.Ctlcontrols.pause();
WaitForStatusWithTimeout(ePlayerStatus.PAUSED, 2);
// load shuffle attribute
WMP.settings.setMode("shuffle", Shuffle);
WaitForStatusWithTimeout(ePlayerStatus.PAUSED, 2);
// set the playing item desired
WMP.Ctlcontrols.playItem(WMP.currentPlaylist.get_Item(Entry));
// wait for player to go there
WaitForStatusWithTimeout(ePlayerStatus.PLAYING, 2);
// pause again
WMP.Ctlcontrols.pause();
WaitForStatusWithTimeout(ePlayerStatus.PAUSED, 2);
// change timeline to desired location
WMP.Ctlcontrols.currentPosition = Location;
}
wmp_PlayStateChange(this, new _WMPOCXEvents_PlayStateChangeEvent((int)ePlayerStatus.PAUSED));
tMP3 = new Thread(new ThreadStart(GetTotalsDurationsThreadFunction));
tMP3.IsBackground = true;
tMP3.Priority = ThreadPriority.BelowNormal;
tMP3.Start();
}
catch (Exception e)
{
StopAndClear();
MessageBox.Show(e.Message);
return false;
}
finally
{
LoadingPlaylist = false;
}
return true;
}
public override bool WaitForPlayerStatus(ePlayerStatus s)
{
try
{
WaitForStatusWithTimeout(s, 2);
}
catch { return false; }
return true;
}
// as described above this function waits a maximum alloted time
// for a player action to take place
private void WaitForStatusWithTimeout(ePlayerStatus value, int seconds)
{
int start = (Environment.TickCount & Int32.MaxValue);
while (pStatus != value)
{
if (((Environment.TickCount & Int32.MaxValue) - start) >= seconds * 1000)
throw new Exception("Timed Out");
Application.DoEvents();
}
}
// function to convert time to string
public override String TimeToString(int time)
{
if(time < 0) return "00:00:00";
int s = time % 60;
int tmp = (time - s) / 60;
int m = tmp % 60;
int h = (tmp - m) / 60;
String str = ((h < 10) ? "0" + h.ToString() + ":" : h.ToString() + ":") +
((m < 10) ? "0" + m.ToString() + ":" : m.ToString() + ":") +
((s < 10) ? "0" + s.ToString() : s.ToString());
return str;
}
public override String TrimTimeString(String str)
{
return (str[0] == '0') ?
((str.Substring(0, 3) == "00:") ? str.Substring(3) : str.Substring(1)) : str;
}
public override void GetTotalsDurationsThreadFunction()
{
try
{
pDurations.Clear();
int total = 0;
for (int n = 0; n < pPlaylistFiles.Count; n++)
{
pDurations.Add(total);
total += new cMP3Info((String)pPlaylistFiles[n]).Duration;
}
pDurations.Add(total);
}
catch
{
pDurations.Clear();
}
}
private void TerminateDurationThread()
{
if (tMP3 != null)
tMP3.Abort();
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.