Multimedia aufs Handy gebracht

Einführung in die Grundlagen des Mobile Media API

David Price und das Forum Nokia Team

Beginnend mit dem Nokia 3650 implementieren einige MIDP-fähige Handys von Nokia das Mobile Media API (MMAPI), das MIDlets den umfangreicheren Umgang mit verschiedenen Medientypen erlaubt. Diese MIDlets sind in der Lage, verschiedene Arten von Audio und Video abzuspielen und außerdem Bilder mithilfe der Kamera aufzunehmen. Dieser Artikel soll die Grundlagen des Mobile Media API beschreiben und stellt dann das Media Sampler MIDlet vor – ein einfaches Beispielprogramm, das die Medienabspielfähigkeiten nutzt, um Sounds und Video wiederzugeben.

Der erste Abschnitt beschreibt die Architektur des Mobile Media API und geht auf deren wichtigste Klassen ein. Manager ist eine Klasse, die lediglich über statische Methoden verfügt. Anwendungen können keine Instanzen von ihr erstellen. Die Klasse Manager stellt statische Methoden zum Erstellen von Player und zum Abfragen von unterstützten Protokollen und Content-Typen bereit. Sie stellt außerdem die Hilfsmethode playTone() zur Verfügung, um einen einzelnen Ton abzuspielen. Die Methode createPlayer der Klasse Manager erzeugt einen Player mit einem assoziierten DataSource-Objekt, das ihn mit Daten versorgt. Dieses DataSource-Objekt kann entweder mit einem InputStream oder einem URI-Style Locator erzeugt werden. Nokias MMAPI-Implementierung unterstützt die folgenden Arten von Locators:

Abb. 1: Übersicht über die Architektur des Mobile Media API

Die Klasse Manager erzeugt die richtige Art der Implementierung der Klasse Player, indem sie den Content-Typ der DataSource überprüft (zum Beispiel anhand des Content-Typ-Header einer HTTP Response). Wenn sie den Content-Typ der DataSource nicht feststellen kann, dann wird eine MediaException ausgelöst. Sobald der Player erstellt wurde, kann man verschiedene Arten von Controls von ihm abfragen. Das können zum Beispiel folgende sein:

  • VolumeControl, um die Audiolautstärke des Player zu steuern
  • StopTimeControl, um den Player nach einer vorgegebenen Zeitspanne automatisch zu stoppen
  • VideoControl, um zu steuern, wie das Bild des Video Players dargestellt wird

Es existieren viele andere Arten von Controls, aber es werden nicht alle von der Mobile-Media-API-Implementierung jedes Mobiltelefons oder von jedem Content Type unterstützt. Man kann herausfinden, welche Fähigkeiten von einem Handy unterstützt werden, indem man die Systemeigenschaften überprüft (zum Beispiel durch Verwendung von System.getProperty(„supports.video.capture“)). Die komplette Liste an möglichen Eigenschaften findet man in der Spezifikation des MMAPI.

Abb. 2: Zustandsdiagramm des Player
Player State Model

Abbildung 2 zeigt das Zustandsdiagramm für den Player auf. Player werden in dem Zustand UNREALIZED erstellt, danach werden sie üblicherweise realisiert, danach PREFETCHED und schließlich gestartet. Wenn sie das Ende der Mediendatei erreichen oder die Methode stop() aufgerufen wurde, dann kehren sie zum PREFETCHED-Zustand zurück. Man kann den Status eines Player-Objektes überprüfen, indem man seine getState()-Methode aufruft. Aber seien Sie sich im Klaren darüber, dass Player ihren Zustand dynamisch ändern können oder dass andere Threads ihren Zustand beeinflussen können, sodass zu dem Zeitpunkt, wo die getState()-Methode zurückkehrt, ihr Ergebnis möglicherweise nicht mehr den aktuellen Zustand des Player widergibt.

Gleichermaßen kann man eine Benachrichtigung über den Zustandswechsel eines Player erhalten, indem man einen PlayerListener für ihn registriert. Aber man sollte beachten, dass die Mobile-Media-API-Spezifikation keine Garantie dafür gibt, wie schnell die Events für die Zustandsänderung geliefert werden, sodass, wenn man das started-Event erhält, das Abspielen des Mediums möglicherweise schon beendet ist (und es kann bereits ein end of media-Event als Nächstes in der Warteschlange stehen, das auf die Zustellung wartet).

