Voorbeeld van geluid: Podcast-speler

Flash Player 9 of hoger, Adobe AIR 1.0 of hoger

Een podcast is een geluidsbestand dat via internet wordt gedistribueerd, op aanvraag of in het kader van een abonnement. Podcasts worden meestal gepubliceerd als onderdeel van een reeks, ook wel podcast-kanaal genoemd. Aangezien podcast-afleveringen één minuut, maar ook meerdere uren kunnen duren, worden deze meestal gestreamd tijdens het afspelen. Podcast-afleveringen, ook wel items genoemd, worden meestal aangeleverd in MP3-indeling. Video-podcasts zijn ook populair, maar in deze voorbeeldtoepassing worden alleen audio-podcasts afgespeeld waarvoor MP3-bestanden worden gebruikt.

Dit voorbeeld is geen aggregatortoepassing met volledige podcast-functionaliteit. De voorbeeldtoepassing voorziet bijvoorbeeld niet in het beheer van abonnementen op specifieke podcasts en houdt niet bij welke podcasts de gebruiker al heeft beluisterd, zodat deze informatie niet beschikbaar is als de gebruiker de toepassing opnieuw uitvoert. De voorbeeldtoepassing is een goed uitgangspunt voor een aggregator met volledige podcast-functionaliteit.

In het voorbeeld van de podcast-speler worden de volgende ActionScript-programmeringstechnieken geïllustreerd:

  • Een externe RSS-feed lezen en de XML-inhoud van de feed parseren

  • Een klasse SoundFacade maken om het laden en afspelen van geluidsbestanden te vereenvoudigen

  • De voortgang van het afspelen van geluid weergeven

  • Het afspelen van geluid onderbreken en hervatten

Zie www.adobe.com/go/learn_programmingAS3samples_flash_nl als u de toepassingsbestanden voor dit voorbeeld wilt downloaden. De bestanden voor de toepassing Podcast Player zijn te vinden in de map Samples/PodcastPlayer. De toepassing bestaat uit de volgende bestanden:

Bestand

Beschrijving

PodcastPlayer.mxml

of

PodcastPlayer.fla

De gebruikersinterface voor de toepassing voor Flex (MXML) of Flash (FLA).

comp/example/programmingas3/podcastplayer/PodcastPlayer.as

Klasse Document die de gebruikersinterfacelogica bevat voor de podcast-player (alleen Flash).

SoundPlayer.mxml

Een MXML-component die afspeelknoppen en voortgangsbalken weergeeft en die het afspelen van geluid regelt (alleen voor Flex).

main.css

Stijlen voor de gebruikersinterface van de toepassing (alleen Flex).

afbeeldingen/

Pictogrammen voor het opmaken van de knoppen (alleen Flex).

comp/example/programmingas3/podcastplayer/SoundPlayer.as

Klasse voor het filmclipsymbool SoundPlayer dat de gebruikersinterfacelogica bevat voor de geluidspeler (alleen Flash).

comp/example/programmingas3/podcastplayer/PlayButtonRenderer.as

Aangepaste celrenderer voor het weergeven van een knop Afspelen in een cel van een gegevensraster (alleen Flash).

com/example/programmingas3/podcastplayer/RSSBase.as

Een basisklasse die algemene eigenschappen en methoden voor de klassen RSSChannel en RSSItem biedt.

com/example/programmingas3/podcastplayer/RSSChannel.as

Een ActionScript-klasse die gegevens over een RSS-kanaal bevat.

com/example/programmingas3/podcastplayer/RSSItem.as

Een ActionScript-klasse die gegevens over een RSS-item bevat.

com/example/programmingas3/podcastplayer/SoundFacade.as

De belangrijkste ActionScript-klasse voor de toepassing. Deze omvat de methoden en gebeurtenissen van de klassen Sound en SoundChannel, aangevuld met ondersteuning voor het onderbreken en hervatten van het afspelen.

com/example/programmingas3/podcastplayer/URLService.as

Een ActionScript-klasse die gegevens van een externe URL ophaalt.

playerconfig.xml

Een XML-bestand met een lijst van RSS-feeds voor podcast-kanalen.

comp/example/programmingas3/utils/DateUtil.as

Klasse die wordt gebruikt om datums gemakkelijk op te maken (alleen Flash).

RSS-gegevens voor een podcast-kanaal lezen

De toepassing Podcast Player begint met het lezen van informatie over een aantal podcast-kanalen en corresponderende afleveringen:

1. Eerst leest de toepassing een XML-configuratiebestand met een lijst van podcast-kanalen en geeft een lijst met kanalen voor de gebruiker weer.

