我们有一个基于UCMA 3.0的应用程序/机器人,可以将最终用户与专家相匹配。它将来自最终用户的传入的一对一聊天请求迁移到多用户会议中,然后邀请专家进入最终的多用户会议。应用程序本身仍然是会议的参与者。在任何给定的时间,我们的应用程序可能会有几个这样的会议,但每个最终用户只有一个。但是,单个专家可能同时参加多个会议。 在我们的应用程序日志中,我们偶尔会看到以下异常。
会议迁移错误调用#63809878,地址:sip:xxxxxx@xxx.com; gruu; opaque = app:conf:focus:id:TQRREACE System.InvalidOperationException:收到会议邀请后无法加入其他会议或会议升级请求。 在Microsoft.Rtc.Collaboration.ConferenceSession.VerifyAndGetConferenceAddress(String conferenceUri,String parameterName) 在Microsoft.Rtc.Collaboration.ConferenceSession.BeginJoinCommon(String conferenceUri,ConferenceJoinOptions选项,AsyncCallback userCallback,Object state) 在Microsoft.Rtc.Collaboration.ConferenceSession.BeginJoin(String conferenceUri,ConferenceJoinOptions选项,AsyncCallback userCallback,Object state) at a(String A_0,String A_1,String A_2,Boolean A_3,Boolean A_4)
Below is the code snippet used to make conference. Previously this site was an OCS 2007 R2 Installation and was migrated to Lync 2010 Server.
Site is running in mixed mode. It occurs only on production server and we are not able to generate this exception on dev server, we
have tested it after generating more than 15 conferences simultaniously but no luck.
private void CreateAdHohConf(string user1Uri,string user2uri,string subject) { 异常异常= null;
// Create conference scheduling details for the conference.
ConferenceScheduleInformation scheduleInfo = new ConferenceScheduleInformation();
// Restrict the conference to invited users only.
scheduleInfo.AccessLevel = ConferenceAccessLevel.Everyone;
// Set a subject for the conference.
scheduleInfo.Subject = subject;
scheduleInfo.Description = subject;
scheduleInfo.ConferenceId = ConferenceServices.GenerateConferenceId();
scheduleInfo.ExpiryTime = System.DateTime.Now.AddHours(8);
scheduleInfo.IsPasscodeOptional = true;
scheduleInfo.PhoneAccessEnabled = false;
// Don't automatically assign a leader.
scheduleInfo.AutomaticLeaderAssignment = AutomaticLeaderAssignment.Everyone;
// Add the caller and recipient as participants.
scheduleInfo.Participants.Add(new ConferenceParticipantInformation("sip:" + user1Uri, ConferencingRole.Leader));
scheduleInfo.Participants.Add(new ConferenceParticipantInformation("sip:" + user2uri, ConferencingRole.Leader));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.ApplicationSharing));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.InstantMessaging));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.AudioVideo));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.Meeting));
//Scheduling conference
ConferenceServices objLocalConfSvc = lyncAgent.LocalEndpoint.ConferenceServices;
Conference confSession = null;
objLocalConfSvc.BeginScheduleConference(scheduleInfo,
result =>
{
try
{
confSession = objLocalConfSvc.EndScheduleConference(result);
}
catch (RealTimeException rtex)
{
exception = rtex;
}
catch (Exception ex)
{
exception = ex;
}
finally
{
_waitForConferenceScheduling.Set();
}
}, objLocalConfSvc);
_waitForConferenceScheduling.WaitOne();
//Begin Join conference
ConferenceSession objLocalConfSession=this.call.Conversation.ConferenceSession;
try
{
ConferenceJoinOptions joinOptions = new ConferenceJoinOptions() { CanManageLobby = false, JoinMode = JoinMode.Default };
objLocalConfSession.BeginJoin(new RealTimeAddress(confSession.ConferenceUri).Uri, joinOptions,
result => {
try
{
objLocalConfSession.EndJoin(result);
}
catch (Exception ex)
{
exception = ex;
}
finally
{
//Again, for sync. reasons.
_waitForConferenceJoin.Set();
}
}
, this.call.Conversation.ConferenceSession);
// Wait until join completes.new RealTimeAddress(this._conference.ConferenceUri).Uri,
_waitForConferenceJoin.WaitOne();
}
catch (InvalidOperationException ioex)
{
exception = ioex;
}
catch (Exception ex)
{
exception = ex;
}
//Begin Escalation
Conversation objLocalConv= this.call.Conversation;
try
{
objLocalConv.BeginEscalateToConference(
result =>
{
try
{
objLocalConv.EndEscalateToConference(result);
}
catch (Exception ex)
{
exception = ex;
}
finally
{
//Sync It
_waitForEscalation.Set();
}
}
, objLocalConv);
// Wait until escalation completes.
_waitForEscalation.WaitOne();
}
catch (InvalidOperationException ioex)
{
exception = ioex;
}
catch (Exception ex)
{
exception = ex;
}
finally
{
if (exception != null)
{
lyncAgent.Logger.Error( "Error in Conference Migration conf call # " + GetHashCode() + " , Address :" + confSession.ConferenceUri , exception);
}
}
}
请建议优先考虑可能存在的问题。
Thanks in advance.
答案 0 :(得分:0)
此方法是否驻留在可能由多个源同时调用的对象中?
如果是这样,使用类似于_waitForConferenceScheduling的类级别变量可能会有问题。在线程B的异步操作实际完成之前,线程A最终可能意外地让线程B继续。因此,线程B可以在调用.EndJoin之前调用.BeginEscalate。
当我编写UCMA代码时,我通常使用嵌套回调来防止这类事情发生。
除此之外,我建议您在应用程序服务器和Lync前端服务器上运行OCSLogger以收集SIPStack,S3和Collaboration日志。详细查看实际的SIP消息将提供一些线索。
您正在寻找会议的邀请和回复该邀请的回复。
答案 1 :(得分:0)
我们设法发现了原因。如果参与者列表中的任何人已添加任何联系人以与我们的端点进行会话,则会发生这种情况。