Exempel på ljud: Podcast Player

Flash Player 9 och senare, Adobe AIR 1.0 och senare

En poddsändning är en ljudfil som distribueras över Internet på begäran eller genom prenumeration. Poddsändningar är vanligtvis publicerade som en del av en serie vilket också kallas en poddsändningskanal. Eftersom poddsändningsavsnitt kan vara allt från en minut till många timmar långa är de vanligtvis direktuppspelade. Poddsändningsavsnitt som också kallas objekt levereras vanligtvis i filformatet MP3. Videopoddsändningar är också populära men i det här exemplet spelas endast ljudpoddsändningar upp som använder MP3-filer.

Det här exemplet är inte ett aggregeringsprogram för poddsändning med alla funktioner. Det hanterar t.ex. inte prenumerationer på specifika poddsändningar och kommer inte ihåg vilka poddsändningar användaren har lyssnat på nästa gång programmet körs. Det kan fungera som en referenspunkt för en poddsändningsaggregering med fler funktioner.

Podcast Player-exemplet illustrerar följande tekniker för ActionScript-programmering:

  • Läsa en extern RSS-matning och tolka dess XML-innehåll

  • Skapa en SoundFacade-klass för att förenkla inläsning och uppspelning av ljudfiler

  • Visa ljuduppspelningsförlopp

  • Pausa och återuppta uppspelning av ljud

Programfilerna för det här exemplet finns på www.adobe.com/go/learn_programmingAS3samples_flash_se. Podcast Player-programfilerna finns i mappen Samples/PodcastPlayer. Programmet består av följande filer:

Fil

Beskrivning

PodcastPlayer.mxml

eller

PodcastPlayer.fla

Användargränssnittet för programmet för Flex (MXML) eller Flash (FLA).

comp/example/programmingas3/podcastplayer/PodcastPlayer.as

Dokumentklass som innehåller användargränssnittslogiken för Podcast Player (endast Flash).

SoundPlayer.mxml

En MXML-komponent som visar uppspelningsknappar och förloppsindikatorer, och styr uppspelning av ljud. Gäller enbart för Flex.

main.css

Format för programmets användargränssnitt (endast Flex).

bilder/

Ikoner för att formatera knapparna (endast Flex).

comp/example/programmingas3/podcastplayer/SoundPlayer.as

Klass för SoundPlayer-filmklippssymbolen som innehåller användargränssnittslogiken för ljudspelaren (endast Flash).

comp/example/programmingas3/podcastplayer/PlayButtonRenderer.as

Anpassad cellrenderare för att visa en Play-knapp i en datarutnätscell (endast Flash).

com/example/programmingas3/podcastplayer/RSSBase.as

En basklass med allmänna egenskaper och metoder för klassen RSSChannel och klassen RSSItem.

com/example/programmingas3/podcastplayer/RSSChannel.as

En ActionScript-klass som innehåller data om en RSS-kanal.

com/example/programmingas3/podcastplayer/RSSItem.as

En ActionScript-klass som innehåller data om ett RSS-objekt.

com/example/programmingas3/podcastplayer/SoundFacade.as

Huvudklassen för ActionScript i programmet. Den kapslar in metoderna och händelserna i klassen Sound och klassen SoundChannel och lägger till stöd för paus och fortsatt uppspelning.

com/example/programmingas3/podcastplayer/URLService.as

En ActionScript-klass som hämtar data om en extern URL.

playerconfig.xml

En XML-fil som innehåller en lista över RSS-matningar som representerar poddsändningskanaler.

comp/example/programmingas3/utils/DateUtil.as

Klass som används för enkel datumformatering (endast Flash).

Läsa RSS-data för en poddsändningskanal

Programmet Podcast Player startar med att läsa information om ett antal poddsändningskanaler och deras avsnitt:

1. Först läser programmet en XML-konfigureringsfil som innehåller en lista över poddsändningskanaler och visar listan över kanalerna för användaren.

2. När användaren väljer en av poddsändningskanalerna, läses RSS-matningen för kanalen och en lista över kanalavsnitten visas.

