2

我是 UCMA 的新手,我正在通过示例学习。我正在尝试使用以下场景构建 2 个 Lync 客户端 A 和 B,

  1. A呼叫B
  2. B 答案
  3. A 播放音频
  4. B 使用 Recorder 记录它。

我一直在尝试在 B 处记录通话。对于 B,它是来电。我需要将音频视频流附加到录音机,但我不知道该怎么做。我将不胜感激。对未格式化的代码表示歉意,我不知道如何正确格式化它,我试过了。

谢谢。克里斯

客户 B 代码:

  1. 接听来电
  2. 记录来电中收到的媒体。***这是我遇到麻烦的部分

    使用系统;使用 System.Threading;使用 Microsoft.Rtc.Collaboration;使用 Microsoft.Rtc.Collaboration.AudioVideo;使用 Microsoft.Rtc.Signaling;使用 Microsoft.Rtc.Collaboration.Lync;

    命名空间 Microsoft.Rtc.Collaboration.LyncUAS { public class LyncUAS { #region Locals private LyncUASConfigurationHelper _helper; 私有用户端点_userEndpoint;私人 AudioVideoCall _audioVideoCall; 私有 AudioVideoFlow _audioVideoFlow; 私人对话_incomingConversation;

        //Wait handles are only present to keep things synchronous and easy to read.
        private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
        private EventHandler<AudioVideoFlowConfigurationRequestedEventArgs> _audioVideoFlowConfigurationRequestedEventHandler;
        private EventHandler<MediaFlowStateChangedEventArgs> _audioVideoFlowStateChangedEventHandler;
        private AutoResetEvent _waitForAudioVideoCallEstablishCompleted = new AutoResetEvent(false);
        private AutoResetEvent _waitForAudioVideoFlowStateChangedToActiveCompleted = new AutoResetEvent(false);
        private AutoResetEvent _waitForPrepareSourceCompleted = new AutoResetEvent(false);
    
        #endregion
    
        #region Methods
        /// <summary>
        /// Instantiate and run the DeclineIncomingCall quickstart.
        /// </summary>
        /// <param name="args">unused</param>
        public static void Main(string[] args)
        {
            LyncUAS lyncUAS = new LyncUAS();
            lyncUAS.Run();
        }
    
        private void Run()
        {
           string filename = "received.wma";
    
            _helper = new LyncUASConfigurationHelper();
    
            // Create a user endpoint, using the network credential object 
            // defined above.
            _userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
            _userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
            Console.WriteLine("Waiting for incoming call...");
            _autoResetEvent.WaitOne();
            Console.WriteLine("came after call is connected");
            //start recording for audio.
    
            Recorder recorder = new Recorder();            
    
            recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
            recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);         
    

    //**********这是问题,当前_audioVideoFlow为空,它没有附加到流 //所以这会失败,如何附加_audioVideoFlow到来电?帮助 !!!

           // recorder.AttachFlow(_audioVideoFlow);  ------------> HELP!
    
    
            WmaFileSink sink = new WmaFileSink(filename);
            recorder.SetSink(sink);
            recorder.Start();
            Console.WriteLine("Started Recording ...");
            _autoResetEvent.WaitOne();
            recorder.Stop();
            Console.WriteLine("Stopped Recording ...");
            recorder.DetachFlow();
            Console.WriteLine("Exiting");
            Thread.Sleep(2000); 
        }
    
    
        private void audioVideoFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
        {
            Console.WriteLine("Flow state changed from " + e.PreviousState + " to " + e.State);
    
            //When flow is active, media operations can begin
            if (e.State == MediaFlowState.Active)
            {
                // Flow-related media operations normally begin here.
                _waitForAudioVideoFlowStateChangedToActiveCompleted.Set();
            }
    
            // call sample event handler
            if (_audioVideoFlowStateChangedEventHandler != null)
            {
                _audioVideoFlowStateChangedEventHandler(sender, e);
            }
        }
    
    
        void recorder_VoiceActivityChanged(object sender, VoiceActivityChangedEventArgs e)
        {
            Console.WriteLine("Recorder detected " + (e.IsVoice ? "voice" : "silence") + " at " + e.TimeStamp);
        }
    
        void recorder_StateChanged(object sender, RecorderStateChangedEventArgs e)
        {
            Console.WriteLine("Recorder state changed from " + e.PreviousState + " to " + e.State);
        }
    
        void On_AudioVideoCall_Received(object sender, CallReceivedEventArgs<AudioVideoCall> e)
        {
            //Type checking was done by the platform; no risk of this being any 
            // type other than the type expected.
            _audioVideoCall = e.Call;
    
            // Call: StateChanged: Only hooked up for logging, to show the call 
            // state transitions.
            _audioVideoCall.StateChanged += new
                EventHandler<CallStateChangedEventArgs>(_audioVideoCall_StateChanged);
            _incomingConversation = new Conversation(_userEndpoint);
    
            Console.WriteLine("Call Received! From: " + e.RemoteParticipant.Uri + " Toast is: " +e.ToastMessage.Message);
            _audioVideoCall.BeginAccept(
                 ar =>
                 {
                     try { 
                         _audioVideoCall.EndAccept(ar);
                         Console.WriteLine("Call must be connected at this point. "+_audioVideoCall.State);
    
                         _autoResetEvent.Set();
                          } catch (RealTimeException ex) { Console.WriteLine(ex); }
                 }, null);
    
        }
    
        //Just to record the state transitions in the console.
        void _audioVideoCall_StateChanged(object sender, CallStateChangedEventArgs e)
        {
            Console.WriteLine("Call has changed state. The previous call state was: " + e.PreviousState +
                " and the current state is: " + e.State);
            if (e.State == CallState.Terminated)
            {               
                Console.WriteLine("Shutting down");
                _autoResetEvent.Set();
                _helper.ShutdownPlatform();
            }
        }
        #endregion
    }
    

    }

