[Banshee-List] Thinking about Mono.Media



Equipped with my shiny new copy of Framework Design Guidelines, I've
begun to mentally revisit the idea of a Mono.Media design. This is
just a rough idea about how things could work. I've got some broad
goals for the namespace, then ideas about the shape of the API. I'll
present the API ideas in the form of code that a Mono.Media user would
write to accomplish some task.

Briefly, I think the scope of Mono.Media should include three major
areas and two domains. The domains are audio and video, and the areas
are playback, transcoding, and profile description (audio profiles,
&c.). Brief indeed! So those are the goals I had in mind. Others are
welcome.

API design: I've given the most thought to the audio playback API b/c
I think that will be the top use of the framework (and it's
predominantly what Banshee will consume).

Idea 1: The Audio Object
Objects for each atomic unit of audio. You new up an Audio object,
passing it some atomic unit of audio (probably filename, maybe streams
or byte arrays). It would work something like this:

Audio a = new Audio ("/home/scott/Music/song.mp3");
a.Play ();

The constructor would acquire a backend appropriate to the audio file.
This allows for multiple audio files to play simultaneously:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
Audio b = new Audio ("/home/scott/Music/song2.wav");
a.Play ();
b.Play ();

I like this approach for its simplicity and strong correlation between
the object model and "real world" objects (songs). An open question in
my mind is whether the Audio object is mutable. For example, should
you be able to do this?:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
a.Play ();
// Begin playing another file
a.AudioFile = "/home/scott/Music/song2.wav";

I'm thinking no, but it's an option. Doing so might require the same
Audio object to switch backends. Then there are problems with concepts
like crossfading (assuming it's supported by the backend). If an Audio
object is mutable, you could do this:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
a.Play ();
a.CrossfadeTo ("/home/scott/Music/song2.wav");

On the other hand, if Audio objects are immutable, it could be a
little trickier:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
a.Play ();
// This method returns a new Audio object and stops the
// instance on which it was called after the fade
Audio b = a.CrossfadeTo ("/home/scott/Music/song2.wav");

There is also the option of:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
a.Play ();
// This constructor will attempt to crossfade from the
// provided Audio object
Audio b = new Audio (a, "/home/scott/Music/song2.wav");

The trouble with this is, the constructor of one object is affecting
another other (calling a.Stop () once the crossfade is complete). This
could also be problematic if the backend gives us only a single audio
stream during the crossfade: there are two objects representing the
same sound.

Another major issue with this API is the matter of backend handling.
Initializing a new backend for each Audio object has a performance
impact, as does disposing it. Ideally we would have a singleton of
each backend, but that might not allow playing multiple audio streams
at once. And even if we were able to manage a pool of backend
instances to be used by Audio objects, disposal still remains a
problem. Having some disposal boilerplate code does not seem idea:

Audio a = new Audio ("/home/scott/Music/song1.mp3");
a.Play ();
a.Stop ();
// This is stupid:
Mono.Media.BackendPool.DisposeAllBackends ();


Idea 2: The AudioPlayer Object
An AudioPlayer object is used to play audio. Each audio player
maintains its own backend pool (as needed) and it implements
IDisposable, so backend disposal is easy. An AudioPlayer can only play
one audio file at a time (with support for crossfading, if the backend
provides it):

using (AudioPlayer p = new AudioPlayer()) {
    p.Open ("/home/scott/Music/song1.mp3");
    p.Play ();
    p.CrossfadeTo ("/home/scott/Music/song2.mp3");
    p.Pause ();
    p.Close ();
    p.OpenAndPlay ("/home/scott/Music/song1.mp3");
    p.Open ("/home/scott/Music/song2.mp3");
    p.Play ();
}

You can have multiple AudioPlayers playing at the same time:

AudioPlayer p1 = new AudioPlayer ();
p1.OpenAndPlay ("/home/scott/Music/song1.mp3");
AudioPlayer p2 = new AudioPlayer ();
p2.OpenAndPlay ("/home/scott/Music/song2.mp3");
p1.Dispose ();
p2.Dispose ();

This object model also maps rather nicely to real-world objects. Thoughts?

-- 
Scott.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]