사운드 예제: 포드캐스트 플레이어

Flash Player 9 이상, Adobe AIR 1.0 이상

포드캐스트는 인터넷이나 주문 또는 구독을 통해 배포되는 사운드 파일입니다. 일반적으로 포드캐스트는 포드캐스트 채널이라고도 하는 시리즈의 일부로 제작됩니다. 포드캐스트 에피소드는 길이가 1분이 될 수도 있고 몇 시간이 될 수도 있으므로 일반적으로 스트리밍으로 재생됩니다. 포드캐스트 에피소드는 아이템이라고도 하며 보통 mp3 파일 형식으로 전달됩니다. 비디오 포드캐스트도 널리 사용되지만 이 샘플 응용 프로그램은 mp3 파일을 사용하는 오디오 포드캐스트만 재생합니다.

이 예제는 모든 기능을 갖춘 포드캐스트 수집기 응용 프로그램이 아닙니다. 예를 들어 특정 포드캐스트에 대한 구독을 관리하지 않으며 사용자가 이전에 들은 포드캐스트가 다음에 응용 프로그램이 실행될 때 기억되지 않습니다. 이 예제는 더 복잡한 기능의 포드캐스트 수집기 작성을 위한 토대가 될 수 있습니다.

Podcast Player 예제는 다음과 같은 ActionScript 프로그래밍 기술을 보여 줍니다.

  • 외부 RSS 피드 읽기 및 해당 XML 내용 파싱

  • SoundFacade 클래스를 만들어 사운드 파일을 간편하게 로드 및 재생

  • 사운드 재생 진행률 표시

  • 사운드 재생 일시 정지 및 다시 시작

이 샘플에 대한 응용 프로그램 파일을 가져오려면 www.adobe.com/go/learn_programmingAS3samples_flash_kr를 참조하십시오. Podcast Player 응용 프로그램 파일은 Samples/PodcastPlayer 폴더에 있습니다. 이 응용 프로그램은 다음과 같은 파일로 구성됩니다.

File

설명

PodcastPlayer.mxml

또는

PodcastPlayer.fla

Flex(MXML) 또는 Flash(FLA)용 응용 프로그램의 사용자 인터페이스입니다.

comp/example/programmingas3/podcastplayer/PodcastPlayer.as

포드캐스트 플레이어용 사용자 인터페이스 논리를 포함하는 문서 클래스입니다(Flash 전용).

SoundPlayer.mxml

Flex에 대해서만 재생 버튼과 진행률 막대를 표시하고 사운드 재생을 제어하는 MXML 구성 요소입니다.

main.css

응용 프로그램 사용자 인터페이스의 스타일입니다(Flex 전용).

images/

버튼 스타일에 대한 아이콘입니다(Flex 전용).

comp/example/programmingas3/podcastplayer/SoundPlayer.as

사운드 플레이어용 사용자 인터페이스 논리를 포함하는 SoundPlayer 동영상 클립 심볼 클래스입니다(Flash 전용).

comp/example/programmingas3/podcastplayer/PlayButtonRenderer.as

데이터 격자 셀에 재생 버튼을 표시하기 위한 사용자 정의 셀 렌더러입니다(Flash 전용).

com/example/programmingas3/podcastplayer/RSSBase.as

RSSChannel 클래스와 RSSItem 클래스에 대한 일반 속성 및 메서드를 제공하는 기본 클래스입니다.

com/example/programmingas3/podcastplayer/RSSChannel.as

RSS 채널에 대한 데이터를 보관하는 ActionScript 클래스입니다.

com/example/programmingas3/podcastplayer/RSSItem.as

RSS 항목에 대한 데이터를 보관하는 ActionScript 클래스입니다.

com/example/programmingas3/podcastplayer/SoundFacade.as

응용 프로그램에 대한 기본 ActionScript 클래스입니다. Sound 클래스와 SoundChannel 클래스의 메서드 및 이벤트를 캡슐화하고 재생 일시 정지 및 다시 시작에 대한 지원을 추가합니다.

com/example/programmingas3/podcastplayer/URLService.as

원격 URL로부터 데이터를 가져오는 ActionScript 클래스입니다.

playerconfig.xml

포드캐스트 채널을 나타내는 RSS 피드 목록이 포함된 XML 파일입니다.

comp/example/programmingas3/utils/DateUtil.as

간편한 날짜 형식을 위해 사용되는 클래스입니다(Flash 전용).

포드캐스트 채널용 RSS 데이터 읽기

Podcast Player 응용 프로그램은 몇 개의 포드캐스트 채널과 해당 에피소드에 대한 정보를 읽는 것으로 시작합니다.

1. 먼저 응용 프로그램은 포드캐스트 채널 목록이 포함된 XML 구성 파일을 읽고 채널 목록을 사용자에게 표시합니다.