I det här exemplet används en URLLoader-hjälpklass för att hämta textbaserad data från en extern plats eller en lokal fil. Podcast Player skapar först ett URLLoader-objekt för att få en lista över RSS-matningar i XML-format från filen playerconfig.xml. Sedan, när användaren väljer en specifik matning i listan, skapas ett nytt URLLoader-objekt för att läsa RSS-data från URL:n för den matningen.

Förenklad ljudinläsning och uppspelning med klassen SoundFacade

Ljudarkitekturen i ActionScript 3.0 är kraftfull men komplex. Program som endast behöver grundläggande funktioner för ljudinläsning och uppspelning kan använda en klass som döljer en del av komplexiteten genom att tillhandahålla en enklare uppsättning av metodanrop och händelser. I programvaruvärlden för designmönster kallas en sådan klass för facade.

Klassen SoundFacade presenterar ett enda gränssnitt för att utföra följande uppgifter:

  • Läsa in ljudfiler med ett Sound-objekt, ett SoundLoaderContext-objekt och klassen SoundMixer

  • Spela upp ljudfiler med Sound-objektet och SoundChannel-objektet

  • Skicka händelser för uppspelningsförloppet

  • Pausa och återuppta uppspelning av ljudet med Sound-objektet och SoundChannel-objektet

Klassen SoundFacade försöker erbjuda de flesta funktionerna som finns i ActionScript-ljudklasserna men inte lika komplicerade.

I följande kod visas klassdeklarationen, klassegenskaperna och konstruktormetoden SoundFacade():

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(); 
        } 
    }

Klassen SoundFacade utökar klassen EventDispatcher så att den kan skicka sina egna händelser. Klasskoden deklarerar först egenskaper för ett Sound-objekt och ett SoundChannel-objekt. Klassen lagrar också URL-värdet för ljudfilen och en bufferTime-egenskap som används vid direktuppspelning av ljudet. Dessutom accepteras några booleska parametervärden som påverkar inläsnings- och uppspelningsbeteendena:

  • Parametern autoLoad anger för objektet att ljudinläsningen ska starta så fort som det här objektet har skapats.

  • Parametern autoPlay indikerar att ljuduppspelningen ska starta så fort som tillräckligt med ljuddata har lästs in. Om det är ett direktuppspelat ljud, börjar uppspelningen så fort som tillräcklig mängd data enligt specifikationen i bufferTime-egenskapen har lästs in.

  • Med streaming-parametern indikeras att ljudfilen kan börja spelas upp innan inläsningen har slutförts.

Parametern bufferTime har standardvärdet -1. Om konstruktormetoden identifierar ett negativt värde i bufferTime-parametern, får bufferTime-egenskapen värdet från SoundMixer.bufferTime. Det här låter programmet valfritt ange standardvärde för det globala SoundMixer.bufferTime-värdet.

Om autoLoad-parametern har värdet true, anropar konstruktormetoden omedelbart följande load()-metod för att starta inläsningen av ljudfilen:

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); 
}

load()-metoden skapar ett nytt Sound-objekt och lägger sedan till avlyssnare för alla viktiga ljudhändelser. Sedan aktiveras Sound-objektet att läsa in ljudfilen och använda SoundLoaderContext-objektet att föra över bufferTime-värdet.

Eftersom url-egenskapen kan ändras, kan en SoundFacade-instans användas för att spela upp olika ljudfiler i följd: Ändra url-egenskapen och anropa load()-metoden så läses den nya ljudfilen in.

Följande tre händelseavlyssningsmetoder visar hur SoundFacade-objekt följer inläsningsförloppet och avgör när uppspelning av ljudet ska starta:

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(); 
    } 
}

Metoden onLoadOpen() körs när ljudinläsningen startar. Om ljudet kan spelas upp i direktuppspelningsläge, sätter onLoadComplete()-metoden isReadyToPlay-flaggan till true direkt. Med isReadyToPlay-flaggan fastställs om programmet kan starta ljuduppspelningen kanske som svar på en användaråtgärd som att klicka på Spela upp. Klassen SoundChannel hanterar buffringen av ljuddata, så det är inte nödvändigt att särskilt kontrollera om tillräckligt med data har lästs in innan play()-metoden anropas.

