This is not a current assignment. If you are currently enrolled in SE1020, do not do this assignment expecting to receive credit for it.

Lab 7: A Complete and Functional Multimedia Player!

Note: Some important updates regarding the MediaCodec classes were made February 5, 2008.

Objectives

  • Be able to use Java file IO to read and write both binary and text files
  • Be able to use classes within the Java Collections Framework
  • Implement inheritance and polymorphism in a Java program

Assignment

By the time you are finished with the second part of this lab, you will be able to actually play the music tracks stored in the playlists. For the second part of this lab, you will need to download and install the Java Media Framework. See the instructions below.

This is a multi-week lab consisting of 2 parts. Only a single lab report is required, but you must demonstrate portions of your program during the week 9 and week 10 lab sessions. Further details regarding the minimum functionality required in the first two demonstrations can be found below.

UML Class Diagram

Week 9 Milestone (demonstration due at beginning of week 9 lab session)

In this part of the project, you will be making modifications to the MediaPlayerUI and the MediaController in order to get ready to have the capability to play back multimedia files.

playlistIndex creation

Add an integer attribute, playlistIndex to the MediaController class that represents an index into the playlist collection maintained by mediaController. This index should be set to 0 when the MediaController is first created, or whenever:

  • a new playlist is loaded
  • a new MediaItem is added to the collection via the Playlist Manager Add button
  • an existing MediaItem is deleted from the collection via the Playlist Manager Remove button

Next and Previous Song Creation

Add to the MediaController class two methods, a nextSong method and a previousSong method. These methods do not have any parameters associated with them, and their return type is void.

The implementation of these methods is simple. If the nextSong method is called, the playlistIndex variable shall be incremented by a value of 1 so long as this does not result in an integer value greater than or equal to the number of songs in the playlist. If the previousSong method is invoked, the index shall be decremented by 1 so long as the value does not become negative. For the first demo, the value of the playlistIndex should be printed to the console if either method is called. Note: additional functionality must be added to these methods (see below).

MediaPlayerPlaybackInterface

Create an interface in your project with the name MediaPlayerPlaybackInterface. This interface has four methods, namely fastForward, fastReverse, playTrack, and stop. Except for the playTrack method, each of these methods has no parameters, and they all return void. The playTrack method accepts a MediaEventListener as a parameter. A MediaEventListener is an interface defined in the file ''MediaEventListener.java'' file you must add to your project. Do not modify the code in this file!

MediaItem class interface implementation

Modify the implementation of the MediaItem class so that it implements the MediaPlayerPlaybackInterface. This requires the fastForward, fastReverse, playTrack, and stop methods to be created. For right now, mark these methods as

// TODO and simply have them return when invoked.

Play implementation

Currently, when you press the Play button on the MediaPlayerUI, you simply display the phrase “Playing…” on a JLabel at the bottom of the window. You will modify the handling of Play button event so that the play() method of MediaController is called when this button is pressed.

Modify MediaController’s play() method to accept a single parameter - a reference to a MediaEventListener object. When the play method is invoked, this parameter shall be stored in the media controller as a variable. As long as the media is playing, it shall be valid. If the stop button is pressed, it shall be set to null.

You will notice that there are several methods defined in this interface; one of them, updatePlayInfo(), accepts a single String argument. When you implement this method in your MediaPlayerPlaybackEventHandler class, this method will be called whenever a new MediaItem media track is played. Your implementation of updatePlayInfo() inside your MediaPlayerPlaybackEventHandler class should take the String passed as an argument and use it to update the text of the JLabel in the MediaPlayerUI window to show what track is currently being played. The MediaPlayerPlaybackEventHandler class should be implemented as an inner class of the MediaPlayerUI class.

The second MediaEventListener method is updatePlayCompletion(), which accepts a single int argument that specifies the percent completion of the currently playing track. When you implement this method in your MediaPlayerPlaybackEventHandler class, it will be called repeatedly as the playing of a media track progresses. You use the percent completion value to update the position of the JProgressBar in the MediaPlayerUI interface. Note that you'll have to specify the range of the JProgressBar to accommodate values from 0 to 100.

The third MediaEventListener method is indicateTrackPlaybackHasCompleted(), which has no parameters. This method will be invoked whenever the currently playing track finishes. When the currently playing track has completed, the MediaPlayerUI shall call the nextSong method on the media controller, causing the next song on the playlist to play.

The overall play behavior is shown in the sequence diagram below.

Play Sequence Diagram

Getting back to MediaController’s play() method: When the play() method is called, it must examine the index attribute you added to MediaController in Step 2. For the MediaItem associated with that index, call the playTrack() method. Note that playTrack() takes a single parameter a reference to a MediaEventListener object.

The behavior when a track finishes playing is shown below.

Play Done Sequence Diagram

Next, Previous Song implementation

If the next or previous buttons on the UI are pressed, the behavior should match that which is shown in the sequence diagram below. Namely, the next or previous method of the controller shall be invoked. This shall cause the controller to stop playing the current song and increment or decrement the index to the next or previous song.

