ActionScript 3.0 声音体系结构功能强大,但非常复杂。如果应用程序只需要基本的声音加载和播放功能,可使用通过提供一组更简单的方法调用和事件来隐藏某些复杂性的类。在软件设计模式领域中,这样的类称为“外观”。
SoundFacade 类表示用于执行以下任务的单个接口:
-
使用 Sound 对象、SoundLoaderContext 对象以及 SoundMixer 类来加载声音文件
-
使用 Sound 对象和 SoundChannel 对象来播放声音文件
-
调度播放进度事件
-
使用 Sound 对象和 SoundChannel 对象来暂停和恢复声音播放
SoundFacade 类尝试以更简化的方式提供 ActionScript Sound 类的大部分功能。
以下代码显示了类声明、类属性以及
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 对象的属性。该类还会存储声音文件 URL 的值以及对声音进行流式传输时使用的
bufferTime
属性。此外,它还接受某些影响加载和播放行为的布尔参数值:
-
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()
方法。它仅调度其 ProgressEvent 对象的克隆,该对象由使用此 SoundFacade 对象的代码使用。
当完全加载了声音数据后,将执行
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 对象,该对象用于按固定间隔调度播放进度事件。