2. Wanneer de gebruiker een van de podcast-kanalen selecteert, wordt de RSS-feed voor het kanaal gelezen en wordt een lijst met kanaalafleveringen weergegeven.

In dit voorbeeld wordt de hulpprogrammaklasse URLLoader gebruikt om tekstgegevens van een externe locatie of uit een lokaal bestand op te halen. De Podcast Player maakt eerst een object URLLoader om een lijst met RSS-feeds in XML-indeling uit het bestand playerconfig.xml op te halen. Wanneer de gebruiker vervolgens een specifieke feed in de lijst selecteert, wordt een nieuw object URLLoader gemaakt om de RSS-gegevens uit de URL van die feed te lezen.

Het laden en afspelen van geluid vereenvoudigen met behulp van de klasse SoundFacade

De ActionScript 3.0-geluidsarchitectuur is krachtig, maar complex. In toepassingen waarvoor alleen elementaire functies voor het laden en afspelen en geluiden nodig zijn, kan een klasse worden gebruikt waarmee de complexiteit deels wordt verborgen door een vereenvoudigde set methodeaanroepen en gebeurtenissen te bieden. In de wereld van softwareontwerppatronen wordt een dergelijke klasse een facade genoemd.

De klasse SoundFacade biedt één enkele interface voor het uitvoeren van de volgende taken:

  • Geluidsbestanden laden met behulp van een object Sound, een object SoundLoaderContext en de klasse SoundMixer

  • Geluidsbestanden afspelen met behulp van het object Sound en het object SoundChannel

  • Gebeurtenissen over de voortgang van het afspelen verzenden

  • Het afspelen van het geluid onderbreken en hervatten met behulp van het object Sound en het object SoundChannel

De klasse SoundFacade probeert het merendeel van de functionaliteit van de ActionScript-geluidsklassen te bieden en daarbij de complexiteit beperkt te houden.

In de volgende code worden de klassendeclaratie, de klasseneigenschappen en de constructormethode SoundFacade() weergegeven:

public class SoundFacade extends EventDispatcher 
{ 
    public var s:Sound; 
    public var sc:SoundChannel; 
    public var url:String; 
    public var bufferTime:int = 1000; 
 
    public var isLoaded:Boolean = false; 
    public var isReadyToPlay:Boolean = false; 
    public var isPlaying:Boolean = false; 
    public var isStreaming:Boolean = true; 
    public var autoLoad:Boolean = true; 
    public var autoPlay:Boolean = true; 
         
    public var pausePosition:int = 0; 
         
    public static const PLAY_PROGRESS:String = "playProgress"; 
    public var progressInterval:int = 1000; 
    public var playTimer:Timer; 
         
    public function SoundFacade(soundUrl:String, autoLoad:Boolean = true, 
                                    autoPlay:Boolean = true, streaming:Boolean = true,  
                                    bufferTime:int = -1):void 
    { 
        this.url = soundUrl; 
 
        // Sets Boolean values that determine the behavior of this object 
        this.autoLoad = autoLoad; 
        this.autoPlay = autoPlay; 
        this.isStreaming = streaming; 
 
        // Defaults to the global bufferTime value 
        if (bufferTime < 0) 
        { 
            bufferTime = SoundMixer.bufferTime; 
        } 
 
        // Keeps buffer time reasonable, between 0 and 30 seconds 
        this.bufferTime = Math.min(Math.max(0, bufferTime), 30000); 
         
        if (autoLoad) 
        { 
            load(); 
        } 
    }

De klasse SoundFacade vormt een uitbreiding van de klasse EventDispatcher, zodat deze eigen gebeurtenissen kan verzenden. In de klassencode worden eerst eigenschappen voor een object Sound en een object SoundChannel gedeclareerd. In de klasse wordt ook de waarde van de URL van het geluidsbestand opgeslagen, evenals de eigenschap bufferTime voor gebruik bij streaming van het geluid. Bovendien worden er bepaalde Booleaanse parameterwaarden geaccepteerd, die invloed hebben op het laad- en afspeelgedrag:

  • Via de parameter autoLoad krijgt het object de opdracht om met het laden van het geluid te beginnen zodra dit object is gemaakt.

  • Met de parameter autoPlay wordt aangegeven dat het afspelen van het geluid moet starten zodra er voldoende geluidsgegevens zijn geladen. Als dit streaming geluid betreft, wordt het afspelen gestart zodra er voldoende gegevens, zoals opgegeven door de eigenschap bufferTime , zijn geladen.