Metoden onLoadProgress() körs periodvis under inläsningsförloppet. Det skickar helt enkelt en klon av sitt ProgressEvent-objekt att användas av koden som använder det här SoundFacade-objektet.

När ljuddata har lästs in fullständigt, körs onLoadComplete()-metoden och anropar play()-metoden efter ljud som inte är direktuppspelade om det behövs. Själva play()-metoden visas nedan.

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(); 
        } 
    } 
}

play()-metoden anropar Sound.play()-metoden om ljudet är klart att spelas upp. Det slutliga SoundChannel-objektet lagras i sc-egenskapen. play()-metoden skapar sedan ett Timer-objekt som används för att skicka förloppshändelser för uppspelningen med regelbundet intervall.

Visa ljuduppspelningsförlopp

Att skapa ett Timer-objekt för att köra uppspelningsövervakning är en invecklad åtgärd som du endast ska behöva skriva kod för en gång. Med inkapslad Timer-logik i en återanvändbar klass som SoundFacade kan programmet avlyssna samma typ av förloppshändelser när ett ljud läses in och när det spelas upp.

Timer-objektet som skapades av SoundFacade.play()-metoden skickar en TimerEvent-instans varje sekund. Metoden onPlayTimer() nedan körs varje gång en ny TimerEvent anländer:

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); 
}

onPlayTimer()-metoden implementerar tekniken för beräkning av storleken som beskrivs i avsnittet Övervaka uppspelning. Sedan skapas en ny ProgressEvent-instans med händelsetypen SoundFacade.PLAY_PROGRESS, med bytesLoaded-egenskapen satt till aktuell position för SoundChannel-objektet och bytesTotal-egenskapen satt till den beräknade längden för ljuddata.

Pausa och återuppta uppspelning

SoundFacade.play()-metoden som visades tidigare accepterar en pos-parameter som motsvarar en startposition i ljuddata. Om pos-värdet är noll startar uppspelningen av ljudet från början.

SoundFacade.stop()-metoden accepterar också en pos-parameter enligt nedan:

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

När SoundFacade.stop()-metoden anropas, anger den pausePosition-egenskapen så att programmet vet var spelhuvudet ska placeras om användaren vill återuppta uppspelningen av samma ljud.

Metoderna SoundFacade.pause() och SoundFacade.resume() som visas nedan startar SoundFacade.stop()- respektive SoundFacade.play()-metoderna och överför ett pos-parametervärde varje gång.

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

pause()-metoden överför aktuellt SoundChannel.position-värde till play()-metoden, vilken lagrar värdet i egenskapen pausePosition. Med resume()-metoden startas uppspelningen av samma ljud igen med värdet i pausePosition som referenspunkt.

Utökning av Podcast Player-exemplet

I det här exemplet presenteras Podcast Player-grunder som visar hur den återanvändningsbara klassen SoundFacade används. Du kan lägga till andra funktioner för att öka användbarheten av det här programmet, inklusive följande:

  • Lagra listan över matningar och användarinformation om varje avsnitt i en SharedObject-instans, som kan användas nästa gång användaren kör programmet.

  • Låta användaren lägga till sin egen RSS-matning i listan över poddsändningskanaler.

  • Komma ihåg placeringen av spelhuvudet när användaren stoppar eller lämnar ett avsnitt så att det kan återstartas från den positionen nästa gång användaren kör programmet.

  • Ladda ned MP3-filer med avsnitt för lyssning offline när användaren inte är ansluten till Internet.

  • Lägga till prenumerationsfunktioner som periodvis söker efter nya avsnitt i en poddsändningskanal och uppdaterar avsnittslistan automatiskt.

  • Lägga till poddsändningssökning och visningsfunktioner med ett API från en poddsändningstjänst som Odeo.com.