2. 사용자가 포드캐스트 채널 중 하나를 선택하면 응용 프로그램은 채널에 대한 RSS 피드를 읽고 채널 에피소드 목록을 표시합니다.

이 예제는 URLLoader 유틸리티 클래스를 사용하여 원격 위치 또는 로컬 파일로부터 텍스트 기반 데이터를 가져옵니다. Podcast Player는 먼저 playerconfig.xml 파일로부터 XML 형식의 RSS 피드 목록을 가져오기 위한 URLLoader 객체를 만듭니다. 그리고 사용자가 목록에서 특정 피드를 선택하면 새로운 URLLoader 객체가 만들어져 해당 피드의 URL로부터 RSS 데이터를 읽습니다.

SoundFacade 클래스를 사용하여 사운드 로드 및 재생 단순화

ActionScript 3.0 사운드 아키텍처는 강력하지만 복잡합니다. 기본적인 사운드 로드와 재생 기능만 필요한 응용 프로그램은 간단한 메서드 호출 및 이벤트 집합을 제공하여 일부 복잡한 기능을 숨기는 클래스를 사용할 수 있습니다. 이러한 클래스는 소프트웨어 디자인 패턴 분야에서 facade라고 합니다.

SoundFacade 클래스는 다음과 같은 작업을 수행하는 단일 인터페이스를 제공합니다.

  • Sound 객체, SoundLoaderContext 객체 및 SoundMixer 클래스를 사용하여 사운드 파일 로드

  • Sound 객체 및 SoundChannel 객체를 사용하여 사운드 파일 재생

  • 재생 진행률 이벤트 전달

  • Sound 객체 및 SoundChannel 객체를 사용하여 사운드 재생 일시 정지 및 다시 시작

SoundFacade 클래스는 대부분의 ActionScript 사운드 클래스 기능을 보다 단순하게 제공하려고 합니다.

다음 코드는 클래스 선언, 클래스 속성 및 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(); 
        } 
    }

SoundFacade 클래스는 EventDispatcher 클래스를 확장하여 자체의 이벤트를 전달하도록 합니다. 이 클래스 코드는 먼저 Sound 객체와 SoundChannel 객체의 속성을 선언합니다. 이 클래스는 사운드를 스트리밍할 때 사용할 bufferTime 속성과 사운드 파일의 URL 값도 저장합니다. 또한 로딩 및 재생 비헤이비어에 영향을 미치는 다음과 같은 몇 가지 부울 매개 변수 값을 받습니다.

  • autoLoad 매개 변수는 객체가 만들어지면 바로 사운드 로드를 시작하도록 객체에 지시합니다.

  • autoPlay 매개 변수는 충분한 사운드 데이터가 로드되면 바로 재생을 시작함을 나타냅니다. 스트리밍 사운드의 경우에는 bufferTime 속성에 지정된 충분한 데이터가 로드되었을 때 재생이 시작됩니다.

  • streaming 매개 변수는 로드가 완료되기 전에 이 사운드 파일 재생을 시작할 수 있음을 나타냅니다.

bufferTime 매개 변수의 기본값은 -1입니다. 생성자 메서드가 bufferTime 매개 변수에서 음수 값을 감지하면 bufferTime 속성이 SoundMixer.bufferTime 값으로 설정됩니다. 이렇게 되면 필요한 전역 SoundMixer.bufferTime 값으로 응용 프로그램의 기본값이 설정될 수 있습니다.

autoLoad 매개 변수가 true로 설정된 경우, 생성자 메서드는 즉시 다음 load() 메서드를 호출하여 사운드 파일 로드를 시작합니다.

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() 메서드는 새로운 Sound 객체를 생성한 후 모든 중요 사운드 이벤트에 대한 리스너를 추가합니다. 그런 다음 Sound 객체에 사운드 파일 로드를 지시하고 SoundLoaderContext 객체를 사용하여 bufferTime 값을 전달하도록 합니다.

url 속성은 변경 가능하므로, SoundFacade 인스턴스를 사용하여 여러 사운드 파일을 연속적으로 재생할 수 있습니다. url 속성을 변경하고 load() 메서드를 호출하기만 하면 새 사운드 파일이 로드됩니다.

다음 세 가지 이벤트 리스너 메서드는 SoundFacade 객체가 로드 프로세스를 추적하고 사운드 재생 시점을 결정하는 방법을 보여 줍니다.

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