  • Met de parameter streaming wordt aangegeven dat er met het afspelen van dit geluidsbestand kan worden begonnen voordat het laden is voltooid.

De parameter bufferTime is standaard ingesteld op -1. Als de constructormethode een negatieve waarde in de parameter bufferTime detecteert, wordt de eigenschap bufferTime ingesteld op de waarde van SoundMixer.bufferTime . Zo kan de toepassing desgewenst standaard worden ingesteld op de algemene waarde van SoundMixer.bufferTime .

Als de parameter autoLoad op true is ingesteld, roept de constructormethode onmiddellijk de volgende methode load() aan om te beginnen met het laden van het geluidsbestand:

public function load():void 
{ 
    if (this.isPlaying) 
    { 
        this.stop(); 
        this.s.close(); 
    } 
    this.isLoaded = false; 
     
    this.s = new Sound(); 
     
    this.s.addEventListener(ProgressEvent.PROGRESS, onLoadProgress); 
    this.s.addEventListener(Event.OPEN, onLoadOpen); 
    this.s.addEventListener(Event.COMPLETE, onLoadComplete); 
    this.s.addEventListener(Event.ID3, onID3); 
    this.s.addEventListener(IOErrorEvent.IO_ERROR, onIOError); 
    this.s.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onIOError); 
     
    var req:URLRequest = new URLRequest(this.url); 
     
    var context:SoundLoaderContext = new SoundLoaderContext(this.bufferTime, true); 
    this.s.load(req, context); 
}

Met de methode load() wordt een nieuw object Sound gemaakt, waarna listeners voor alle belangrijke geluidsgebeurtenissen worden toegevoegd. Vervolgens krijgt het object Sound de opdracht het geluidsbestand te laden, waarbij een object SoundLoaderContext wordt gebruikt om de waarde voor bufferTime door te geven.

Aangezien de eigenschap url kan worden gewijzigd, kan er een instantie SoundFacade worden gebruikt om verschillende geluidsbestanden na elkaar af te spelen: wijzig eenvoudig de eigenschap url en roep de methode load() aan; het nieuwe geluidsbestand wordt geladen.

De volgende drie methoden voor gebeurtenislisteners laten zien hoe het object SoundFacade de voortgang van het laden traceert en bepaalt wanneer er wordt gestart met het afspelen van het geluid:

public function onLoadOpen(event:Event):void 
{ 
    if (this.isStreaming) 
    { 
        this.isReadyToPlay = true; 
        if (autoPlay) 
        { 
            this.play(); 
        } 
    } 
    this.dispatchEvent(event.clone()); 
} 
 
public function onLoadProgress(event:ProgressEvent):void 
{  
    this.dispatchEvent(event.clone()); 
} 
 
public function onLoadComplete(event:Event):void 
{ 
    this.isReadyToPlay = true; 
    this.isLoaded = true; 
    this.dispatchEvent(evt.clone()); 
     
    if (autoPlay && !isPlaying) 
    { 
        play(); 
    } 
}

De methode onLoadOpen() wordt uitgevoerd zodra het laden van het geluid wordt gestart. Als het geluid in streaming modus kan worden afgespeeld, stelt de methode onLoadComplete() de markering isReadyToPlay direct in op true . De markering isReadyToPlay bepaalt of de toepassing met het afspelen van het geluid kan beginnen, bijvoorbeeld na een bepaalde gebruikershandeling, zoals het klikken op een afspeelknop. De klasse SoundChannel beheert de buffering van geluidsgegevens, wat betekent dat het niet nodig is om expliciet te controleren of er voldoende gegevens zijn geladen voordat de methode play() wordt aangeroepen.

De methode onLoadProgress() wordt periodiek aangeroepen tijdens het laadproces. Er wordt een kloon van het object ProgressEvent verzonden, die kan worden gebruikt door code die gebruikmaakt van dit object SoundFacade.

Wanneer de geluidsgegevens volledig zijn geladen, wordt de methode onLoadComplete() uitgevoerd en wordt zo nodig de methode play() voor niet-streaming geluiden aangeroepen. De methode play( ) zelf wordt hieronder weergegeven.

public function play(pos:int = 0):void 
{ 
    if (!this.isPlaying) 
    { 
        if (this.isReadyToPlay) 
        { 
            this.sc = this.s.play(pos); 
            this.sc.addEventListener(Event.SOUND_COMPLETE, onPlayComplete); 
            this.isPlaying = true; 
             
            this.playTimer = new Timer(this.progressInterval); 
            this.playTimer.addEventListener(TimerEvent.TIMER, onPlayTimer); 
            this.playTimer.start(); 
        } 
    } 
}

De methode play() roept de methode Sound.play() aan als het geluid gereed is om te worden afgespeeld. Het resulterende object SoundChannel wordt opgeslagen in de eigenschap sc . De methode play() maakt vervolgens een object Timer dat wordt gebruikt om gebeurtenissen over de voortgang van het afspelen met een regelmatig interval te verzenden.