Eine weitere Erschwernis ist, dass die Benachrichtigungen asynchron sind. Somit kann zum Beispiel die Event-Callback-Methode von einem anderen Thread als dem gewöhnlichen User Interface Thread aufgerufen werden und sie kann auch aufgerufen werden, während Ihre Klasse gerade ein User Interface Event in einem anderen Thread abarbeitet. Um wieder zum rein sequentiellen Event-Modell zurückzukehren, verwendet die Player-State-Change-Callback-Methode in dem Beispiel-MIDlet dieses Artikels die callSerially()-Methode der Display-Klasse des MIDlets und stellt neue User Interface Events einfach in eine Warteschlange. Diese neuen Events werden dann sequentiell mit den anderen User Interface Events abgearbeitet, anstatt sich möglicherweise mit diesen zu überlappen.

Wiedergeben von Tönen und Tonsequenzen

Um einmalig einen einfachen Ton abzuspielen, verwendet man die folgende Methode: Manager.playTone(note, duration, volume); . Um eine Tonsequenz abzuspielen, muss man allerdings ein ToneControl einsetzen. Hierfür erstellt man zunächst einen Player mit einem speziellen Locator, danach ermittelt man das ToneControl, setzt seine Kommandosequenz und startet dann den Player:

Player player = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
player.realize();
ToneControl tc = (ToneControl)(player.getControl("ToneControl"));
tc.setSequence(newbyte[] {ToneControl.C4,8ToneControl.C4+2,8}); //D4
player.start();

Beachten Sie, dass man player.realize() aufrufen muss, bevor man das ToneControl ermitteln kann. Man kann keinerlei Control von einem Player ermitteln, solange er noch nicht realisiert ist.

Das ToneControl nimmt Byte-Kommandos zum Abspielen von Noten, Erstellen und Abspielen von wiederholbaren Blöcken von Noten und zum Verändern des Tempos, der Lautstärke usw. entgegen [Brief Introduction to MIDP Programming]. Der Einfachheit halber beinhaltet keines der hier gezeigten Codefragmente die notwendigen try/catch-Blöcke für die verschiedenen Exceptions, die von den Methodenaufrufen ausgelöst werden können.

Abspielen von gesampletem Sound und MIDI

Gesampelter Sound wird durch Soundformate wie .wav dargestellt, in denen die Daten einen Stream von Sound Samples darstellen, die den Sound in jedem Bruchteil einer Sekunde repräsentieren. MIDI hingegen ist eine Folge von Kommandos für einen virtuellen Multi-Instrument-Synthesizer. Um über HTTP zugängliche Sound-Dateien abzuspielen, geht man folgendermaßen vor:

Playerplayer = Manager.createPlayer("http://something.com/somefile.wav");
player.start(); //ruft implizit auch realize() und prefetch() auf

Um eine Sound-Datei abzuspielen, die im jar-Archiv des MIDlets enthalten ist, muss man im Voraus ihren MIME Type (z.B. audio/x-wav) kennen. Danach verwendet man folgenden Aufruf:

InputStream is = getClass().getResourceAsStream("/somefile.wav");
Player player = Manager.createPlayer(is, "audio/x-wav");
player.start();

Um eine Sound-Datei abzuspielen, die in einem RMS Record Store abgelegt ist, geht man folgendermaßen vor:

RecordStore rs = RecordStore.open("name");
byte[] data = rs.getRecord(id);
ByteArrayInputStream is = new ByteArrayInputStream(data);
Player player = Manager.createPlayer(is, "audio/x-wav");
player.start();
Abspielen von Videos

Das Abspielen von Videos ist dem Abspielen von Audiodaten sehr ähnlich. Allerdings muss dem Video Player mitgeteilt werden, wo das Video angezeigt werden soll. Hierfür ermittelt man ein VideoControl mithilfe des Video Player und stellt dieses dann entweder als Formularelement oder als Canvas dar. Um Videos als Formularelement darzustellen, kann man folgenden Code verwenden:

InputStream is = getClass().getResourceAsStream("/somefile.3gp");
Player player = Manager.createPlayer(is, "video/3gpp");
player.realize();
VideoControl vc = (VideoControl)player.getControl("VideoControl");
If (vc != null)
{
     Item it = (Item)vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null);
     myForm.append(it);
     p.start();
}
Geschrieben von
David Price und das Forum Nokia Team
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.