4

1 回答 1

0

我想我已经弄清楚了这里不完全正确的地方。

你的代码

    // Create a user endpoint, using the network credential object 
    // defined above.
    _userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
    _userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
    Console.WriteLine("Waiting for incoming call...");
    _autoResetEvent.WaitOne();
    Console.WriteLine("came after call is connected");
    //start recording for audio.

    Recorder recorder = new Recorder();            

    recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
    recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);         

     //**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow //So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
     // recorder.AttachFlow(_audioVideoFlow);  ------------> HELP!

到目前为止看起来不错。我假设你在你的CreateEstablishedUserEndpoint方法中建立等等,但我没有看到你从哪里获得 _audioVideoFlow 的价值。

我猜你可能会在其他地方做,但如果这实际上是你遇到问题的地方,那就是:

获得 AVFlow 的最简单模式

    public static void RegisterForIncomingCall(LocalEndpoint localEndpoint)
    {
        localEndpoint.RegisterForIncomingCall
                          <AudioVideoCall>(IncomingCallDelegate);
    }

    private static void IncomingCallDelegate(object sender, CallReceivedEventArgs<AudioVideoCall> e)
    {
        e.Call.AudioVideoFlowConfigurationRequested += IncomingCallOnAudioVideoFlowConfigurationRequested;
    }

    private static void IncomingCallOnAudioVideoFlowConfigurationRequested(object sender, AudioVideoFlowConfigurationRequestedEventArgs e)
    {
        AudioVideoFlow audioVideoFlow = e.Flow; // <--- There's your flow, gentleman.
    }

现在,无需注册您的来电,只需调用RegisterForIncomingCall(_userEndpoint);.

您的 AVFlow 将挂在上面的 e.Flow 上,然后您可以将其传递到您的记录器中:recorder.AttachFlow(e.Flow)或者只是将流分配给您班级中的一个字段,autoResetEvent.WaitOne();然后在您现在设置的位置进行设置。

显然,这是一个非常幼稚的实现。在这几行代码中可能会出错(立即想到异常处理/静态事件处理程序内存泄漏);不要忘记连接与对话/呼叫和端点上的状态更改相关的事件,以及任何与恢复相关的项目。

于 2015-05-07T10:49:21.447 回答