代码之家  ›  专栏  ›  技术社区  ›  Alexander Zwitbaum

如何在Silverlight中同时播放多个音频源

  •  0
  • Alexander Zwitbaum  · 技术社区  · 14 年前

    我想在Silverlight中同时播放多个音频源。

    我的原型使用两个MediaElement(me和me2)对象。

    DateTime startTime;
    
    private void Play_Clicked(object sender, RoutedEventArgs e) {
      me.SetSource(new FileStream(file1), FileMode.Open)));
      me2.SetSource(new FileStream(file2), FileMode.Open)));
      var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1) };
      timer.Tick += RefreshData;
      timer.Start();
    }
    

    第一个文件应该在00:00秒播放。第二次是00:02秒。

    void RefreshData(object sender, EventArgs e) {
        if(me.CurrentState != MediaElementState.Playing) {
          startTime = DateTime.Now;
          me.Play();
          return;
        }
    
        var elapsed = DateTime.Now - startTime;
        if(me2.CurrentState != MediaElementState.Playing && 
          elapsed >= TimeSpan.FromSeconds(2)) {
          me2.Play();
          ((DispatcherTimer)sender).Stop();
        }
      }
    

    每次播放的音轨都不一样,而不是同时播放(作为一种声音)。

    加法 : 我测试了鲍比答案中的一个代码。

    private void Play_Clicked(object sender, RoutedEventArgs e) { 
      me.SetSource(new FileStream(file1), FileMode.Open))); 
      me2.SetSource(new FileStream(file2), FileMode.Open)));
      // This code plays well enough.
      // me.Play(); 
      // me2.Play();
    
      // But adding the 2 second offset using the timer, 
      // they play no simultaneous.
      var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; 
      timer.Tick += (source, arg) => { 
        me2.Play(); 
        ((DispatcherTimer)source).Stop(); 
      };
      timer.Start();
    }
    

    是否可以只使用一个MediaElement或任何可以播放多个源的MediaStreamSource实现来一起播放它们?

    附加2

    添加调试信息可以明确地显示me与计时器的滴答声不同

    ...
    me2.Play();
    System.Diagnostics.Debug.WriteLine(
      me.Position.TotalMilliseconds + " -> " + me2.Position.TotalMilliseconds);
    // 1820 -> 0 (but not 2000 -> 0)
    

    附加3 :使用标记器的经验

    我在TimeLineMarker中体验了时间,下面的代码在我的电脑上运行得很好

    me.Markers.Clear();
    me.Markers.Add(new TimelineMarker { Time = TimeSpan.FromMilliseconds(1892) });
    me.MarkerReached += (source, args) => {
                                me2.Play();
                                me.Markers.Clear();
                              };
    me.Play();
    
    1 回复  |  直到 14 年前
        1
  •  0
  •   Bobby    14 年前

    因为您使用FileStreams来加载文件,所以我假设您不是通过web读取文件,而是从本地文件系统读取文件。

    如果没有必要的话,您不想从计时器滴答处理程序调用Play()——例如对于第一个ME。

    另外,您每毫秒运行一次计时器,而不是每秒钟(不确定这是否真的是您想说的)。如果要在第一次播放2秒后开始第二次播放,请尝试调用me.play(),然后创建计时器以2秒的间隔运行,它所做的只是调用me2.play()并停止自己。

    private void Play_Clicked(object sender, RoutedEventArgs e) {
      me.SetSource(new FileStream(file1), FileMode.Open)));
      me2.SetSource(new FileStream(file2), FileMode.Open)));
      me.Play();
      me2.Play();
    }
    

    .. 编辑:

    计时器不能保证执行 正好在时间间隔发生的时候, 和其他行动一样。当 dispatchermer操作正在执行 依赖于公司的其他工作 队列及其优先级。 (msdn : DispatcherTimer)

    在多线程上下文中实现完美的同步可能非常困难。。dispatchermer将在间隔滴答作响时将对UI Dispatcher中的处理程序进行调用,但这并不意味着它将立即被调用。在这一点上唯一值得一试的就是调整 DispatcherPriority (例如“发送”(最高的))。

    使用此构造函数执行此操作:

    public DispatcherTimer(
        DispatcherPriority priority
    )