사운드 로드가 시작되면 onLoadOpen() 메서드가 실행됩니다. 사운드가 스트리밍 모드에서 재생될 수 있는 경우 onLoadComplete() 메서드는 즉시 isReadyToPlay 플래그를 true로 설정합니다. isReadyToPlay 플래그는 사용자가 재생 버튼을 클릭하는 등의 액션을 수행할 때 응용 프로그램이 사운드 재생을 시작할 수 있는지 여부를 결정합니다. SoundChannel 클래스는 사운드 데이터의 버퍼링을 관리하므로 play() 메서드를 호출하기 전에 충분한 데이터가 로드되었는지 명시적으로 확인할 필요가 없습니다.

onLoadProgress() 메서드는 로드 프로세스 중에 정기적으로 실행됩니다. 이 메서드는 이 SoundFacade 객체를 사용하는 코드가 사용할 해당 ProgressEvent 객체의 복제본을 전달합니다.

사운드 데이터가 완전히 로드되었으면 onLoadComplete() 메서드가 실행되어, 필요한 경우 비스트리밍 사운드에 대해 play() 메서드를 호출합니다. play() 메서드는 아래와 같습니다.

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() 메서드가 Sound.play() 메서드를 호출합니다. 결과 SoundChannel 객체는 sc 속성에 저장됩니다. 그런 다음 play() 메서드는 재생 진행률 이벤트를 정기적으로 전달하는 데 사용될 Timer 객체를 만듭니다.

재생 진행률 표시

재생 모니터링을 구동하는 Timer 객체 생성은 복잡한 작업으로 한 번만 코딩해야 합니다. 이 Timer 논리를 SoundFacade 클래스 등의 다시 사용할 수 있는 클래스에 캡슐화하면 사운드 로드와 재생 시 동일한 종류의 진행률 이벤트를 응용 프로그램이 수신할 수 있습니다.

SoundFacade.play() 메서드가 생성한 Timer 객체는 매초 TimerEvent 인스턴스를 전달합니다. 다음 onPlayTimer() 메서드는 새 TimerEvent가 도착할 때마다 실행됩니다.

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() 메서드는 재생 모니터링 단원에 설명된 크기 예측 기법을 구현합니다. 그런 다음, 이벤트 유형이 SoundFacade.PLAY_PROGRESSbytesLoaded 속성이 SoundChannel 객체의 현재 위치로 설정되고 bytesTotal 속성이 사운드 데이터의 추정된 길이로 설정된 새로운 ProgressEvent 인스턴스를 만듭니다.

재생 일시 정지 및 다시 시작

앞에서 설명한 SoundFacade.play() 메서드는 사운드 데이터의 시작 위치에 해당하는 pos 매개 변수를 받습니다. pos 값이 0이면 사운드는 처음부터 재생을 시작합니다.

아래와 같이 SoundFacade.stop() 메서드도 pos 매개 변수를 받습니다.

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

SoundFacade.stop() 메서드가 호출될 때마다 동일한 사운드의 재생을 사용자가 다시 시작하려는 경우 응용 프로그램이 재생 헤드의 위치를 지정할 수 있도록 pausePosition 속성이 설정됩니다.

아래와 같은 SoundFacade.pause()SoundFacade.resume() 메서드는 SoundFacade.stop()SoundFacade.play() 메서드를 각각 호출하여 pos 매개 변수 값을 전달합니다.

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

pause() 메서드는 현재의 SoundChannel.position 값을 play() 메서드에 전달하고 play() 메서드는 해당 값을 pausePosition 속성에 저장합니다. resume() 메서드는 pausePosition 값을 시작 위치로 사용하여 동일한 사운드의 재생을 다시 시작합니다.

Podcast Player 예제 확장

이 예제에서는 재사용 가능한 SoundFacade 클래스의 기능을 보여 주는 Podcast Player의 핵심을 나타냅니다. 이 응용 프로그램의 기능을 확장하기 위해 다음과 같은 기타 기능을 추가할 수 있습니다.

  • 사용자가 응용 프로그램을 다음에 실행할 때 사용할 수 있는 SharedObject 인스턴스에 각 에피소드와 관련한 피드 및 사용 정보 목록을 저장합니다.

  • 사용자가 자신의 RSS 피드를 포드캐스트 채널 목록에 추가할 수 있도록 합니다.

  • 사용자가 에피소드를 중지하거나 종료했을 때 재생 헤드의 위치를 기억하여 사용자가 다음에 응용 프로그램을 실행할 때 해당 위치에서 다시 시작할 수 있도록 합니다.

  • 사용자가 인터넷에 연결되어 있지 않을 때 오프라인 상태에서 수신하도록 에피소드 mp3 파일을 다운로드합니다.

  • 포드캐스트 채널에서 새로운 에피소드가 있는지 정기적으로 확인하고 에피소드 목록을 자동으로 업데이트하는 구독 기능을 추가합니다.

  • Odeo.com 등의 포드캐스트 호스팅 서비스로부터 API를 사용하여 포드캐스트 검색 및 탐색 기능을 추가합니다.