De voortgang van het afspelen weergeven

Het maken van een object Timer ter controle van het afspelen is een complexe aangelegenheid, waarvoor u slechts één keer code zou moeten schrijven. Door deze Timer-logica onder te brengen in een herbruikbare klasse zoals de klasse SoundFacade stelt u toepassingen in staat naar dezelfde soorten voortgangsgebeurtenissen te luisteren wanneer een geluid wordt geladen als wanneer het wordt afgespeeld.

Het object Timer dat door de methode SoundFacade.play() wordt gemaakt, verzendt elke seconde een instantie TimerEvent. De volgende methode onPlayTimer() wordt uitgevoerd zodra er een nieuwe TimerEvent arriveert:

public function onPlayTimer(event:TimerEvent):void  
{ 
    var estimatedLength:int =  
        Math.ceil(this.s.length / (this.s.bytesLoaded / this.s.bytesTotal)); 
    var progEvent:ProgressEvent =  
        new ProgressEvent(PLAY_PROGRESS, false, false, this.sc.position, estimatedLength); 
    this.dispatchEvent(progEvent); 
}

De methode onPlayTimer() implementeert de techniek voor het schatten van grootte die wordt beschreven in de sectie De status van het afspelen volgen . Vervolgens wordt er een nieuwe instantie ProgressEvent met het gebeurtenistype SoundFacade.PLAY_PROGRESS gemaakt, waarbij de eigenschap bytesLoaded is ingesteld op de huidige positie van het object SoundChannel en de eigenschap bytesTotal is ingesteld op de geschatte lengte van de geluidsgegevens.

Afspelen onderbreken en hervatten

De eerder weergegeven methode SoundFacade.play() accepteert de parameter pos , die correspondeert met een startpositie in de geluidsgegevens. Als de waarde van pos nul is, wordt het afspelen van het geluid vanaf het begin gestart.

De methode SoundFacade.stop() accepteert ook de parameter pos zoals deze hier wordt weergegeven:

public function stop(pos:int = 0):void 
{ 
    if (this.isPlaying) 
    { 
        this.pausePosition = pos; 
        this.sc.stop(); 
        this.playTimer.stop(); 
        this.isPlaying = false; 
    }     
}

Steeds wanneer de methode SoundFacade.stop() wordt aangeroepen, wordt de eigenschap pausePosition zodanig ingesteld dat de toepassing weet waar de afspeelkop moet worden geplaatst als de gebruiker het afspelen van datzelfde geluid wil hervatten.

De hieronder weergegeven methoden SoundFacade.pause() en SoundFacade.resume() roepen respectievelijk de methode SoundFacade.stop() en SoundFacade.play() aan, waarbij steeds een waarde voor de parameter pos wordt doorgegeven.

public function pause():void 
{ 
    stop(this.sc.position); 
} 
 
public function resume():void 
{ 
    play(this.pausePosition); 
}

De methode pause() geeft de huidige waarde van SoundChannel.position door aan de methode play() , die deze waarde in de eigenschap pausePosition opslaat. De methode resume() begint opnieuw met het afspelen van hetzelfde geluid, waarbij de waarde van pausePosition als startpunt wordt gebruikt.

Het Podcast Player-voorbeeld uitbreiden

In dit voorbeeld wordt een elementaire podcast-speler gepresenteerd, waarmee het gebruik van de herbruikbare klasse SoundFacade wordt geïllustreerd. U kunt andere functies toevoegen om het nut van deze toepassing verder uit te breiden, zoals:

  • De lijst van feeds en gebruiksgegevens over elke aflevering opslaan in een instantie SharedObject die kan worden gebruikt wanneer de gebruiker de toepassing weer gebruikt.

  • De gebruiker toestaan eigen RSS-feeds aan de lijst met podcast-kanalen toe te voegen.

  • De positie van de afspeelkop onthouden wanneer de gebruiker een aflevering stopzet of verlaat, zodat deze vanaf dat punt kan worden hervat wanneer de gebruiker de toepassing opnieuw uitvoert.

  • MP3-bestanden met afleveringen downloaden om deze offline te kunnen beluisteren, wanneer de gebruiker niet met internet is verbonden.

  • Abonnementsfuncties toevoegen waarmee periodiek op nieuwe afleveringen in een podcast-kanaal wordt gecontroleerd en de lijst met afleveringen automatisch wordt bijgewerkt.

  • Zoek- en bladerfunctionaliteit voor podcasts toevoegen met behulp van een API van een podcast-hostingservice zoals Odeo.com.