Next/Previous Song Sequence Diagram

Week 10 Milestone (demonstration due at beginning of week 10 lab session)

In the first part of this lab, you set up for the multimedia player to be capable of playing tracks. In this series of steps, you will actually make the player play your playlists.

Installing the Java Media Framework

You need to install the Java Media Framework from Sun Microsystems in order to get Java support for sound. This involves downloading two .jar files from SUN, installing them onto your PC, and making a few changes within your Eclipse project, as well as downloading a .jar file from Sorceforge.

First, you will need to download the Java MP3 pluggin. After agreeing to the license agreement, download javamp3-1_0.zip. Open this file using the zip extraction tool on your PC and extract mp3plugin.jar to the C:\Program Files\Java\jre1.6.0_02\lib\ext directory on your machine.

Second, you will need to download the Java JMF Library. Download jmf-2_1_1e-alljava.zip. Extract the jmf.jar file into the C:\Program Files\Java\jre1.6.0_02\lib\ext directory as well.

Once you have done this, you will need to download the jid3lib.jar from sourceforge. This library assists in the handling of id3 tags. Extract this file into your local development repository at the same level as the src and bin directories. Right click on your project in Eclipse and press refresh to refresh the development directory. Right click on the project and select properties. Highlight Java Build Path and select libraries. Click add Jar and select the jid3lib-0.5.4.jar file and include it into your project.

MediaPlayers Class Diagram

Adding the MediaCodec Classes to Your Project

Create a package called mediaCodecs to your project. Extract the contents of the MediaCodec.zip file into this folder created when the mediaCodecs package was created.

Modifying the MediaItem class

To finally allow audio to be played, you will need to modify the MediaItem class to contain a transient instance of a MediaCodec class. The transient modifier, when applied to a class's attribute, excludes that attribute from being serialized along. We don't want to serialize the contained MediaCodec object when we serialize a MediaItem, which is why we mark this attribute transient.

The MediaCodec class is actually an abstract class; you can not instantiate instances of it. However, there are three classes which extend the class, namely MP3Player, WavPlayer, and MidiPlayer. The relationship between these classes is shown in the figure above. Download the MediaEventListener and MediaPlayerPlaybackInterface interfaces and MediaCodec, WavPlayer, MP3Player, and MidiPlayer classes. Do not create these classes.

MediaItem Implementations

Next, in the MediaItem class, implement the functionality for the play and stop methods:

When the playTrack method is called on a MediaItem object, you'll create the appropriate type of MediaCodec object – that is, MidiPlayer, MP3Player, or WavPlayer (since MediaCodec is an abstract class). You will need to determine if the filename being passed in is for an MP3, Wave, or Midi file. You can do this by parsing the string looking for “MP3”, “mp3”, “Mp3”, “mP3” or any other case combination for MP3 files, “wav”, “WAV”, “WaV”, or any other case combinations for wave files, and “mid” or any combination thereof for midi files. Based on this, instantiate the mediaCodec variable to the proper class type. Once this has been done, call the MediaCodec.playTrack method, passing in the event handler that was passed with the MediaItem.playTrack method invocation. Here's where polymorphism occurs - mediaCodec is a MediaCodec reference, but you're actually calling the playTrack method of a WavPlayer, MP3Player, or MidiPlayer.

When the stop method of the MediaItem is invoked, a call should be made to the stop method on the MediaCodec-derived object. After calling the stop() method, set the mediaCodec reference to null. (Warning: Make certain that the MediaCodec reference is not null before making the stop() call, in order to prevent null pointer exceptions when the user presses the Stop button more than once.)

The fastForward and fastReverse MediaItem classes need to be modified simply to call the codec fastForward and fastReverse methods; no further processing is necessary.

Notes on inheritance and polymorphism

Using inheritance and abstract classes for the first time can be a little confusing. You are going to be using instances of MP3Player, MidiPlayer, or WavPlayer, but you'll be referring to them as instances of MediaCodec. It is the inheritance hierarchy that allows us to do this: we can refer to objects of any of the derived classes (subclasses) as though they were an instance of the base class (superclass).

We can never instantiate an abstract base class:

// BAD 
MediaCodec myItem = new MediaCodec(mediaFile, eventListener);

However, we can refer to instances of the derived classes as though they were instances of the base class:

// GOOD
MediaCodec myItem = new MP3Player(mediaFile, MediaEventListener);

Report

Submit your assignment, including a lab report, according to your instructor's directions.

FAST Data

You should indicate how much time (in minutes) you spend on this assignment in the FAST database. You are encouraged to log your activity as you work on the project. At a minimum, you should log all of the time spent on this assignment before the due date given above. All time spent on this assignment should be entered into the weeks 8-10 columns.

se1020labs/lab7.txt · Last modified: 2009/06/03 11:22 (external edit)
 

This website is not owned or managed by the Milwaukee School of Engineering.

© 2003-2010 Dr. Christopher C. Taylor, et. al. • Office: L-343 • Phone: 277-7339 • npǝ˙ǝosɯ@ɹolʎɐʇ • -> RSS <-