如何停止AS3中的声音以播放另一个声音?

问题描述:

我的代码如何停止AS3中的声音以播放另一个声音?

if(_snd !=null) 
{ 
    _channel.stop(); 
} 

_snd = new SoundBeep(); 
_channel = new SoundChannel(); 
_channel = _snd.play(); 

,但如果用户点击了几次快速,闪存等待了一下,然后发出蜂鸣声他们快。我不确定发生了什么问题。有任何想法吗?

试试这个:

if(_channel != null) 
{ 
    _channel.stop(); 
} 

_snd = new SoundBeep(); 
_channel = _snd.play(); 
+0

这比其他疯狂的@Paul记录的方式更简洁。 – charlesclements 2015-02-09 20:20:15

我有这个问题 - 这是郁闷!在其他语言(Java,C#)中,我会在关键部分使用同步。在Flash中,我不得不伪造它。它并不完美 - 第二个声音在第一声中播放的可能性很小,但它非常小。

这里是关键:实现工厂和单件模式的组合。

我做出的一个重要发现是,在我采取行动之前,我需要将我的成员变量复制到一个临时变量中,以防其他一些对该对象的调用在完成清理之前尝试在新声音中进行交换前一个。这里是做一个片段:

/** Seek into the audio to the given position in milliseconds. */ 
    public function seek(position:Number, resumePlay:Boolean) { 
     trace("--> Seek(" + position + ") " + name); 

     var tempAudioChannel:SoundChannel = audioChannel; 
     audioChannel = null; 
     if (tempAudioChannel != null) { 
      tempAudioChannel.stop(); 
      tempAudioChannel.removeEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
     } 
     audioLastPosition = position; 

     if (resumePlay) { 
      tempAudioChannel = audio.play(audioLastPosition); 
      tempAudioChannel.addEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
      audioChannel = tempAudioChannel; 
     }     
    } 

注意如何我不仅从AudioChannel中复制到tempAudioChannel,但我必须空出AudioChannel中,直到该方法已接近完成,然后再设置它的值。除了在测试audioChannel的值和完成复制和清零之间的短时间段内,我可以安全地避免同步错误,这应该非常简短。

回到我对工厂和单件模式的评论。当一个声音被清除 - 停止并被丢弃 - 另一个声音可能正在开始,所以我需要多个SoundManager。因此,我为每个音频文件名创建一个SoundManager。每次我需要对一个音频文件进行操作时,SoundManager类会告诉我要调用哪个管理器实例,因此我不会听到因此而开始的相同声音的重复。

以下代码是我当前商业项目中的完整SoundManager。它引用另一个未示出的类 - 配置,但该类仅处理从配置文件获取音频文件的路径,并从另一个XML文件获取放大值。 (客户端提供的文件没有被归一化到相同的音量级别,所以我们必须为它们做这件事。)因此,您必须编辑所有对此配置对象的引用。

注意:我至少使用了两个成员变量audio和audioChannel中的临时变量技巧ALL OVER THE PLACE。

package com.vpg.rns.audio { 
    import flash.system.System; 
    import flash.events.*; 
    import flash.media.Sound; 
    import flash.media.SoundChannel; 
    import flash.media.SoundTransform; 
    import flash.net.NetStream; 
    import flash.net.NetConnection; 
    import flash.net.URLLoader; 
    import flash.net.URLRequest; 
    import flash.errors.IOError; 



    /** Load a Sound from an MP3 file, then hold onto it and mediate playing and disposing of the object, and keep the several Sounds from interfering with one another. 
    * This class stores each SoundManager instance in a collection keyed by the step name. 
    * 
    * Do not call the Constructor directly to acquire a SoundManager. Instead, use getInstance. 
    */ 
    public class SoundManager { 
     private static var allSounds:Object = new Object(); 

     public static function getInstance(name:String, config:Configuration) { 
      var soundMgr:SoundManager = allSounds[name]; 
      if (soundMgr == null) { 
       soundMgr = new SoundManager(name, config); 
       addSoundManager(soundMgr); 
      } 
      return soundMgr; 
     } 

     private static function addSoundManager(soundMgr:SoundManager) { 
      allSounds[soundMgr.name] = soundMgr; 
     } 

     private static function removeSoundManager(name) { 
      var soundMgr:SoundManager = allSounds[name] as SoundManager; 
      allSounds[name] = null; 
      if (soundMgr != null) { 
       soundMgr.dispose(); 
      } 
     } 

     public static function removeAllManagers() { 
      var allSoundsTemp:Object = allSounds; 
      allSounds = new Object(); 
      for (var prop:String in allSoundsTemp){ 
       var soundMgr:SoundManager = allSoundsTemp[prop] as SoundManager; 
       if (soundMgr != null) { 
        soundMgr.dispose(); 
       } 
      } 
     } 

     public static function stopManagers(exceptMgrName:String) { 
      for (var prop:String in allSounds){ 
       var soundMgr:SoundManager = allSounds[prop] as SoundManager; 
       if (soundMgr != null && soundMgr.name != exceptMgrName) { 
        soundMgr.stop(); 
       } 
      } 
     } 

     private var mgrName:String; 
     public function get name():String { return mgrName; } 

     public var config:Configuration; 
     public var audio:Sound; 
     public var audioChannel:SoundChannel; 
     public var audioLoadStatus:String; // States: no audio, loading, loaded, ready. "loaded" means loaded enough to start playing, but possibly still loading more. 

     private var rootPath:String; 
     private var dataPath:String; 
     private var mediaPath:String; 
     public var audioFilename:String; 
     private var onLoadHandler:Function; // Called When loading file is complete 
     private var onAudioCompleteHandler:Function; // Called When playing audio is complete 

     public var duration:Number; 
     public var audioLastPosition:Number; 

     private var volumeAdjustment:Number; 

     /** Construct a SoundManager. Do not call this directy. Use the factory method getInstance instead. */ 
     function SoundManager(name:String, config:Configuration) { 
      mgrName = name; 
      this.config = config; 
      audioLoadStatus = "no audio"; 
      duration = 0; 
      audioLastPosition = 0; 
      volumeAdjustment = 1; 
     } 

     /* 
     * Load the audio, then tigger the loading of the optional cue point xml file, and initialization of the controls. 
     * 
     * @param rootDirectory ...... Directory containing the config file. 
     * @param dataDirectory ...... Directory where cuepoint data is located. Expect the cuepoints file to be in the xml/cuepoints subdirectory. 
     * @param mediaDirectory ..... Directory where audio files are located. 
     * @param audioFile .......... Name of audio file with extension. Does not include path. 
     * @param onLoadHandler ...... Called once the audio is loaded, so the caller can start playing it. 
     */ 
     public function loadAudio(rootDirectory:String, dataDirectory:String, mediaDirectory:String, audioFile:String, onLoadHandler:Function, onAudioCompleteHandler:Function) { 
      audioLoadStatus = "loading"; 
      //Load the audio file. 
      this.rootPath = rootDirectory; 
      this.dataPath = dataDirectory; 
      this.mediaPath = mediaDirectory; 
      this.audioFilename = audioFile; 
      this.onLoadHandler = onLoadHandler; 
      this.onAudioCompleteHandler = onAudioCompleteHandler; 
      this.volumeAdjustment = config.getAmplification(this.audioFilename); 

      var mySoundReq:URLRequest = new URLRequest(config.osSpecificPath(mediaPath + "/" + audioFilename)); 

      audio = new Sound(); 
      audio.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{ trace("SoundLoader.loadAudio ERROR!!!"); trace(e); }); 
      if (config.platform == "Flash_IDE") { 
       audio.addEventListener(Event.COMPLETE, audioReady); 
      } 
      else { 
       // We can't afford to wait for whole audio to load, so wait until some of it is loaded. 
       audio.addEventListener(ProgressEvent.PROGRESS, audioProgress1); 
       audio.addEventListener(Event.COMPLETE, audioCompletelyLoaded); 
      } 
      audio.load(mySoundReq); 

     }  

     // A sufficient portion of the audio has loaded, so start playing. 
     private function audioProgress1(evt:ProgressEvent) { 
      var loadPercent:Number = Math.round(100 * evt.bytesLoaded/evt.bytesTotal); 
      if (loadPercent > 10 && audioLoadStatus == "loading") { //TODO: Deduce a better threshold. 
       var audioTemp:Sound = audio; 
       audioTemp.removeEventListener(ProgressEvent.PROGRESS, audioProgress1); 
       audioTemp.addEventListener(ProgressEvent.PROGRESS, audioProgress2); 
       audioLoaded(); 
      } 
     }  

     // As the audio continues to load, the duration lengthens, affecting the scrubber thumb position. 
     private function audioProgress2(evt:ProgressEvent) { 
      var loadPercent:Number = Math.round(100 * evt.bytesLoaded/evt.bytesTotal); 
      if (audioLoadStatus == "loading" || audioLoadStatus == "loaded") { 
       var audioTemp:Sound = audio; 
       if (audioTemp != null) { 
        duration = audioTemp.length/1000; // Convert from milliseconds to seconds. 
       } 
      } 
     }  

     private function audioCompletelyLoaded(evt:Event) { 
      var audioTemp:Sound = audio; 
      if (audioTemp != null) { 
       audioTemp.removeEventListener(Event.COMPLETE, audioCompletelyLoaded); 
       audioTemp.removeEventListener(ProgressEvent.PROGRESS, audioProgress1); 
       audioTemp.removeEventListener(ProgressEvent.PROGRESS, audioProgress2); 
       duration = audioTemp.length/1000; 
      } 
     } 

     private function audioReady(evt:Event) { 
      var audioTemp:Sound = audio; 
      if (audioTemp != null) { 
       audioTemp.removeEventListener(Event.COMPLETE, audioReady); 
       audioLoaded(); 
      } 
     } 

     private function audioLoaded() { 
      audioLoadStatus = "loaded"; 

      var audioTemp:Sound = audio; 
      if (audioTemp != null) { 
       duration = audioTemp.length/1000; // Convert from milliseconds to seconds. 
       var audioChannelTemp:SoundChannel; 
       audioChannelTemp = audioTemp.play(); 
       audioChannelTemp.stop(); 
       audioChannel = null; 
       audioLastPosition = 0; 
       audioLoadStatus = "ready"; 
       onLoadHandler(this); 
      } 
     } 

     public function play() { 
      pause(); 
      trace("--> Play " + name); 
      audioChannel = audio.play(audioLastPosition); 
      audioChannel.addEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
     } 

     /** Seek into the audio to the given position in milliseconds. */ 
     public function seek(position:Number, resumePlay:Boolean) { 
      trace("--> Seek(" + position + ") " + name); 

      var tempAudioChannel:SoundChannel = audioChannel; 
      audioChannel = null; 
      if (tempAudioChannel != null) { 
       tempAudioChannel.stop(); 
       tempAudioChannel.removeEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
      } 
      audioLastPosition = position; 

      if (resumePlay) { 
       tempAudioChannel = audio.play(audioLastPosition); 
       tempAudioChannel.addEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
       audioChannel = tempAudioChannel; 
      }     
     } 

     public function pause() { 
      trace("--> Pause " + name); 
      if (audioChannel != null) { 
       audioLastPosition = audioChannel.position; 
       audioChannel.stop(); 
       audioChannel.removeEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
       audioChannel = null; 
      } 
     } 

     public function stop() { 
      trace("--> Stop " + name); 
      audioLastPosition = 0; 
      if (audioChannel != null) { 
       audioChannel.stop(); 
       audioChannel.removeEventListener(Event.SOUND_COMPLETE, onAudioCompleteHandler); 
       audioChannel = null; 
      } 
     }  

     /** Elapsed time of audio in seconds. */ 
     public function get audioElapsed():Number { 
      if (audioLoadStatus == "ready") { 
       if (audioChannel != null) { 
        return audioChannel.position/1000.0; 
       } 
       else { 
        return audioLastPosition/1000.0; 
       } 
      } 
      else { 
       return 0; 
      } 
     }    

     /** Set the audio volume to a number between zero (mute) and one (loud). */ 
     public function setVolume(volume:Number, soundTransform:SoundTransform = null) { 
      if (audioChannel != null) { 
       if (soundTransform == null) { 
        soundTransform = new SoundTransform(); 
       } 
       if (volumeAdjustment != 1.0) { 
        trace("setVolume using volume adjustment of " + volumeAdjustment); 
       } 
       soundTransform.volume = volume * volumeAdjustment; 
       audioChannel.soundTransform = soundTransform; 
      } 
     } 

     public function unloadAudio() { 
      dispose(); 
     }    

     private function dispose() { 
      audioLoadStatus = "no audio"; 
      var audioTemp:Sound = audio; 
      audio = null; 
      stop(); 
      if (audioTemp != null) { 
       try { 
        audioTemp.close(); 
       } 
       catch (error:IOError) { 
        trace("Error: Couldn't close audio stream: " + error.message);  
       } 

      } 
     } 

    } 

}