Microsoft Press books are available through booksellers and distributors
worldwide. For further ... 3 Programming a Microsoft Office Communicator.
Automation ...
Foreword by Gurdeep Singh Pall Corporate Vice President, Office Communications Group, Microsoft Corporation
Programming for
Unified Communications with Microsoft Office Communications Server 2007 R2 ®
Rui Maximo, Kurt De Ding, Vishwa Ranjan, Chris Mayo, Oscar Newkerk, and the Microsoft Office Communications Server Team
What do you think of this book? We want to hear from you! Microsoft is interested in hearing your feedback so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit:
What do you think of this book? We want to hear from you! Microsoft is interested in hearing your feedback so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit:
www.microsoft.com/learning/booksurvey
Foreword The Microsoft Unified Communications (UC) platform, which includes Microsoft Exchange Server and Office Communications Server, provides a unified infrastructure for communication and offers a single-user experience for e-mail, instant messaging (IM), Voice over Internet Protocol (VoIP), application sharing, audio/video (A/V), and Web conferencing. This user experience is centered on a single identity (provided by Active Directory Domain Services) combined with an inbox (managed by Exchange Server) and enhanced presence (provided by Office Communications Server). This integrated solution realizes the unified view in UC as opposed to a collection of disparate solutions. As a software-based platform, UC provides a rich and open API set for developers to extend the UC platform. In fact, our own products are built using these same APIs. These APIs make presence, e-mail, IM, and VoIP a programmable platform that developers can use to create innovative solutions easily. With rich and open APIs, we’re infusing UC into new business applications, workflow technologies, and content management. This effort wouldn’t be possible without the rapidly growing number of Microsoft Most Valued Professionals (MVPs), developer partners who are building these enterprise applications for customers. It is, therefore, important to help the developer community by providing the necessary information, training, and support to make them successful. Already, many customers have enhanced Office Communications Server with custom applications. This book launches an important series that UC developers will want to add to their library of programming books. Written by experts from the Unified Communications Group at Microsoft, you’ll find informative and valuable technical coverage, complete with examples to illustrate best practices. I want to recognize the efforts of members of the Unified Communications Group who demonstrated perseverance and dedication in producing this book. Publishing this title required vision and commitment from Tim Toyoshima, Ben Ryan, Rui Maximo, Susan Bradley, Kurt De Ding, Vishwa Ranjan, Oscar Newkerk, Chris Mayo, Albert Kooiman, Victoria Thulman, Mitch Duncan, 15 technical reviewers, and a large support crew. It is my pleasure to introduce the first book on programming for Office Communications Server. Gurdeep Singh Pall Corporate Vice President Unified Communications Group
xi
Acknowledgments The authors of Programming for Unified Communications with Microsoft Office Communications Server 2007 R2 want to thank the numerous members of the Office Communications Server product team, Microsoft Learning team, and numerous other key contributors who helped make this first edition of the book as thorough, comprehensible, and accurate as possible. These individuals have contributed their time and effort to this project in several important ways, which include: N
Reviewing each chapter for technical accuracy and completeness
N
Providing project management, technical management, lab management, art management, and editorial support
N
Providing vision, leadership, advice, encouragement, resource support, and funding support
We acknowledge and thank the following product experts for their extensive and invaluable technical reviews: N
Ajay Soni
N
Chloe Brussard
N
Dongkyun Nam
N
Ellen Zehr
N
George Durzi
N
John Austin
N
K. Ganesan
N
Marshall Harrison
N
Niko Schuessler
N
Sara Morgan
N
Srivatsa Srinivasan
N
Srividya Mohan
N
Vincent Bannister
N
Weimin Li
If we have forgotten anyone, please forgive us!
xiii
xiv
Acknowledgments
We acknowledge and thank the following key contributors, without whom this book would be a dream rather than a reality. Rui Maximo, senior technical writer, for his role as technical lead for the first-ever programming book about Office Communications Server. Rui worked with dedication, perseverance, and passion, reviewing each chapter draft multiple times and working closely with authors to ensure technical accuracy, logical presentation, consistency, cohesion, and coherence across 10 chapters, 7 writers, and 20 reviewers. Rui, we could not have delivered this book without you. Chris Mayo, UC technical evangelist, for his role in creating and managing the lab environment used by authors to take their screenshots. Diane Forsyth, senior technical editor, for her role as glossary and forward link editor. Thanks to Diane’s earlier efforts, we have a glossary with an extensive list of key terms and definitions as well as links that point to the latest resources. Janet Lowen, lead technical editor, for her thorough editorial reviews and oversight, as well as her able assistance with the glossary, forward links, template, and style guidelines. Kate Gleeson, technical editor, for her editorial assistance during the end game when chapters were flying so fast that we could barely keep up with them. Victoria Thulman, Microsoft Learning project editor, for managing our delayed deliveries, endless rounds of questions, and hundreds of e-mails a day with good humor and focused professionalism. Vicky, this would have been a far more difficult journey without your expertise and support. John Clarkson, senior programming writer, for his role in managing the art across all chapters and ensuring that all art met quality standards and guidelines. Mitch Duncan, Microsoft Learning technical reviewer, who tested all procedures and identified errors so that this book is an accurate and comprehensive resource for our customers. Susan S. Bradley, senior content project manager and “Master of the Universe,” who managed this project from inception to delivery. Her infectious laughter and positive energy kept everyone motivated to work through the details of producing the book and tracking to the finish line. The number of moving parts to track across a large cast is mind-numbing. Without her leadership and perseverance, this book wouldn’t exist. Ben Ryan, Microsoft Learning lead product manager, who championed and supported this first-edition book and new authoring team. Without Ben’s vision and support, Programming for Unified Communications with Microsoft Office Communications Server 2007 R2 would not exist.
Acknowledgments
xv
Juan-Carlos Rivas, Office Communications Group senior group manager, for believing in the value of this book and for allocating writers from his team to assist with writing, chapter reviews, and art review and management. Tim Toyoshima, Office Communications Group user assistance principal group manager, for envisioning the need for this book, evangelizing that need, and sponsoring this crossteam project. Without Tim’s vision, leadership, and continuing support, which included both funding and resources for this book, Programming for Unified Communications with Microsoft Office Communications Server 2007 R2 would not exist. We also thank our outstanding and dedicated editorial team at Microsoft Learning, including Devon Musgrave, our development editor. Thanks also to Custom Editorial Productions, who handled the production aspects of this book, and to Susan McClung, our copy editor. —The Author Team
Personal Acknowledgments Rui Maximo I want to thank my coauthors, who endured multiple rigorous reviews and incorporated my feedback into their chapters. To Susan Bradley, thank you for managing this project as well as previous projects. It’s a pleasure to be your sidekick as we work together on ever more ambitious projects. I’ve really enjoyed working with you since we started working together on the first edition of the Microsoft Office Communications Server 2007 Resource Kit. To Mitch Duncan, you’ve become a good friend and respected colleague. To Vicky and Janet, whom we’ve been fortunate to work with over the past two books, thank you! To Tim Toyoshima, thanks for your continual support and for trusting in me to deliver. To my friends in the product group, thank you for reviewing and sharing your expertise. These books are dedicated to the great work you do on Office Communications Server. To my wife and kids, you are my inspiration. Kurt De Ding First, I want to express my gratitude to all current and former members of the Unified Communications Group who helped me understand and appreciate the technologies of the Office Communications Server products family. In particular, I want to thank Sam Bedekar, Subbu Chandrasekaran, K. Ganesan, Adrian Potra, and Stephane Taine for their insights, their helpfulness, and their patient explanations. My gratitude also goes to Sara Morgan for her insightful comments and expert suggestions on the earlier drafts of Chapters 9 and 10. I want to thank Juan-Carlos Rivas for giving me the opportunity to contribute to this book and creating a supportive work environment. I also want to thank Tim Toyoshima for letting me be part of this wonderful team working on interesting UC technologies. Finally, for my colleagues on the SDK documentation team, thank you for all your support.
xvi
Acknowledgments
Vishwa Ranjan I have to start by thanking my wife, Rajpreet, who was very patient with me while I worked on this book during the last month of her pregnancy. I would also like to thank my brother, Peeyush, without whose efforts I would not be in the computer industry. I would like to thank all my peers on the product team, especially Dongkyun Nam, for making sure that the right technical content went into the book. Finally, I would like to extend my gratitude to all the team members working on this project who helped me through the rigors of writing a book. A special thanks to Rui Maximo for turning the pile of information that I put on paper into something that is comprehensible and to Susan S. Bradley for driving us in the right direction. Chris Mayo In 1981, Naperville School District 203 purchased computers for my elementary school. My third-grade science teacher, Mike Manolakes, taught me how to write software after school. That investment in technology in the classroom and the extra effort by a generous teacher changed my life forever. My parents, Calvin and Judy, were way ahead of their time when they bought me my first computer in 1983, a time when a computer in the home was truly a luxury. That luxury turned an interest into a career I truly love. Marg and Bill Brannen listen with genuine interest when I blather on for hours about computers, software, and new technologies and deal with constant “upgrades” that often break something that worked previously. I appreciate their patience and hope I fix more things than I break. With regard to this book, Susan Bradley, Rui Maximo, Kurt De Ding, Diane Forsyth, Janet Lowen, Kate Gleeson, John Clarkson, and George Durzi did the impossible by taking something I wrote and turning it into something worth reading. That was no small feat. Kerry Brannen supported me through the long hours I spent locked in my office working on this book. I couldn’t have done it without her. She makes anything possible and everything more fun. Oscar Newkerk Thanks to all the people in the Unified Communications Group for the opportunity to work with such talented people on such a fun product. I want to especially thank Kyle Marsh for his help, knowledge, and all the brainstorming sessions.
Introduction Why We Wrote This Book Microsoft Office Communications Server is a relatively new product. Although it has its origins in the Enterprise Instant Messaging products, such as Exchange Instant Messaging, Live Communications Server 2003, and Live Communications Server 2005, it has evolved to become a comprehensive platform for all real-time communications. The current release, Office Communications Server 2007 R2, not only supports enterprise instant messaging (IM) and rich presence, but also offers a powerful Voice over Internet Protocol (VOIP)–based telephony system, multiparty audio conferencing, Web conferencing, and application sharing. This server offers tangible benefits in direct cost savings (for example, by eliminating costly audio conferencing services provided by telecom carriers) and improves productivity by providing more efficient ways for people to contact each other. Office Communications Server is one of the fastest-growing server products in Microsoft history, with tens of millions of licenses sold. Office Communications Server is a software-based solution that runs on standard computing and networking hardware. This server offers a rich, open API platform, making it an open and extensible part of the Microsoft Unified Communications (UC) platform. There are many opportunities for developers to build new applications on this platform. We know that developers are looking for resources to help them develop applications using the UC APIs, and this book is the only one on the market today that addresses this need. Written by experts from the product group, Programming for Unified Communications with Microsoft Office Communications Server 2007 R2 offers an easy-to-read exploration of the APIs. We hope it serves you well.
What This Book Is About This book is organized into five parts. Part I, “Understanding Unified Communications,” introduces the UC platform and provides an overview of the APIs. Part II, “Office Communicator Automation API,” explains the Office Communicator Automation API in depth and provides a detailed walkthrough of an example.
xvii
xviii
Introduction
Part III, “Unified Communications Managed API Workflow,” explains the UCMA Workflow API in detail and walks through an example of a business process communication. Part IV, “Unified Communications Managed API,” covers the Unified Communications Managed API architecture and shows how to extend the Office Communications Server Enhanced Presence model by using this API. Part V, “Debugging, Tuning, and Deploying Unified Communications Applications,” explains how to debug, tune, and deploy UC applications.
Who This Book Is For This book is intended for developers who want to create enterprise applications that include communications functionality built on the UC platform. Familiarity and experience with Microsoft Windows COM, Microsoft .NET Framework, and Windows Workflow Foundation development is recommended. This book is written on the assumption that the reader has this knowledge. Code examples in this book are written in C# unless otherwise noted. For clarity and to better illustrate how to use the APIs, the code samples are not written with defensive coding practices in mind. Please apply defensive code practices when reusing the samples in your own production applications. For an in-depth resource on the internals of Office Communications Server 2007 R2, see the Microsoft Office Communications Server 2007 R2 Resource Kit (Microsoft Press, 2009), which you can purchase in a bookstore or order from http://www.microsoft.com/learning/en/us/ Books/13113.aspx. That book also covers the Office Communications Server Software Development Kit (SDK), which is intended for administering and controlling compliance of the conversations (for example, ethical walls and custom disclaimers) with Office Communications Server, and therefore is outside the scope of this book. We sincerely hope that you find the technical information within this book useful and lucrative to your work.
Companion Content This book features a companion Web site that makes available to you all of the code used in the book. This code is organized by chapter, and you can download it from the companion site at http://code.msdn.microsoft.com/programmingocs.
Introduction
xix
Hardware and Software Requirements You need the following hardware and software to work with the companion content that is included with this book:
Servers Hardware Use only a 64-bit computer that is running a 64-bit edition of Windows Server (see more about the operating system below). Other technical specifications include the following: N
CPU
Dual-core 2.0-gigahertz (GHz) 4-way processor
N
RAM 2 gigabytes (GB) of memory
N
Hard drive 100-GB hard drive
N
Network adapter
100 megabit-per-second (Mbps) network adapter
Operating System Use only the 64-bit edition of Windows Server 2003 SP2, Windows Server 2003 R2 SP2, or Windows Server 2008. Supported editions include Standard, Enterprise, and Data Center versions of Windows Server 2003 and Windows Server 2008.
Client Computers Hardware Use any 32-bit or 64-bit computer that is running Windows Vista SP1. Other technical specifications include the following: N
CPU
A minimum 1.6-GHz Pentium III+ processor
N
RAM 1 GB of memory
N
Hard drive 50-GB hard drive
N
Network adapter
N
Video
N
A CD-ROM or DVD-ROM drive
N
A Microsoft mouse or compatible pointing device
100-Mbps network adapter
A video monitor with 800 × 600 or higher resolution and at least 256 colors
Operating System The 32-bit or 64-bit edition of Windows Vista SP1 or later. Windows Vista Home Premium Edition, Windows Vista Business Edition, or Windows Vista Ultimate Edition.
xx
Introduction
Database Requirements Use the 32-bit version of Microsoft SQL Server 2005 Express Edition SP2, which is included with Office Communications Server 2007 R2.
Office Communications Server 2007 R2 Deploy Office Communications Server 2007 R2 Standard Edition on a private network.
More Info For more information about deployment for the UC test environment, see the “Deploying Office Communications Server Standard Edition” section in Chapter 9, “Preparing the UC Development Environment.”
Administrative Tools Install the Office Communications Server Administrative Tools. The administrative tools can be installed independent of the Office Communications Server deployment on a computer that is running the 32-bit or 64-bit edition of Windows Server 2003 SP2, Windows Server 2003 R2 SP2, Windows Server 2008, Windows Vista Business, or Windows Vista Enterprise with SP1.
Development Tools The software development environment and tools required to build UC applications include the following: N
Microsoft Visual Studio 2008 SP1
N
Microsoft .NET Framework 3.5 SP1
N
Microsoft Visual C++ 2008 Redistributable Package
N
Office Communicator Automation API SDK
N
Unified Communications Managed API (UCMA) Core 2.0 SDK
Visual Studio 2008 SP1–supported software includes Visual Studio 2008 Standard Edition, Visual Studio 2008 Enterprise Edition, Visual C# 2008 Express Edition, and Microsoft Visual Web Developer 2008 Express Edition.
More Info For more information about configuring the UC software development environment, see the “Configuring Application Development Components” section in Chapter 9.
Introduction
xxi
Sample Test Topology To build and test the samples included in this book, a typical test topology includes the following clients and servers: N
A Windows Server 2008 domain controller, including the Domain Name System (DNS) and Certificate Authority (CA) roles
N
Office Communications Server 2007 R2 Standard Edition deployment
N
A Windows Server 2008 member server serving as the application server to run the sample applications
N
Two Windows Vista clients running Office Communicator
Find Additional Content Online As new or updated material becomes available that complements your book, it will be posted online on the Microsoft Press Online Developer Tools Web site. The type of material you might find includes updates to book content, articles, links to companion content, errata, sample chapters, and more. This material is available at www.microsoft.com/learning/books/ online/developer, and the site is updated periodically.
Support for This Book Every effort has been made to ensure the accuracy of this book and the contents of the Web site. As corrections or changes are collected, they will be added to a Microsoft Knowledge Base article. Microsoft Press provides support for books and companion content at the following Web site: http://www.microsoft.com/learning/support/books/.
Questions and Comments If you have comments, questions, or ideas regarding the book or the companion content, or questions that are not answered by visiting the sites mentioned previously, please send them to Microsoft Press via e-mail to [email protected]
xxii
Introduction
or via postal mail to Microsoft Press Attn: Programming for Unified Communications with Microsoft® Communications Server® 2007 R2 Editor One Microsoft Way Redmond, WA 98052-6399. Please note that Microsoft software product support is not offered through these addresses.
Part I
Understanding Unified Communications In this part, Chapter 1, “Microsoft Unified Communications,” introduces the Microsoft Unified Communications (UC) platform. This chapter highlights the challenges of UC and the opportunities that these challenges offer developers. UC opens up a new category of applications that were previously reserved for specialized systems with limited public interfaces. UC makes it easier to build instant messaging (IM) and voice or video solutions into existing and new applications. Chapter 1 also provides insight into the future direction of the UC platform. Chapter 2, “Microsoft Unified Communications APIs Foundation,” provides an overview of the APIs that are available. If you are unsure which API to use to build your application, this chapter helps you select the most appropriate one by providing examples of the types of applications each API can be used to build, the constraints of each API, and a high-level view of each API’s architecture and object model. If you are already familiar with the UC platform and know which API you want to use, you can skip directly to the chapter that covers that API in Part II, “Office Communicator Automation API.”
1
Chapter 1
Microsoft Unified Communications This chapter will help you to: N
Understand the challenges and opportunities for application developers in unified communications.
N
Understand the features and values of the Microsoft Unified Communications (UC) platform.
Unified Communications: Challenges and Opportunities What is unified communications? The term unified communications refers to technologies that integrate various and often disparate communication systems and capabilities in order to provide a more seamless and enhanced communication experience. The goal of unified communications can be summarized with the following statement: Connect to the right individuals at the right time with the right information using the right capability. For example, UC technology enables a user to place a call to another user, to receive a call from another user, and to transfer a call to another user using Microsoft Office Communicator. This call can be an instant messaging (IM) conversation, a computer-tocomputer audio/video (A/V) call, or a voice call conducted between a computer and a Public Switched Telephone Network (PSTN) or Private Branch eXchange (PBX) phone. The call can be between two users or between three or more conference participants. With Office Communicator, users can make and take calls anywhere with an Internet connection as if they were using the phone in their office. Before each call, the user can utilize Office Communicator to check the presence of the called party and determine whether that user is available and willing to take the call. The presence information can also include contact information, such as the primary and alternate phone numbers that can be used to direct an outgoing call. Without knowing a contact’s presence, callers may have to make several attempts before reaching their contact. Before getting into the specifics of building UC applications, let’s explore the challenges and opportunities that application developers can seize in the UC space. Applications that help people and businesses communicate more efficiently can provide a compelling package.
3
4
Part I
Understanding Unified Communications
Challenges in Unified Communications Over the last decade, the number of available communication modalities has multiplied rapidly. A business card today barely has enough space to list them all. Professionals can be reached on their PBX work phone, work and personal cell phone by voice or Short Message Service (SMS), work and personal e-mail address, corporate IM address, personal IM provider, Facebook account, LinkedIn account, blog URL, and many other options. With so many ways of contacting people, how do you know which method is the most effective to reach them or what is the best time to reach them? Is the contact in the same time zone (or even in the same country) as you? Maybe the person is in a meeting and will not respond to a phone call but will respond to an IM or SMS message. Depending on the modality, the person might be responsive depending on what he or she is doing at that moment. In today’s world of high-tech communication, UC is beginning to address three main challenges: N
Reducing communications overload
N
Connecting disparate and disconnected communications systems
N
Using communications to improve collaboration
The first challenge is exacerbated by the explosion of media and devices that can be used to communicate. Therefore, to reach your contact, it’s important to understand what methods of communication are most effective at any given time. The converse of this challenge is also a problem. Given the various ways you can be reached, how do you make it easy for others to contact you? It’s no wonder that address book management software offers so many fields that can be filled for each contact. Imagine the frustration your family, friends, coworkers, and professional contacts experience trying to reach you with all of the various methods you are providing them. Although the available modalities that can be used to contact a person are intended to make individuals more accessible, the proliferation of communication modalities can affect communication negatively. The second challenge illustrates the state of today’s communications systems. Because of the explosion of communication solutions, they still work in silos, and it is hard to connect the communication experience across applications. Communications systems are disconnected. Until recently, enterprises bought a PBX and phones from one vendor, bought an additional voice mail system from another vendor or as part of the PBX bundle, and then obtained audio-conferencing solutions from another vendor. The contact center side of the enterprise bought an Automatic Call Distributor (ACD) and Interactive Voice Response (IVR) system from yet a different set of vendors. Meanwhile, the IT side of the enterprise bought an e-mail system and a corporate IM system, as well as line-of-business applications from yet another vendor or vendors. Most of these systems offer APIs with limited access to the entire functionality of their platform or APIs that are not designed to exchange data between the silos to enable them to work together. Consequently, users are forced to learn and work across
Chapter 1
Microsoft Unified Communications
5
different devices or must buy expensive applications to tie together the data from various communications system for their needs. The interaction between various silo solutions becomes taxing and reduces efficiency. The third challenge highlights the difficulty of communicating with remote parties. Whether communicating by e-mail, phone, or IM, communicating effectively requires sufficient context. Often, context is best conveyed in face-to-face interaction; however, this requires teams to be collocated or to incur costly travel expenses. As costs, regulations, and personal preferences make it more and more difficult to relocate workers to the same region, companies must find ways for employees to work together effectively and productively even if they are in different places. Remote communication and collaboration can be improved substantially by making it simpler to share context automatically and easily. Contextual information can include visually sharing information (application sharing), providing a link to an e-mail of interest for discussion, or synchronizing the same application across all parties in the call. Certainly, there are more challenges to effective and efficient communication; however, these three are the major sources of the frustration that users experience when communicating and collaborating in remote scenarios.
Opportunities in Unified Communications Microsoft Office Communications Server and Microsoft Exchange Server are foundational pieces of UC because they manage two important communication repositories: Enhanced Presence and the unified inbox. Office Communications Server uses presence to address the premise that individuals want actual contact with other users rather than reaching a mechanized inbox, voice mail, or IM response. Users have no interest in dialing a number only to get a voice mail greeting. Users do not want to send an e-mail if the likelihood of a timely response is low. To avoid such scenarios, it’s necessary to know the user’s availability. Office Communications Server makes it possible to expose user presence information so that the contact can be reached more quickly and easily. Alternatively, users do not want to be reachable at every moment because they want to focus on a project, meet with a client, or perform other necessary business functions without being interrupted. With Office Communications Server, users can control the level of availability they want to have at any particular time. In the same way that users can control how their time is allocated through their calendar, users can manage their presence. Presence information is a set of metadata about a person’s availability or, more precisely, their willingness to be available to others. Office Communications Server manages presence as an Extensible Markup Language (XML) schema that can be extended to include additional information, such as location or skills, which can be relevant to the context of communications.
6
Part I
Understanding Unified Communications
Now that a user can view your presence (at least the level of presence you’re willing to advertise), how does that improve communication? With any of the Office Communications Server clients, such as Office Communicator, communicating—whether by e-mail, IM, phone, or application sharing—is only a click away. The user no longer needs to track all of the devices on which you’ve published and are accessible. This addresses the first challenge discussed in the previous section. From the presence icon, users can launch additional modalities of communication (such as escalating an IM conversation to a voice call or adding application sharing) without having to start multiple independent applications. Because the process of communicating becomes simpler, Office Communications Server reduces human latency— the time it takes to establish a call with another user. While tens of millions of information workers use Enterprise IM, the majority of enterprise applications that exist today do not offer embedded presence and the real-time communications functionality that comes with it. There’s a wide opportunity to embed Office Communications Server presence and real-time communications modalities into existing and new applications. As the popularity increases and enterprises recognize the value that UC offers, demand for UC-enabled applications will continue to rise. Microsoft builds UC as a pure software solution running on standard general-purpose computing and networking hardware. Building UC as a software solution overcomes the second challenge of integrating disparate and disconnected communications systems. By using the same programming paradigms (such as Component Object Model [COM], Microsoft .NET Framework, and Web Services) and the same tools (such as Microsoft Visual Studio) familiar to Microsoft Windows developers, programmers can create and integrate communications into new and existing applications as easily as developing Windows applications without having to deal with the deeper underpinnings of communications, such as Session Initiation Protocol (SIP) protocols, media stacks, and speech technology. While the key elements of the UC platform are Office Communications Server and Exchange Server, this software platform integrates and includes many other Microsoft products such as Microsoft Windows, Microsoft SharePoint, Microsoft Dynamics, Microsoft Office, and Visual Studio. By extension, this software-based communications experience can be embedded in any line-of-business application that developers are creating. Because all of UC is built as a software solution, new innovative scenarios are possible. When communicating over the phone, IM, or e-mail, explaining the context of what you’re trying to communicate can be laborious at best. Users sometimes have to go into a long explanation to convey the scenario or problem before they can get into their question. Conveying context across a modality, whether it is IM, e-mail, or voice, is challenging at best. Meeting face to face is universally the preferred mode of communication, and for good reason. However, this is not always possible, and optimizing remote communications is sometimes necessary. UC tackles this third challenge by providing contextual collaboration. Contextual collaboration is about sending metadata with the actual communication. This
Chapter 1
Microsoft Unified Communications
7
metadata can be as simple as a link to the e-mail that the caller is interested in discussing. The caller can click the link to open the specific e-mail in her or his inbox. A caller can set the subject line so that the recipient of the call knows what the caller wants to discuss before answering the call. Metadata can be more elaborate, such as starting an application-sharing or A/V session or synchronizing the view of a design within an application used by both parties. All of these ways of providing context (and more) are possible with Office Communications Server. Because Office Communications Server uses the data or Internet Protocol (IP) network to send IM, audio, and video, it can be used to send metadata (documents, Web pages, application-specific protocols, and so on) easily with the communication. Building these contextual collaboration experiences is a major opportunity for developers to enhance existing applications. Contextual collaboration can significantly improve the collaboration experience and help streamline communications between people. The UC platform also offers key opportunities to use communications in business processes. For example, business processes often require human intervention. Business processes can use communications to cut down the latency period when a human decision is required. For example, to notify users, you can build alerts and notifications that use the IM or voice channels supported by Office Communications Server or the e-mail channel offered by Exchange Server. Such systems provide a push model wherein users no longer need to check whether a document is ready for signing but can be notified when it’s ready for the user to sign. Communications also can be automated in reverse: a caller can contact IVR applications via the telephone or automated agents (query/response bots). This allows organizations to reduce costs by having automated systems answer customers’ frequently asked questions (FAQs) instead of using human representatives. The ability to create automated agents easily is another key capability that comes as an integral part of Office Communications Server. There are many more types of applications that developers will undoubtedly imagine and create using UC APIs. These APIs are discussed in the rest of this chapter.
The Unified Communications Platform UC is a software-based platform. Integrated with Active Directory Domain Services, this platform provides a unified view of the user’s identity, presence, and inbox. All means of communications with the user evolve around this single identity and inbox. Users are not interested in remembering a long list of phone numbers (work, cell, and so on), IM handles (one for each public IM provider), or e-mail addresses to reach a contact. With Exchange Server and Office Communications Server, enterprises can create a standardized e-mail, IM address, and phone number for every user. This is illustrated in Figure 1-1.
Unified Communications APIs Just as Windows makes it easy to develop graphical user interface (GUI) applications, Office Communications Server extends this user interface to voice and IM applications. Because of the software-based nature of the platform and its rich public API set offering, UC APIs can undoubtedly be used to create many different applications that build on Office Communications Server and Exchange Server. There are at least three types of applications that developers can build with UC APIs. These are as follows: N
Contextual collaboration Integrating modalities and context into existing and new enterprise applications to facilitate communications between humans.
N
Business process communications Applications that contact users based on triggers defined by the business, such as alerts. For example, a server failure in the datacenter can alert the set of administrators who are currently online and available.
N
Anywhere information access Employees using various forms of communication to obtain information within the enterprise, such as bots and IVR systems. For example, users can use the phone or IM to request information.
The UC platform offers client-side and server-side APIs to fit the type of application that you want to build. These APIs are either .NET Framework–based or COM-based. The COM-based APIs integrate into the .NET Framework using the COM-Interoperability wrappers, which means that you can use any of these APIs in a .NET Framework application. Where appropriate, these APIs are well integrated with Visual Studio.
Chapter 1
Microsoft Unified Communications
9
Programming Office Communications Client Applications The Office Communications Server client API is UC Client API (UCC API) 1.0. It is a COM-based API, although it is accessible to .NET Framework applications through an interop assembly. The UCC API offers all of the functionality used by Office Communicator, including presence, IM, voice, video, and conferencing. This API provides signaling, media, and the capability to traverse firewalls using the Interactive Connectivity Establishment (ICE) standard to connect media channels. In the Office Communications Server 2007 R2 release, the API has been updated with only QFEs (Quick Fix Engineering) to make the UCC API 1.0 compatible with the new features of R2. The Office Communicator Automation API is a client API that uses the business logic built into Office Communicator. It is an automation API, and its functionality is less comprehensive than the UCC API. With the Office Communicator Automation API, you can program an Office Communicator instance from a third-party application, as well as extend and customize user experiences with Office Communicator. The Office Communicator Automation API is used by the sample presence controls and a sample ActiveX control that Microsoft published on MSDN, available at http://msdn.microsoft.com/en-us/office/cc718982.aspx, as well as the Name Control that ships and installs with Office. In the “Microsoft Office Communicator 2007 R2 Deployment Guide” located at http:// go.microsoft.com/fwlink/?LinkID=133744, you can find information on how to customize the Office Communicator look and feel to some extent. Custom Tabs is one of these customizable capabilities. A Custom Tab uses a browser window in the lower third of the Office Communicator main window with the contact list. In Office Communicator 2007 R2, context-sensitive information related to a person can be linked to a tab button in the Office Communicator contact card. Note that the functionality is more streamlined in the R2 release and behaves different from OCS 2007. The UC Asynchronous JavaScript and XML (AJAX) API is an API that talks to the Communicator Web Access server role in Office Communications Server 2007. Application developers can use it to create Office Communicator–compatible clients that allow users to manage and share presence information, to manage contacts and groups, to send and receive instant messages, and to search for users within an enterprise. Such clients can be a browser-based Web application (for example, an ASP or ASP.NET application) or a standalone network application (for example, a .NET Framework executable). The client applications can be written in a wide range of programming languages, including JavaScript, C#, Microsoft Visual Basic .NET, Perl, and C/C++. The UC AJAX API supports only presence, IM, and call deflection. The API does not support voice, video, or conferencing. In Office Communications Server 2007 R2, the UC AJAX API is deemphasized. It will not be available in the next release of Office Communications Server. Because the Unified
FIGURE 1-2 Client APIs.
Middle-tier
Client-side
Unified Communications AJAX Service
Your Application
Communicator Web Access Server
Unified Communications Managed API 2.0
Your Application
Office Communications Server 2007 R2
Unified Communications Client API 1.0
Customizations
Office Communicator 2007 R2
Your Application
Exchange 2007 Client Access Server
Exchange Web Services
Exchange Web Services Managed API 1.0
Your Application
Middle-tier
Client-side
Part I
Communicator Automation API
Your Application
10 Understanding Unified Communications
Communications Managed API (UCMA) scales better than the UC AJAX API, it is preferable to use UCMA. Therefore, it’s recommended to build your own Web Service using UCMA server-side to extend the reach to non-Windows platforms.
Figure 1-2 illustrates the client APIs for building client-based applications.
Chapter 1
Microsoft Unified Communications
11
Programming Office Communications Server Applications On the server side, the UCMA offers a SIP stack, a media stack, and powerful speech engines for both Automatic Speech Recognition (ASR) and speech synthesis (Text-to-Speech [TTS]). UCMA 2.0 can be used to build outbound applications, such as alerts, notifications, and surveys, and inbound applications, such as conferencing services, IVR solutions, automated agents (query response bots), and ACDs, which perform skill-based routing. The API provides access to the presence information available in Office Communications Server 2007 R2 and can be used to build role agents that use this presence information to streamline communications between people. The UCMA 2.0 Workflow API is a higher API abstraction layer of UCMA, which provides Windows Workflow Activities for Office Communications Server. UCMA 2.0 Workflow builds on top of the .NET Framework 3.5 SP1 Windows Workflow Foundation. This VUCMA Workflow API workflow defines new Workflow Activities for querying presence and creating IM and voice dialogs in workflow-based applications. Simple drag-and-drop operation development is now possible to build sophisticated applications. UCMA Workflow simplifies development of voice and IM-based communications into applications that facilitate business processes. Ideally, developers start developing a project on the UCMA 2.0 Workflow and then fall back to the lower-level UCMA in case the UC Workflow Activities do not offer the capabilities they required. The Microsoft Office Communications Server 2008 Speech Server APIs target the development of Interactive Voice Response applications using the UC platform. Speech Server includes speech recognition and speech synthesis engines. Speech Server (2007) provides the following APIs: N
Speech Server Workflow Activities
N
Speech Server Managed API
N
VoiceXML (VXML) 2.1
N
Speech Application Language Tags (SALT) 1.0
Speech Server (2007) is certified for VXML 2.0/2.1 by the VoiceXML Forum. And Speech Server (2007) Developer Edition (http://go.microsoft.com/fwlink/?LinkID=70208) comes with a comprehensive toolset for building speech applications and is tightly integrated with Visual Studio 2005. Speech Server (2007) is the last release of a standalone voice recognition platform. Applications developed using VXML 2.1 are supported on UCMA. The tools for developing speech grammars, lexicons, tuning tools, and other elements is integrated with UCMA. Figure 1-3 illustrates the server APIs for building server-based applications.
12
Part I
Understanding Unified Communications
Your Application
Your Application
Your Application
Your Application
Windows Workflow Activities and VoiceXML /SALT
Speech Server Managed API
Exchange Web Services Managed API
Unified Communications Managed API 2.0
UCMA 1.0
Exchange Web Services
Office Communications Server 2007 R2
OCS 2007 Speech Server
UC Workflow API
Exchange 2007 Client Access Server
FIGURE 1-3 Server APIs.
Summary With Office Communications Server 2007 R2, Microsoft innovates by using the .NET Framework and tools familiar to developers, such as the Visual Studio Integrated Development Environment (IDE), to provide a development platform familiar to Windows developers. The UC platform makes it easy for Windows developers to extend their expertise into building IM-based and voice-based applications previously reserved to developers with a very specialized skill set.
Microsoft Unified Communications APIs Foundation This chapter will help you to: N
Understand the scenarios that you can build using the API.
N
Understand the considerations to help you determine whether this API meets your requirements.
N
Understand the API’s architecture.
N
Understand the API’s design model.
This chapter provides a technical overview of the Microsoft Unified Communications (UC) APIs so that you can understand them, how they relate to each other, and what purpose they serve. The intent of this chapter is to provide you with sufficient information to help you decide which UC APIs best fulfill your needs. If you already know which APIs meet your needs, you can look only at the sections that cover the APIs of interest to you, or skip this chapter altogether if you wish.
Unified Communications Managed API 2.0 The Unified Communications Managed API (UCMA) is a code platform managed by Microsoft .NET Framework, which provides access to presence, instant messaging (IM), telephony, and audio/video (A/V). UCMA is a Session Initiation Protocol (SIP)–based platform. SIP is a signaling protocol that is used for setting up and tearing down multimedia communication sessions. This API abstracts the details of the communication protocols used by Microsoft Office Communications Server.
13
14
Part I
Understanding Unified Communications
Scenarios UCMA is used to build scalable middle-tier applications that work with Office Communications Server 2007 R2, provide large-scale message throughput, and represent multiple endpoints. You can use this API to build the following types of applications: N
N
Highly scalable notification and alert systems that perform the following actions: O
Send outbound alert messages.
O
Use the Enhanced Presence feature of the Office Communications Server 2007 R2 platform to determine the appropriate channel and media to deliver alerts, such as instant messages, e-mail, or voice calls.
Interactive automated agents (query/response bots) that perform the following actions: O
Respond to user requests for information by means of IM or voice sessions.
O
Create custom call routing and interactive voice response systems.
More advanced applications include the following: N
N
Contact center or help desk applications that do the following: O
Route incoming communications sessions to available agents.
O
Use the Enhanced Presence capabilities of the Office Communications Server 2007 R2 platform to route to agents based on specific skill sets.
O
Provide “music on hold” functionality for voice sessions.
O
Create back-to-back user agents (B2BUAs) for help desk scenarios; for example, so that the specific identity of the help desk agent is not exposed to the customer.
Conferencing portal applications that do the following: O
Create custom conference bridging.
O
Record the contents of conference calls.
O
Schedule and manage instances of conferences.
Considerations UCMA 2.0 is considered a middle-tier API written completely in C#. Therefore, it runs only in environments where the .NET Framework is supported. It provides the following characteristics: N
Scalability UCMA 2.0 is able to support thousands of endpoints and concurrent communications and collaboration sessions. It is designed for building server
Chapter 2
Microsoft Unified Communications APIs Foundation
15
applications (the recommended operating system is Microsoft Windows Server 2008 on 64-bit hardware). UCMA 2.0 is multithreaded, and operations are performed asynchronously to maximize throughput. N
Availability The deployment model supports running multiple instances of the UCMA 2.0 application for load balancing and failover across multiple computers with the use of hardware load balancers.
N
Extensibility New modalities can be added in the conversation framework. Extension headers and Uniform Resource Identifier (URI) parameters can be supplied and consumed through the APIs to support the creation of custom sessions.
UCMA 2.0 supports two types of SIP endpoints that are designed for distinct application scenarios: the ApplicationEndpoint class and the UserEndpoint class. You use the ApplicationEndpoint class in applications that represent automated applications, such as bots that interact with users. You use the UserEndpoint class in applications that connect to Office Communications Server on behalf of users and perform operations on behalf of those users. To configure Office Communications Server to trust connections from UCMA applications that use the ApplicationEndpoint and UserEndpoint classes, the application provisioning process must define a Globally Routable User Agent URI (GRUU). For more information about GRUUs, see Chapter 9, “Preparing the UC Development Environment.” This is all that is necessary if the application creates only UserEndpoints. After the application has authenticated the user, it does not need to supply those credentials to Office Communications Server for authentication. For applications that create ApplicationEndpoints, the provisioning process also must create a Contact object that defines the application’s SIP URI. You also have the option to create a display name and a TEL URI. The ApplicationEndpoint uses this Contact object to register with Office Communications Server. Examples of applications that use the ApplicationEndpoint class are Automatic Call Distributor (ACD), interactive IM or voice bots, and conference bridges. For more information about these applications, see the “UCMA 2.0 Workflow API” section later in this chapter. These applications use a Contact object to identify the application in Active Directory Domain Services. The Contact object specifies the application’s SIP URI and phone number. Examples of applications that use the UserEndpoint class are those that publish additional presence information. Examples of additional presence information include showing a Global Positioning System (GPS) location on behalf of a user or acting as a proxy when the user is not available and routing incoming IM messages through a Short Message Service (SMS) gateway.
16
Part I
Understanding Unified Communications
API Architecture UCMA is composed of the following two interfaces: N
UCMA 2.0 Core API
N
UCMA 2.0 Speech API
This architecture can be represented as shown in Figure 2-1. Unified Communications Managed API 2.0 UCMA 2.0 Core API Signaling Stack
Media Stack
UCMA 2.0 Speech API Speech Recognition Engine
Text-to-Speech Engine
FIGURE 2-1 UCMA version 2.0 architecture.
UCMA 2.0 Core API The UCMA 2.0 Core API hides the complexity of most of the Office Communications Server SIP/SIMPLE (Session Initial Protocol for Instant Messaging and Presence Leveraging Extensions)-Based protocols by offering an API that exposes almost all of the features of the protocol but is simpler to understand and use. The UCMA Core API provides access to the signaling and media stack as follows: N
The SIP stack in UCMA 2.0 offers a managed code SIP endpoint API.
N
The Media stack in UCMA 2.0 provides a protocol abstraction over the multiple real-time media protocols. This protocol abstraction is exposed in the Microsoft.Rtc. Collaboration namespace. This interface provides access to the following functionality: O
Publication of and subscription to Enhanced Presence
O
Creation and management of multiparty conference sessions
O
Creation, modification, and deletion of Contacts and Groups
O
Call Control for routing audio sessions
O
Management of audio media in sessions
UCMA 2.0 Speech API The UCMA 2.0 Speech API is a server-grade speech API that allows developers to build multichannel speech recognition– and speech synthesis–enabled applications using Microsoft
Chapter 2
Microsoft Unified Communications APIs Foundation
17
state-of-the-art speech technology. The UCMA 2.0 Speech API supports 12 different languages, including English (North America, United Kingdom), French (France, Canada), German, American Spanish, Portuguese (Brazil), Italian, Japanese, Korean, and Chinese (Simplified and Traditional). The Speech API provides access to the Automatic Speech Recognition (ASR) engine and Textto-Speech (TTS) engine that ship as part of UCMA 2.0: N
ASR Engine This state-of-the art speech recognizer supports triphone phonetics, as well as whole-word modeled speech recognition, for optimal speech recognition, not only for natural language recognition but also for command and control and number recognition.
N
TTS Engine This very accurate speech synthesizer uses Hidden Markov Model (HMM)–based Speech Synthesis (HTS) for maximum intelligibility.
Object Model In UCMA 2.0 Core API, the entry point class is CollaborationPlatform. An application can create multiple CollaborationPlatform instances. Each instance can host multiple endpoints. An endpoint is the basis for communication and collaboration functionality with Office Communications Server. The properties and methods of these classes provide access to the functionality of the collaboration sessions. The CollaborationPlatform class can be used to: N
Initiate and manage a conversation (Conversation class).
N
Schedule and manage conferences (ConferenceServices class).
N
Subscribe to the presence of remote users (RemotePresence class).
N
Publish presence for the endpoint owner (LocalOwnerPresence class).
N
Manage contacts and groups (ContactGroupServices class).
Figure 2-2 shows the relationships among the principal classes of the architecture, as well as the personas involved in each type of object. The numbers shown between two objects indicate the mapping between classes. For example, one local endpoint object can be associated with zero or more Presence Subscription objects.
18
Part I
Understanding Unified Communications
CollaborationPlatform 1 0+ Local Owner
1
LocalEndpoint
1
0+
1
1
1
1
Conversation Local Participant Remote Participant
0+
Conference Scheduling and Management
Presence Publication Local Presentity
Organizer Conference Participant
0+
0+
Contacts and Groups Contact
Presence Subscription Remote Presentity
Collaboration
Communication FIGURE 2-2 UCMA 2.0 Object Model.
In UCMA 2.0 Speech API, Microsoft.Speech is the main namespace. It is modeled very closely after the System.Speech client namespace in the .NET Framework, yet it provides the ability to run many recognizers and synthesizers in parallel. The two key classes in this namespace are: N
Microsoft.Speech.Recognition
N
Microsoft.Speech.Synthesis
This class controls the Recognizer.
This class controls the Synthesizer.
Microsoft.Speech.Recognition.SrgsGrammar provides a class to optimize performance of handling speech recognition grammars.
UCMA 2.0 Workflow API The UCMA Workflow API and Workflow Activities extend the Windows Workflow Foundation with additional activities that provide access to UCMA functionality. This API consists of a set of custom workflow activities and supporting classes on top of the Windows Workflow Foundation of .NET Framework 3.5 SP1. It consists of the following items: N
A set of custom activities for unified communications (for example, AcceptCall)
Chapter 2 N
Microsoft Unified Communications APIs Foundation
19
Two Workflow Runtime services (CommunicationsWorkflowRuntimeService and TrackingDataWorkflowRuntimeService) that enable the custom activities to run
Scenarios The UCMA Workflow API and Workflow Activities are a higher-level API built on top of UCMA 2.0. Using the .NET Framework 3.5 SP1 Windows Workflow Foundation, it offers developers an abstraction layer of UCMA that is easier to use. UCMA Workflow Activities can add value at communication points in business processes. You can use the UCMA Workflow API to build the following types of applications: N
Presence queries for individuals
N
Alerts and notification applications that use the IM or voice channel
When writing a presence-aware application, the business logic in the workflow can make presence-based, intelligent modality decisions. For example, it is better to send an instant message to a person who is in the middle of a phone call than to call the person. Alerts and notifications can make more intelligent decisions based on the user’s presence state, such as whether to start a phone call or IM session with a user when triggered by an event. IM-based automated agents understand text-based input using grammar-modeled speech technology. IM-based automated agents can be used to navigate through menu-based systems as well as provide information services, such as querying a database or knowledge base system. For example, an automated IM bot can spell out acronyms, such as converting “MSFT” to “Microsoft.” Incoming voice calls can be understood using the same grammars used for IM calls, powered by ASR using UCMA 2.0 Speech API and DTMF-based touch-tone input. UCMA Workflow voice applications respond by prerecorded speech, or speech synthesis. The UCMA Workflow API creates sophisticated voice- and text-based dialogs easily. It provides a great dialog experience to the user by understanding commands (for example, “Help” or “Repeat”) or by providing guidance in its intelligent responses for invalid inputs (for example, “I’m sorry I didn’t understand you”). The UCMA Workflow API provides a set of Workflow Activities for call control, such as accepting incoming IM invitations, transferring a call to another party, and disconnecting the call.
20
Part I
Understanding Unified Communications
Windows Workflow Foundation To better understand UCMA Workflow, it is important to understand the Windows Workflow Foundation. The Windows Workflow Foundation is a framework, available as part of .NET Framework 3.0, .NET Framework 3.5, and .NET Framework 3.5 SP1, that enables developers to create applications that can be modeled as a workflow. These workflows can be automated (for example, a workflow that alerts an administrator about specific events) or can require human interaction (for example, an expense report–processing workflow that requires human approval). The Windows Workflow Foundation API supports the Microsoft Visual Basic .NET and C# languages. It consists of the following high-level components: N
A workflow runtime workflows.
Provides capacity to the host application for the executing
N
A workflow compiler Used to compile workflows, developed using C#, Visual Basic .NET, or Microsoft Extensible Application Markup Language (XAML), into an assembly.
N
A graphical Workflow Designer A graphical user interface that you can use to design the workflow. You can drag the activities to this designer canvas to define the flow of the application logic. The Workflow Designer can also be rehosted in any application outside Microsoft Visual Studio. For more information about rehosting the Workflow Designer, see http://msdn.microsoft.com/en-us/library/cc835242.aspx.
N
A workflow debugger A debug engine that enables you to debug a workflow application. You can also use this to set breakpoints on the activities on the designer canvas.
N
A rules engine Conditions in workflow (for example, as used in if-else or while constructs) can be specified either in code or as a declarative rule condition. You use the rules engine to evaluate these conditions at run time.
N
A set of Windows Workflow Activities An out-of-the-box set of activities that range from simple activities, such as the Code, IfElse, and While activities, to a more complex set of activities like Conditional Group Activity. An activity is the building block of a workflow. A custom activity, such as the ones defined in UCMA Workflow Activities, is a class that is derived from the Activity class defined in the Windows Workflow Foundation. You can create the workflows either by using code or markup language. The framework also provides an extensible model to build custom activities that you can reuse across projects. For details about Windows Workflow Foundation, see the Windows Workflow Foundation tutorials at http://msdn.microsoft.com/en-us/library/ ms735927.aspx.
Note Even though Windows Workflow Foundation is available in .NET Framework 3.0 and .NET Framework 3.5, UCMA Workflow Activities is supported only on .NET Framework 3.5 SP1.
Chapter 2
Microsoft Unified Communications APIs Foundation
21
For more information about these components, see http://msdn.microsoft.com/en-us/ netframework/aa663328.aspx.
Considerations The Windows Workflow Runtime must satisfy two requirements for the UCMA Workflow Activities to execute. These requirements are as follows: N
The Windows Workflow Runtime must allow custom Workflow Runtime services, such as the UCMA Workflow Activities, to be added. The two Workflow Runtime services (CommunicationsWorkflowRuntimeService and TrackingDataWorkflowRuntimeService) provide infrastructure for the UCMA Workflow Activities to execute. Therefore, you should configure the workflow run time to allow these services to be added for UCMA Workflow Activities to execute properly.
N
Disable persistence during the execution of UCMA Workflow Activities. Some workflow run times allow persistence by using custom workflow services that are derived from the WorkflowPersistenceService class. You use these services to store workflow state information on disk when idle and then recreate it when needed. UCMA Workflow Activities do not support persistence. Therefore, persistence should be disabled when running these activities.
From a high level, UCMA Workflow Activities offers the following functionalities: N
Call control functionalities for both phone and IM calls (for example, accepting the call, disconnecting the call, or creating an outbound call).
N
Specific call control functionalities for phone calls (for example, blind transfers, hold events, and retrieve events).
N
Play messages to the user over the phone. These messages can be recorded prompts or can be synthesized by using the TTS engine.
N
Recognize user input over the phone, both by means of speech and DTMF.
N
Send, receive, and recognize messages over an IM channel.
N
Query for presence information from the workflow.
N
Enable moving the execution of the workflow from one activity to another using a GotoActivity object.
N
Support for multiple calls (that is, phone or IM) in one workflow.
You should use UCMA Workflow Activities to create or enhance applications that are state engine workflows. Examples of such applications are applications that interact with the user over the phone or IM channel.
22
Part I
Understanding Unified Communications
Workflow Architecture Figure 2-3 illustrates a high-level architecture of UCMA Workflow and its dependencies. UC Workflow Activities UC Workflow Runtime Services Windows Workflow Foundation
Unified Communications Managed API 2.0
.NET Framework FIGURE 2-3 UCMA Workflow architecture. N
Windows Workflow Foundation The Windows Workflow Foundation is a framework that is part of .NET Framework 3.0 and .NET Framework 3.5.
N
UCMA
This API consists of the following interfaces:
O
UCMA Core The UCMA 2.0 collaboration platform. It provides functionalities such as calling, presence, and conferencing.
O
UCMA Speech The UCMA 2.0 speech platform. It provides functionalities such as TTS, speech recognition, and DTMF recognition.
N
UCMA Workflow Runtime Services These are custom Workflow Runtime services built on top of the Windows Workflow Foundation that enable UCMA Workflow Activities to execute properly. For details about these run-time services, see Chapter 4, “Embedding Contextual Collaboration.”
N
UCMA Workflow Activities These are custom activities that encapsulate UCMA Core (for example, call and IM) and UCMA Speech (for example, recognizing user input and TTS synthesis) functionality into an activity format. Examples of such functionalities are having a question-and-answer-based dialog with the user over the phone call or IM session. However, all functionalities of UCMA Core and UCMA Speech are not provided in the form of workflow activities as part of UCMA Workflow Activities. Developers can create their own custom workflow activities to capture the functionalities not available from UCMA Workflow Activities.
Object Model The UCMA Workflow provides managed classes, events, and enumerations to allow you to build communication-enabled workflow applications.
Chapter 2
Microsoft Unified Communications APIs Foundation
23
When you install the UCMA Software Development Kit (SDK), the following two libraries are included: N
Microsoft.Rtc.Workflow.dll This library contains all of the workflow activities and custom Workflow Runtime services that are used in the development of the communications-enabled workflow application.
N
Microsoft.Rtc.Workflow.Toolbox.dll This library contains the package that is installed in Visual Studio so that the UCMA Workflow Activities show up in the Visual Studio toolbox.
Office Communicator Automation API The Office Communicator Automation API provides programmatic access to Microsoft Office Communicator 2007 R2 so that you can automate this software running on the client. It is a quick and easy way to integrate Office Communicator functionality into your applications. This API is used in Microsoft Office 2007 and Microsoft SharePoint 2007 to integrate presence information and real-time communications from Office Communicator into these products.
Scenarios The Office Communicator Automation API provides access to most of the functionalities in Office Communicator 2007 R2 programmatically. Your code can sign in the user to Office Communicator and perform actions on behalf of this user (for example, starting an IM session or calling a contact), change user preferences (for example, tagging a contact), and manage contacts (for example, retrieving the contact list, adding and removing contacts from the list, and working with contact groups). The API can also raise events from Office Communicator to alert you to things like changes in contact presence or an incoming call. With these capabilities in mind, the following examples are the types of features that you can add to your applications using the API: N
Embedding presence with application-specific contact lists You can use the API to add Office Communicator contact presence to your applications by building a custom contact list. This application-specific contact list can show the presence of contacts even if they are not in the user’s Office Communicator contact list.
N
Enhancing communications You can enhance your applications by using the API to allow users to communicate by IM, voice, and video directly from your application.
N
Creating application context-specific communications You can use the API to integrate data from your application into the conversations your application creates to provide application-specific context for the conversation.
24
Part I
Understanding Unified Communications
Considerations The Office Communicator Automation API was created for integrating presence and communication features into client applications. The API is not appropriate for server-side solutions because it requires Office Communicator to be running on the local machine and signed in to Office Communications Server 2007 R2 with a valid user account. Because the Office Communicator Automation API automates Office Communicator, very little code is required to provide sophisticated communication features. While this increases your productivity as a developer by allowing you to create communication features quickly, keep in mind that the API requires Office Communicator to be installed on the client machine for communication features built with the API to work. Also note that when using this API, your code shows elements of the Office Communicator user interface (UI) (for example, when you add a contact or start a voice conversation) rather than allowing you to provide your own UI for these actions. Consider using the Office Communicator Automation API if you want to integrate presence and collaboration functionality into your application quickly without having to write your own client or to understand SIP and real-time communications protocols.
Application Architecture Only a single instance of Office Communicator 2007 R2 can be installed and run on the client. Office Communicator (that is, Communicator.exe) is a Component Object Model (COM) server that runs out of process with your application and provides a programmatic interface to Office Communicator by using the libraries supplied by the API. The Office Communicator Automation API libraries (that is, CommunicatorAPI.dll and CommunicatorPrivate.dll) run in your application process. Figure 2-4 illustrates the run-time architecture of your application when using the API. Application2.exe
Application1.exe CommunicatorAPI.dll
CommunicatorAPI.dll
CommunicatorPrivate.dll
CommunicatorPrivate.dll
Communicator.exe
FIGURE 2-4 Office Communicator Automation API application architecture.
Chapter 2
Microsoft Unified Communications APIs Foundation
25
For more information about COM and interoperating with COM from managed code, see the “Additional Resources” section at the end of this chapter.
Note The Office Communicator Automation API automates either Office Communicator 2007 R2 or Office Communicator 2007 depending on which client is installed on the computer.
Object Model The Office Communicator Automation API provides two classes, Messenger and MessengerPriv. Each of these classes exposes interfaces for you to build your communication features. Figure 2-5 shows the relationship between the classes supported by the API and the interfaces each class implements.
IMessenger IMessenger2 IMessenger3 IMessengerAdvanced Messenger Class
IMessengerPrivate MessengerPriv Class
FIGURE 2-5 Messenger class and MessengerPriv class interface implementation.
The Messenger Class The Messenger class represents the instance of Office Communicator 2007 R2 running on the local computer and is the entry point to most of the information and functionalities you can access in the API by using the interfaces it supports. Messenger also supports a number of key events for keeping your application in sync with Office Communicator. When using the Messenger class, some methods display Office Communicator dialog windows (for example, calling the method to add a contact shows the Add Contact dialog box). Messenger class interfaces
The Messenger class implements the following interfaces:
N
IMessenger interface Supports the most basic features of the API, such as working with the local user’s information (that is, displayed name and phone number) and contact list.
N
IMessenger2 interface Inherits from the IMessenger interface (and thus supports all of its properties and methods) and adds methods and properties for working with Office Communicator contact groups.
26
Part I
Understanding Unified Communications
N
IMessenger3 interface Inherits from the IMessenger2 interface (and thus supports all of its properties and methods) and adds two unsupported properties. This interface is not used.
N
IMessengerAdvanced interface Inherits from the IMessenger3 interface (and therefore inherits all of the properties and methods of IMessenger3, IMessenger2, and IMessenger) and adds a method for starting conversations programmatically.
Note Because IMessengerAdvanced includes all of the properties and methods available in the Messenger class, it is the interface used most often with UCMA.
Specialized Messenger class interfaces The following Messenger class interfaces provide specialized interfaces to access contacts, contact groups, and active IM conversations: N
IMessengerContactAdvanced interface Represents a contact in Office Communicator and allows you to work with contact information (that is, displayed name and phone number) and presence information for that contact programmatically.
N
IMessengerContacts interface Provides access to the contacts list in Office Communicator 2007 R2 by letting you iterate through the contact list as well as remove contacts from the contact list. Contacts are added to the contact list by using the IMessengerAdvanced interface.
N
IMessengerGroup interface Provides programmatic access to an individual contact group defined in Office Communicator 2007 R2, including enabling you to change the name of the group and to manage contacts within that group programmatically.
N
IMessengerGroups interface Provides access to the collection of contact groups in Office Communicator as a collection of IMessengerGroup by enabling you to access the collection of groups, retrieve an individual group (that is, as an instance of IMessengerGroup), and remove a group from the collection. Groups are added to Office Communicator by using the IMessengerAdvanced interface.
N
IMessengerConversationWndAdvanced interface Provides methods and properties for working with an active conversation in Office Communicator, including the ability to send IM text and read the IM conversation history.
Note The conversations are multimodal, so IMessengerConversationWndAdvanced applies to all conversation modalities (that is, IM, voice, and video).
The MessengerPriv Class Like the Messenger class, the MessengerPriv class represents the instance of Office Communicator 2007 R2 running on the local computer. However, when using the
Chapter 2
Microsoft Unified Communications APIs Foundation
27
MessengerPriv class, your method calls suppress any Office Communicator UI and performs each action silently. The MessengerPriv class supports a single interface, IMessengerPrivate, which provides the ability to add contacts to the signed-in user’s contact list without showing the Office Communicator Add Contact dialog box.
Unified Communications Client API The Unified Communications Client (UCC) API is a comprehensive client-side API that provides connectivity and access to the functionality of Office Communications Server. It’s the API that is used to build Office Communicator, and it is a SIP-based application framework for building and deploying real-time communications client applications against Office Communications Server 2007. In addition to the standard features (such as IM, voice calling, video chatting, contact managing, and presence tracking), this framework allows the application to provide users with telephony integration, conferencing, encrypted A/V calls, and the publication and subscription of custom presence information and other application-specific data. The flexible publication and subscription framework makes the application framework appealing for custom applications that do not need to expose the full functionality of Office Communicator 2007 or use the SIP protocol in innovative ways to provide new features.
Scenarios This API enables you to create the following types of applications: N
N
N
A custom Office Communications Server client Similar to Office Communicator, but customized for your specific application. For example: O
Call center client
O
Conference-only client
Integrated real-time communications into line-of-business applications For example, UC client functionality can be deeply integrated into CAD/CAM applications, financial trading applications, and other line-of-business applications. You can create custom presence categories and clients that use these custom categories in innovative ways. For example: O
A collaboration client that synchronizes three-dimensional views between remote medical imaging applications.
O
Enhance user attributes with GPS information.
A standalone Office Communications Server–enabled application Unlike the Office Communicator Automation API, the UCC API enables you to redistribute the UCC dynamic link libraries (DLLs) with your application. This enables you to ship your application as a standalone Office Communications Server–enabled application.
28
Part I
Understanding Unified Communications
Considerations Before embarking on building your solution using the UCC API, it is advisable to consider the intended purpose of this API. The API is intended to be used for client-side, single endpoint Windows applications. Office Communicator 2007 was built using the UCC API, and consequently the UCC API provides access to all of the functionality available in Office Communicator 2007 and more. The UCC API is a low-level client-side API. It does not include any of the business logic that is embedded in Office Communicator. Developers must build their own business logic and user experience. To embed presence and real-time communications into existing applications, therefore, it is advisable to use the Office Communicator Automation API instead of the UCC API. The Office Communicator Automation API requires less code to embed a UC experience into an existing application. For more information, see the “Office Communicator Automation API” section earlier in this chapter.
Application Architecture The UCC API encapsulates two major functional features in real-time communications: signaling and media handling. Signaling is responsible for setting up and tearing down multimedia communication sessions, such as voice and video calls over an Internet Protocol (IP) network in this context. Media refers to the various real-time modes of communication: audio, video, IM, or e-mail. The encapsulation of signaling provides a higher-level object abstraction of the following protocols: N
SIP
N
Centralized Conferencing Control Protocol (CCCP)
N
Computer Supported Telephony Applications (CSTA)
The UCC API also provides a set of signaling interfaces for developers interested in working at a lower SIP abstraction level. The encapsulation of media handling provides an object representation of the following protocols: N
Real-Time Transport Protocol (RTP)
N
Real-Time Transport Control Protocol (RTCP)
N
Secure Real-Time Transport Protocol (SRTP)
N
Interactive Connectivity Establishment (ICE)
The UCC API design separates the signaling and media handling between an application and the underlying SIP stack and media management over the RTP stack. Figure 2-6 illustrates the UCC API application architecture stack.
Chapter 2
Microsoft Unified Communications APIs Foundation
29
Unified Communications Client API Instant Messaging
Audio & Video
Telephony
Generic Modalities
Conference Control
Presence
Contacts & Groups
Generic Data
Communication Modalities
Publish/Subscribe Infrastructure
Conferencing
Media Codecs (RTP, RTCP)
State Notifications
Signaling
Encryption (SRTP)
Session Initiation Protocol (SIP)
NAT/FW Traversal (ICE)
Conferencing Protocol (CCCP)
Telephony Integration (CSTA)
FIGURE 2-6 UCC API architecture.
The SIP stack handles signaling following the standard SIP. It is responsible for carrying out all low-level SIP operations, such as sending a session request, dispatching and receiving provisional responses, and accepting, forwarding, or rejecting an invitation. These operations are necessary for establishing communications and conference sessions in which participants can communicate and collaborate with each other. The media stack (that is, Media Manager) is responsible for the low-level media management functions, including establishing communication channels to transmit audio, video, or other application data between endpoints. The UCC API exposes a set of COM-based APIs encapsulating the low-level functionalities and provides applications with SIP and media functionalities in object-oriented programming patterns. With the UCC API, developers can create unified multimodal communication applications, including IM, voice calling (computer-to-computer, computer-to-phone, and phoneto-phone), video chatting, application sharing, and conferencing. It also works with Office Communications Server 2007 and other SIP registrar or proxy servers to manage presence information, and it facilitates communications among communication parties.
The UCC API Object Model UCC API objects can be grouped logically into the following feature-based categories: N
Platform objects
The entry point to all other UCC API functionalities.
N
Endpoint objects The object representation of a user in real-time communications and collaborations.
30
Part I
Understanding Unified Communications
N
Session objects Encapsulation of signaling and collaboration sessions, including IM, A/V, application-sharing, and conference.
N
Publication and Subscription objects Encapsulation of the general framework for publishing and subscribing to data or information.
N
Device Management objects Encapsulation of the management functionalities for local devices to render media.
N
Media Connectivity objects Encapsulation of the management functionality for enabling media transmission across firewalls.
Figure 2-7 illustrates a diagram of the UCC API object model. Unified Communications Client API Architecture Platform
Device Manager
Endpoint
Session
Media Connectivity
Publication
Media Connectivity Server
Subscription
Category Instance
Media Device
Instant Messaging Audio/ Video
Participant
Presence State
Application
Participant Endpoint
Group
Conference
Media Channel
Contact
FIGURE 2-7 The UCC API object model.
The Platform object corresponds to the UCC API application framework. It is the starting point for such an application to access API functionalities, including the following: N
Enabling an endpoint When you enable an endpoint, you are registering a user with Office Communications Server. An enabled endpoint means a user who is logged on to the UC network successfully.
Chapter 2
Microsoft Unified Communications APIs Foundation
31
N
Creating a session to invite other participants and communicate with each other using text messaging, A/V calls, and other communication means No session can be created unless an endpoint is enabled.
N
Publishing, subscribing, or querying category instances A user cannot publish, subscribe, or query category instances unless its endpoint is enabled.
N
Maintaining media connectivity for establishing media channels across firewalls This also requires that the endpoint be enabled.
N
Managing local devices for rendering or capturing media
Figure 2-8 shows the UCC API interfaces. IUccInstantMessagingSession IUccSession IUnknown
Unified Communications AJAX API The UC Asynchronous JavaScript and XML (AJAX) API is an API to the Office Communicator Web Access server. Although it is not Simple Object Access Protocol (SOAP)–based, it is a Web service API for building applications against the Office Communicator Web Access server, which in turn communicates with Office Communications Server 2007 and Office Communications Server 2007 R2. These APIs allow the application to provide users with IM, presence tracking, publication and subscription of custom presence information, and call deflection. These APIs are based on JavaScript, Extensible Markup Language (XML), and the browser’s support for the XMLHTTPRequest API or for the .NET C# System.Net. HttpWebRequest API. The client sends requests to the server in the form of XML payloads, and the server returns XML responses. The UC AJAX API supports only presence, IM, and call control capabilities. It does not offer A/V, Web conferencing, or telephony support.
Scenarios The UC AJAX API enables you to create your own non-Windows and Web-based clients, similar to the Office Communicator Web Access client. The following examples are the types of applications that you can create: N
Mobile/phone clients
N
Web applications that combine information from different Web services into a single user interface (known as a mashup)
N
IM- and presence-enabled Web portals
N
High-touch customer service by means of a personalized Web portal
Considerations Before deciding to build your solution using the UC AJAX API, it is advisable to consider the intended purpose of this API. This API is targeted at building client-side, single-endpoint Web or non-Windows applications. The UC AJAX API makes it possible to build Office Communicator–like applications for users running operating systems that are not Windows and access a subset of the functionalities available in Office Communicator. The UC AJAX API is supported only on Office Communications Server 2007. For Office Communications Server 2007 R2 deployments, customers are required to deploy an Office Communications Server 2007, Office Communicator Web Access Server to use your UC AJAX API–based application. This lack of forward compatibility occurs because the UC AJAX API is being deemphasized in the Office Communications Server 2007 R2 release and will not be supported in future releases.
Chapter 2
Microsoft Unified Communications APIs Foundation
33
Due to the performance aspects, these APIs are not intended for multiendpoint applications that need to scale out. A better choice is the UCMA.
Application Architecture The UC AJAX API architecture consists of XML messages sent over two Hypertext Transfer Protocol Secure (HTTPS) channels to the Office Communicator Web Access servers that are persistent for the duration of the session while the user is logged on. The user logs on to Office Communicator Web Access, which authenticates the user by using integrated Windows authentication (NT LAN Manager [NTLM]), forms-based authentication, or a custom single sign-on method, and then an authentication (Auth) ticket is issued to the user. This Auth ticket must be provided in every request to the server. The server can refresh this Auth ticket anytime during the lifetime of the user session. Therefore, it is important that the application always uses the latest Auth ticket sent by the server. Note that the user is logged on to only Office Communicator Web Access, not Office Communications Server. Office Communicator Web Access connects to the user’s home computer running Office Communications Server once a session is initiated and retrieves the user’s contact list, inband provisioning settings, and so on, which it then sends to the client application. After the user is authenticated, the application must establish two secure channels (HTTPS) to Office Communicator Web Access. The XMLHTTPRequest browser API is used to establish these communication channels with the server. One channel is used to issue requests to the server. This is referred to as the command channel. The client application uses the command channel to send commands to the server. It is recommended to batch requests before issuing the command to the server. When a command is sent to Office Communicator Web Access, the server immediately responds to acknowledge whether the request was received successfully or whether an error occurred. The servicing of the client request is performed by the server asynchronously. This response is sent by the server by using another communication channel. Figure 2-9 illustrates the UC AJAX API communications architecture. HTTP(S) XML Command Channel https://cwaserver/cwa/MainCommandHandler.ashx Send , Receive Data Channel
Application uses 2 HTTPS connections
https://cwaserver/cwa/AsyncDataChannel.aspx Open Connection, Receive FIGURE 2-9 The UC AJAX API communications architecture.
For the server to be able to push events to the client application (for example, responses to requests sent over the command channel), the client must create a long-held HTTPS connection with the server named the data channel. Anytime Office Communicator Web
34
Part I
Understanding Unified Communications
Access has an event for the user, it sends it immediately on the data channel without the client application having to request it explicitly. The server holds this connection open for up to 35 seconds. If there are no events for the client application, the server dynamically requests the client to delay the next open GET call on the data channel. This mechanism (referred to as Comet) makes it possible for the server to push events to a Web client. All of the APIs are defined as an XML schema. When the client application logs on the user, the user is signed in to Office Communicator Web Access only. After the user is logged on, the user can create multiple sessions. Each session represents an endpoint registered with Office Communications Server. At this point, user presence is made known to Office Communications Server by means of the server running Office Communicator Web Access. Because Office Communicator Web Access does not keep user state, it transforms SIP traffic from Office Communications Server into XML payloads that are sent to the Web clients. The client must cache any information that Office Communicator Web Access returns (for example, contact list, in-band provisioning settings, and roaming user settings). All caching must be performed on the client side.
XML Model When communicating with Office Communicator Web Access, the client application uses the following URLs where refers to the base URL of the server running Internet Information Services (IIS). The Logon channel is used to sign in the user. Depending on the type of authentication used, this URL is slightly different. After the user is signed, this channel is no longer needed. The Command and Data channels persist for the duration of the session. Each session begins with the XML request, cwaRequests, that contains the initiateSession element and ends with another XML request, cwaRequests, that contains the terminateSession element. Every request and response occurs within a session. Logon channel: N
UC AJAX APIs are defined as XML elements. These XML elements are organized into the following categories: N
cwaRequests This element defines the type of requests a Web client application can submit to the Office Communicator Web Access server on the Command channel.
N
cwaResponses This element defines the response that Office Communicator Web Access returns immediately after receiving a request. The server returns only whether the request was accepted or rejected and why it was rejected.
N
cwaEvents This element defines the type of events the application can expect to receive from Office Communicator Web Access. These events are the results from the request sent to the server. Because the result is returned asynchronously to the application, there needs to be a way to match the event to the request. This is done by matching the event ID (eid) with the request ID (rid) of the corresponding cwaRequests element.
cwaRequests Every request to the server is a cwaRequests element of type CwaRequestsType. This complex type consists of a sid attribute of type CwaSessionId (unsigned long) and one or more of the subelements listed in Table 2-1. TABLE 2-1
Subelements for CwaRequestType
Element
Type
Logon
CwaLogonRequestType
initiateSession
CwaInitiateSessionRequestType
terminateSession
CwaRequestBaseType
addGroup
CwaAddGroupRequestType
updateGroup
CwaUpdateGroupRequestType
deleteGroup
CwaDeleteGroupRequestType
addContact
CwaContactRequestType
updateContact
CwaContactRequestType
deleteContact
CwaUriRequestType
acknowledgeSubscriber
CwaUriRequestType
conference
CwaRequestBaseType
updateContainer
CwaUpdateContainerRequestType
publishSelfPresence
CwaPublishSelfPresenceRequestType
subscribePresence
CwaUriListRequestType
unsubscribePresence
CwaUriListRequestType
queryPresence
CwaUriListRequestType
publishRawCategories
CwaPublishRawCategoriesRequestType
Search
CwaSearchRequestType
36
Part I
Understanding Unified Communications
Each of the types listed in Table 2-1 inherits from the base type CwaRequestBaseType. This complex type, CwaRequestBaseType, consists of a single attribute, rid, which is a request ID that is used to uniquely identify every request. The XML schema (xsd) defines this attribute to be of type CwaRequestId (string).
cwaResponses Office Communicator Web Access immediately responds to cwaRequests to indicate the status of the request. These statuses are defined as elements of the cwaResponses element, which is of type CwaResponsesType. The element CwaResponses is composed of the attribute requestProcessed and zero or more of the subelements listed in Table 2-2. TABLE 2-2
Subelements for CwaResponses
Element
Type
requestSucceeded
CwaRequestSucceededType
requestAccepted
CwaRequestAcceptedType
requestFailed
CwaRequestFailedResponseType
requestRejected
CwaRequestFailedResponseType
Error
CwaFailureType
Each of the types listed in Table 2-2 inherits from the base type CwaResponseBaseType, with the exception of the complex type CwaFailureType. This complex type, CwaResponseBaseType, consists of a single attribute, rid, which is the ID of the matching request. The XML schema (xsd) defines new complex types for these subelements.
cwaEvents Office Communicator Web Access returns the results of each cwaRequests item as a cwaEvents element. A cwaEvents element, which is of type CwaEventsType, is transmitted by Office Communicator Web Access on the data channel. The element CwaEvents is composed of the attributes sid, ackId, pollWaitTime, sessionTimeout, and zero or more of the subelements listed in Table 2-3. TABLE 2-3
Subelements for CwaEvents
Element
Type
pollFailed
CwaFailureType
requestSucceeded
CwaRequestSucceededEventType
requestFailed
CwaRequestFailedEventType
requestCancelled
CwaRequestCancelledEventType
contactGroup
CwaContactGroupEventType
Subscribers
CwaSubscribersEventType
Chapter 2
Microsoft Unified Communications APIs Foundation
TABLE 2-3
Subelements for CwaEvents
Element
Type
Conference
CwaConferenceEventType
Containers
CwaContainerListEventType
selfPresence
CwaSelfPresenceEventType
userPresence
CwaUserPresenceEventType
selfRawCategories
CwaSelfRawCategoriesEventType
userRawCategories
CwaUserRawCategoriesEventType
presenceSubscriptionState
CwaPresenceSubscriptionStateEventType
Configuration
CwaConfigurationsEventType
searchResult
CwaSearchResultsEventType
locationProfiles
CwaLocationProfilesEventType
contactGroup
CwaContactGroupEventType
37
Each of the types listed in Table 2-3 inherits from the base type CwaEventBaseType. This complex type, CwaEventBaseType, consists of a single attribute, erid, which is a unique ID of the event. The XML schema (xsd) defines new complex types for these subelements.
Office Communications Server 2007 Speech Server Developer Edition Using Speech Server (2007) APIs, developers can build applications by using managed code, .NET Framework 3.0–based Windows Workflow Foundation Activities, and Web-based standards, such as the World Wide Web Consortium (W3C) specifications for VoiceXML 2.1 or Speech Application Language Tags (SALT) 1.0, as used in Speech Server 2004 and Speech Server 2004 R2. Dialog flows can be implemented by using any of the following techniques: N
.NET Framework 3.0–based Windows Workflow Foundation Speech Dialog Workflow Activities
N
The Speech Server Managed API
N
VoiceXML 2.1
N
SALT 1.0
The Speech Dialog Workflow Activities available with Speech Server (2007) are very elaborate. They can be used to perform a wide variety of activities related to telephone call management, dialog flow, and application logic and structure.
38
Part I
Understanding Unified Communications
In case the Workflow Activities do not suffice, developers can use the lower-level Speech Server Managed API. The Speech Server Managed API covers the following core areas, which are needed to produce speech-enabled telephony applications: N
Speech synthesis When the application prompts the caller for information or simply provides the caller with information, the prompt is handled through the Synthesizer property. This property is a reference to a SpeechSynthesizer instance, which provides capabilities for converting text into speech.
N
Speech recognition When a caller responds to a prompt, the recognition is handled through the SpeechRecognizer property. This property is a reference to a SpeechRecognizer instance, which parses speech by using a set of grammars and by extracting meaningful information.
N
Call handing and control The TelephonySession property provides methods for call control, such as answering or transferring a call.
N
DTMF processing When a caller presses a keypad button (DTMF input), the application processes it by using the DtmfRecognizer property.
N
Application hosting With the IApplicationHost and IHostedSpeechApplication interfaces, Speech Server manages the lifetime of an application instance.
Speech Server (2007) is a VoiceXML Forum–certified platform that supports the W3C VoiceXML 2.1 standard. For more information about the VoiceXML standard, see the W3C site at http://www.w3.org/TR/voicexml20/ and MSDN at http://msdn.microsoft.com/en-us/ library/bb857664.aspx. Speech Server 2004 and Speech Server 2004 R2 support the ASP.NET-based SALT 1.0 standard. Speech Server (2007) still supports running these SALT applications for backward compatibility.
Scenarios Office Communications Server 2007 Speech Server (Speech Server 2007) is the IVR platform that is part of Office Communications Server 2007 and Office Communications Server 2007 R2. The Developer Edition is available as a free download and contains the Speech Server APIs, speech technology tools that are fully integrated into Visual Studio 2005, and a data warehousing solution for processing call log files. The product is licensed as Office Communications Server when it is deployed. Speech Server (2007) supports sophisticated speech technology, such as Conversational Understanding. This technology is suitable for building sophisticated speech-enabled IVR applications that support human interaction with callers. It supports mixed-initiative form filling that lets users control dialog flow by providing all needed information in a single
Chapter 2
Microsoft Unified Communications APIs Foundation
39
utterance or as a sequence of utterances. By using the mixed-initiative style to fill a form (a FormFillingDialog instance), a user can answer multiple questions at once. The application can accept an answer in response to a specific question, but it can also accept and fill a form with extra answers that apply to questions the application has not yet asked. This style enables a nonsequential dialog. Each question-and-answer cycle includes one question and one or more answers. Mixed-initiative dialogs are typically more difficult to design than system-initiative dialogs (in which the system asks a question and expects a single answer), but they provide users with greater flexibility when answering questions. Mixed-initiative dialogs simulate human interaction more closely than system-initiative dialogs and can recognize either DTMF keypad presses or speech input. Speech Server (2007) is the most appropriate API for building complex IVR applications, such as Voice Portal applications that include multislot speech recognition where callers enter multiple items all in one utterance. Of course, Speech Server (2007) also supports simple call routing applications and DTMF menu-driven applications. Speech Server (2007) differs from the UCMA 2.0 Workflow speech capabilities not only in the conversational understanding technology used, but also in its support of different types of IVR and speech technology–specific tools. Speech Server (2007) provides a Conversational Grammar Builder, a Prompt Recording and Editing tool, lexicon tools, and tuning tools, such as tools that detect words in utterances that are outside the grammar. Speech Server supports speech recognition and speech synthesis in five languages: N
English (North America, United Kingdom)
N
American Spanish
N
Canadian French
N
German
Speech Server supports DTMF applications and speech synthesis in nine additional languages: N
Australian English
N
French
N
Castilian Spanish
N
Portuguese (Brazil)
N
Italian
N
Japanese
N
Korean
N
Chinese (Simplified and Traditional)
40
Part I
Understanding Unified Communications
Considerations Before you create an interactive voice response telephony application, consider the following points: N
Complexity of the speech technology For simple speech applications, often the UCMA Workflow API suffices. For more sophisticated speech technology, such as conversational understanding, use Speech Server (2007).
N
Standards support Currently, VoiceXML support is not available on UCMA, so if VoiceXML support is mandatory, Speech Server (2007) provides the functionality.
N
Language support Speech Server supports ASR and TTS in 5 languages, and UCMA supports 12 languages. Depending on your language needs, one or both might be a better fit.
Application Architecture Figure 2-10 illustrates the Speech Server components and the relationships between them as applied to the design stage of application development. This diagram assumes that you have a single computer that is running Visual Studio 2005, Speech Server, and Web server software. The SIP peer represents all possible client endpoints, including IP Private Branch eXchange (IP/PBX) telephony clients, Voice over Internet Protocol (VoIP) gateways, SIP phones and softphones, and Telephony Interface Manager Connector (TIMC). The SIP peer communicates with the application by using SIP for signaling data and RTP for audio data. The developer uses Visual Studio 2005 to create a speech application, choosing one of the following application types: N
Voice Response Workflow Application To create a managed code interactive voice response application, choose this application type from the New Project dialog box.
N
Voice Response Web Application To create a Web-based SALT interactive voice response application, choose this application type from the New Web Site dialog box.
N
VoiceXML Speech Application To create a Web-based VoiceXML application, choose this application type from the New Web Site dialog box.
FIGURE 2-10 Speech Server (2007) components.
PSTN
Telephony clients
TIM
TIMC
IP PBX
VoIP Gateway
SIP Phone
Soft Phone
SIP clients
SIP Peers
TCP
RTP
SIP
SALT Interpreter
VoiceXML Interpreter
DTMF Recognizer
Automatic Speech Recognizer
Speech Synthesis & Prompt Engine
Unified Communications Managed API 1.0
Speech Server Managed API
Dialog Workflow (WF)
ASP.NET
Microsoft Office Communications Server 2007 Speech Server
HTTP
Deploy
.etl
Visual Studio 2005
SQL Server Reporting Services
Speech Server (2007) MOM Pack
Operations Manager
Prompts, Grammars, and VoiceXML or SALT Web Applications
Web Server
Deploy
Speech Server (2007) SDK
SQL
Tuning and Reporting Server
Chapter 2 Microsoft Unified Communications APIs Foundation
41
42
Part I
Understanding Unified Communications
Application Components Following the Web model for which they are designed, SALT voice response applications and VoiceXML applications are deployed to the Web server. However, because the code that drives a managed code assembly from one state to the next is located on the computer running Speech Server, the assembly must be deployed to the computer running Speech Server itself. After deploying the application, the developer tests it with a connected SIP peer or simulator. The principal application components depicted in Figure 2-10 are described in the next two sections. ASP.NET Components
The ASP.NET run time hosts IVR applications in any of four types:
N
Speech Server Managed API Runs the assembly that contains the code that is used by the managed code IVR application. The Speech Server Managed API is the lowestlevel API. It includes the signaling stack (UCMA 1.0) and provides access to speech and media resources.
N
Dialog Workflow Run Time For a Dialog Workflow–based application, the Dialog Workflow run time executes dialog workflow activities. The Dialog Workflow activities are based on the .NET Framework 3.0 Windows Workflow Foundation.
N
VoiceXML Interpreter For a VoiceXML speech application, the VoiceXML interpreter is responsible for loading, parsing, and running VoiceXML code, which is stored on the Web server.
N
SALT Interpreter For a Voice Response Web application, the SALT interpreter manages dialog flow with the caller and controls telephone calls as it interprets SALT code, which is stored on the Web server.
Web Server Components A Web server running IIS 6.0 or IIS 7.0 is an integral part of a complete Speech Server deployment. IIS is included with Windows Server 2003, Microsoft Windows XP Professional SP2, and Windows Vista. However, you must install IIS explicitly the first time it is used with Speech Server. N
Grammars A grammar file contains a structured list of words and phrases that the Speech Server API parses for the Speech Engine Services (SES) speech recognition engine. Grammars are specific to applications developed for Speech Server.
N
Prompts A prompt database is an application-specific repository of prerecorded sound files used by the SES speech output engines. To improve prompt quality and therefore the quality of the speech output, consider hiring a professional to record the prompts for the database.
Chapter 2
Microsoft Unified Communications APIs Foundation
43
N
VoiceXML Code Developer-written VoiceXML code for the Web-based voice response application.
N
SALT + JScript + HTML Code Developer-written SALT, JScript, and Hypertext Markup Language (HTML) code for the Web-based voice response application.
Object Model A simplified Speech Server API object model is shown in Figure 2-11. At the top of the hierarchy is a SpeechSequentialWorkflowActivity object, which has an ApplicationHost property (as well as others not shown in the illustration), which in turn has a TelephonySession property. Three of the properties on the TelephonySession object are DtmfRecognizer, SpeechRecognizer, and Synthesizer. These properties are references to instances of the DtmfRecognizer, SpeechRecognizer, and Synthesizer classes, respectively. An application can use these TelephonySession properties to access the members of these classes. Each of the two Recognizer objects has a Grammars property, which is a collection of Grammar objects that can be used by the Recognizer. Each Grammar object contains one or more rules that a speech recognizer or DTMF recognizer can use to extract semantic meaning from user input. SpeechSequentialWorkflowActivity
ApplicationHost
TelephonySession
DtmfRecognizer
SpeechRecognizer
Grammars
Grammars
Synthesizer
FIGURE 2-11 Simplified Speech Server object model.
Speech Server API The Speech Server API, shown in Figure 2-12, consists of five namespaces that developers can use to create managed-code voice response applications.
Microsoft.SpeechServer namespace Provides low-level control of core speech services, such as creating hosted application containers, creating telephony and conference sessions, manipulating caller information, controlling logging, and controlling recording.
N
Microsoft.SpeechServer.Dialog namespace Provides a number of classes derived from Windows Workflow Foundation activities. Applications can use the classes provided in the Microsoft.SpeechServer.Dialog namespace to do any of the following: O
Perform tasks related to managing phone calls, such as answering a call, disconnecting a call, transferring a call to a third party, and recording a call. These classes are AnswerCallActivity, MakeCallActivity, BlindTransferActivity,
Chapter 2
Microsoft Unified Communications APIs Foundation
45
DeclineCallActivity, DisconnectCallActivity, RecordAudioActivity, RecordMessageActivity, and DetectAnsweringMachineActivity.
N
N
O
Perform tasks related to dialog flow, such as issuing simple prompts, responding to commands or requests for help, asking a question and receiving an answer, specifying how silences or nonrecognitions are handled, playing a menu of choices from which the user can select one, playing a list of choices through which the user can navigate, validating user input, and responding to system events. These classes are StatementActivity, CommandActivity, HelpCommandActivity, RepeatCommandActivity, QuestionAnswerActivity, GetAndConfirmActivity, ConsecutiveNoInputsSpeechEventActivity, ConsecutiveNoRecognitionsSpeechEventActivity, ConsecutiveSilencesSpeechEventActivity, MenuActivity, FormFilling DialogActivity, NavigableListActivity, ValidatorActivity, SpeechEventActivity, and SpeechEventsActivity.
O
Support complex application logic with activities for branching, grouping related activities into tasks, and partitioning applications into modules. These classes are GoToActivity, SetTaskStatusActivity, InvokeWorkflowActivity, SpeechSequenceActivity, SpeechCompositeActivity, SpeechSequentialWorkflowActivity, SaltInterpreterActivity, and VoiceXMLInterpreterActivity.
Microsoft.SpeechServer.Recognition namespace Provides a number of classes that can be used in conjunction with grammars to parse user speech and extract semantic information from it. The classes in this namespace can be used to do any of the following: O
Create instances of speech or DTMF recognizers
O
Construct and load grammar objects into a speech or DTMF recognizer
O
Create objects that contain recognized words and phrases as well as recognition results
Microsoft.SpeechServer.Recognition.SrgsGrammar namespace The classes in this namespace provide the ability to create and compile grammars that adhere to the Speech Recognition Grammar Specification (SRGS). Most of the classes in this namespace map directly to SRGS elements, such as item, one-of, rule, and ruleref. Grammars can be created manually using a text editor, programmatically in an application, or dynamically at run time and can be compiled to binary context-free grammar (CFG) files for optimization purposes.
N
Microsoft.SpeechServer.Synthesis namespace The classes in this namespace can be used to create TTS output. The text can take the form of character strings and can include Speech Synthesis Markup Language (SSML) markup, bookmarks, “say as” information, pronunciation cues, and audio output. For speech output, there are a variety of options, such as voice gender, age, speaking rate, culture, and others.
46
Part I
Understanding Unified Communications
Summary The Microsoft UC platform offers several APIs that you can choose among depending on your development needs, whether they are client-side or server-side, Windows-based or non–Windows-based, and so on. This chapter provides a condensed technical overview of each of these APIs to help you decide which API or APIs best suit your application needs. From this starting point, you can refer to the individual API SDK documentation for more in-depth details of every method, event, and property that the API exposes.
Additional Resources N
“Microsoft Office Communications Server 2007 R2 Developer References” (http://technet.microsoft.com/en-us/library/dd425166(Office.13).aspx)
N
Microsoft Unified Communications AJAX SDK download (http://go.microsoft.com/ fwlink/?LinkId=142478)
N
Microsoft Unified Communications Client API SDK download (http://go.microsoft.com/ fwlink/?LinkID=141197)
N
“Office Communicator 2007 and Office Communicator 2007 R2 Automation API Documentation” (http://msdn.microsoft.com/en-us/library/bb758719.aspx)
N
Microsoft Unified Communications Managed API 2.0 SDK (32 bit) download (http://go.microsoft.com/fwlink/?LinkID=140790)
N
Microsoft Unified Communications Managed API 2.0 SDK (64 bit) download (http://go.microsoft.com/fwlink/?LinkID=139195)
N
Microsoft Office Communications Server 2007 Speech Server Developer Edition download (http://go.microsoft.com/fwlink/?LinkID=70208)
Integrating Web Chat Functionality - Microsoft Unified Communications AJAX API Sample (http://www.microsoft.com/downloads/details.aspx?FamilyId=C8C3F7627BE4-4541-9B18-82499DB61293&displaylang=en)
Part II
Office Communicator Automation API After reviewing the APIs that are available in the Microsoft Unified Communications (UC) platform in Part I, “Understanding Unified Communications,” Part II covers the Microsoft Office Communicator Automation API, as shown in the following figure. Your Application
Your Application
Your Application
Office Communicator Automation API Office Communicator 2007 R2 Customizations
UCMA 1.0
UC Workflow API
Unified Communications Managed API 2.0
Office Communications Server 2007 R2
Chapter 3, “Programming a Microsoft Office Communicator Automation API Application,” explains how to use this API. Chapter 4, “Embedding Contextual Collaboration,” covers an example of how to embed contextual collaboration into an application and includes a complete walkthrough of the source code.
47
Chapter 3
Programming a Microsoft Office Communicator Automation API Application This chapter will help you to: N
Sign in and sign out of Microsoft Office Communicator 2007 R2 programmatically and react to sign-in status events.
N
Work with local user and contact information programmatically.
N
Subscribe to presence events for the local user and contacts to display up-to-date presence in applications.
N
Manage the contact list programmatically.
N
Start conversations using instant messaging (IM), audio, and video.
Signing In to and Out of Office Communicator Chapter 2, “Microsoft Unified Communications APIs Foundation,” introduces the Office Communicator Automation API and the classes, interfaces, and events that you can use to automate Office Communicator. In this chapter, you learn how to use this API. When using the Office Communicator Automation API, you can provide Office Communicator features in your application. For your code to automate Office Communicator successfully, you must meet the following conditions: N
Office Communicator is running on the local computer.
N
The local user is signed in to Office Communicator.
Using the Messenger Class The Messenger class encapsulates Office Communicator 2007 R2 running on the local computer and is the main entry point to the API. The Messenger class supports a number of properties, methods, and events for keeping track of the sign-in state of the local user. After installing the Office Communicator 2007 Software Development Kit (SDK) and referencing the Office Communicator Automation API, the first thing you need to do is instantiate the Messenger class, as follows. 49
50
Part II
Office Communicator Automation API Messenger _messenger = new Messenger();
The Messenger class, like all classes in the Office Communicator Automation API, is an unmanaged Component Object Model (COM) class that you access from the Microsoft .NET Framework’s managed code by using COM Interop. This means that you must explicitly release every reference of the Messenger class and other classes instantiated from this API. The reference can be released by calling the System.Runtime.InteropServices.Marshal. ReleaseComObject() method and then setting the reference to NULL, as shown in the following code example. Messenger _messenger = new Messenger(); System.Runtime.InteropServices.Marshal .ReleaseComObject(_messenger); _messenger = null;
If you fail to call Marshal.ReleaseComObject() and set the reference to NULL, this results in memory leaks in your application.
Note You must release references in this manner for all references that you create using the Office Communicator Automation API.
Determining Whether Office Communicator Is Running To determine whether Office Communicator is running on the local computer, you can use the HKEY_CURRENT_USER\Software\IM Providers\Communicator registry key. When Office Communicator is running, the UpAndRunning value of that key is set to 2. Use the following code to determine whether Office Communicator is running on the local computer. // OC Automation API class can't be instantiated unless // Office Communicator is running. if (Convert.ToInt32(Microsoft.Win32.Registry.CurrentUser .OpenSubKey("Software").OpenSubKey("IM Providers") .OpenSubKey("Communicator") .GetValue("UpAndRunning", 1)) == 2) { Console.WriteLine("Office Communicator is running."); } else { Console.WriteLine("Office Communicator is *not* running."); }
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
51
Checking Local User Status The Messenger class provides the MyStatus property to determine the sign-in status of the local user. Office Communicator displays the status of the user to the right of their name, as shown in Figure 3-1.
Status
FIGURE 3-1 The status of the user in Office Communicator.
MyStatus returns a value from the MISTATUS enumeration. The values defined in MISTATUS are shown in Table 3-1. TABLE 3-1
MISTATUS Enumeration Values
Element
Value
MISTATUS_UNKNOWN
0x0000
MISTATUS_OFFLINE
0x0001
MISTATUS_ONLINE
0x0002
MISTATUS_INVISIBLE
0x0006
MISTATUS_BUSY
0x000A
MISTATUS_BE_RIGHT_BACK
0x000E
MISTATUS_IDLE
0x0012
MISTATUS_AWAY
0x0022
MISTATUS_ON_THE_PHONE
0x0032
MISTATUS_OUT_TO_LUNCH
0x0042
MISTATUS_IN_A_MEETING
0x0052
MISTATUS_OUT_OF_OFFICE
0x0062
MISTATUS_DO_NOT_DISTURB
0x0072
MISTATUS_IN_A_CONFERENCE
0x0082
MISTATUS_ALLOW_URGENT_INTERRUPTIONS
0x0092
52
Part II
Office Communicator Automation API
TABLE 3-1
MISTATUS Enumeration Values
Element
Value
MISTATUS_MAY_BE_AVAILABLE
0x00A2
MISTATUS_CUSTOM
0x00B2
MISTATUS_LOCAL_FINDING_SERVER
0x0100
MISTATUS_LOCAL_CONNECTING_TO_SERVER
0x0200
MISTATUS_LOCAL_SYNCHRONIZING_WITH_SERVER
0x0300
MISTATUS_LOCAL_DISCONNECTING_FROM_SERVER
0x0400
By using the following code, you can use the MyStatus property to check whether the local user is in any of the online states such as Available, In a Call, or In a Meeting. Messenger _messenger = new Messenger(); // Check if the user is already signed in to // Office Communicator. if ((_messenger.MyStatus & MISTATUS.MISTATUS_ONLINE) == MISTATUS.MISTATUS_ONLINE) { Console.WriteLine("Local user is signed in to Office Communicator"); } else { Console.WriteLine("Local user is *not* signed in to Office Communicator"); }
This code performs a logical bitwise AND of Messenger.MyStatus and the MISTATUS. MISTATUS_ONLINE value. If Messenger.MyStatus returns any of the status values that represent an online state (that is, any value from Table 3-1 other than MISTATUS_UNKNOWN or MISTATUS_OFFLINE), this operation is equal to MISTATUS.MISTATUS_ONLINE.
Signing In to Office Communicator The Messenger class provides methods and events to sign the local user in to and out of Office Communicator.
Messenger.Signin() Method The Messenger.Signin() method signs the local user in to Office Communicator using a given Session Initiation Protocol (SIP) Uniform Resource Identifier (URI) and password. For example, the following code signs in a user with the SIP URI [email protected] and “password” as the password.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
53
Messenger _messenger = new Messenger(); _messenger.Signin(0, "sip:[email protected]", "password");
Messenger.AutoSignin() Method The Messenger.AutoSignin() method signs in the local user based on the credentials cached in Office Communicator. For example, the following code signs in the local user automatically using the last used credentials. Messenger _messenger = new Messenger(); _messenger.AutoSignin();
Messenger.OnSignin Event Signing in to Office Communicator is performed asynchronously. When you call Messenger. Signin() or Messenger.AutoSignin(), you are making a request to Microsoft Office Communications Server 2007 R2 to sign in the local user to Office Communicator. When the local user is signed in successfully, the Messenger class raises the OnSignin event. The following code shows you how to subscribe to the OnSignin event using the DMessengerEvents_ OnSigninEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnSignin += new DMessengerEvents_OnSigninEventHandler( _messenger_OnSignin); … void _messenger_OnSignin(int hr) { if (hr == 0) { Console.WriteLine("OnSignin()"); } }
The Messenger.OnSignin event passes a single parameter, an integer to represent the success of the sign-in, to the corresponding event handler. A value equal to 0 represents a successful sign-in.
Note The Messenger.OnSignin event fires every time the local user signs in either through Office Communicator or the Office Communicator Automation API.
54
Part II
Office Communicator Automation API
Signing Out of Office Communicator The following sections describe the methods and events associated with signing out of Office Communicator.
Messenger.Signout() Method The Messenger.Signout() method signs out the local user from Office Communicator. Use the following code to sign out the local user. Messenger _messenger = new Messenger(); _messenger.Signout();
Messenger.OnSignout Event Similar to signing in, signing out of Office Communicator is done asynchronously. When you call Messenger.Signout(), you are making a request to Office Communications Server 2007 R2 to sign the local user out of Office Communicator. When the local user is actually signed out, the Messenger class raises the OnSignout event. The following code shows you how to subscribe to the OnSignout event using the DMessengerEvents_OnSignoutEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnSignout += new DMessengerEvents_OnSignoutEventHandler( _messenger_OnSignout); … void _messenger_OnSignout() { Console.WriteLine("OnSignout()"); }
Note The Messenger.OnSignout event fires every time the local user signs out either through Office Communicator or the Office Communicator Automation API.
Messenger.AppShutdown Event If the local user shuts down Office Communicator, the Office Communicator Automation API raises the Messenger.OnSignout event, followed by the Messenger.AppShutdown event. The following code shows you how to subscribe to the AppShutdown event using the DMessengerEvents_AppShutdownEventHandler event handler.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
55
Messenger _messenger = new Messenger(); _messenger.OnAppShutdown += new DMessengerEvents_OnAppShutdownEventHandler( _messenger_OnAppShutdown); … void _messenger_OnAppShutdown() { Console.WriteLine("OnAppShutdown()"); }
Putting It All Together Using the concepts from the preceding sections, you can quickly put together code to determine whether Office Communicator is running, as well as the sign-in status of the local user. In this section, you create a console application and use the Messenger class by performing the following steps: 1. Download and install the Office Communicator 2007 SDK. For details, see the “Additional Resources” section later in this chapter. 2. Start Microsoft Visual Studio 2008 and create a new Microsoft Visual C# Windows console application named SignInSignOut. 3. In Solution Explorer, right-click the References node, click Add Reference, and then, from the COM tab, add references to Microsoft Office Communicator 2007 API Type Library. 4. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
This code brings the Office Communicator Automation API and InteropServices namespaces into scope. 5. Add the following static declarations inside the Program class. private static Messenger _messenger; private static bool _signedIn = false;
The _messenger member variable provides an instance of the Messenger class. The _signedIn variable represents the signed-in state of the local user in Office Communicator.
56
Part II
Office Communicator Automation API
6. Add the following method to the Program class. static bool IsCommunicatorRunning() { return Convert.ToInt32( Microsoft.Win32.Registry.CurrentUser .OpenSubKey("Software").OpenSubKey("IM Providers") .OpenSubKey("Communicator") .GetValue("UpAndRunning", 1)) == 2; }
If Office Communicator is running, the IsCommunicatorRunning() method returns True. 7. Add the following code to the Main() method in the Program class. static void Main(string[] args) { // OC Automation API classes can't be instantiated unless // Office Communicator is running. if (IsCommunicatorRunning()) { Console.WriteLine("Office Communicator is running."); _messenger = new Messenger(); _messenger.OnAppShutdown += new DMessengerEvents_OnAppShutdownEventHandler( _messenger_OnAppShutdown); _messenger.OnSignin += new DMessengerEvents_OnSigninEventHandler( _messenger_OnSignin); _messenger.OnSignout += new DMessengerEvents_OnSignoutEventHandler( _messenger_OnSignout); // Check if the user is already signed in to // Office Communicator and sign in if they are not. if ((_messenger.MyStatus & MISTATUS.MISTATUS_ONLINE) == MISTATUS.MISTATUS_ONLINE) { _signedIn = true; Console.WriteLine("Local user is signed in to Office Communicator"); } else { _signedIn = false; Console.WriteLine("Local user is signed in to Office Communicator"); Console.WriteLine("Signing in local user to Office Communicator via AutoSignin()."); _messenger.AutoSignin(); }
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
57
// Sign out of Office Communications Server _messenger.Signout(); Console.WriteLine("\nPress Enter key to exit the application.\n"); Console.ReadLine(); _messenger.OnAppShutdown -= new DMessengerEvents_OnAppShutdownEventHandler( _messenger_OnAppShutdown); _messenger.OnSignin -= new DMessengerEvents_OnSigninEventHandler _messenger_OnSignin); _messenger.OnSignout -= new DMessengerEvents_OnSignoutEventHandler( _messenger_OnSignout); Marshal.ReleaseComObject(_messenger); _messenger = null; } else { Console.WriteLine("Office Communicator is *not* running."); Console.WriteLine("Please start Office Communicator and run the application again."); Console.WriteLine("\nPress Enter key to exit the application."); Console.ReadLine(); } }
In the preceding code, the IsCommunciatorRunning() method checks to see whether Office Communicator is running. If IsCommunicatorRunning() returns True, an instance of the Messenger class is created and event subscriptions are established for the OnSignin, OnSignout, and AppShowdown events. Next, Messenger.MyStatus checks the status of the local user and sets the _signedIn variable. If the local user is not signed in, Messenger. AutoSignin() signs the local user in to Office Communicator. Messenger.Signout() is called to sign out the local user. When the user exits the application, references to the Messenger class are released using Marshal.ReleaseComObject(). 8. Add the following code to the Program class to define the event delegates defined in Main(). static void _messenger_OnSignout() { _signedIn = false; Console.WriteLine("OnSignout()"); }
In the preceding code, the _signedIn variable is set to False when the local user is signed out. The variable is set to True when the user signs in. Note that the _signedIn variable does not need to be set when the OnAppShutdown event fires because that event is always preceded by the OnSignout event. 9. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 10. Sign in to and sign out of Office Communicator, noting the effect of these actions in the console application. 11. Close the console application and save your work in Visual Studio. This console application provides the logic to create Office Communicator API classes only when Office Communicator is running and manages a variable to keep track of the current signed-in state of the local user.
Working with Contact Information and Contact Presence With the Office Communicator Automation API, you can display information from Office Communicator for the local user and her or his contacts. This information includes information such as name, phone number, and presence.
Displaying Local User Information The Messenger class has properties and methods to provide programmatic access to information about the local user signed in to Office Communicator. Use these properties to display information about the local user in your applications. The Messenger class also provides events to notify your application of changes to this information so you can keep information up to date in your application.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
59
Messenger.MySigninName Property You can get the sign-in name (or SIP URI) for the local user by using the Messenger. MySigninName property. For example, the following code writes the local user’s sign-in name to the console. Messenger _messenger = new Messenger(); Console.WriteLine("MySigninName: {0}", _messenger.MySigninName);
Messenger.MyFriendlyName Property You can get the friendly name (that is, a name readable by humans) for the local user using the Messenger.MyFriendlyName property. For example, the following code writes the local user’s friendly name to the console. Messenger _messenger = new Messenger(); Console.WriteLine("MyFriendlyName: {0}", _messenger.MyFriendlyName);
Messenger.OnMyFriendlyNameChange Event If the friendly name of the local user changes, the Messenger class raises the OnMyFriendlyNameChange event. The following code shows how to subscribe to the OnMyFriendlyNameChange event by using the DMessengerEvents_OnMyFriendlyNameChangeEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnMyFriendlyNameChange += new DMessengerEvents_ OnMyFriendlyNameChangeEventHandler(_messenger_OnMyFriendlyNameChange); … static void _messenger_OnMyFriendlyNameChange(int hr, string bstrPrevFriendlyName) { if (hr == 0) { Console.WriteLine( "OnMyFriendlyNameChange: PrevFriendlyName: {0} MyFriendlyName: {1}", bstrPrevFriendlyName, _messenger.MyFriendlyName); } }
When the OnMyFriendlyNameChange event is raised, an integer is passed that represents the success of the change (that is, a value equal to 0 represents success) and the previous friendly name of the local user is passed as a string.
60
Part II
Office Communicator Automation API
Messenger.get_MyPhoneNumber Property You can get the phone numbers for the local user using the Messenger.get_MyPhoneNumber property. An enumeration named MPHONE_TYPE is used to specify which phone number is returned by the method. For example, the following code writes the local user’s phone numbers to the console. Messenger _messenger = new Messenger(); Console.WriteLine("\tMyPhoneNumber (Work): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_WORK)); Console.WriteLine("\tMyPhoneNumber (Mobile): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_MOBILE)); Console.WriteLine("\tMyPhoneNumber (Home): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_HOME)); Console.WriteLine("\tMyPhoneNumber (Other): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_CUSTOM));
Messenger.OnMyPhoneChange Event If the phone number of the local user changes, the Messenger class raises the OnMyPhoneChange event. The following code shows how to subscribe to the OnMyPhoneChange event by using the DMessengerEvents_ OnMyPhoneChangeEventHandler event handler. _messenger = new Messenger(); _messenger.OnMyPhoneChange += new DMessengerEvents_OnMyPhoneChangeEventHandler( _messenger_OnMyPhoneChange); … static void _messenger_OnMyPhoneChange(MPHONE_TYPE PhoneType, string bstrNumber) { Console.WriteLine("OnMyPhoneChange: PhoneType: {0} Number: {1}", PhoneType.ToString(), bstrNumber); }
When the OnMyPhoneChange event is raised, a MPHONE_TYPE value is passed to specify which phone number changed (that is, work, mobile, home, or other) along with the new phone number as a string.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
61
Putting It All Together Using the concepts in this section, you can display local user information in your application and keep that information up to date easily by using the events raised by the Messenger class. In this section, you create a console application and use the Messenger class to display local user information and react to changes in that information. 1. Start Visual Studio (if it’s not already running) and create a new Visual C# Windows console application named LocalUserInfo. 2. In Solution Explorer, right-click the References node, click Add References, and then, from the COM tab, add a reference to Microsoft Office Communicator 2007 API Type Library. 3. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
The preceding code brings the Office Communicator Automation API and InteropServices namespaces into scope. 4. Add the following declaration inside the Program class. private static Messenger _messenger;
5. Add the following code to the Main() method in the Program class. static void Main(string[] args) { _messenger = new Messenger(); _messenger.OnMyFriendlyNameChange += new DMessengerEvents_OnMyFriendlyNameChangeEventHandler( _messenger_OnMyFriendlyNameChange); _messenger.OnMyPhoneChange += new DMessengerEvents_OnMyPhoneChangeEventHandler( _messenger_OnMyPhoneChange); Console.WriteLine("Local User Info for {0}:", _messenger.MyFriendlyName); Console.WriteLine("\tMySigninName: {0}", _messenger.MySigninName); Console.WriteLine("\tMyPhoneNumber (Work): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_WORK)); Console.WriteLine("\tMyPhoneNumber (Mobile): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_MOBILE)); Console.WriteLine("\tMyPhoneNumber (Home): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_HOME));
62
Part II
Office Communicator Automation API Console.WriteLine("\tMyPhoneNumber (Other): {0}", _messenger.get_MyPhoneNumber( MPHONE_TYPE.MPHONE_TYPE_CUSTOM)); Console.WriteLine("\nPress Enter key to exit the application.\n"); Console.ReadLine(); _messenger.OnMyFriendlyNameChange -= new DMessengerEvents_OnMyFriendlyNameChangeEventHandler( _messenger_OnMyFriendlyNameChange); _messenger.OnMyPhoneChange -= new DMessengerEvents_OnMyPhoneChangeEventHandler( _messenger_OnMyPhoneChange); Marshal.ReleaseComObject(_messenger); _messenger = null; }
The preceding code uses the Messenger class to write the friendly name, sign-in name, and phone numbers for the local user. 6. Add the following code to Program.cs to define the event delegates for the local user information events. static void _messenger_OnMyPhoneChange(MPHONE_TYPE PhoneType, string bstrNumber) { Console.WriteLine("OnMyPhoneChange: PhoneType: {0} Number: {1}", PhoneType.ToString(), bstrNumber); } static void _messenger_OnMyFriendlyNameChange(int hr, string bstrPrevFriendlyName) { if (hr == 0) { Console.WriteLine("OnMyFriendlyNameChange: PrevFriendlyName: {0} MyFriendlyName: {1}", bstrPrevFriendlyName, _messenger.MyFriendlyName); } }
7. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 8. Change the phone numbers listed in Office Communicator to see the result of the event being raised in the console application. 9. Close the console application and save your work in Visual Studio. This console application provides the logic to display local user information and present updated information in the event of changes.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
63
Retrieving Contact Information The IMessengerContactAdvanced class represents a contact in Office Communicator and enables you to display contact information, such as the contact’s name and phone numbers.
Messenger.GetContact() Method To obtain an instance of IMessengerContactAdvanced, you pass the SIP URI of the contact to the Messenger.GetContact() method. For example, the following code gets an instance of IMessengerContactAdvanced for the contact with the SIP URI [email protected]. Messenger _messenger = new Messenger(); IMessengerContactAdvanced contact = (IMessengerContactAdvanced) _messenger.GetContact("sip:[email protected]", _messenger.MyServiceId);
In the preceding code, note the use of the Messenger.MyServiceID property. This property provides a globally unique identifier of the Office Communications Server 2007 R2 instance that the local user has signed in to.
Getting Contact Information The IMessengerContactAdvanced class supports properties to display the friendly name, sign-in name, and phone numbers of a contact in a way that resembles the Messenger class support of similar properties for the local user. For example, the following code displays contact information for the contact [email protected]. Messenger _messenger = new Messenger(); IMessengerContactAdvanced contact = (IMessengerContactAdvanced) _messenger.GetContact("sip:[email protected]", _messenger.MyServiceId); if (contact != null) { Console.WriteLine("Contact Info for {0}:", contact.FriendlyName); Console.WriteLine("\tSigninName: {0}", contact.SigninName); try { Console.WriteLine("\tPhoneNumber (Work): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_WORK)); Console.WriteLine("\tPhoneNumber (Mobile): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_MOBILE));
Note Office Communications Server 2007 R2 and Office Communicator 2007 R2 support the implementation of a new presence model named Enhanced Presence. With Enhanced Presence, the local user has access to contact information based on the level of access granted by the contact. For example, if the local user has been granted team-level access by a contact, the local user has access to the work and mobile phone numbers, but not the home phone number of the contact. When calling IMessengerContactAdvanced.get_PhoneNumber on a contact, the method throws an exception when trying to access the home phone number. Therefore, it is important to wrap such calls in a try/catch block. For more information about the different levels of access defined by Office Communicator, see Office Communicator Help at http://go.microsoft.com/ fwlink/?linkid=143210.
Messenger.OnContactFriendlyNameChange Event If the friendly name of a contact in the local user’s contact list changes, the Messenger class raises the Messenger.OnContactFriendlyNameChange event. The following code shows how to subscribe to this event by using the DMessengerEvents_OnContactFriendlyNameChangeEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnContactFriendlyNameChange += new DMessengerEvents_OnContactFriendlyNameChangeEventHandler( _messenger_OnContactFriendlyNameChange); … static void _messenger_OnContactFriendlyNameChange(int hr, object pMContact, string bstrPrevFriendlyName) { IMessengerContactAdvanced contact = (IMessengerContactAdvanced)pMContact;
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
65
if (hr == 0) { Console.WriteLine("OnMyFriendlyNameChange for {0}: \n\tPrevFriendlyName: {1} FriendlyName: {2}", contact.FriendlyName, bstrPrevFriendlyName, contact.FriendlyName); } }
When the OnContactFriendlyNameChange event is raised, an instance of IMessengerContactAdvanced is passed as an object in the pMContact parameter. By casting this parameter to be of type IMessengerContactAdvanced, you provide access to a reference of the contact.
Note The Messenger.OnContactFriendlyNameChange event fires only for contacts in the local user’s contact list in Office Communicator.
Messenger.OnContactPhoneChange Event If the phone number for a contact in the local user’s contact list changes, the Messenger class raises the Messenger.OnContactPhoneChange event. The following code shows how to subscribe to this event using the DMessengerEvents_OnContactPhoneChangeEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnContactPhoneChange += new DMessengerEvents_OnContactPhoneChangeEventHandler( _messenger_OnContactPhoneChange); … static void _messenger_OnContactPhoneChange(int hr, object pContact, MPHONE_TYPE PhoneType, string bstrNumber) { IMessengerContactAdvanced contact = (IMessengerContactAdvanced)pContact; if (hr == 0) { Console.WriteLine("OnContactPhoneChange for {0}: \n\tPhoneType: {1} Number: {2}", contact.FriendlyName, PhoneType.ToString(), bstrNumber); } }
66
Part II
Office Communicator Automation API
When the OnContactPhoneChange event is raised, an instance of IMessengerContactAdvanced is passed as an object in the pContact parameter. By casting this parameter to be of type IMessengerContactAdvanced, you provide access to a reference of the contact.
Note The Messenger.OnContactPhoneChange event fires only for contacts in the local users contact list in Office Communicator. Furthermore, the Messenger.OnContactPhoneChange event fires only for phone numbers that the local user has access to by using Enhanced Presence. For example, the Messenger.OnContactPhoneChange event fires for changes to the work and mobile numbers if the local user has been granted team-level access by the contact and does not fire when the contact changes her or his home phone number.
Putting It All Together Using the concepts in this section, you can add contact information to your application and keep that information up to date easily by using the events raised by the Messenger class. In this section, you create a console application and use the Messenger class and its IMessengerContactAdvanced interface to display contact information by performing the following steps: 1. Start Visual Studio (if it’s not already running) and create a new Visual C# Windows console application named ContactInfo. 2. In Solution Explorer, right-click the References node, click Add References, and then, from the COM tab, add a reference to Microsoft Office Communicator 2007 API Type Library. 3. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
4. Add the following declaration inside the Program class. private static Messenger _messenger;
The _messenger member variable provides an instance of the Messenger class. 5. Add the following code to the Main() method in the Program class. static void Main(string[] args) { _messenger = new Messenger(); _messenger.OnContactFriendlyNameChange += new DMessengerEvents_OnContactFriendlyNameChangeEventHandler( _messenger_OnContactFriendlyNameChange); _messenger.OnContactPhoneChange += new DMessengerEvents_OnContactPhoneChangeEventHandler( _messenger_OnContactPhoneChange);
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
67
IMessengerContactAdvanced contact = (IMessengerContactAdvanced)_messenger.GetContact( "sip:[email protected]", _messenger.MyServiceId); if (contact != null) { Console.WriteLine("Contact Info for {0}:", contact.FriendlyName); Console.WriteLine("\tSigninName: {0}", contact.SigninName); try { Console.WriteLine("\tPhoneNumber (Work): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_WORK)); Console.WriteLine("\tPhoneNumber (Mobile): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_MOBILE)); Console.WriteLine("\tPhoneNumber (Home): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_HOME)); Console.WriteLine("\tPhoneNumber (Other): {0}", contact.get_PhoneNumber( MPHONE_TYPE.MPHONE_TYPE_CUSTOM)); } catch { //Your exception logic goes here. } } Console.WriteLine("\nPress Enter key to exit the application.\n"); Console.ReadLine(); _messenger.OnContactFriendlyNameChange -= new DMessengerEvents_OnContactFriendlyNameChangeEventHandler( _messenger_OnContactFriendlyNameChange); _messenger.OnContactPhoneChange -= new DMessengerEvents_OnContactPhoneChangeEventHandler( _messenger_OnContactPhoneChange); Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(_contact); _contact = null; }
The preceding code uses Messenger.GetContact() to get an instance of the IMessengerContactAdvanced interface of a contact with the SIP URI [email protected]. Then, the code writes contact information to the console. Also, the Messenger class is used to subscribe to event changes to the contact’s information.
68
Part II
Office Communicator Automation API
6. Add the following code to Program.cs to define the event delegates for the contact information. static void _messenger_OnContactPhoneChange(int hr, object pContact, MPHONE_TYPE PhoneType, string bstrNumber) { if (hr == 0) { Console.WriteLine("OnContactPhoneChange for {0}: \n\tPhoneType: {1} Number: {2}", contact.FriendlyName, PhoneType.ToString(), bstrNumber); } } static void _messenger_OnContactFriendlyNameChange(int hr, object pMContact, string bstrPrevFriendlyName) { IMessengerContactAdvanced contact = (IMessengerContactAdvanced)pMContact; if (hr == 0) { Console.WriteLine("OnMyFriendlyNameChange for {0}: \n\tPrevFriendlyName: {1} FriendlyName: {2}", contact.FriendlyName, bstrPrevFriendlyName, contact.FriendlyName); } }
In each delegate implementation, note that an instance of IMessengerContactAdvanced is passed as an object in the pMContact parameter. Cast this pMContact to IMessengerContactAdvanced to use that instance. 7. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 8. Change the Work phone number for a contact in the local user’s contact list. 9. Close the console application and save your work in Visual Studio. This console application provides the logic to display contact information for a contact and changes to contact information for any contact in the local user’s contact list. By running the preceding code, you display the information for the contact with the sign-in name adamb@ uc.contoso.com and display changes to the friendly name or phone number for any contact in the user’s contact list.
Publishing and Subscribing to Contact Presence The IMessengerContactAdvanced interface provides access to presence information for both the local user and his or her contacts. The Messenger class provides events that are raised when presence information changes, which enables your application to subscribe to presence
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
69
for the local user and his or her contacts. By using both of these features of the API, you can display up-to-date presence information in your application. When using Office Communicator, you can see elements of presence for the local user, as shown in Figure 3-2.
Availability
Status Presence Note
FIGURE 3-2 The user’s presence information in Office Communicator.
Similarly, you can see presence information for the user’s contacts in the contact list within Office Communicator.
IMessengerContactAdvanced.PresenceProperties Property Use the IMessengerContactAdvanced.PresenceProperties property to access presence information for any contact, including the local user. For example, the following code gets the presence information for the local user and then writes the status to the console. IMessengerContactAdvanced _contact = (IMessengerContactAdvanced) _messenger.GetContact(_messenger.MySigninName, _messenger.MyServiceId); object[] presenceProps = object[])_contact.PresenceProperties; // Sign In Status. Console.WriteLine("Local User Status: {0}", (MISTATUS)presenceProps[ (int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]);
IMessengerContactAdvanced.PresenceProperties returns an array of objects that holds each of the presence values for a contact. The array can be indexed by using the PRESENCE_ PROPERTY enumeration. Table 3-2 explains each PRESENCE_PROPERTY enumeration value.
70
Part II
Office Communicator Automation API
TABLE 3-2
PRESENCE_PROPERTY Enumeration Values
Element
Explanation
PRESENCE_PROP_MSTATE
Gives the status of the contact as a value in the enumeration MISTATUS. Read-only.
PRESENCE_PROP_AVAILABILITY
Gives the availability of the contact as an integer. Read/ write for the local user. Read-only for contacts.
PRESENCE_PROP_IS_BLOCKED
Represents whether the contact is blocked by the local user. Boolean value.
PRESENCE_PROP_PRESENCE_NOTE
Presence note as displayed in Office Communicator as a string. Read/write for the local user; read-only for contacts.
PRESENCE_PROP_IS_OOF
Represents whether the contact has set their out of office state. Boolean value. Read-only.
PRESENCE_PROP_TOOL_TIP
Tooltip displayed in Office Communicator for a contact as a string. Read-only.
PRESENCE_PROP_CUSTOM_STATUS_ STRING
Custom status string for the contact as a string. Read-only.
IMessengerContactAdvanced.PresenceProperties returns presence information for any contact, but it returns current presence information only for contacts in the local user’s contact list. If the contact is not in the user’s contact list, calling IMessengerContactAdvanced. PresenceProperties returns presence information that is up to two minutes old. To get up-todate presence information, add the contact to the local user’s contact list. Calls to IMessengerContactAdvanced.PresenceProperties return only presence information based on the level of access granted to the user by the contact. You can use IMessengerContactAdvanced.PresenceProperties to publish presence information for the local user. For example, the following code sets the availability for the signed-in user to available. IMessengerContactAdvanced _localUser = (IMessengerContactAdvanced)_messenger.GetContact( _messenger.MySigninName, _messenger.MyServiceId); // Set the local user to available (3000). object[] _presProps = new object[8]; _presProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY] = 3000; _localUser.PresenceProperties = (object)_presProps;
Note IMessengerContactAdvanced.PresenceProperties can set presence information for the settings that the local user can set from Office Communicator.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
71
Messenger.OnMyStatusChange Event The Messenger class raises the OnMyStatusChange event if any element of the local user’s presence changes. The following code shows how to subscribe to the OnMyStatusChange event by using the DMessengerEvents_OnMyStatusChangeEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnMyStatusChange += new DMessengerEvents_OnMyStatusChangeEventHandler( _messenger_OnMyStatusChange); … static void _messenger_OnMyStatusChange(int hr, MISTATUS mMyStatus) { // Your code to work with presence goes here... }
Note The Messenger.OnMyStatusChange event passes a parameter, mMyStatus, of type MISTATUS when the event is raised. The mMyStatus parameter specifies the presence status of the local user. Because the Messenger.OnMyStatusChange event is raised when any element of the local user’s presence changes (for example, the local user’s presence note), use the IMessengerContactAdvanced.PresenceProperties property rather than mMyStatus because PresenceProperties provides full access to the presence information for a contact. For details, see step 7 in the next “Putting It All Together” section.
Messenger.OnContactStatusChange Event The Messenger class raises the OnContactStatusChange event if any element of presence for a contact in the local user’s contact list changes. The following code shows how to subscribe to the OnContactStatusChange event by using the DMessengerEvents_OnContactStatusChangeEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnContactStatusChange += new DMessengerEvents_OnContactStatusChangeEventHandler( _messenger_OnContactStatusChange); … static void _messenger_OnContactStatusChange(object pMContact, MISTATUS mStatus) { // Your code to work with presence goes here... }
72
Part II
Office Communicator Automation API
Note The MessengerOnContactStatusChange event fires only for contacts in the local user’s contact list.
Tip Like Messenger.OnMyStatusChange, Messenger.OnContactStatusChange passes a parameter mStatus of type MISTATUS when the event is raised. Use the IMessengerContactAdvanced. PresenceProperties property rather than mMyStatus when subscribing to presence information.
Putting It All Together By using the concepts in this section, you can add local user and contact presence information to your application by using IMessengerContactAdvanced and keep that information up to date easily by using the events raised by the Messenger class. In this section, you create a console application, use the Messenger class and IMessengerContactAdvanced interface to display presence information for the local user and a contact, and display changes to presence information for contacts in the local user’s contact list, as follows: 1. Start Visual Studio (if it’s not already running) and create a new Visual C# Windows console application named ContactPresence. 2. In Solution Explorer, right-click the References node, click Add References, and then, from the COM tab, add references to Microsoft Office Communicator 2007 API Type Library. 3. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
4. Add the following declaration inside the Program class. private static Messenger _messenger;
The _messenger member variable provides an instance of the Messenger class. 5. Add the following code to the Main() method in the Program class. static void Main(string[] args) { _messenger = new Messenger(); _messenger.OnContactStatusChange += new DMessengerEvents_OnContactStatusChangeEventHandler( _messenger_OnContactStatusChange); _messenger.OnMyStatusChange += new DMessengerEvents_OnMyStatusChangeEventHandler( _messenger_OnMyStatusChange);
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
73
IMessengerContactAdvanced _localUser = (IMessengerContactAdvanced)_messenger.GetContact( _messenger.MySigninName, _messenger.MyServiceId); if (_localUser != null) { DisplayContactPresence(_localUser); } // Set the local user to Available (3000) in code. object[] _presProps = new object[8]; _presProps[ (int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY] = 3000; _localUser.PresenceProperties = (object)_presProps; IMessengerContactAdvanced _contact = (IMessengerContactAdvanced)_messenger.GetContact( "[email protected]", _messenger.MyServiceId); if (_contact != null) { DisplayContactPresence(_contact); } Console.WriteLine("\nPress Enter key to exit the application.\n"); Console.ReadLine(); _messenger.OnContactStatusChange -= new DMessengerEvents_OnContactStatusChangeEventHandler( _messenger_OnContactStatusChange); _messenger.OnMyStatusChange -= new DMessengerEvents_OnMyStatusChangeEventHandler( _messenger_OnMyStatusChange); Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(_localUser); _localUser = null; Marshal.ReleaseComObject(_contact); _contact = null; }
In the preceding code, the Messenger class is instantiated and used to subscribe to status event changes for the local user (that is, by using the OnMyStatusChange event) and the user’s contacts (that is, by using the OnContactStatusChange event). Next, you use Messenger.GetContact() to get an instance of the local user by using the IMessengerContactAdvanced interface to display presence information. You use the IMessengerContactAdvanced.PresenceProperties property to publish presence for the local user. You call Messenger.GetContact() again to get an instance of a contact by using the IMessengerContactAdvanced interface to display presence information for the contact.
74
Part II
Office Communicator Automation API
6. Add the following code to Program.cs to define the event delegates for the presence information events. static void _messenger_OnMyStatusChange(int hr, MISTATUS mMyStatus) { DisplayContactPresence((IMessengerContactAdvanced) _messenger.GetContact(_messenger.MySigninName, _messenger.MyServiceId)); } static void _messenger_OnContactStatusChange(object pMContact, MISTATUS mStatus) { DisplayContactPresence((IMessengerContactAdvanced) pMContact); }
7. Implement the DisplayContactPresence method in the Program class by using the following code. static void DisplayContactPresence( IMessengerContactAdvanced contact) { object[] _presenceProps = (object[]) contact.PresenceProperties; if (contact.IsSelf) { Console.WriteLine("Local User Presence Info for {0}:", contact.FriendlyName); } else { Console.WriteLine("Contact Presence Info for {0}:", contact.FriendlyName); } // Status. Console.WriteLine("\tStatus: {0}", (MISTATUS) _presenceProps[ (int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]); Console.WriteLine("\tStatus String: {0}", GetStatusString((MISTATUS) _presenceProps[ (int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE])); // Status string if status is set to custom. Console.WriteLine("\tCustom Status String: {0}", _presenceProps[(int) PRESENCE_PROPERTY.PRESENCE_PROP_CUSTOM_STATUS_STRING]); // Presence or User state. Console.WriteLine("\tAvailability: {0}", _presenceProps[ (int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]); Console.WriteLine("\tAvailability String: {0}", GetAvailabilityString((int) _presenceProps[(int) PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]));
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
The preceding code uses the IMessengerContactAdvanced.PresenceProperties property to retrieve the presence information for a contact and local user. 8. Implement the GetAvailabilityString and GetStatusString methods by adding the following code to the Program class. static string GetAvailabilityString(int availability) { switch (availability) { case 3000: return "Available"; case 4500: return "Inactive"; case 6000: return "Busy"; case 7500: return "Busy-Idle"; case 9000: return "Do not disturb"; case 12000: return "Be right back"; case 15000: return "Away"; case 18000: return "Offline"; default: return ""; } } static string GetStatusString(MISTATUS mStatus) { switch (mStatus) { case MISTATUS.MISTATUS_ALLOW_URGENT_INTERRUPTIONS: return "Urgent interruptions only"; case MISTATUS.MISTATUS_AWAY: return "Away"; case MISTATUS.MISTATUS_BE_RIGHT_BACK: return "Be right back";
76
Part II
Office Communicator Automation API case MISTATUS.MISTATUS_BUSY: return "Busy"; case MISTATUS.MISTATUS_DO_NOT_DISTURB: return "Do no disturb"; case MISTATUS.MISTATUS_IDLE: return "Idle"; case MISTATUS.MISTATUS_INVISIBLE: return "Invisible"; case MISTATUS.MISTATUS_IN_A_CONFERENCE: return "In a conference"; case MISTATUS.MISTATUS_IN_A_MEETING: return "In a meeting"; case MISTATUS.MISTATUS_LOCAL_CONNECTING_TO_SERVER: return "Connecting to server"; case MISTATUS.MISTATUS_LOCAL_DISCONNECTING_FROM_SERVER: return "Disconnecting from server"; case MISTATUS.MISTATUS_LOCAL_FINDING_SERVER: return "Finding server"; case MISTATUS.MISTATUS_LOCAL_SYNCHRONIZING_WITH_SERVER: return "Synchronizing with server"; case MISTATUS.MISTATUS_MAY_BE_AVAILABLE: return "Inactive"; case MISTATUS.MISTATUS_OFFLINE: return "Offline"; case MISTATUS.MISTATUS_ONLINE: return "Online"; case MISTATUS.MISTATUS_ON_THE_PHONE: return "In a call"; case MISTATUS.MISTATUS_OUT_OF_OFFICE: return "Out of office"; case MISTATUS.MISTATUS_OUT_TO_LUNCH: return "Out to lunch"; case MISTATUS.MISTATUS_UNKNOWN: return "Unknown"; default: return string.Empty; } }
The preceding code returns the availability and status information of a contact in human-readable form as a string. 9. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 10. Change the presence information for the local user and one of the local user’s contacts. 11. Close the console application and save your work in Visual Studio. This console application provides the logic to display presence information for the local user and her or his contacts. For example, by running the preceding code, you display presence information for the local user and one of her or his contacts and then change the availability for the local user to Online.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
77
Working with the Office Communicator Contact List The IMessengerContacts interface provides access to the user’s contact list in Office Communicator 2007 R2, as well as the ability to remove contacts from the contact list. You use the Messenger class to add contacts to the contact list.
Messenger.MyContacts Property A call to the Messenger.MyContacts property returns an instance of the IMessengerContacts interface. For example, the following code gets an instance of IMessengerContacts by using the Messenger class. _messenger = new Messenger(); IMessengerContacts _contacts = (IMessengerContacts) _messenger.MyContacts;
IMessengerContacts.Item() Method The IMessengerContacts interface provides a collection of IMessengerContactAdvanced instances, one for each contact in the user’s contact list. You use the IMessengerContacts.Count property and IMessengerContacts.Item() to iterate though this collection, as illustrated in the following code. _messenger = new Messenger(); IMessengerContacts _contacts = (IMessengerContacts)_messenger.MyContacts; IMessengerContactAdvanced _contact; Console.WriteLine("Contact list for the local user:"); for (int i = 0; i < _contacts.Count; i++) { _contact = (IMessengerContactAdvanced) _contacts.Item(i); Console.WriteLine("\t{0}", _contact.FriendlyName); }
Messenger.AddContact() Method Use the Messenger.AddContact() method to add contacts to the local user’s contact list. For example, the following code adds a contact with the SIP URI [email protected]. _messenger = new Messenger(); // Adding a contact to the contact list. _messenger.AddContact(0, "[email protected]");
78
Part II
Office Communicator Automation API
Note In the call to the Messenger.AddContact() method, the first parameter, hwndParent, is reserved and always set to 0.
IMessengerContacts.Remove() Method Contacts are removed from the user’s contact list by using the IMessengerContacts.Remove() method. For example, the following code removes a contact with the SIP URI [email protected]. com from the contact list. Messenger _messenger = new Messenger(); IMessengerContacts _contacts = (IMessengerContacts)_messenger.MyContacts; // Removing a contact from the contact list. _contacts.Remove((IMessengerContactAdvanced) _messenger.GetContact("[email protected]", _messenger.MyServiceId));
Messenger.OnContactListAdd Event IMessengerContacts is a static collection representing the local user’s contact list when Messenger.MyContacts is called. If contacts are added or removed from the contact list, the IMessengerContacts instance is not updated. To be notified when a contact is added to the user’s contact list, you use the Messenger.OnContactListAdd event to receive change notifications. For example, the following code subscribes to this event by using the DMessengerEvents_OnContactListAddEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnContactListAdd += new DMessengerEvents_OnContactListAddEventHandler( _messenger_OnContactListAdd); … static void _messenger_OnContactListAdd(int hr, object pMContact) { IMessengerContactAdvanced _contact = (IMessengerContactAdvanced)pMContact; if (hr == 0) { Console.WriteLine("OnContactListAdd: {0}", _contact.FriendlyName); } }
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
79
MessengerOnContactListRemove Event To be notified when a contact is removed from the user’s contact list, you use the Messenger. OnContactListRemove event. For example, the following code uses the DMessengerEvents_ OnContactListRemoveEventHandler to subscribe this event. Messenger _messenger = new Messenger(); _messenger.OnContactListRemove += new DMessengerEvents_OnContactListRemoveEventHandler( _messenger_OnContactListRemove); … static void _messenger_OnContactListRemove(int hr, object pMContact) { IMessengerContactAdvanced _contact = (IMessengerContactAdvanced) pMContact; if (hr == 0) { Console.WriteLine("OnContactListRemove: {0}", _contact.FriendlyName); } }
Putting It All Together Using the concepts in this section, you can display the contact list, add and remove contacts from that list, and subscribe to events raised by changes to the contact list easily by using the Messenger class and the IMessengerContacts interface. In this section, you create a console application that displays the contact list and changes to the contact list. The code also adds and removes contacts from the contact list to raise these events. 1. Start Visual Studio (if it’s not already running) and create a new Visual C# Windows console application named ContactList. 2. In Solution Explorer, right-click the References node, click Add References, and then, from the COM tab, add references to Microsoft Office Communicator 2007 API Type Library. 3. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
4. Add the following declaration inside the Program class. private static Messenger _messenger;
The _messenger member variable provides an instance of the Messenger class.
80
Part II
Office Communicator Automation API
5. Add the following code to the Main() method in the Program class. static void Main(string[] args) { _messenger = new Messenger(); _messenger.OnContactListAdd += new DMessengerEvents_OnContactListAddEventHandler( _messenger_OnContactListAdd); _messenger.OnContactListRemove += new DMessengerEvents_OnContactListRemoveEventHandler( _messenger_OnContactListRemove); IMessengerContacts contacts = (IMessengerContacts) _messenger.MyContacts; IMessengerContactAdvanced contact = null; Console.WriteLine("Contact list for the local user:"); for (int i = 0; i < contacts.Count; i++) { contact = (IMessengerContactAdvanced) contacts.Item(i); Console.WriteLine("\t{0}", contact.FriendlyName); } // Adding a contact to the contact list. _messenger.AddContact(0, "[email protected]"); // Removing a contact from the contact list. contacts.Remove((IMessengerContactAdvanced) _messenger.GetContact("[email protected]", _messenger.MyServiceId)); Console.WriteLine("\nPress Enter key to exit the application.\n"); Console.ReadLine(); _messenger.OnContactListAdd += new DMessengerEvents_OnContactListAddEventHandler( _messenger_OnContactListAdd); _messenger.OnContactListRemove += new DMessengerEvents_OnContactListRemoveEventHandler( _messenger_OnContactListRemove); Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(contacts); contacts = null; Marshal.ReleaseComObject(contact); contact = null; }
The preceding code uses IMessengerContacts to write the friendly name of each contact in the contact list to the console. You use Messenger.AddContact() to add a contact to the contact list and IMessengerContacts.Remove() to remove a contact.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
81
6. Add the following code to the Program class to write the friendly name of the contact when the contact is added or removed. static void _messenger_OnContactListRemove(int hr, object pMContact) { IMessengerContactAdvanced contact = (IMessengerContactAdvanced) pMContact; if (hr == 0) { Console.WriteLine("OnContactListRemove: {0}", contact.FriendlyName); } } static void _messenger_OnContactListAdd(int hr, object pMContact) { IMessengerContactAdvanced contact = (IMessengerContactAdvanced)pMContact; if (hr == 0) { Console.WriteLine("OnContactListAdd: {0}", contact.FriendlyName); } }
7. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 8. Verify that the contact list for the local user is written to the console and the contacts specified are added and removed from the contact list. 9. Close the console application and save your work in Visual Studio. This console application provides the logic to display the contact list and show the results of adding and removing contacts from the contact list.
Starting Conversations By using the Office Communicator Automation API, you can start conversations on behalf of the local user. Conversation modalities can include IM, voice, and video.
Using the IMessengerAdvanced Interface As described in Chapter 2, “Microsoft Unified Communications APIs Foundation,” IMessengerAdvanced is an interface implemented by the Messenger class.
82
Part II
Office Communicator Automation API
To get a reference to IMessengerAdvanced, you need to create an instance of the Messenger class and cast it to IMessengerAdvanced as shown in the following code. Messenger _messenger = new Messenger(); IMessengerAdvanced _messengerAdv = (IMessengerAdvanced)_messenger;
IMessengerAdvanced, like all classes and interfaces in the API, is an unmanaged COM type that you access in managed code by using COM Interop. This means that you must release each reference to the IMessengerAdvanced interface explicitly. You release the reference by calling the System.Runtime.InteropServices.Marshal.ReleaseComObject() method and setting the reference to NULL, as shown in the following code. Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(_messengerAdv); _messengerAdv = null;
If you fail to call Marshal.ReleaseComObject() and set the reference to NULL, your application does not release resources allocated by the API and results in memory leaks.
Note This manner of releasing references applies to all references created by using the Office Communicator Automation API.
IMessengerAdvanced.StartConversation() Method The IMessengerAdvanced interface provides the StartConversation() method for creating conversations with one or more contacts using a specific modality. For example, the following code starts an audio conference with the contacts specified in the sipUris array and sets the conversation window title to “My Conversation.” // An object array of SIP URIs strings for the participants // in the conversation. object[] sipUris = new object[] { "[email protected]", "[email protected]" }; _messengerAdv.StartConversation( // The conversation modality (audio in this case). CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO, // List of participants. sipUris, // Not supported. null, // The conversation window title as as string. "My Audio Conversation", // Not supported. Specify "1". "1", // Not supported. Specify NULL null);
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
83
Figure 3-3 shows the results of this code, an audio conference.
FIGURE 3-3 An audio conference started with StartConversation().
The sipUris variable is an object array that specifies the SIP URIs of the participants. By passing a single SIP URI in the array, you create a conversation with the contact corresponding to that SIP URI. By passing multiple SIP URIs, you start a conference with all of the contacts specified. The conversation modality is specified by using the CONVERSATION_TYPE enumeration. Table 3-3 provides an explanation of the values supported in CONVERSATION_TYPE. TABLE 3-3
CONVERSATION_TYPE Enumeration Values
Value
Explanation
CONVERSATION_TYPE_IM
Specifies IM communication
CONVERSATION_TYPE_PHONE
Specifies a phone call by using telephone URIs
CONVERSATION_TYPE_LIVEMEETING
Not supported
CONVERSATION_TYPE_AUDIO
Specifies a phone call by using Voice over Internet Protocol (VoIP), Public Switched Telephone Network (PSTN), or both
CONVERSATION_TYPE_VIDEO
Specifies a video conversation
CONVERSATION_TYPE_PSTN
Specifies a phone call by using PSTN
Putting It All Together By using IMessengerAdvanced.StartConversation(), you can start conversations easily on behalf of the local user. In this section, you create a console application that creates an audio conference programmatically. 1. Start Visual Studio (if it’s not already running) and create a new Visual C# Windows console application named StartConversation. 2. In Solution Explorer, right-click the References node, click Add References, and then, from the COM tab, add references to Microsoft Office Communicator 2007 API Type Library. 3. Open Program.cs and add the following using statements. using CommunicatorAPI; using System.Runtime.InteropServices;
84
Part II
Office Communicator Automation API
4. Add the following declarations inside the Program class. private static Messenger _messenger; private static IMessengerAdvanced _messengerAdv;
The _messenger member variable provides an instance of the Messenger class and _messengerAdv provides a reference to the IMessengerAdvanced interface. 5. Add the following code to the Main() method in the Program class. static void Main(string[] args) { _messenger = new Messenger(); _messengerAdv = (IMessengerAdvanced)_messenger; // An object array of SIP URIs strings for the participants // in the conversation. object[] sipUris = new object[] { "[email protected]", "[email protected]" }; _messengerAdv.StartConversation( // The conversation modality (audio in this case). CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO, // The participants. sipUris, // Not supported. null, // The conversation window title as as string. "My Audio Conversation", // Not supported. Pass "1". "1", // Not supported. null); Console.WriteLine("Press Enter key to exit the application."); Console.ReadLine(); Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(_messengerAdv); _messengerAdv = null; }
6. The previous code creates an instance of IMessengerAdvanced and calls StartConversation() to create an audio conference with the contacts specified. 7. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. Note that the audio conference started with the contacts specified. 8. Close the console application and save your work in Visual Studio.
Chapter 3
Programming a Microsoft Office Communicator Automation API Application
85
This console application provides the basic logic for using the IMessengerAdvanced. StartConversation() method to start a conversation. For example, Figure 3-4 shows the results of running this code.
FIGURE 3-4 A conversation started with IMessengerAdvanced.StartConversation().
Summary This chapter explains the Office Communicator Automation API classes, interfaces, and events that you use to automate Office Communicator. By using this API, you can sign the local user in to and out of Office Communicator, display contact information, publish and subscribe to presence information, work with the contact list, and start conversations programmatically.
Additional Resources N
Microsoft Communicator 2007 SDK (http://go.microsoft.com/fwlink/?linkid=143206)
COM Interoperation with .NET Overview (http://go.microsoft.com/fwlink/?linkid=143208)
N
Office Communicator 2007: Enhanced Presence Model White Paper (http://go.microsoft.com/ fwlink/?linkid=143209)
N
Office Communicator Help (http://go.microsoft.com/fwlink/?linkid=143210)
N
Communicator 2007 and Communicator 2007 R2 Automation API Documentation (http://go.microsoft.com/fwlink/?LinkID=126311)
Chapter 4
Embedding Contextual Collaboration This chapter will help you to: Implement the end-to-end contextual collaboration scenario by building a sample application that:
N
O
Displays an application-specific contact list with presence.
O
Starts application-specific conversations.
O
Accepts application-specific conversations in your application.
Introduction to Contextual Collaboration In Chapter 2, “Microsoft Unified Communications APIs Foundation,” we discussed the scenarios that the Microsoft Office Communicator Automation application programming interface (API) enables, including the following: N
Embedding presence with application-specific contact lists Using the API to build contact lists specific to your application and showing Office Communicator presence for those contacts.
N
Enhancing communications Adding instant messaging (IM), audio, and video communications directly in your application to allow your users to communicate and collaborate directly from your application.
N
Driving application context-specific communications Using the API to integrate data from your application into the conversations that your application starts to provide application-specific context for the conversation.
In this chapter, you learn how to implement these scenarios in a sample application. Implemented together, these scenarios are often called contextual collaboration.
Microsoft Office Outlook 2007 and Office Communicator 2007 R2 Integration Chris Mayo Technical Evangelist This article looks at the integration of Microsoft Office Communicator 2007 R2 with Office Outlook 2007 as an example of the communication features you can build into an end-toend contextual collaboration solution with the Office Communicator Automation API. When Office Communicator 2007 R2 is installed on a computer with Outlook 2007, Outlook 2007 automatically provides new integrated communication features. 87
88
Part II
Office Communicator Automation API
Figure 4-1 shows an e-mail from Adam Barr to Chris. Notice how the presence of every contact is displayed on the From:, To:, and Cc: lines (in this case, it’s just Adam). This is an example of custom contact list integration. The contacts displayed on the From:, To:, and Cc: lines do not need to be added to Chris’s Office Communicator contact list.
FIGURE 4-1 E-mail in Outlook 2007 with integrated Office Communicator presence.
Right-click the presence icon to display a context menu that is similar to what you see in Office Communicator 2007 R2, as shown in Figure 4-1. This context menu, as well as the IM and Call menu items on the Message tab of the ribbon, can be used to communicate with contacts in this e-mail thread using IM or an audio call. For example, selecting the Call menu item sends Adam an invitation to an audio call with the subject of the call set to the subject of the e-mail (in this case, “Change in Contoso Project Design”). The IM and Call menu items are examples of providing custom communication features in an application. When Adam accepts the call, he receives a hyperlink in the IM portion of the conversation that allows him to retrieve the context of the call (in this case, the e-mail about the design change). Clicking that hyperlink opens the e-mail, as shown in Figure 4-2. This hyperlink supplies context to the conversation (why Chris called Adam) and provides an application-specific way for Adam to view that context (opening the e-mail).
Chapter 4
Embedding Contextual Collaboration
FIGURE 4-2 An active audio call started from Outlook 2007 using e-mail as context.
89
90
Part II
Office Communicator Automation API
This immediately improves the communication experience for users of Outlook 2007. Outlook 2007 users can use presence to determine how to communicate with other contacts and start conversations directly from Outlook 2007. In addition, application context integrated into those conversations allows both parties to start the conversation with the same information. In this example, this process allows Adam to know immediately why Chris is calling.
Scenario The contextual collaboration scenario defined previously can be implemented in any client application using the Office Communicator Automation API. In this chapter, we implement the contextual collaboration feature using a sample scenario to illustrate this point. For example, in a retail enterprise, employees in one store often call employees in other stores to check the availability of an item for a customer. To confirm the accuracy of the inter-store inventory system, which is refreshed only every 24 hours, employees call the target store to make sure the item is available and to ask the store to hold that item for the customer before directing the customer to drive to the other store. If both the calling employee and the called employee are running an application with integrated contextual collaboration features, the communication experience can be more efficient. For the employee checking on the inventory, the application can place the call and specify the item of interest within the communication context. When the other employee receives the call, the application can use the context to look up the inventory of the item and display information to help expedite the communication.
Business Value Implementing the Office Communicator Automation API contextual collaboration scenario adds business value to any client application by increasing ease of communication and associated productivity for information workers. Communication becomes more convenient and more focused when it is seamlessly integrated into the information workers’ typical workflow. Communication is also more efficient because all participants in the conversation share the same context within the conversation.
Chapter 4
Embedding Contextual Collaboration
91
Choice of Technology The Office Communicator Automation API is a great solution for the contextual collaboration scenario for the following reasons: N
Developer productivity Using the Office Communicator Automation API to take advantage of the functionality in Office Communicator 2007 R2 is much faster than building a real-time communications solution from scratch.
N
Proven solution The Office Communicator Automation API is already in use, providing contextual collaboration features in Outlook 2007 as well as other Microsoft products.
N
Ease of use Users already using Office Communicator 2007 R2 are familiar with the user interface when integrated in your application.
However, keep in mind that when using the Office Communicator Automation API, your application works in tandem with Office Communicator 2007 R2 by automating it. If you need to integrate communication features directly into your client application (such as hosting the video stream in your application user interface) or you don’t want to require Office Communicator to be deployed with your application, you need to use one of the other API options discussed in Chapter 2.
Test Environment To develop and test this solution, you need the following: N
Microsoft Office Communications Server 2007 R2, deployed as described in Chapter 9, “Preparing the UC Development Environment.”
N
Two domain accounts, including an account to develop the solution and an account to test the solution, configured for Office Communications Server 2007 R2 and able to sign in to Office Communicator as detailed in Chapter 9.
N
A development environment that meets the Office Communicator Automation API requirements, as specified in the “Office Communicator 2007 and Office Communicator 2007 R2 Automation API” documentation at http://go.microsoft.com/fwlink/ ?LinkID=126311 in the section titled “Getting Started Using Office Communicator Automation API.”
92
Part II
Office Communicator Automation API
Overall Code Structure This section walks through the steps required to build a contextual collaboration solution using the Office Communicator Automation API and Microsoft Visual Studio 2008. This application provides a solution for the inventory request scenario described earlier in this chapter by doing the following: N
Displaying application-specific contact lists for employees to call other stores to make inventory requests
N
Launching application-specific conversations directly from the application
N
Accepting application-specific conversations in the application and displaying the context of the application
Displaying Application-Specific Contact Lists When building a contextual collaboration solution, you want to display application-specific contact lists populated with contacts particular to the data displayed in your application. For example, you may want to display the presence of employees who are working in a store. You can use the Office Communicator Automation API to display application-specific contact lists and contact presence. For most projects, embedding the same presence icon and context menu that you see in Office Communicator 2007 R2 directly into your application is the best option because Office Communicator users are already familiar with this interface. The easiest way to integrate Office Communicator 2007 R2 contact presence information is to use one of the various presence control samples provided by the Office Communicator Automation API team. For example, the WPF Presence Controls for Microsoft Office Communicator 2007—Microsoft Office Communicator 2007 SDK Sample (http://go.microsoft .com/fwlink/?linkid=143214) provides Windows Presentation Foundation (WPF) presence controls with full source code.
Displaying User Presence with MyPersona If you want to show the presence of the local user and a custom contact list, you can use the WPF Presence Controls sample to create a WPF application such as the one shown in Figure 4-3. This application uses the MyPersona control to show the presence of the local user and the PersonaList control to show a custom contact list. The PersonaList control is made up of Persona controls, which are used to show the presence of a single contact.
Chapter 4
Embedding Contextual Collaboration
93
MyPersona Control PersonaList Control
Persona Control FIGURE 4-3 Showing presence with the MyPersona, PersonaList, and Persona controls.
The MyPersona control automatically shows the presence for the local user using the Office Communicator API. The Persona and PersonaList controls need a specific SIP URI of a contact to show the presence of that contact. For example, the following Microsoft Extensible Application Markup Language (XAML) code defines a PersonaList control named personaList1.
The following code populates personaList1 with the contacts Adam, Renee, and James. // Create a list of contacts specific to your application. // Note: They don’t have to be contacts in the // local user’s contact list. List sipUris = new List() { "[email protected]", "[email protected]", "[email protected]" }; // Add the list of contacts to the SipUris property // to populate the control. personaList1.SipUris = sipUris;
Displaying Application-Specific Context Menus with PersonaList When you right-click a contact, the Persona control displays a context menu similar to the context menu displayed by Office Communicator, as shown in Figure 4-4. Note that the context menu also includes a custom communication menu item named Inventory Request. The Persona control supports creating custom menu items for application-specific communication features.
94
Part II
Office Communicator Automation API
FIGURE 4-4 The Persona control showing a contact’s context menu.
The custom context menu item is added to a PersonaList control, personaList1, by using the following code. // Create a new menu item for your application specific // communication feature. List customItems = new List(); MenuItem customMenuItem1 = new MenuItem(); customMenuItem1.Header = "Inventory Request"; customMenuItem1.Name = "inventoryRequest"; customItems.Add(customMenuItem1); personaList1.CustomMenuItemList = customItems; personaList1.CustomMenuItemClicked += new EventHandler (personaList1_CustomMenuItemClicked); } void personaList1_CustomMenuItemClicked(object sender, CustomMenuItemClickedEventArgs e) { // Your code goes here… }
Putting It All Together: Displaying an Application-Specific Contact List with Contact Presence Using the concepts from the preceding sections, you can quickly build an application that displays an application-specific contact list with contact presence. In this section, you create a WPF application with these features using the WPF Presence Controls. 1. Download and install the Office Communicator 2007 Software Development Kit (SDK) located at http://go.microsoft.com/fwlink/?LinkID=85980.
Chapter 4
Embedding Contextual Collaboration
95
2. Download, install, and build the WPF Presence Controls for Microsoft Office Communicator 2007—Microsoft Office Communicator 2007 SDK Sample located at http://go.microsoft.com/fwlink/?linkid=143214. 3. Start Visual Studio 2008, and create a new Microsoft Visual C# Windows WPF application named ContextualCollaboration. 4. Right-click the References node in Solution Explorer, select Add Reference, click the COM tab, and select the Microsoft Office Communicator 2007 API Type Library in the Component Name list box. Click OK. 5. Right-click the References node in Solution Explorer, select Add References, click the Browse tab, and browse to the WPFMOCPresenceControls.dll file in the install directory of the WPF Presence Controls Sample. 6. Open Window1.xaml, click the XAML tab, and then add the bold text that is shown in the following code example.
7. The XAML in the previous code example defines a MyPersona control named myPersona for showing the presence of the signed-in user and a PersonaList control named personaList1 for showing a custom list of contacts. 8. Right-click the design surface of Window1.xaml, and select View Code.
96
Part II
Office Communicator Automation API
9. Add the following lines of code to the existing using statements to bring the Office Communicator, InteropServices, and WPF Presence Controls sample into scope. using CommunicatorAPI; using System.Runtime.InteropServices; using Microsoft.Samples.Office.UnifiedCommunications.PresenceBase;
10. To populate the contact list and add a custom menu item for making application-specific calls about an inventory request, enter the following code in the constructor of Window1. public Window1() { InitializeComponent(); // Create a list of contacts specific to your application. // Note: They don’t have to be contacts in the // local user’s contact list. List sipUris = new List() { "[email protected]", "[email protected]", "[email protected]" }; // Add the list of contacts to the SipUris property // to populate the control. personaList1.SipUris = sipUris; // Create a new menu item for your application specific // communication feature. List customItems = new List(); MenuItem customMenuItem1 = new MenuItem(); customMenuItem1.Header = "Inventory Request"; customMenuItem1.Name = "inventoryRequest"; customItems.Add(customMenuItem1); personaList1.CustomMenuItemList = customItems; personaList1.CustomMenuItemClicked += new EventHandler (personaList1_CustomMenuItemClicked); }
11. Define the event handler in the Window1 class for the Inventory Request custom menu item, as shown in the following code example. This event handler triggers when the user clicks this menu item. void personaList1_CustomMenuItemClicked(object sender, CustomMenuItemClickedEventArgs e) { // Your code goes here... }
Chapter 4
Embedding Contextual Collaboration
97
12. To run the application, click Debug, and then click Start Debugging. 13. Change the presence of the local user in Office Communicator. Log on to Office Communicator on another computer using one of the accounts in the applicationspecific contact list shown previously, and change the presence of the contact in Office Communicator. Note the changes in presence shown in the MyPersona and PersonaList controls. 14. Right-click a contact in the application contact list and click Call, and then click Communicator Call. Note the call being placed between the local user and the contact. 15. Close the ContextualCollaboration application, and save your work in Visual Studio. ContextualCollaboration shows how easy it is to use the WPF Presence Controls sample to embed presence and communication features in an application. Following the steps described previously produces a WPF application, as shown in Figure 4-4. Note the context application-specific menu item named Inventory Request. When the Office Communicator Call menu item is selected, a call is placed with the contact, Adam Barr, as shown here.
Starting Application-Specific Conversations Chapter 3, “Programming a Microsoft Office Communicator Automation API Application,” shows that you can start conversations for the local user programmatically using the IMessengerAdvanced interface. These conversations can include IM, audio, and video modalities. The IMessengerAdvanced interface also provides the ability to send application data in the IM portion of a conversation to create application-specific communication features.
98
Part II
Office Communicator Automation API
IMessengerAdvanced.StartConversation() As discussed in Chapter 3, IMessengerAdvanced provides the StartConversation() method for creating conversations with one or more contacts using a specific modality. For example, the following code starts an audio conference with the contacts specified in the sipUris array and creates a conversation window named “My Audio Conversation.” Messenger _messenger = new Messenger(); IMessengerAdvanced _messengerAdv = (IMessengerAdvanced)_messenger;
// An object array of SIP URIs strings for the participants // in the conversation. object[] sipUris = new object[] { "[email protected]", "[email protected]" }; object obj = _messengerAdv.StartConversation( // The conversation modality (audio in this case). CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO, // The participants. sipUris, // Not supported. null, // The conversation window title as as string. "My Audio Conversation", // Not supported. Specify "1". "1", // Not supported. Specify NULL null);
Figure 4-5 shows the result of this code, which initiates an audio conference using Office Communicator.
FIGURE 4-5 Starting an audio conference using StartConversation().
Notice that StartConversation() returns an object. This object is a window handle (HWND) of the conversation window created. You can use this value to refer to the conversation window after it’s created.
Chapter 4
Embedding Contextual Collaboration
99
Receiving Notification of New Conversations Conversations using the Office Communicator Automation API are started asynchronously. When calling StartConversation(), the conversation invitations are sent to the participants, but the conversation window is not actually created until the first invitation is accepted. When the conversation window is created, the Messenger class raises the OnIMWindowCreated event. This event is raised for all conversations, not just IM conversations as the name implies. The following code shows how to subscribe to the OnIMWindowCreated event using the DMessengerEvents_OnIMWindowCreatedEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnIMWindowCreated += new DMessengerEvents_OnIMWindowCreatedEventHandler( _messenger_OnIMWindowCreated); … void _messenger_OnIMWindowCreated(object pIMWindow) { IMessengerConversationWndAdvanced newConversation = (IMessengerConversationWndAdvanced)pIMWindow; // Code to run when the conversation is created }
The DMessengerEvents_OnIMWindowCreatedEventHandler supports a single parameter, pIMWindow, of the object type. This parameter is an instance of IMessengerConversationWndAdvanced, which represents the conversation created. IMessengerConversationWndAdvanced is an important interface because it provides access to the conversation after it’s created and allows you to manipulate the conversation (such as sending IM to the conversation window). If you want to refer to the conversation window after the OnIMWindowCreated event is raised, store this object instance in a variable in your code.
Receiving Notification of Destroyed Conversations A conversation window is destroyed when the local user closes the conversation window or when all participants leave the conversation. The Messenger class raises the OnIMWindowDestroyed event when the conversation window is destroyed. The following code subscribes to the OnIMWindowDestroyed event through the DMessengerEvents_ OnIMWindowDestroyedEventHandler event handler. Messenger _messenger = new Messenger(); _messenger.OnIMWindowDestroyed -= new DMessengerEvents_OnIMWindowDestroyedEventHandler( _messenger_OnIMWindowDestroyed); …
100
Part II
Office Communicator Automation API static void _messenger_OnIMWindowDestroyed(object pIMWindow) { // Code to run when the conversation is closed... }
Like OnIMWindowCreated, OnIMWindowDestroyed applies to all conversation types, not just IM conversations. A single parameter, pIMWindow, is passed of the object type, which is an instance of IMessengerConversationWndAdvanced. Use this event to release any references you have of the conversation window that has been destroyed.
Note When OnIMWindowDestroyed is raised, the IMessengerConversationWndAdvanced instance passed is no longer a valid reference to the conversation window because the conversation window has been destroyed. If you want to compare the reference passed to OnIMWindowDestroyed to an instance of IMessengerConversationWndAdvanced from the OnIMWindowCreated event, you have to compare the object references by using Object. ReferenceEquals().
Sending IM Text to Conversations The IMessengerConversationWndAdvanced interface provides the SendText() method for sending IM text to a conversation window. You can also use this method to transmit application-specific metadata within the conversation. For example, you can send IM to a newly created conversation window using the following code. static void _messenger_OnIMWindowCreated(object pIMWindow) { IMessengerConversationWndAdvanced newConversation = (IMessengerConversationWndAdvanced)pIMWindow; newConversation.SendText("Some IM text…"); }
SendText() takes a single parameter—the string to be sent to the IM conversation window.
Putting It All Together: Sending Application IM Text to Your Conversation Using the concepts from the preceding sections, you can build an application quickly that starts a conversation and sends some application metadata in the IM portion of the conversation. In this section, you build on the ContextualCollaboration sample code shown earlier in this chapter by performing the following steps to add the communication features: 1. Start Visual Studio 2008 (if it’s not already running) and open the ContextualCollaboration.csproj project.
Chapter 4
Embedding Contextual Collaboration
101
2. Open Window1.xaml.cs and add the following declarations to the Window1 class. private Messenger _messenger; private IMessengerAdvanced _messengerAdv; // Store the HWND of conversation created // with StartConversation(). private int _myConversationHWND; // Store reference to conversation // created with StartConversation(). private IMessengerConversationWndAdvanced _myConversation; // Used to store context to pass in call to SendText(). private string _myContext;
The variable, _myConversationHWND, holds the value returned from the call to IMessengerAdvanced.StartConversation(). The _myConversation variable refers to the conversation window after it is created. Finally, _myContext is used to store the application metadata passed to the conversation after it is created. 3. Add the code to the constructor of the Window1 class to instantiate the variables _messenger and _messengerAdv and subscribe to the conversation events. public Window1() // Constructor for class Window1 { InitializeComponent(); … _messenger = new Messenger(); _messengerAdv = (IMessengerAdvanced)_messenger; _messenger.OnIMWindowCreated += new DMessengerEvents_OnIMWindowCreatedEventHandler( _messenger_OnIMWindowCreated); _messenger.OnIMWindowDestroyed += new DMessengerEvents_OnIMWindowDestroyedEventHandler( _messenger_OnIMWindowDestroyed); }
4. Add the following code to start a conversation when the Inventory Request menu item is clicked. void personaList1_CustomMenuItemClicked(object sender, CustomMenuItemClickedEventArgs e) { _myContext = "12345"; object obj = _messengerAdv.StartConversation( // The conversation modality (audio in this case). CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO, // The participants selected by the local user. e.SipUri,
102
Part II
Office Communicator Automation API // Not supported. null, // The conversation window title as as string. "Inventory Request: Item 12345", // Not supported. Pass "1". "1", // Not supported. null); _myConversationHWND = int.Parse(obj.ToString()); }
Note that the conversation window handle returned from the call to StartConversation() is stored in the _myConversationHWND variable so that the conversation window can later be identified when the event handler, OnIMWindowCreated, is called to notify your application that the conversation window was created. 5. Add the following code to implement OnIMWindowCreated in the Window1 class to send application-specific data, _myContext (defined in step 4), when the conversation window is created. void _messenger_OnIMWindowCreated(object pIMWindow) { IMessengerConversationWndAdvanced newConversation = (IMessengerConversationWndAdvanced) pIMWindow; // Is the conversation the one I started by calling // StartConversation()? if (newConversation.HWND == _myConversationHWND) { // Get a reference to the conversation if needed // later to add/remove contacts, send IM, retreive // history... _myConversation = newConversation; // Send the application data to the IM conversation. _myConversation.SendText(_myContext); } }
In the previous code, if the window handle of the new conversation (provided by the IMessengerConversationWndAdvanced.HWND property) matches the window handle of the conversation created by StartConversation() (stored in the _myConversationHWND variable), the code uses the IMessengerConversationWndAdvanced.SendText() method to send the application data to the IM conversation. 6. Next, add code to implement the OnIMWindowDestroyed event handler in the Window1 class to release the reference to the conversation window when the conversation window is destroyed. void _messenger_OnIMWindowDestroyed(object pIMWindow) { // When the conversation is destroyed, compare window
Chapter 4
Embedding Contextual Collaboration
103
// destroyed to conversation window reference. // Note: When OnIMWindowDestroyed is called the // pIMWindows is no longer a valid COM object. // The only way you can refer it is as an object, // hence the use of ReferenceEquals. if (object.ReferenceEquals((object)_myConversation, pIMWindow)) { Marshal.ReleaseComObject(_myConversation); _myConversation = null; _myConversationHWND = 0; } }
In the previous code, object.ReferenceEquals() is used to compare the window destroyed (passed in the pIMWindow parameter) to the _myConversation variable. If the references match, the conversation window destroyed is the conversation started by your application. Therefore, the reference should be freed using MarshalReleaseComObject(). 7. Add the code in bold to the Window1 class to implement the IDisposable interface so Office Communicator Automation API references can be freed when the window is released. public partial class Window1 : Window, IDisposable
8. Implement the IDisposable interface by adding the following code to the Dispose() method in the Window1 class. public void Dispose() { _messenger.OnIMWindowCreated -= new DMessengerEvents_OnIMWindowCreatedEventHandler( _messenger_OnIMWindowCreated); _messenger.OnIMWindowDestroyed -= new DMessengerEvents_OnIMWindowDestroyedEventHandler( _messenger_OnIMWindowDestroyed); Marshal.ReleaseComObject(_messenger); _messenger = null; Marshal.ReleaseComObject(_messengerAdv); _messengerAdv = null; if (_myConversation != null) { Marshal.ReleaseComObject(_myConversation); _myConversation = null; } }
The previous code uses Marshal.ReleaseComObject() to release references to Office Communicator Automation API classes and interfaces.
104
Part II
Office Communicator Automation API
9. Run the application by clicking Debug on the Visual Studio menu, and then click Start Debugging. 10. Select an online contact in the contact list, and right-click and select the Inventory Request menu item. 11. A conversation is started, and the contents of the _myContext variable are transmitted. 12. Close the ContextualCollaboration application, and save your work in Visual Studio. ContextualCollaboration shows how easy it is to use the Office Communicator Automation API to add an application-specific communication feature to your application. Following the steps in the previous procedure produces a conversation like the one shown in Figure 4-6.
FIGURE 4-6 An application-specific communication feature.
Accepting Application-Specific Conversations The previous section demonstrated how to start a new application-specific conversation. This section demonstrates how to accept incoming conversations and process application-specific data.
Retrieving Text from IM Conversations IMessengerConversationWndAdvanced provides the History property for retrieving the IM conversation from the conversation window. This property can be used to accept application-specific data when a conversation is started. Due to the asynchronous nature of the API, the History method doesn’t return the IM message from a conversation when the
Chapter 4
Embedding Contextual Collaboration
105
conversation window is first created, which is when the OnIMWindowCreated event handler is triggered. Your application must spawn a new thread to poll the History property.
Putting It All Together: Receiving Application-Specific Conversations with IMessengerAdvanced Using the concepts from the preceding section, you can add the ability to accept application-specific conversations from other users. In this section, you build on the ContextualCollaboration example by adding this feature, as follows: 1. Start Visual Studio 2008 (if it’s not already running) and open the ContextualCollaboration.csproj project. 2. Open Window1.xaml to define a list box to show the item number of incoming inventory requests (application-specific conversations) by adding the code in bold text to the following code example. …
3. Open Window1.xaml.cs and add the following declarations to the Window1 class. // Timer used to poll IM history from application specific conversations. private Timer _historyTimer; // Counter to track number of polls for incoming messages. private int _historyTicks;
The _historyTimer variable is used to poll for the IM conversation history using a new thread. The _historyTicks variable is used to stop polling if the IM conversation history is not returned after a reasonable amount of time has passed. 4. From the following code example, add the code in bold to the _messenger_ OnIMWindowCreated method. void _messenger_OnIMWindowCreated(object pIMWindow) { IMessengerConversationWndAdvanced newConversation = (IMessengerConversationWndAdvanced) pIMWindow; // Is the conversation the one I started by calling // StartConversation()? if (newConversation.HWND == _myConversationHWND) { … }
106
Part II
Office Communicator Automation API else // incoming new conversation { //When a new conversation is created, start a timer // to poll for History() for one second. _historyTimer = new Timer( new TimerCallback(ConversationHistory_Tick), newConversation, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1) ); } }
In the previous code, if the newly created conversation window was not started by our application (where IMessengerConversationWndAdvanced.HWND does not equal _myConversationHWND), you can assume that this incoming new conversation could be an application-specific conversation sent from another user. A System.Threading. Timer is created and assigned to _historyTimer to poll for IM conversation text. 5. Implement the TimerCallback method inside the Window1 class. private void ConversationHistory_Tick(object state) { IMessengerConversationWndAdvanced conversationWnd = (IMessengerConversationWndAdvanced)state; try { // Check if the conversation has // application specific data. if ((conversationWnd.History != null)) { // Turn off the timer. _historyTimer.Change(Timeout.Infinite, Timeout.Infinite); _historyTimer.Dispose(); DisplayApplicationContext(conversationWnd.History); } else { _historyTicks += 1; // If polling has not found History within // 1 sec, assume it’s not an application // specific conversation and stop polling. if (_historyTicks > 1000) { // Shut down the timer. _historyTimer.Change(Timeout.Infinite, Timeout.Infinite); _historyTimer.Dispose(); } } }
Chapter 4
Embedding Contextual Collaboration
107
catch { // In the event that an exception is thrown trying // to access the convesatoin window, turn off the // timer to stop polling. _historyTimer.Change(Timeout.Infinite, Timeout.Infinite); _historyTimer.Dispose(); } }
In the previous code, the IMessengerConversationWndAdvanced instance from OnIMWindowCreated is passed as state to the callback (in the state parameter). If IMessengerConversationWndAdvanced.History returns a value, Timer is disabled, and History is passed to a method named DisplayApplicationContext to determine whether it actually contains application-specific data. If IMessengerConversatonWndAdvanced. History does not return a value, a counter named _historyTicks is incremented. If _historyTicks is greater than 1,000 (1,000 milliseconds [ms] because the Timer “ticks” every 1 ms), it can be assumed that the conversation was not started by the remote user’s application, and _historyTimer can be disabled and polling stopped. 6. Implement the DisplayApplicationContext method in the Window1 class. private void DisplayApplicationContext(string context) { try { // Process context to identify if the context is of // interest to your application. if (context.Contains("InventoryRequest")) { // When you pull History from a // IMessengerConversationAdvanced, it’s HTML. // Strip off everything so it only contains // the text passed to SendText(). string contextBody = context.Replace(""); int start = contextBody.IndexOf( "", 0); int end = contextBody.IndexOf( "", start) + 19; contextBody = contextBody.Substring(start, end - start); XmlDocument doc = new XmlDocument(); doc.InnerXml = contextBody; string item = doc.DocumentElement.InnerText; Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
In the previous code, the DisplayApplicationContext method takes the contents of the IMessengerConversationWndAdvanced.History property passed to it and checks for application-specific conversations by looking for the InventoryRequest tag in the message string. If application-specific conversation data is found, any formatting is removed and the contents are added to the lbConversations list box.
Testing the Application To test your application, you copy it to another computer running Office Communicator 2007 R2 using the following procedure: 1. Copy the contents of the ContextualCollaboration\Bin\Debug folder to the computer of one of the contacts listed in the application-specific contact list and run ContextualCollaboration.exe. 2. Run the application on the computer where you wrote the application by clicking Debug and then clicking Start Debugging. 3. Select and right-click an online contact in the contact list, and select the Inventory Request menu item. Note that the conversation started on one computer and is received on the other computer, as shown by the item number “12345” displayed in the application. 4. Close the application on both computers, and save your work in Visual Studio. The ContextualCollaboration example shows how easy it is to use the Office Communicator Automation API to transmit metadata to communicate between two or more remote applications. Following the steps described previously produces the results shown in Figure 4-7.
Chapter 4
Embedding Contextual Collaboration
FIGURE 4-7 An application-specific conversation started by Chris and accepted by Adam.
109
110
Part II
Office Communicator Automation API
Summary This chapter defined a contextual collaboration solution that uses the Office Communicator Automation API to automate Office Communicator 2007 R2 so that it sends and receives application-specific messages between remote applications. The Office Communicator Automation API makes it possible to embed the local user’s presence and contact list quickly and provides the ability to initiate and accept conversations to transmit application-specific metadata.
Additional Resources N
Microsoft Unified Communications Managed API 2.0 SDK (32 bit) (http://go.microsoft .com/fwlink/?LinkID=139195)
N
“Unified Communications Managed API 2.0 Core SDK” documentation (http://go.microsoft.com/fwlink/?LinkID=126312)
N
Microsoft Communicator 2007 SDK (http://go.microsoft.com/fwlink/?LinkID=141199)
N
“Communicator 2007 and Communicator 2007 R2 Automation API” documentation (http://go.microsoft.com/fwlink/?LinkID=126311)
N
WPF Presence Controls for Microsoft Office Communicator 2007—Microsoft Office Communicator 2007 SDK Sample (http://go.microsoft.com/fwlink/?linkid=143214)
Part III
Unified Communications Managed API Workflow Part III covers the Unified Communications Managed API (UCMA) Workflow API, as shown in the following figure. The UCMA Workflow API provides specialized Windows Workflow activities to help you quickly build instant messaging and voice-based workflow applications using the visual designer in Visual Studio. Because of the abstraction provided by the UCMA Workflow API, you do not have to work with the more complex underlying UCMA for large portions of your application. Your Application
Your Application
Your Application
Communicator Automation API Office Communicator 2007 R2 Customizations
UCMA 1.0
Unified Communications Workflow API
Unified Communications Managed API 2.0
Office Communications Server 2007 R2
Chapter 5, “Unified Communications Managed API (UCMA) Workflow,” explains the API in detail, and Chapter 6, “Business Process Communication,” walks through an example of creating a business process communications application using UCMA Workflow Activities.
111
Chapter 5
Unified Communications Managed API (UCMA) Workflow This chapter will help you to: N
Understand how the Unified Communications Managed API (UCMA) Workflow Activities provide a way to develop applications that can interact with the user over the phone or instant messaging (IM) channel as new interfaces.
N
Understand how UCMA Workflow enables faster development of applications by providing prepackaged custom activities for common tasks.
N
Understand how UCMA Workflow enables intelligent routing decisions by providing a way to query for presence information.
UCMA Workflow UCMA Workflow consists of a few Workflow Runtime services and a set of custom Workflow Activities that provide Unified Communications (UC) functionality. UCMA Workflow builds on Windows Workflow Foundation, which is part of Microsoft .NET Framework 3.0 and .NET Framework 3.5. Before jumping into the details of this API, it is important to understand how the activities and services relate to the application. Figure 5-1 shows how the UCMA Workflow Runtime services and Workflow Activities are related to each other.
Workflow Runtime UCMA Workflow Runtime Service
Application Host Code
Application Process
FIGURE 5-1 Anatomy of an application using the UCMA Workflow.
113
114
Part III
Unified Communications Managed API Workflow
A UCMA Workflow application consists of workflow components and nonworkflow components. In Figure 5-1, workflow components are depicted by blocks designated as “UCMA Workflow Runtime Service” and “Workflow Runtime.” The nonworkflow component is represented by the block designated as “Application Host Code.” Within the application host code, the UCMA Core is used to handle the connection to Microsoft Office Communications Server 2007 R2. This means that the application provisioning required to run a UCMA Workflow application as a trusted service is the same as the application provisioning required to run a UCMA Core application. (For details about configuring and provisioning a UCMA Workflow application, see Chapter 9, “Preparing the UC Development Environment.”) The UCMA Workflow application must create the Workflow Runtime and add the necessary UCMA Workflow Runtime services. The UCMA Workflow Runtime services are used to pass data from the application host code to the workflow instances running under the Workflow Runtime.
Using Project Templates To use the UCMA Workflow, you must install the UCMA 2.0 Software Development Kit (SDK). (For details on how to install the UCMA 2.0 SDK, see the “Configuring UCMA Core” section in Chapter 9.) This SDK comes with project templates that are specific to the UCMA Workflow and make it easier to get started with developing UCMA Workflow applications. The templates are available for both C# and Microsoft Visual Basic. The following project templates are supported in the UCMA SDK: N
Inbound Sequential Workflow Console Application This project template is the starting point for creating UC-enabled workflow applications that handle incoming phone calls or instant messages.
N
Outbound Sequential Workflow Console Application This project template is the starting point for creating UC-enabled workflow applications that create outgoing phone calls or instant messages.
In both cases, the host process is a console application by default, but you can easily change it to any suitable application host (for example, a Windows service). After installing the UCMA 2.0 SDK, these project templates are available in Microsoft Visual Studio 2008 under the Communications Workflow node in the Project Types pane of the New Project dialog box. This is shown in Figure 5-2.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
115
FIGURE 5-2 New project templates for the Communications Workflow.
The previous example shows the location of a C# project template. The Visual Basic template is located in the same relative location under the Visual Basic node.
Selecting a Workflow Language After you create the new UCMA Workflow project by clicking OK in the New Project dialog box, the Select Language dialog box appears. This dialog box lists all of the language packs installed on the machine. If no language packs are installed, the user cannot create a project using this template. Language packs are required for speech recognition and for playing a message to the user (that is, text-to-speech message).
Using Workflow Designer Visual Studio 2008 supports Workflow Designer to allow the workflow part of a UCMA Workflow application to be constructed by dragging and dropping appropriate activities from the Visual Studio Toolbox. The designer surface also helps you visualize the flow logic of the application. The designer surface is also known as the designer canvas. As shown in Figure 5-3, the toolbox in the left panel lists all of the UCMA Workflow Activities under the Unified Communications Workflow tab. The designer canvas in the right panel is the sequential workflow as generated by the Inbound Sequential Workflow Console Application project template. As with other workflow activities, you can drag UCMA Workflow Activities onto the designer canvas.
116
Part III
Unified Communications Managed API Workflow
FIGURE 5-3 The Unified Communications Workflow Toolbox and designer canvas.
Workflow Runtime Services UCMA Workflow Activities need custom workflow services to interact with the nonworkflow world. These are added to the Workflow Runtime for the UCMA Workflow Activities to execute properly. Two services are included in the UCMA Workflow: CommunicationsWorkflowRuntimeService and TrackingDataWorkflowRuntimeService. CommunicationsWorkflowRuntimeService The Workflow Runtime is the execution environment in which workflow instances execute. The CommunicationsWorkflowRuntimeService is required for UCMA Workflow Activities to execute properly; UCMA Workflow Activities fail to execute and throw exceptions at run time if you do not add this service to the Workflow Runtime. The application uses this service to pass objects (for example, phone calls and IM calls) or data (for example, the language to use) to the workflow. In UCMA, IM connections are also referred to as a call. This service can be added to the Workflow Runtime, as shown in the InitializeWorkflow method of the Program.cs file, which is automatically generated by the project templates. WorkflowRuntime _wRuntime = new WorkflowRuntime(); _wRuntime.AddService(new CommunicationsWorkflowRuntimeService());
Chapter 5
Unified Communications Managed API (UCMA) Workflow
117
This service provides the following functionality: N
Add phone or IM calls to a particular workflow instance. In a typical scenario, the application receives a call. The application creates an instance of a workflow to handle the incoming call or IM by associating the call or IM with a workflow instance, as shown in the following code example. // Create an instance of the workflow class called Workflow1 WorkflowInstance _wInstance = _wRuntime.CreateWorkflow(typeof(Workflow1)); // Get the CommunicationsWorkflowRuntimeService from the Workflow Runtime CommunicationsWorkflowRuntimeService _cWFRService = (CommunicationsWorkflowRuntimeService) _wRuntime.GetService(typeof(CommunicationsWorkflowRuntimeService)); // Pass the call to the CommunicationsWorkflowRuntimeService service and associate it with the workflow instance created _cWFRService.EnqueueCall(_wInstance.InstanceId, call);
N
Retrieve call(s) associated with a particular workflow instance. When the workflow instance executes, the calls associated with the workflow instance can be retrieved by calling either of the following two methods. _cWFRService.DequeueCall(/* specify Workflow Instance ID */);
or _cWFRService.GetWorkflowCalls(/* specify Workflow Instance ID */);
Workflow Instance ID is a property of the Workflow instance. The AcceptCall activity uses the DequeueCall method to accept the call. Custom activities can also use these methods to retrieve the call as needed. As the name suggests, DequeueCall removes the call from the service. However, GetWorkflowCalls does not remove the calls from the service. DequeueCall is useful in cases in which each phone call is handled by a new instance of the workflow instance. For example, in a help desk application, a new instance of the application’s workflow is created for each incoming call to walk the caller through a dialog with the automated system. GetWorkflowCalls is useful in cases in which the application logic might depend on multiple calls being received. For example, the application might need to connect two calls. In this case, you use the GetWorkflowCalls method to get both calls before connecting them. N
The GetWorkFlowCulture and SetWorkFlowCulture methods are used to retrieve or set the language culture of the workflow instance.
118
Part III
Unified Communications Managed API Workflow
Because many UCMA Workflow Activities involve interacting with the user, you are required to specify a language. This language is used to ensure that the correct speech recognition engine is used to recognize user input and that the appropriate synthesis engine is used for voice output. The language of the workflow instance can be set as follows. // Create an instance of the workflow, Workflow1 is the workflow class name WorkflowInstance _wInstance = _wRuntime.CreateWorkflow(typeof(Workflow1)); // Get the CommunicationsWorkflowRuntimeService from the Workflow Runtime CommunicationsWorkflowRuntimeService _cWFRService = (CommunicationsWorkflowRuntimeService) _wRuntime.GetService(typeof(CommunicationsWorkflowRuntimeService)); // Set the workflow instance language _cWFRService.SetWorkflowCulture(_wInstance.InstanceId, new CultureInfo("en-US")); N
The GetEndpoint and SetEndpoint methods are used to retrieve and set (respectively) the endpoint to be used in a workflow instance. The UCMA Workflow Activities OutboundCall and GetPresence require an endpoint (as described in the “Endpoints” section in Chapter 7, “Structure of a UCMA Application”) to execute. An endpoint is associated with a workflow instance in the same way that a call is associated with a workflow instance. The activities in a workflow instance automatically assume the context of the endpoint associated with the workflow. You can set the endpoint that you want the workflow instance to use as follows. // Definition of an endpoint private static ApplicationEndpoint _endpoint; // Create an instance of the workflow class called Workflow1 WorkflowInstance _wInstance = _wRuntime.CreateWorkflow(typeof(Workflow1)); // Get the CommunicationsWorkflowRuntimeService from the Workflow Runtime CommunicationsWorkflowRuntimeService _cWFRService = (CommunicationsWorkflowRuntimeService) _wRuntime.GetService(typeof(CommunicationsWorkflowRuntimeService)); // Specify the endpoint for the workflow instance _cWFRService.SetEndpoint(_wInstance.InstanceId, _endpoint);
TrackingDataWorkflowRuntimeService You use TrackingDataWorkflowRuntimeService to track values from the MainPrompt and RecognitionResult properties of certain activities. It is represented by the TrackingDataWorkflowRuntimeService object of the UCMA Workflow. For example, when the SpeechStatementActivity property, IsDataTrackingEnabled, is set to True, the SpeechStatement activity stores the value of its Main prompt in this service. This data is
Chapter 5
Unified Communications Managed API (UCMA) Workflow
119
stored in the service for the lifetime of the workflow instance in which the activity is running. This service is optional and is applicable only for the following activities: N
SpeechStatementActivity
N
SpeechQuestionAnswerActivity
N
InstantMessagingStatementActivity
N
InstantMessagingQuestionAnswerActivity
This functionality is useful in the cases when the caller has to be transferred to a human operator or agent. This service contains a record of the dialog between the user and the automated system, which can then be sent to the agent to provide context about the caller. This prevents the agent from asking the caller the same questions that the automated system already asked. All of the data for a particular workflow instance is deleted when the workflow instance terminates. You add this service in the InitializeWorkflow method in the Program.cs file. The Program.cs file is generated automatically by the project templates. WorkflowRuntime _wRuntime = new WorkflowRuntime(); _wRuntime.AddService(new TrackingDataWorkflowRuntimeService());
Using the TrackingDataWorkflowRuntimeService, the developer can achieve the following: N
Add property values to track during the lifetime of the workflow instance. The SpeechStatement, SpeechQuestionAnswer, InstantMessagingStatement, and InstantMessagingQuestionAnswer activities automatically add property values to this service when the IsDataTrackingEnabled property on these activities is set to True. The MainPrompt property for all of these activities is tracked. In addition, the RecognitionResult property is tracked for SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswerActivity. Before custom activities can add property values to this service, they must obtain a handle to the service object. In a workflow instance, any object that implements the IServiceProvider interface can access TrackingDataWorkflowRuntimeService. ActivityExecutionContext is an example of such an object. You can access ActivityExecutionContext by overriding the Execute method of SequentialWorkflowActivity. You can retrieve the TrackingDataWorkflowRuntimeService as follows. /// /// Override method of the Sequential Workflow Activity ///
To add new properties to the TrackingDataWorkflowRuntimeService to be tracked, use the AddTrackingData(Guid, ActivityTrackingData) method. The ActivityTrackingData object represents the name of the activity and the value of that property. N
Retrieve data tracked for a particular workflow instance. You can retrieve data that is being tracked by using the GetTrackingData(Guid) method from TrackingDataWorkflowRuntimeService. This returns a collection of type ActivityTrackingData. Each ActivityTrackingData object represents the name of an activity, the name of the property to be tracked for that activity, and the value of that property.
General Activities The two activities in the UCMA Workflow, which are listed in Table 5-1, are important because they define the flow of the work. TABLE 5-1
General UCMA Workflow Activities
Activity
Description
CommunicationsSequenceActivity
An activity that provides infrastructure for most UCMA Workflow Activities to execute. You can use this for scoping and as a container activity.
GotoActivity
An activity that moves the execution of the workflow to the target activity.
CommunicationsSequenceActivity CommunicationsSequenceActivity provides a base container specific for executing most UCMA Workflow Activities. CommunicationsSequenceActivity provides the following benefits: N
Acts as a container for other activities
N
Provides custom views for dialog functionality
N
Enables the use of GotoActivity
N
Provides a call to its child activities to execute
Chapter 5
Unified Communications Managed API (UCMA) Workflow
121
Acting as a Container Activities can be dropped inside a CommunicationsSequenceActivity to take advantage of the functionality defined in CommunicationsSequenceActivity. CommunicationsSequenceActivity is derived from a Windows Workflow Sequence activity. You can expand and collapse this activity. You can collapse this activity to save screen space so that you can work on other areas of the workflow. Providing custom views for dialog functionality CommunicationsSequenceActivity provides two custom views, Commands and CommunicationsEvents, as shown in Figure 5-4. You use these views to enable commands and handle communication events, which are important to implement any useful dialog. For more information about how to use these views, see the “Command Activities,” “Call Control Communications Event Activities,” and “Dialog Communications Event Activities” sections later in this chapter.
FIGURE 5-4 CommunicationsSequenceActivity views.
Note You can also navigate to these views by right-clicking CommunicationsSequenceActivity and selecting View Commands or View CommunicationsEvents.
You can use CommunicationsSequenceActivity to define a scope of CommunicationEvents activities. For example, a CommunicationEvent defined in a CommunicationsSequenceActivity is not visible outside of that scope. For more information about how to use CommunicationsSequenceActivity for scoping communications events, see the “What Are Communication Events?” sidebar later in this chapter. Enabling the use of the Goto activity After a Workflow Runtime executes an activity, that activity cannot be executed again in the same workflow instance. As a result, special logic is required in constructs like the While activity, which requires you to execute the same activity more than once. You achieve this by cloning, which is a Windows Workflow construct. Before executing the activity, a clone of the activity is made and the cloned activity is executed. This preserves the original activity to be executed later (at which point, it is cloned again). For
122
Part III
Unified Communications Managed API Workflow
more information about activity execution context and cloning, see the “Understanding the Activity Execution Context” article at http://msdn.microsoft.com/en-us/library/aa349099.aspx. Because the Goto activity by its nature can cause its target activity to be executed again, the target activity has to be cloned. The CommunicationsSequence activity clones each of its children before executing them. As a result, these activities are available to be executed again. Providing a call to its children activities to execute Because UCMA Workflow Activities perform actions on a call whether it is a phone call or an IM call, CommunicationsSequenceActivity defines the call to be operated on by its children activities. For example, the SpeechStatement activity needs to know which call on which to play the message, and the InstantMessagingStatement activity needs to know which IM session to reply to. Determining which phone or IM call is associated with an activity is accomplished by the CallProvider activity. The AcceptCall activity and the OutboundCall activity expose the CallProvider object as a property. Table 5-2 lists the properties defined by the CallProvider object, which are required to establish a dialog with the user. TABLE 5-2
Properties of the CallProvider object
Property
Description
Call
The call to be used
DtmfRecognizer
The engine used to recognize dual-tone multifrequency (DTMF) input against DTMF grammars for the call
RecognitionConnector
The object to help in media flow during recognition for the call
SpeechRecognizer
The engine to recognize speech or IM input against speech grammars for the call
SynthesisConnector
The object to help in media flow voice synthesis for the call
Synthesizer
The engine to synthesize the voice output for the call
ToneController
The object that identifies the DTMF tones
Binding to a CallProvider property The CallProvider property of CommunicationsSequenceActivity can be linked to the CallProvider property that is exposed by one of the following activities: AcceptCall or OutboundCall. You perform this linking by using ActivityBind so that the value of the property is available only at run time. For information about ActivityBind, see the “Using Dependency Properties” MSDN article at http://msdn.microsoft.com/en-us/library/ ms734499.aspx. This linking ensures that all children activities of CommunicationsSequenceActivity manipulate the call provided by the CallProvider on CommunicationsSequenceActivity. Figure 5-5 demonstrates how a CallProvider property is created and passed on to UCMA Workflow Activities by using CommunicationsSequenceActivity.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
123
FIGURE 5-5 CommunicationsSequenceActivity binding to the CallProvider property of the AcceptCall activity.
The following list describes the activities in Figure 5-5: N
The AcceptCall activity named acceptCallActivity1 creates a CallProvider object that is exposed publicly as a property of the same name.
N
The CallProvider property of the CommunicationsSequenceActivity named communicationsSequenceActivity1 is bound to the CallProvider property of the activity, acceptCallActivity1. This is denoted by the line running from CommunicationsSequenceActivity to the acceptCall activity.
N
At run time, the SpeechStatementActivity named speechStatementActivity1 uses the call associated with its parent CommunicationsSequenceActivity (in this case, communicationsSequenceActivity1). Because the CallProvider property of communicationsSequenceActivity1 is bound to the CallProvider property created by acceptCallActivity1, speechStatementActivity1 plays the message on the same call that was accepted by acceptCallActivity1. Similarly, disconnectCallActivity1 terminates the call accepted by acceptCallActivity1, which it obtained from its parent CommunicationsSequenceActivity.
124
Part III
Unified Communications Managed API Workflow
Using CallProvider to support multiple calls The same concept can be extended to have multiple calls in a workflow, as shown in Figure 5-6. In this example, there are two CommunicationsSequenceActivity activities. The CallProvider property of parentActivity1 is bound to the CallProvider property of acceptCallActivity1 (as shown by the dotted arrow) and the CallProvider property of parentActivity2 is bound to the CallProvider property of outboundCallActivity1 (as shown by the solid arrow). All of the children of parentActivity1 (that is, speechStatementActivity1 and disconnectCallActivity1) perform operations on the call bound to acceptCallActivity1. All of the children of parentActivity2 (that is, speechStatementActivity2 and disconnectCallActivity2) perform operations on the call established by outboundCallActivity1.
FIGURE 5-6 Two CommunicationsSequenceActivity activities binding to different CallProvider properties.
Using CallProvider in nested CommunicationsSequenceActivity The same binding concept can then define which call to use in nested CommunicationsSequence activities. In the workflow shown in Figure 5-7, all of the children of parentActivity2 use the call placed by outboundCallActivity1 even though parentActivity2 is nested inside parentActivity1. This occurs because the CallProvider property of parentActivity2 is bound to the CallProvider property of outboundCallActivity1.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
125
FIGURE 5-7 Binding to different CallProvider properties within nested CommunicationsSequence activities.
To figure out which call is used with a particular activity (that is, Activity A), just search its parent tree to find the first CommunicationsSequenceActivity whose CallProvider property is bound to a CallProvider property of another activity (for example, an AcceptCall activity, an Outbound Call activity, or a custom CallProvider activity). It is possible that a CommunicationsSequenceActivity in a parent tree does not have its CallProvider activity bound to anything. In this case, continue through the tree until you reach a CommunicationsSequenceActivity in the tree that has the CallProvider property set.
The Goto Activity The Goto activity moves the execution to a different activity in the workflow. A good dialog design involves jumps in execution. For example, if the caller wants to return to the beginning of the dialog tree, the dialog execution should move to the start of the application. The Goto activity facilitates such dialog designs. To specify a target for a Goto activity, set the TargetActivityName property of the Goto activity as shown in Figure 5-8. You can open the panel in Figure 5-8 by clicking the … button in
126
Part III
Unified Communications Managed API Workflow
the window of the TargetActivityName property. In the following example, the valid target activities (that is, speechStatementActivity1, sequenceActivity1, and disconnectCallActivity1) are enabled for selection and invalid targets are disabled for selection.
FIGURE 5-8 Valid targets for the TargetActivityName property of Goto.
Call Control Activities Four activities are available to perform call control actions, as shown in Table 5-3. Some of these activities are valid for both phone calls and IM calls, but some are specific only to phone calls. TABLE 5-3
Call Control Activities
Activity
Description
AcceptCall
Accepts the incoming call associated with the workflow instance. This activity accepts both phone calls and IM calls.
DisconnectCall
Disconnects the call specified by the CallProvider property of CommunicationsSequenceActivity to which it belongs. This activity disconnects both phone and IM calls.
OutboundCall
Places an outbound call using the endpoint associated with the workflow instance. This can create either a phone call or an IM call.
BlindTransfer
Transfers the current call to the specified target. The current call is defined by the CallProvider property of CommunicationsSequenceActivity to which the BlindTransfer belongs. This activity can perform a blind transfer on phone calls, but not IM calls.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
127
The AcceptCall Activity The AcceptCall activity accepts either a phone call or an IM call. If the call is not incoming, AcceptCall throws an InvalidOperation exception. The AcceptCall is associated with the workflow instance to which it belongs. The call is retrieved from the CommunicationsWorkflowRuntimeService using the DequeueCall API. The AcceptCall activity also creates a CallProvider object that is exposed as a property. Because an AcceptCall activity can accept one call, one CallProvider object is created for that call. Table 5-4 describes the properties of the AcceptCall activity. TABLE 5-4
Properties of AcceptCallActivity
Property
Description
CallProvider
Exposes an object that wraps other objects needed to support a dialog (for example, Call, SpeechSynthesizer, or SpeechRecognizer). This is available after the AcceptCall activity executes.
ContentIds
A list of ContentIds to be passed to the UCMA as part of accepting the call. You need to set this property before the AcceptCall activity executes.
Headers
Defines Session Initiation Protocol (SIP) headers (referred to as SignalingHeaders) that are passed when accepting the call. You can specify the SignalingHeaders by using this property before the AcceptCall activity executes.
The DisconnectCall Activity The DisconnectCall activity disconnects a phone call or an IM call that is exposed by the CallProvider property of the parent CommunicationsSequenceActivity. If the parent CommunicationsSequenceActivity does not have a value specified for CallProvider, it tries to get it from the grandparent CommunicationsSequenceActivity. It follows the tree upward until it finds a CommunicationsSequenceActivity that has the specified CallProvider value. If the call is already disconnected, DisconnectCall does not throw any exceptions. It is likely that the caller will end the call before the DisconnectCall activity executes. DisconnectCall also cleans up all of the CallProvider objects associated with the call. Table 5-5 lists a property and description of the DisconnectCall activity. TABLE 5-5
Property of DisconnectCallActivity
Property
Description
Headers
Defines SIP headers (that is, SignalingHeaders) passed when disconnecting the call. You can specify the SignalingHeaders by using this property before the DisconnectCall activity executes.
The OutboundCall Activity The OutboundCall activity creates a new outbound call. The type of call created by this activity depends on the value of the CallType property.
128
Part III
Unified Communications Managed API Workflow
The OutboundCall activity also creates a list of objects needed for supporting a dialog to be used by other UCMA Workflow Activities. These objects are wrapped as a CallProvider object, which is exposed as a property on OutboundCall. Because only one call is created by the OutboundCall activity, only one CallProvider object is created per call. Table 5-6 describes the properties of the OutboundCall activity. Properties of OutboundCallActivity
TABLE 5-6
Property
Description
CalledParty
The party to which the call is being placed. The value should be a valid SIP Uniform Resource Identifier (URI). Examples: sip:[email protected] or tel:1112223333
CallProvider
Exposes an object that contains all of the objects needed to support a dialog (for example, Call, SpeechSynthesizer, or SpeechRecognizer). This is available after the OutboundCall activity executes.
CallType
The type of the call created by the OutboundCall activity. Possible values are AudioVideoCall or InstantMessagingCall.
CustomMimeParts
A list of custom Multipurpose Internet Mail Extensions (MIME) part descriptions.
Headers
A list of SignalingHeaders to be passed to the UCMA as part of accepting the call. You need to set this property before the AcceptCall activity executes.
The BlindTransfer Activity The BlindTransfer activity transfers the call to a specified party without waiting for the transfer to succeed or fail. This is valid only for phone calls, as described in Table 5-7. TABLE 5-7
Properties of BlindTransferActivity
Property
Description
CalledParty
The party the call is being transferred to. The value should be a valid SIP URI. Examples: sip:[email protected] or tel:1112223333
Dialog Activities Dialog activities are the backbone of the interaction between the user and an application. Using these activities, an application can play or send messages to the user and recognize their responses. The UCMA Workflow has four activities that enable interaction with the user. Each activity is valid for either a phone call or an IM call, as described in Table 5-8.
Chapter 5 TABLE 5-8
Unified Communications Managed API (UCMA) Workflow
129
Dialog Activities
Activity
Description
InstantMessagingStatement
Sends an instant message to the user.
InstantMessagingQuestionAnswer
Asks a question by sending an instant message to the user and recognizes the user’s text response.
SpeechQuestionAnswer
Asks the user a question and recognizes user response via a phone call. You can use either a recorded .wav file or a synthesized text-to-speech message. Both speech and DTMF inputs from the user can be recognized.
SpeechStatement
Plays a message to the user via a phone call. You can use either a recorded .wav file or a synthesized text-to-speech message.
The SpeechStatement Activity The SpeechStatement activity plays a specified message to the user. This activity can execute only in an audio-video (A/V) call. The message can be a prerecorded .wav file or a synthesized message using a text-to-speech engine, as described in Table 5-9. TABLE 5-9
Properties of SpeechStatementActivity
Property
Description
IsDataTrackingEnabled
When this property is set to True, if TrackingDataWorkflowRuntimeService has been added to the Workflow Runtime, it stores the value of MainPrompt.
MainPrompt
The prompt that the activity plays to the user when it executes. This is of the type Microsoft.Speech.Synthesis.PromptBuilder.
Playing a message A message can be played to the user by setting the prompt on the SpeechStatement activity. You can set the prompt on the SpeechStatement activity either at the designer level or in code. At design time, you can set static prompts in the Properties window, as shown in Figure 5-9.
FIGURE 5-9 Setting static prompts for the SpeechStatement activity.
130
Part III
Unified Communications Managed API Workflow
Alternatively, you can set a dynamic prompt in code by using the TurnStarting event handler. For details, see the “Turn and the TurnStarting Event” sidebar. The following code example is a sample event handler. private void speechStatementActivity1_TurnStarting(object sender, Microsoft.Rtc.Workflow.Activities.SpeechTurnStartingEventArgs e) {}
SpeechTurnStartingEventArgs exposes the prompt that is played and the type of the prompt. The prompt type is not relevant to SpeechStatement because it has only one type (Main). You can use this event handler to change the prompt dynamically on this activity.
Turn and the TurnStarting Event A turn is a unit of dialog between two parties. In the case of a SpeechStatement activity, turn corresponds to the activity playing the message and the user receiving it. TurnStarting is an event that is raised just before the SpeechStatement activity is ready to play the message. TurnStarting event handler can be registered like any other .NET event handler. Visual Studio provides an easy way to do this in the property window of the selected activity.
The SpeechQuestionAnswer Activity The SpeechQuestionAnswer activity plays a message to the user and recognizes the user’s response. The user can respond via speech or DTMF. This activity can execute only in an A/V call. The message can be a prerecorded .wav file or a synthesized message using a text-tospeech engine. The SpeechQuestionAnswer activity properties are described in Table 5-10. TABLE 5-10
Properties of SpeechQuestionAnswerActivity
Property
Description
CanBargeIn
When set to True, the user can interrupt the question with an answer. If it is set to False, the user’s response is discarded until the question finishes playing.
CompleteTimeout
The length of silence following user speech before the speech recognizer finalizes a result.
DtmfGrammars
A collection of grammar files for recognizing the user’s DTMF input.
ExpectedDtmfInputs
An array of strings that are valid for the user’s DTMF input.
ExpectedSpeechInputs
An array of strings that are valid for the user’s speech input.
Grammars
A collection of grammar files for recognizing the user’s speech input.
IncompleteTimeout
The length of silent time after which recognition ends. This value applies when the speech prior to the silence is an incomplete match of all active grammars.
Chapter 5 TABLE 5-10
Unified Communications Managed API (UCMA) Workflow
131
Properties of SpeechQuestionAnswerActivity
Property
Description
InitialSilenceTimeout
The length of time in which the user has to start responding or the activity treats the user’s response as silence. The default is 3 seconds.
IsDataTrackingEnabled
When set to True, if TrackingDataWorkflowRuntimeService has been added to the Workflow Runtime, it stores the value of MainPrompt that is played and the corresponding recognition result.
MainPrompt
The prompt that the activity plays to the user when this activity executes. This is of the type Microsoft.Speech.Synthesis.PromptBuilder.
PreFlushDtmf
When set to True, all of the DTMF digits in the buffer are discarded and the users cannot type ahead their DTMF responses. When set to False, users can type ahead their DTMF responses.
Prompts
A collection of all of the prompts available for this activity.
RecognitionResult
The result of the recognition of the user’s speech or DTMF response.
Asking a question You can ask the user a question by setting the prompt on the SpeechQuestionAnswer activity. The prompt on the activity can be set in the same way as you would with the SpeechStatement activity, either at the designer level or in code. At design time, you can set static prompts in the Properties window, as shown in Figure 5-10.
FIGURE 5-10 Setting static prompts for the SpeechQuestionAnswer activity.
Alternatively, you can set a dynamic prompt in code by using the TurnStarting event handler. For details, see the “Turn and the TurnStarting Event” sidebar earlier in this chapter. The following code example is a sample event handler. private void speechQuestionAnswerActivity1_TurnStarting(object sender, Microsoft.Rtc.Workflow.Activities.SpeechTurnStartingEventArgs e) {}
132
Part III
Unified Communications Managed API Workflow
SpeechTurnStartingEventArgs exposes the prompt that is played and the type of the prompt. You can use this event handler to change the prompt on this activity dynamically.
Prompt Types The SpeechQuestionAnswer and InstantMessagingQuestionAnswer activities have many types of prompts. Table 5-11 describes what each prompt type is used for. TABLE 5-11
Prompt Types
Prompt Type
Description
Acknowledge
This prompt is played before the user input is sent for recognition. This is available only for the InstantMessagingQuestionAnswer activity.
EscalatedNoRecognition
This prompt is played by the activity when the user’s response is not recognized a second time. This is not mandatory. This is available only for the SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswer activities.
EscalatedSilence
This prompt is played by the activity when the user does not respond in the time specified in the InitialSilenceTimeout. This is not mandatory. This is available only for the SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswer activities.
Help
This prompt is played by the activity when the user response triggers a help command in that scope. For details, see the “What Is a Command?” sidebar later in this chapter. This is not mandatory. This is available only for the SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswer activities.
Main
This is the first prompt that the activity plays. This is mandatory. If it is not set, the activity throws an exception. This is available only for the SpeechStatement, SpeechQuestionAnswerActivity, InstantMessagingStatement, and InstantMessagingQuestionAnswer activities.
NoRecognition
This prompt is played by the activity the first time the user’s response is not recognized. This is not mandatory. This is available only for the SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswer activities.
Repeat
This prompt is played by the activity when the user response triggers a repeat command in that scope. For details, see the “What Is a Command?” sidebar later in this chapter. This is not mandatory. This is available only for SpeechQuestionAnswerActivity.
Silence
This prompt is played by the activity the first time the user does not respond in the time specified in InitialSilenceTimeout. This is not mandatory. This is available only for the SpeechQuestionAnswerActivity and InstantMessagingQuestionAnswer activities.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
133
Prompt Fallback Logic As mentioned in Table 5-11, all prompts except Main are optional. However, there are conditions in which one of these nonoptional prompts needs to be played. For example, if a user’s response cannot be recognized but the NoRecognition prompt has not been specified, then a fallback prompt is played. The fallback prompt that is played depends on the prompt that was supposed to be played. Prompt types and their fallback prompt types are listed in Table 5-12. TABLE 5-12
Prompt Types and the Associated Fallback Prompt Types
Prompt Type
Fallback Prompt Type
Main
Not applicable; this prompt is mandatory.
Acknowledge
No fallback. If it is not set, then this prompt is not played.
EscalatedNoRecognition
NoRecognition
EscalatedSilence
Silence
Help
Main
NoRecognition
Help
Repeat
Main
Silence
Help
For example, suppose that you have set only the Main prompt for a SpeechQuestionAnswer activity. If the user’s response is not recognized, ideally the NoRecognition prompt is played. However, because the NoRecognition prompt is not specified, SpeechQuestionAnswer tries to play the Help prompt. Again, because the Help prompt is also not specified (that is, only the Main prompt is specified), the Main prompt, which is the fallback prompt for the Help prompt, is played.
Recognizing user responses SpeechQuestionAnswer needs to know a set of expected user responses to recognize. SpeechQuestionAnswer has four properties that enable the developer to specify this set. The following description uses speech as the example. The process for recognizing DTMF input is very similar. Specifying expected inputs ExpectedSpeechInputs, a property on SpeechQuestionAnswer, is an array of strings that the developer can specify. At run time, this array is converted to a grammar so that, if the user responds with anything in this set, it can be recognized. You can specify the set of valid user responses by using the String Collection Editor window from the Properties window, as shown in Figure 5-11. This is useful in scenarios in which the list of expected inputs is finite; for example, a list of pizza sizes or yes/no responses. Similarly, you can use ExpectedDtmfInputs for DTMF inputs.
134
Part III
Unified Communications Managed API Workflow
FIGURE 5-11 A String Collection Editor window opened from the ExpectedSpeechInputs property of
SpeechQuestionAnswer.
Specifying the grammar file You can use a grammar file to list the expected inputs. A grammar file is a more flexible and powerful way of specifying the set of expected inputs (for example, dates and numbers). These grammar files have to follow a certain schema, as described by the Speech Recognition Grammar Specification (SRGS). Given a grammar file, the file can be attached to SpeechQuestionAnswer by using the Grammars property. This is a collection of grammar files used to recognize user input. In the Properties window, you can specify multiple grammar files by separating them with a semicolon. Similarly, you can specify DTMF grammars by using the DTMFGrammars property.
What Is a Grammar? A grammar is intended for use by speech recognizers so that developers can specify the words and patterns of words for which you want the speech recognizer to listen. For example, the grammar file should contain all of the words or pattern of words that the developer deems a valid response to the question, “What size pizza would you like?”
InstantMessagingStatementActivity InstantMessagingStatementActivity sends a specified message to the user. This activity can execute only on IM calls. Table 5-13 lists InstantMessagingStatementActivity properties. TABLE 5-13
Properties of InstantMessagingStatementActivity
Property
Description
IsDataTrackingEnabled
When set to True, and if TrackingDataWorkflowRuntimeService has been added to the Workflow Runtime, it stores the value of MainPrompt.
MainPrompt
The message that the activity sends to the user when this activity executes. This is of the type string.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
135
Setting the prompt You can set the prompt on InstantMessagingStatementActivity either at the designer level or in code. At design time, you can set static prompts in the Properties window, as shown in Figure 5-12.
FIGURE 5-12 Setting a static prompt for InstantMessagingStatementActivity.
Alternatively, you can set a dynamic prompt in code by using the TurnStarting event handler. For details, see the “Turn and the TurnStarting Event” sidebar earlier in this chapter. The following code example is a sample event handler. private void instantMessagingStatementActivity1_TurnStarting(object sender, Microsoft.Rtc.Workflow.Activities.InstantMessagingTurnStartingEventArgs e) {}
InstantMessagingTurnStartingEventArgs exposes the prompt that is played and the type of the prompt. The type of prompt is not relevant to InstantMessagingStatement because it has only one type (Main). You can use this event handler to change the prompt on this activity dynamically.
InstantMessagingQuestionAnswerActivity InstantMessagingQuestionAnswerActivity sends a message to the user and recognizes the user’s response. This activity can execute only on IM calls. Table 5-14 lists the InstantMessagingQuestionAnswerActivity properties. TABLE 5-14
Properties of InstantMessagingQuestionAnswerActivity
Property
Description
ExpectedInputs
An array of strings that are valid for the user’s IM input.
Grammars
A collection of grammar files for recognizing a user’s IM input.
InitialSilenceTimeout
The length of time in which the user has to start responding or the activity treats the user’s response as silence. The default is 30 seconds.
136
Part III
Unified Communications Managed API Workflow
TABLE 5-14
Properties of InstantMessagingQuestionAnswerActivity
Property
Description
IsDataTrackingEnabled
When set to True, and if TrackingDataWorkflowRuntimeService has been added to the Workflow Runtime, it stores the value of MainPrompt that is played and the corresponding recognition result.
MainPrompt
The message that the activity sends to the user when this activity executes. This is of the type string.
Prompts
A collection of all of the prompts available for this activity.
RecognitionResult
The result of the recognition of the user’s IM response.
Asking an IM question You can ask the user an IM question by setting the prompt on InstantMessagingQuestionAnswerActivity. The prompt on the activity can be set in the same way as you would with InstantMessagingStatementActivity, either at the designer level or in code. At design time, you can set static prompts in the Properties window, as shown in Figure 5-13.
FIGURE 5-13 Setting static prompts for InstantMessagingQuestionAnswerActivity.
Alternatively, you can set a dynamic prompt in code by using the TurnStarting event handler. For details, see the “Turn and the TurnStarting Event” sidebar earlier in this chapter. The following code example is a sample event handler. private void instantMessagingQuestionAnswerActivity1_TurnStarting(object sender, Microsoft.Rtc.Workflow.Activities.InstantMessagingTurnStartingEventArgs e) {}
Chapter 5
Unified Communications Managed API (UCMA) Workflow
137
InstantMessagingTurnStartingEventArgs exposes the prompt that is played and the type of the prompt. You can use this event handler to change the prompt on this activity dynamically. Recognizing the user’s text response Similar to SpeechQuestionAnswer, InstantMessagingQuestionAnswerActivity needs to have a set of expected user text responses to recognize. InstantMessagingQuestionAnswerActivity has two properties that enable the developer to specify this set. Specifying expected inputs ExpectedInputs, a property on InstantMessagingQuestionAnswerActivity, is an array of strings that the developer can specify. This is exactly the same as the ExpectedSpeechInputs or ExpectedDTMFInputs property of SpeechQuestionAnswer. Specifying the grammar file You can use a grammar file to list the expected inputs. Even though these files follow a certain schema as described by the SRGS, you can use it to recognize IM input. Given a grammar file, the file can be attached to InstantMessagingQuestionAnswerActivity by using the Grammars property in the exact way that you would with SpeechQuestionAnswer.
Command Activities Five activities are available to enable developers to add commands to the dialog interaction with the user. Each activity is valid for either a phone call or an IM call. Command activities and descriptions are listed in Table 5-15. TABLE 5-15
Different Types of Command Activities
Activity
Description
InstantMessagingCommand
A generic command that is triggered based on the attached grammar file. Valid only for IM calls.
InstantMessagingHelpCommand
A command used for scenarios to provide help to the user. It is triggered based on the attached grammar file. Valid only for IM calls.
SpeechCommand
A generic command that is triggered based on the attached speech or DTMF grammar file. Valid only for phone calls.
SpeechHelpCommand
A command used for scenarios to provide help to the user. It is triggered based on the attached speech or DTMF grammar file. Valid only for phone calls.
SpeechRepeatCommand
A command used for scenarios to repeat the question back to the user. It is triggered based on the attached speech or DTMF grammar file. Valid only for phone calls.
138
Part III
Unified Communications Managed API Workflow
What Is a Command? A command can be considered a valid user response that may not be a direct answer to the question asked. For example, answers to the question, “Which size pizza would you like?” could include “Small” or “Large.” However, the following responses are also valid, even though they do not answer the question: N
What sizes do you have?
N
Do you have a family-size pizza?
N
What was that again?
N
I think I have changed my mind. I don’t want pizza anymore.
The first two responses ask for more information (that is, requesting help). The third response asks for the question to be repeated. The last response just states that the user does not want any pizza. These responses can be called commands because the user is commanding that more information be provided or that the dialog be ended. Commands are an integral part of a good dialog user interface when interacting with an automated system, be it over the phone or via IM. They allow users to ask for more information (that is, Help), replay the question again (that is, Repeat), or perform more generic actions, such as restarting. It increases the chance that users understand what is expected of them so that they can provide the correct input.
SpeechCommandActivity SpeechCommandActivity is a command activity that you can use for any generic command when interacting via a phone call. You can specify this activity for a scope as defined by a CommunicationsSequence activity. Anytime SpeechQuestionAnswer is active in that scope, the SpeechCommand activity, if defined, is also active in that scope. For example, a SpeechQuestionAnswer activity is defined to ask for a pizza size, as shown in Figure 5-14. Also, SpeechCommandActivity is defined in that scope as well. You can add SpeechCommandActivity in the command view of CommunicationsSequenceActivity only. You can open the Command view by right-clicking CommunicationsSequenceActivity and then clicking View Commands. A snapshot of a SpeechCommandActivity is added in the Command view, as shown in Figure 5-15. The SpeechCommandActivity is named operatorCommand.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
139
FIGURE 5-14 A simple workflow with a SpeechQuestionAnswer activity named askPizzaSize.
FIGURE 5-15 A Command view of communicationsSequenceActivity1 showing the SpeechCommand named operatorCommand.
In this particular example, when the askPizzaSize activity is executing, operatorCommand is also active. If the user’s response matches the grammar defined in the operatorCommand grammar, the operatorCommand activity executes all of its children. In this case, the transferToOperator activity, which is a Blind Transfer activity, executes. Table 5-16 lists the properties of SpeechCommandActivity.
140
Part III
Unified Communications Managed API Workflow
TABLE 5-16
Properties of SpeechCommandActivity
Property
Description
DtmfGrammars
A collection of grammar files for recognizing the user’s DTMF input for this command
ExpectedDtmfInputs
An array of strings that are valid for the user’s DTMF input for this command
ExpectedSpeechInputs
An array of strings that are valid for the user’s speech input for this command
Grammars
A collection of grammar files for recognizing the user’s speech input for this command
RecognitionResult
The result of the recognition of the user’s speech or DTMF response if matched by the command grammar
SpeechHelpCommandActivity SpeechHelpCommandActivity is a custom speech command activity. It is added to the Commands view of a CommunicationsSequenceActivity in the same way as for SpeechCommandActivity. Like SpeechCommandActivity, it is also active during all of the SpeechQuestionAnswer activities in the scope that this command is defined within. However, when the user input is matched with any of the grammars defined for SpeechHelpCommandActivity, the Help prompt of SpeechQuestionAnswerActivity is played automatically. For example, a SpeechQuestionAnswerActivity named askPizzaSize, shown previously in Figure 5-14, is defined with the MainPrompt and HelpPrompt sets, as shown in Figure 5-16. Also imagine a SpeechHelpCommandActivity called helpCommand is defined in the Commands view in the same way operatorCommand was defined.
FIGURE 5-16 The MainPrompt and HelpPrompt set for the askPizzaSize activity.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
141
When the askPizzaSize activity executes, it plays its MainPrompt, “What size pizza would you like?” If the user’s response is matched with the helpCommand grammar, the askPizzaSize activity automatically plays its HelpPrompt, “You can choose from large, medium, or small.” If the HelpPrompt is not defined, the prompt fallback logic is used.
SpeechRepeatCommandActivity SpeechRepeatCommandActivity behaves exactly the same way as SpeechHelpCommandActivity except when the user input is matched with any of the grammars defined for SpeechRepeatCommandActivity. In this case, the Repeat prompt of SpeechQuestionAnswerActivity is played automatically. If the Repeat prompt is not defined, the prompt fallback logic is used.
InstantMessagingCommandActivity InstantMessagingCommandActivity is the IM version of SpeechCommandActivity. You can use it to implement generic commands for IM dialog interactions, and it is active for IM calls when InstantMessagingQuestionAnswerActivity is executing. By replacing all speech activities with their equivalent IM activities in the example given earlier in this chapter for SpeechCommandActivity, you can easily create a sample application for InstantMessagingCommandActivity. Table 5-17 lists the properties of InstantMessagingCommandActivity. TABLE 5-17
Properties of InstantMessagingCommandActivity
Property
Description
ExpectedInputs
An array of strings that are valid for the user’s IM input for this command
Grammars
A collection of grammars for recognizing the user’s IM input for this command
RecognitionResult
The result of the recognition of the user’s IM response if matched by the command grammar
InstantMessagingHelpCommandActivity InstantMessagingHelpCommandActivity is a custom IM command activity. It behaves the same way as SpeechHelpCommandActivity except for IM dialogs using InstantMessagingQuestionAnswerActivity.
Call Control Communications Event Activities Four call control communication event activities available in the UCMA Workflow allow for the handling of call control communication events. One activity is valid for both phone calls and IM calls, while others are specific to either a phone call or an IM call, as described in Table 5-18.
142
Part III
Unified Communications Managed API Workflow
TABLE 5-18
Call Control Communications Event Activities
Activity
Description
CallDisconnectedEvent
An event when the call (phone or IM) is disconnected.
CallOnHoldEvent
An event when the call is put on hold. Valid only for phone calls.
CallOnHoldTimeoutEvent
An event when the call is on hold for a specified amount of time. Valid only for phone calls.
CallRetrievedEvent
An event when the call that was on hold is retrieved. Valid only for phone calls.
What Are Communication Events? There are two different types of communication events. A call control communication event occurs on the call that is used for communication. A dialog communication event is an event that occurs as part of the dialog process. They are distinguished from call control communication events because call control communication events are based on the events on the call, whereas dialog communication events are related only to the dialog between the two parties. For example, if a pizza counter attendant asks a user, “What size pizza would you like?” but the user does not say anything, the attendant is going to ask the question again. After a while (that is, after the attendant has asked the same question n number of times), the attendant realizes that the user is either not interested in getting pizza or does not understand the question. The attendant can then take specific action. This realization by the pizza counter attendant can be called a dialog event. Dialog events are an integral part of a good dialog user interface. They allow the system to realize that the user is not making progress with the automated system. The system can then decide to either transfer the call to an agent or disconnect the call and play or send a (hopefully) useful message to the user if no agents are available.
CallDisconnectedEventActivity CallDisconnectedEventActivity is an event handler activity for a “call disconnected” event, whether a phone call or an IM call. You can specify this activity for a scope, as defined by a CommunicationsSequenceActivity. This activity can be added only in the CommunicationEvents view of CommunicationsSequenceActivity. You can open the CommunicationsEvents view of CommunicationsSequenceActivity by right-clicking CommunicationsSequenceActivity and then clicking View Communication Events on the context menu. An example of a CommunicationsSequenceActivity with a CallDisconnectedEventActivity added in its CommunicationsEvents view is shown in Figure 5-17.
Chapter 5
Unified Communications Managed API (UCMA) Workflow
143
FIGURE 5-17 The CommunicationsEvents view of communicationsSequenceActivity1 showing
callDisconnectedEventActivity1.
In the preceding example, a code activity, postCallDisconnectedProcessing, is executed when the call is disconnected. When CallDisconnectedEventActivity is executed, it cancels all of the other activities that are executing in CommunicationsSequenceActivity. For example, if a SpeechQuestionAnswerActivity is executing when the call is disconnected, CallDisconnectedEventActivity in that scope cancels SpeechQuestionAnswerActivity. If no such CallDisconnectedEventActivity is present in the scope, the activities that need a call to execute (in this example, SpeechQuestionAnswerActivity) throw an InvalidOperationException because they cannot execute without a call. Table 5-19 lists the property of CallDisconnectedEventActivity. TABLE 5-19
Property of CallDisconnectedEventActivity
Property
Description
CallStateTransitionReason
Exposes the reason why the call was disconnected
CallOnHoldEventActivity CallOnHoldEventActivity is an event handler activity for a “call put on hold.” This works only for a phone call because IM calls cannot be put on hold. This activity can be specified for a scope as defined by a CommunicationsSequenceActivity. This activity can be added only in the CommunicationEvents view of CommunicationsSequenceActivity.
144
Part III
Unified Communications Managed API Workflow
Note The speech dialog activities, like SpeechQuestionAnswerActivity and SpeechStatementActivity, intrinsically handle calls being put on hold. CallOnHoldEventActivity is used if the application wants to perform extra processing when the call is put on hold.
CallOnHoldTimeoutEventActivity CallOnHoldTimeoutEventActivity is an event handler activity for a “call on hold for a certain amount of time.” Its property and description are shown in Table 5-20. Due to the nature of this event, it can occur only after the call has been put on hold. The amount of time after which this event occurs can be set using a property on the activity. This works only for a phone call because IM calls cannot be put on hold. This activity can be specified for a scope as defined by a CommunicationsSequenceActivity. This activity can be added only in the CommunicationEvents view of CommunicationsSequenceActivity. TABLE 5-20
Property of CallOnHoldTimeoutEventActivity
Property
Description
CallOnHoldTimeout
The length of time for which the call is on hold before this activity is executed
CallRetrievedEventActivity CallRetrievedEventActivity is an event handler activity for a “call being retrieved.” Due to the nature of this event, it can occur only after the call has been put on hold. This works only for a phone call because IM calls cannot be put on hold or retrieved. You can specify this activity for a scope as defined by CommunicationsSequenceActivity. This activity can be added only in the CommunicationEvents view of CommunicationsSequenceActivity.
Note The speech dialog activities, like SpeechQuestionAnswerand SpeechStatement, intrinsically handle calls being retrieved. The CallRetrievedEventActivity is used if the application wants to perform extra processing when the call is retrieved.
Dialog Communications Event Activities Six dialog communication event activities are available that allow for handling dialog events. Each activity is valid for either a phone call or an IM call, as described in Table 5-21.
Chapter 5 TABLE 5-21
Unified Communications Managed API (UCMA) Workflow
145
Dialog Communications Event Types
Activity
Description
ConsecutiveNoInputsInstantMessagingEvent
An event when the application fails to understand a user response or the user fails to respond n times in a row. Valid only for IM calls.
ConsecutiveNoInputsSpeechEvent
An event when the application fails to understand a user response or the user fails to respond n times in a row. Valid only for phone calls.
ConsecutiveNoRecognitionsInstantMessagingEvent
An event when the application fails to understand a user response n times in a row. Valid only for IM calls.
ConsecutiveNoRecognitionsSpeechEvent
An event when the application fails to understand a user response n times in a row. Valid only for phone calls.
ConsecutiveSilencesInstantMessagingEvent
An event when the user fails to respond n times in a row. Valid only for IM calls.
ConsecutiveSilencesSpeechEvent
An event when the user fails to respond n times in a row. Valid only for phone calls.
ConsecutiveNoInputsSpeechEventActivity ConsecutiveNoInputsSpeechEventActivity is an event handler activity for a user providing an invalid input n times in a row. Its property is listed in Table 5-22. By default, the value of n is 3. An invalid input is when the user either does not provide any input (that is, remains silent) or the user’s input is not recognized. This works only for speech dialogs over a phone call. This activity can be specified for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity. TABLE 5-22
Property of ConsecutiveNoInputsSpeechEventActivity
Property
Description
MaximumNoInputs
The number of consecutive times that invalid user input is received before this activity is executed. The default value is 3.
ConsecutiveSilencesSpeechEventActivity ConsecutiveSilencesSpeechEventActivity is an event handler activity for a user remaining silent n times in a row. Its property is listed in Table 5-23. By default, the value of n is 3. This works only for speech dialogs over a phone call. This activity can be specified for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity.
146
Part III
Unified Communications Managed API Workflow
TABLE 5-23
Property of ConsecutiveSilencesSpeechEventActivity
Property
Description
MaximumSilences
The number of consecutive times that the user remains silent before this activity is executed. The default value is 3.
ConsecutiveNoRecognitionsSpeechEventActivity ConsecutiveNoRecognitionsSpeechEventActivity is an event handler activity for user input not being recognized n times in a row. Its property is listed in Table 5-24. By default, the value of n is 3. This works only for speech dialogs over a phone call. This activity can be specified for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity. TABLE 5-24
Property of ConsecutiveNoRecognitionsSpeechEventActivity
Property
Description
MaximumNoRecognitions
The number of consecutive times that user input is not recognized before this activity is executed. The default value is 3.
ConsecutiveNoInputsInstantMessagingEventActivity ConsecutiveNoInputsInstantMessagingEventActivity is an event handler activity for a user providing an invalid input n times in a row. Its property is listed in Table 5-25. By default, the value of n is 3. An invalid input is when the user either does not provide any input (that is, does not respond) or the user’s input is not recognized. This works only for IM dialogs over an IM call. You can specify this activity for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity. TABLE 5-25
Property of ConsecutiveNoInputsInstantMessagingEventActivity
Property
Description
MaximumNoInputs
The number of consecutive times that invalid user input is received before this activity is executed. The default value is 3.
ConsecutiveSilencesInstantMessagingEventActivity ConsecutiveSilencesInstantMessagingEventActivity is an event handler activity for a user not responding n times in a row. Its property is described in Table 5-26. By default, the value of n is 3. This works for only for IM dialogs over an IM call. You can specify this activity for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity.
Chapter 5 TABLE 5-26
Unified Communications Managed API (UCMA) Workflow
147
Property of ConsecutiveSilencesInstantMessagingEventActivity
Property
Description
MaximumSilences
The number of consecutive times that the user does not respond before this activity is executed. The default value is 3.
ConsecutiveNoRecognitionsInstantMessagingEventActivity ConsecutiveNoRecognitionsInstantMessagingEventActivity is an event handler activity for user input not being recognized n times in a row. Its property is described in Table 5-27. By default, the value of n is 3. This works only for IM dialogs over an IM call. You can specify this activity for a scope as defined by a CommunicationsSequenceActivity. You add this activity in the CommunicationEvents view of CommunicationsSequenceActivity. TABLE 5-27
Property of ConsecutiveNoRecognitionsInstantMessagingEventActivity
Property
Description
MaximumNoRecognitions
The number of consecutive times that user input is not recognized before this activity is executed. The default value is 3.
Presence-Related Activity Presence is one of the most important value propositions of any UC platform. The UCMA Workflow ships with an activity related to presence, as described in Table 5-28. TABLE 5-28
Presence-Related Activity
Activity
Description
GetPresence
Queries the presence information for user(s)
GetPresenceActivity GetPresenceActivity queries the presence information of a user or a group of users. In addition to the presence state, it returns the current activity of the user (for example, in a meeting, in a call) and also out-of-office message if set. Its properties are described in Table 5-29. The outof-office message is published if the user has set it in Microsoft Office Outlook. If the user has not set an out-of-office message, this value is NULL. TABLE 5-29
Properties of GetPresenceActivity
Property
Description
Targets
A list of RealTimeAddress objects that represents the users whose presence will be queried.
Results
A dictionary representing the RealTimeAddress and its presence query result. The RealTimeAddress is used as a key in the dictionary. The PresenceResult object is the value representing the result of the query.
148
Part III
Unified Communications Managed API Workflow
PresenceResult PresenceResult is the object that represents the result of the presence query performed by the GetPresence activity. Its properties are described in Table 5-30. TABLE 5-30
Properties of PresenceResult
Property
Description
CurrentState
A string representing the current activity of the user (for example, “In a meeting”, “In a call”).
OofNote
A string representing the out-of-office message as published by the user. If the user has not published an out-of-office message, this value is NULL.
PresenceStatus
An enum value listing the presence status of the user. It is of type Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.
Summary The UCMA Workflow Activities provide a way to develop applications that can interact with the user over the phone or an IM channel as new interfaces. It enables faster development of such applications by providing prepackaged custom activities for common tasks (for example, playing or sending a message to the user or asking the user a question and recognizing user input). It also enables intelligent routing decisions by providing a way to query for presence information. Finally, because this API does not dictate which application to use, developers are free to use any application host that they choose.
Additional Resources N
“Getting Started with Workflow Foundation (WF)” (http://msdn.microsoft.com/en-us/ netframework/aa663328.aspx)
N
Microsoft Unified Communications Managed API 2.0 SDK (32 bit) (http://go.microsoft .com/fwlink/?LinkID=140790)
N
Microsoft Unified Communications Managed API 2.0 SDK (64 bit) (http://go.microsoft .com/fwlink/?LinkID=139195)
N
“Unified Communications Managed API 2.0 Workflow SDK Documentation” (http://go.microsoft.com/fwlink/?LinkID=133578&clcid=0x409)
N
“Understanding the Activity Execution Context” (http://msdn.microsoft.com/en-us/ library/aa349099.aspx)
Business Process Communication This chapter will help you to: N
Understand how to implement a workflow application.
N
Understand the advantages of using a workflow application.
N
See how to support both phone and instant message modalities in the same application.
Scenario Expense reporting and approval is a business process common to most enterprises. These processes have a deadline, and human intervention is required to complete them. For example, the typical approval process requires that a supervisor review expense reports and sign off on them before they are sent to the reimbursement department. Failure to meet payment deadlines can result in either penalty fees (for example, for credit cards) or extra processing. This scenario can be enhanced by monitoring unapproved expense reports, and as the deadline approaches, alerting the approver with the information necessary to take effective and timely action. This chapter covers the step-by-step implementation of a Unified Communications Managed API (UCMA) Workflow application that does the following: N
Queries for the presence of the approver to determine the best communication channel
N
Notifies the approver of pending tasks
N
Provides different communication channel options to complete pending tasks based on the approver’s availability
N
Informs a delegate of pending tasks if the approver is out of the office
Business Value By using multiple communications channels and presence information, the business process can make better decisions, help reduce costs to the enterprise, and increase productivity. For example, if the approver is out of the office and the pending tasks are important, the
149
150
Part III
Unified Communications Managed API Workflow
delegate is asked to complete the task. This ensures that important tasks do not become critical due to lack of action. The value added to the business process derives from the following: N
Reduced human latency in automated business processes
N
Increased productivity due to choosing the best communication channel
N
Cost reduction created by increasing the process efficiency due to presence-based intelligent routing
Choice of Technology The UCMA Workflow provides the following benefits that make it ideal in the preceding scenarios: N
An interactive application is easy to create by dragging activities onto the workflow canvas.
N
Custom activities provide the infrastructure to interact with users over a phone call or instant messaging (IM) call.
N
Custom activities also provide constructs to enable a more natural dialog with the user.
N
It can be integrated to use the benefits of Microsoft Office Communications Server 2007 R2.
Overall Code Structure The rest of this chapter lists and explains the steps for building an expense reporting and approval application using UCMA Workflow Activities and Microsoft Visual Studio 2008. This application provides a solution to the preceding scenario.
Test Environment To build and test this solution, you need the following: N
Office Communications Server 2007 R2 installed and configured on your domain.
N
At least two users with Microsoft Office Communicator 2007 R2 installed who are able to sign in to the Office Communicator.
N
Your development environment must match the UCMA Workflow specified in the UCMA Software Development Kit (SDK) documentation at http://go.microsoft.com/ fwlink/?LinkID=133578.
Chapter 6
Business Process Communication
151
Building the Application The following sections break down the application-building process into smaller tasks. For each task, there is a list of steps to be followed.
Task 1: Create a New Communication Workflow Project The Outbound Sequential Workflow Console Application project template, which is part of the UCMA SDK, provides a good starting point for building this application because it automatically generates code to integrate with Office Communications Server 2007 R2. To create a project using this template, perform the following steps: 1. Start Visual Studio as an administrator. In Windows Vista, you may have to do this by right-clicking the Microsoft Visual Studio 2008 icon and then clicking Run As Administrator. 2. On a computer running Windows Vista, click Continue when the User Account Control prompts to allow this operation. 3. On the Visual Studio menu, click File, New Project to open the New Project dialog box. 4. In the Project Types tree, click Communications Workflow. 5. Select Outbound Sequential Workflow Console Application and then click OK. 6. In the Select Language dialog box, choose the language type and then click OK. Table 6-1 lists the files generated by this project template. TABLE 6-1
Defines a console application similar to the one generated by the Console Application project template that comes with Visual Studio 2008. This file, which is generated automatically, contains all of the code needed to integrate with Office Communications Server 2007 R2.
Workflow1.xoml
Defines the semantics of the application’s workflow as viewed in the designer canvas. This file, in combination with the Workflow1.xoml.cs file, defines the workflow.
Workflow1.xoml.cs
Contains the code-besides for the workflow. This file, in combination with the Workflow1.xoml file, defines the workflow.
Task 2: Configure the Application to Connect to Office Communications Server You need to modify the automatically generated code in the Program.cs file to connect to your specific server running Office Communications Server.
152
Part III
Unified Communications Managed API Workflow
To deploy a UCMA Workflow application, the application must sign in to Office Communications Server. Because an application is not a user, the administrator cannot use an Active Directory Domain Services (AD DS) user account. Instead, the administrator needs to create an AD DS Contact object to represent the application and specify the application as a trusted service. You need to gather the information listed in Table 6-2 before you modify the Program.cs file. You can obtain this information from your Office Communications Server administrator, who creates the AD DS Contact object and specifies your application as a trusted service. TABLE 6-2
Information Needed to Update Program.cs
Name
Description
Action to Be Taken
Application Port
Port that the application listens on.
Update the value in the constructor of platformSettings in the Initialize method.
Application URI
The Session Initiation Protocol (SIP) Uniform Resource Identifier (URI) assigned to the Contact object that represents your applications, to which users place calls or send IM messages.
Update the value of the variable applicationUri in the Initialize method.
Certificate
The certificate that authenticates the application machine running Office Communications Server. This certificate must be trusted by servers running Office Communications Server.
Install the certificate in the Local Computer certificate store on the computer where the application is installed.
FQDN
The fully qualified domain name (FQDN) for the server running Office Communications Server on which the Contact object to be created is homed.
Update the value of the variable ocsFqdn in the Initialize method.
GRUU
The Globally Routable User Agent URI (GRUU) of the trusted service added to Office Communications Server for this application.
Update the value of the variable gruu in the Initialize method.
SIP Port
Port number on which your server running Office Communications Server listens for SIP connections. The default is 5061.
Update the value of the variable ocsTlsPort if the value is not the default.
More Info For details, see Chapter 9, “Preparing the UC Development Environment.”
Task 3: Allow User Input to the Workflow Instance In this scenario, a specific event triggers the business workflow. Examples of such events are “Approval deadline in three days” or “Going over the expense limit requires signoff.” In this example, you use console input to trigger the workflow. You can replace this easily with a handler for any event you choose.
Chapter 6
Business Process Communication
153
1. Update the Main method with the following code. /// /// Main /// private static void Main() { bool _continue = true; string _approverUri = string.Empty; string _reportTitle = string.Empty; string _amount = string.Empty; string _filedBy = string.Empty; string _onlineDelegateUri = string.Empty; Initialize(); while (_continue) { Console.Write("Enter the approver's SIP URI or 'exit' to quit: "); _approverUri = Console.ReadLine(); if(_approverUri != "exit") { Console.Write("Enter the expense report title: "); _reportTitle = Console.ReadLine(); Console.Write("Enter the expense report amount: "); _amount = Console.ReadLine(); Console.Write("Enter the name of person filing the report: "); _filedBy = Console.ReadLine(); Console.Write("Enter the SIP URI of an online delegate: "); _ onlineDelegateUri = Console.ReadLine(); StartWorkflow(_approverUri, _reportTitle, _amount, _filedBy, _onlineDelegateUri); } else { _continue = false; } } Cleanup(); }
When you run this application, the application prompts the user to enter the SIP address of the approver, an expense report name, an expense amount, the name of the person filing the report, and the SIP address of a delegate that is online. If the user types Exit, the application closes. After the user enters the required input, the application starts the workflow by calling the StartWorkflow() method. In a real-world implementation, this information would be provided by the process that triggers the workflow. 2. Modify the signature of the StartWorkflow method as follows. private static void StartWorkflow(string approverUri, string reportTitle, string amount, string filedBy, string onlineDelegate)
154
Part III
Unified Communications Managed API Workflow
3. Add the following lines at the beginning of the StartWorkflow method to pass the approver URI, expense report details, and online delegate URI to the workflow instance. Dictionary namedArgs = new Dictionary(); namedArgs.Add("ApproverSipAddress", new RealTimeAddress("sip:" + approverUri)); namedArgs.Add("ReportTitle", reportTitle); namedArgs.Add("Amount", amount); namedArgs.Add("FiledBy", filedBy); namedArgs.Add("OnlineDelegate", new RealTimeAddress("sip:" + onlineDelegate)); WorkflowInstance workflowInstance = _workflowRuntime.CreateWorkflow(typeof(Workflow1), namedArgs);
Note You may have to add using Microsoft.Rtc.Signaling; and using System.Collections .Generic; to the top of Program.cs if they are not already in the file.
4. To make the data passed into the Workflow instance accessible, public properties are defined in the workflow. In Workflow1.xoml.cs, add the following lines of code inside the definition of the Workflow1 class as follows. public public public public public
Task 4: Get the Approver’s Presence Information By using the presence information of the approver, the application can use more efficient logic to get the expense report approved. If the approver is online, the application can contact the approver directly. If the approver is offline, the application can contact the designated delegate. The following steps query for the presence of the approver: 1. The workflow file (that is, Workflow1.xoml) is prepopulated with activities to start an outbound call. However, in this scenario you need to get the approver’s presence information before making an outbound call. To start from a clean state, delete all of the activities from the designer canvas. 2. Drag a CommunicationsSequence activity from the Unified Communications Workflow tab onto the designer canvas over the text Drop Activities To Create A Sequential Workflow and, in the Property pane, rename it overallContainer. This activity is needed to define a dialog with the user.
Chapter 6
Business Process Communication
155
3. Drag a Code activity from the Windows Workflow v3.0 tab onto the designer canvas inside the overallContainer activity and, in the Property pane, rename it setParameters. You use this activity to set any parameters needed to execute the workflow, such as access data passed into the workflow (see Tasks 4, 6, 7.2.1, and 7.3.1). 4. Drag a GetPresence activity from the Unified Communications Workflow tab onto the designer canvas after the setParameters activity and rename it getApproverPresence. You use this activity to get the presence information of the approver. The workflow should look like the following:
5. Double-click the setParameters activity to generate the code handler for that activity. Update the handler method with the following code to set the Target property of the getApproverPresence activity with the value of ApproverSipAddress. private void setParameters_ExecuteCode(object sender, EventArgs e) { /// Set the target of getApproverPresence activity this.getApproverPresence.Targets.Clear(); this.getApproverPresence.Targets.Add(ApproverSipAddress); }
Task 5: Implement Branching Logic Based on the Approver’s Presence The objective is to have the expense report reviewed and then approved or rejected. Therefore, the application logic follows different branches based on the presence of the approver. In cases in which the approver’s presence status is Offline, Do Not Disturb, or Out of Office, the application determines that the approver is not available and contacts its delegate. For all other presence states, the approver is considered to be available to review the request.
156
Part III
Unified Communications Managed API Workflow
The following steps implement branching logic based on the approver’s presence: 1. Drag an IfElse activity from the Windows Workflow Foundation v3.0 pane onto the designer canvas after the getApproverPresence activity. 2. In the Property pane, select the ifElseBranchActivity1 branch and rename it cantBeContactedBranch. You use cantBeContactedBranch to define the business logic for the situation in which the approver cannot be reached. 3. In the Property pane, select the ifElseBranchActivity2 branch and rename it canBeContactedBranch. You use canBeContactedBranch to define the business logic for the situation in which the approver can be reached. 4. Select cantBeContactedBranch and change the value of the Condition property from (None) to Code Condition. 5. The cantBeContactedBranch branch executes only if a specified condition, which is defined in step 6, is True. To specify this condition, click the plus sign (+) to expand the Condition property. Type the method name CheckIfUserCantBeContacted, and then press Enter. This takes you to the automatically generated method stub. This method defines the logic to check whether this condition is met. 6. Update the CheckIfUserCantBeContacted method with the following code. private void CheckIfUserCantBeContacted(object sender, ConditionalEventArgs e) { if(this.getApproverPresence.Results[ApproverSipAddress].CurrentState.ToLower(). Contains("out of office") || this.getApproverPresence.Results[ApproverSipAddress].PresenceStatus == Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.Offline || this.getApproverPresence.Results[ApproverSipAddress].PresenceStatus == Microsoft.Rtc.Collaboration.Presence.PresenceAvailability.DoNotDisturb) { // Set the value of e.Result so that ifElse executes this branch e.Result = true; } else { // Set the value of e.Result so that ifElse does not execute this branch e.Result = false; } }
You use the getApproverPresence activity to obtain the approver’s presence status. If the approver is unavailable, cantBeContactedBranch is executed. Otherwise, canBeContactedBranch is executed. The Results property of the getApproverPresence activity contains the result of the presence query. The getApproverPresense.Results activity is a Dictionary object. To obtain the approver’s presence, the approver’s SIP URI is specified as a key.
Chapter 6
Business Process Communication
157
At this point, the workflow should look like the following:
Task 6: Update cantBeContactedBranch Now you update cantBeContactedBranch, which determines the actions taken when the approver cannot be contacted. In this situation, the workflow contacts the delegate instead. 1. Drag a Code activity inside cantBeContactedBranch and change its name from codeActivity1 to findDelegate. You use this Code activity to find the delegate of the approver. 2. Double-click the findDelegate activity to generate the method stub, and update the method with the following code. The approver’s SIP address is replaced with the delegate’s SIP address. private void findDelegate_ExecuteCode(object sender, EventArgs e) { ApproverSipAddress = OnlineDelegate; }
3. Drag a Goto activity onto the designer canvas below the findDelegate code activity, and then change its name from gotoActivity1 to gotoPresenceQuery.
158
Part III
Unified Communications Managed API Workflow
4. In the Property pane of the gotoPresenceQuery activity, open the TargetActivityName pane by clicking the ellipsis (…) button at the end of the field. 5. Double-click the setParameters code activity to set it as the target activity. At the end of these steps, the workflow should look like the following:
If the approver is unavailable, the workflow returns to the “restart from the presence query” step with the delegate of the primary approver.
Task 7: Update canBeContactedBranch Now you update canBeContactedBranch, which determines the actions to be taken when the approver can be contacted.
Chapter 6
Business Process Communication
159
Task 7.1: Create Branches for Different Modalities Before contacting the approver, the application needs to determine the appropriate modality to use. If the approver’s presence is set to Away, Be Right Back, or Offline, the approver is contacted by phone. If the approver is in a phone call or her presence status is set to Available or Busy, the approver is contacted by IM. The following steps implement this logic: 1. Drag an IfElse activity from the Windows Workflow Foundation v3.0 tab onto the designer canvas inside canBeContactedBranch. 2. In the Property pane, change the name of the first branch from ifelseBranchActivity1 to PhoneMode. PhoneMode defines the path to use to call the approver. 3. Click the PhoneMode branch and change the value of the Condition property from (None) to Declarative Rule Condition. 4. Click the plus sign (+) next to the Condition property to expand it. Type PhoneModeCondition as the value for ConditionName. 5. Click the ellipsis (…) button at the end of the Expression field to open the Select Condition dialog box. Select PhoneModeCondition from the list and click Edit… to open the Rule Condition Editor dialog box. 6. Add the following declarative rule in the Rule Condition Editor dialog box and then click OK. This ensures that canBeContactedBranch is executed if the approver is set to Away or Be Right Back. this.getApproverPresence.Results[ApproverSipAddress].PresenceStatus == Microsoft.Rtc. Collaboration.Presence.PresenceAvailability.Away || this.getApproverPresence.Results[ApproverSipAddress].PresenceStatus == Microsoft.Rtc. Collaboration.Presence.PresenceAvailability.BeRightBack
7. In the Property pane, change the name of the second branch from ifelseBranchActivity2 to IMMode. No condition is required to be set for the IMMode branch because this branch is executed only if the conditions for the PhoneMode branch are not satisfied.
160
Part III
Unified Communications Managed API Workflow
The workflow should look like the following:
Task 7.2: Contact the Approver by Phone The following tasks define the logic for calling and interacting with the approver by phone: 1. Place an outbound phone call to the approver. 2. Bind the outbound phone call to a CommunicationsSequenceActivity. 3. Play an introductory message. 4. Ask the approver about the action he or she wants to take and recognize speech or dual-tone multifrequency (DTMF) input. 5. Branch the responses based on the approver’s input. 6. Define Approve and Decline actions.
Chapter 6
Business Process Communication
161
Task 7.2.1: Place an Outbound Phone Call to the Approver 1. Drag an OutboundCall activity inside the PhoneMode branch and change its name from outboundCallActivity1 to startPhoneCall. The startPhoneCall activity initiates the phone call with the approver. 2. Set the CallType property to AudioVideoCall. 3. Open the Workflow1.xoml.cs file and then add the following code to the setParameters_ ExecuteCode method. This sets up the startPhoneCall activity to place an outbound phone call to the approver’s SIP URI. this.startPhoneCall.CalledParty = ApproverSipAddress;
Task 7.2.2: Bind the Outbound Phone Call to a CommunicationsSequenceActivity In the UCMA Workflow, each CommunicationsSequenceActivity must know on which call it is executing. You achieve this by binding the CallProvider property of CommunicationsSequenceActivity to the CallProvider property of an AcceptCall activity or an OutboundCall activity. 1. Drag a CommunicationsSequence activity after the startPhoneCall activity and change its name from communicationsSequenceActivity1 to speechDialog. The speechDialog activity contains the logic flow of the dialog with the approver over the phone. 2. In the speechDialog Property pane, click the ellipsis (…) button at the end of the field of the CallProvider property to open the Bind CallProvider To An Activity’s Property dialog box, as shown here.
162
Part III
Unified Communications Managed API Workflow
3. Expand the overallcontainer, ifElseActivity1, and canBeContactedBranch nodes in the tree to reach the CallProvider node, which is a property of the startPhoneCall activity, as shown previously. Click on the CallProvider node to select it. 4. Click OK to close the Bind dialog box. This binds the CallProvider property of the speechDialog activity with the CallProvider property of the startPhoneCall activity. The workflow should look like the following:
Chapter 6
Business Process Communication
163
Task 7.2.3: Play an Introductory Message 1. Add a SpeechStatementActivity inside the speechDialog activity and change its name from speechStatementActivity1 to introMessage. The introMessage activity plays the introduction message to the approver. 2. In the MainPrompt property of the introMessage activity, type the message Hello, this is the expense report alerting system.
Task 7.2.4: Prompt the Approver for an Action and Recognize Speech or DTMF Input 1. Add a SpeechQuestionAnswerActivity after the introMessage activity and change its name from speechQuestionAnswerActivity1 to askForActionsQuestion. The askForActionsQuestion activity prompts the approver for input regarding the pending expense report. 2. Type askForActionsQuestion_TurnStarting as the value of the TurnStarting property and then press Enter to generate the stub for the askForActionsQuestion_TurnStarting event handler automatically. The askForActionsQuestion_TurnStarting method dynamically generates the prompt that the askForActionsQuestion activity plays. 3. Update this event handler stub with the following code. private void askForActionsQuestion_TurnStarting(object sender, Microsoft.Rtc.Workflow. Activities.SpeechTurnStartingEventArgs e) { this.askForActionsQuestion.MainPrompt.SetText(string.Format("Report Title Name: {0}, Filed By: {1}, Amount: {2}. Please say approve or decline", ReportTitle, FiledBy, Amount)); }
At this point, you must specify a list of valid speech and DTMF inputs for the question asked by the askForActionsQuestion activity. Define the valid speech and DTMF responses for this question as follows: 4. At the end of the ExpectedSpeechInputs property of the askForActionsQuestion activity, click the ellipsis (…) button to open the String Collection Editor dialog box. 5. Type approve and decline on separate lines. You can type additional synonyms on separate lines as well. 6. Click OK. 7. At the end of the ExpectedDTMFInputs property, click the ellipsis (…) button to open the String Collection Editor dialog box.
164
Part III
Unified Communications Managed API Workflow
8. Type 1 and 2 on separate lines. The DTMF value 1 corresponds to the approve speech input and the DTMF value 2 corresponds to the decline speech input, as specified in step 5. 9. Click OK.
Task 7.2.5: Branch the Responses Based on the Approver’s Action 1. Drag an IfElse activity from the Windows Workflow Foundation v3.0 tab onto the designer canvas after the askForActionsQuestion activity. 2. In the Property pane, change the name of the first branch from ifElseBranchActivity1 to approveBranch. You use approveBranch to define the logic for when the user chooses to approve the pending expense report. 3. Click approveBranch and then change the value of the Condition property from (None) to Declarative Rule Condition. 4. Click the plus sign (+) next to the Condition property to expand it. Type ApproveCondition as the value for ConditionName. 5. At the end of the Expression field, click the ellipsis (…) button to open the Select Condition dialog box. Select ApproveCondition from the list and click Edit… to open the Rule Condition Editor dialog box. 6. In the Rule Condition Editor dialog box, add the following declarative rule. This condition ensures that the branch is executed if the approver wants to approve the expense. this.askForActionsQuestion.RecognitionResult.Text.ToLower().Contains("approve") || this.askForActionsQuestion.RecognitionResult.Text.ToLower().Contains("1")
7. In the Property pane, change the name of ifElseBranchActivity2 to declineBranch. There is no need to set the condition for declineBranch because it is executed only if the condition specified in step 6 is not met. Now, you can use approveBranch to interface with the expense report approval system to approve the expense in question. You can use declineBranch to interface with the expense report approval system to decline the expense in question.
Chapter 6
165
Business Process Communication
The PhoneMode branch that defines the speech dialog should look like the following:
Task 7.2.6: Define Approve and Decline Actions 1. Drag a Code activity inside approveBranch and change its name from codeActivity1 to ApproveExpense. You use ApproveExpense to approve the expense. 2. Drag a Code activity inside declineBranch and change its name from codeActivity1 to DeclineExpense. You use DeclineExpense to decline the expense. 3. Double-click these Code activities to generate the code handlers. You can use these handlers to integrate with the expense reporting system to approve or decline the expense. 4. For this example, update the handlers as follows. private void ApproveExpense_ExecuteCode(object sender, EventArgs e) { // Update this to integrate with expense report management system to approve Console.WriteLine("Expense Approved"); }
expense
private void DeclineExpense_ExecuteCode(object sender, EventArgs e) { // Update this to integrate with expense report management system to decline expense Console.WriteLine("Expense Declined"); }
166
Part III
Unified Communications Managed API Workflow
The phone dialog branch should look like the following:
5. Drag a SpeechStatementActivity after the ApproveExpense code activity inside approveBranch and change its name from speechStatementActivity1 to ExpenseApprovedMessage. You use ExpenseApprovedMessage to play a message to the approver that notifies her or him that the approval process succeeded. 6. Update the MainPrompt property with the message The expense report has been approved. 7. Drag a SpeechStatementActivity after the DeclineExpense code activity inside declineBranch and change its name from speechStatementActivity1 to ExpenseDeclinedMessage. You use ExpenseDeclinedMessage to play a message to the approver that notifies her or him that the decline process finished. 8. Update the MainPrompt property with the message The expense report has been declined. 9. Drag a SpeechStatementActivity after the ifElseActivity3 activity and change its name from speechStatementActivity1 to GoodbyeMessage. You use GoodbyeMessage to play a goodbye message. 10. Update the MainPrompt property with the message Goodbye.
Chapter 6
Business Process Communication
The speech dialog branch should look like the following:
Task 7.3: Contact the Approver by IM The following tasks define the logic for interacting with the approver by IM: 1. Place an outbound IM call to the approver. 2. Bind the outbound IM call to a CommunicationsSequenceActivity. 3. Send an introductory IM message. 4. Prompt the approver for an action and recognize IM input. 5. Branch the responses based on the approver’s input. 6. Define approve and decline actions.
167
168
Part III
Unified Communications Managed API Workflow
Task 7.3.1: Place an Outbound IM Call to the Approver 1. Drag an OutboundCallActivity inside the IMMode branch and change its name from outboundCallActivity1 to startIMSession. You use startIMSession to start an outbound IM session with the approver. 2. Set the CallType property of startIMSession to InstantMessagingCall. 3. Open the Workflow1.xoml.cs file and then add the following code to the setParameters_ ExecuteCode method to set the SIP URI to match the approver’s SIP URI. this.startIMSession.CalledParty = ApproverSipAddress;
Task 7.3.2: Bind the Outbound IM Call with a CommunicationsSequenceActivity As mentioned during Task 7.2, the CallProvider property of CommunicationsSequenceActivity must be bound with the CallProvider property of the OutboundCall activity. 1. Drag a CommunicationsSequenceActivity after the startIMSession and change its name from communicationsSequenceActivity1 to imDialog. imDialog defines the IM dialog that interacts with the approver. 2. In the imDialog Property pane, click the ellipsis (…) button at the end of the field next to the CallProvider property to open the Bind dialog box, as shown here.
3. Expand the tree in the Bind dialog box until you reach the properties of startIMSession. 4. Click the CallProvider property of startIMSession and then click OK.
Chapter 6
Business Process Communication
169
The speechDialog activity is collapsed in all screenshots while you develop the IM dialog. The workflow should look like the following:
Task 7.3.3: Send an Introductory IM Message 1. Add an InstantMessagingStatementActivity inside imDialog and change its name from instantMessagingStatementActivity1 to introIMMessage. 2. Update the MainPrompt property with the message Hello, this is the expense report alerting system.
170
Part III
Unified Communications Managed API Workflow
Task 7.3.4: Prompt the Approver for an Action and Recognize IM Input 1. Add an InstantMessagingQuestionAnswerActivity after the introIMMessage activity and change its name from instantMessagingStatementActivity1 to askForActionsIMQuestion. 2. Type askForActionsIMQuestion_TurnStarting as the value of the property TurnStarting and then press Enter to generate the stub for the TurnStarting event handler automatically. 3. Update the TurnStarting event handler stub with the following code. private void askForActionsIMQuestion_TurnStarting(object sender, Microsoft.Rtc. Workflow.Activities.InstantMessagingTurnStartingEventArgs e) { this.askForActionsIMQuestion.MainPrompt = string.Format("Report Title Name: {0}, Filed By: {1}, Amount: {2}. Please enter approve or decline", ReportTitle, FiledBy, Amount); }
You must specify a list of valid text inputs for the question asked by the askForActionsIMQuestion activity. Specify the following text inputs as valid answers. 4. At the end of the ExpectedInputs property, click the ellipsis (…) button to open the String Collection Editor dialog box. 5. Type approve or decline in separate lines in the dialog box. You can type additional synonyms on separate lines as well. 6. Click OK.
Task 7.3.5: Branch the Responses Based on the Approver’s Input 1. Drag an IfElse activity from the Windows Workflow Foundation v3.0 tab onto the designer canvas after the askForActionsIMQuestion activity. 2. In the Property pane, change the name of the ifElseBranchActivity1 branch to approveIMBranch. You use approveIMBranch to define the logic when the user approves the pending expense report. 3. Click approveIMBranch and change the Condition property from (None) to Declarative Rule Condition. 4. Click the plus sign (+) next to the Condition property to expand it, and then type ApproveIMCondition as the value of ConditionName. 5. At the end of the Expression field, click the ellipsis (…) button to open the Select Condition dialog box. Select ApproveIMCondition from the list and click Edit… to open the Rule Condition Editor dialog box.
Chapter 6
Business Process Communication
171
6. In the Rule Condition Editor dialog box, add the following declarative rule. This condition ensures that the branch is executed if the approver wants to approve the expense. this.askForActionsIMQuestion.RecognitionResult.Text.ToLower().Contains("approve")
7. In the Property pane, change the name of the ifElseBranchActivity2 branch to declineIMBranch. There is no need to set the condition for this branch because it is executed only if the condition specified in step 6 is not met. Now, you can use approveIMBranch to interface with the expense report approval system to approve the expense in question. You can use declineIMBranch to interface with the expense report approval system to decline the expense in question. The workflow should now look like the following:
Task 7.3.6: Define Approve and Decline Actions 1. Drag a Code activity inside approveIMBranch and change its name from codeActivity1 to ApproveIMExpense. You use ApproveIMExpense to approve the expense. 2. Drag another Code activity inside declineIMBranch and change its name from codeActivity1 to DeclineIMExpense. You use DeclineIMExpense to reject the expense.
172
Part III
Unified Communications Managed API Workflow
3. Select ApproveIMExpense and, in the Property pane, set the ExecuteCode value to ApproveExpense_ExecuteCode as follows:
4. Take the same action for DeclineIMExpense and set its ExecuteCode value to DeclineExpense_ExecuteCode. By performing these steps, you ensure that the approval or decline actions through speech or IM execute the same code. The IM dialog branch should now look like the following:
5. Drag an InstantMessagingStatementActivity after ApproveIMExpense and change its name from instantMessagingStatementActivity1 to ExpenseApprovedIMMessage. You
Chapter 6
Business Process Communication
173
use ExpenseApprovedIMMessage to send a message to the approver notifying him or her that the approval process succeeded. 6. Update the MainPrompt property with the message The expense report has been approved. 7. Drag an InstantMessagingStatementActivity after DeclineIMExpense and change its name from instantMessagingStatementActivity1 to ExpenseDeclinedIMMessage. You use ExpenseDeclinedIMMessage to play a message to the approver notifying him or her that the decline process succeeded. 8. Update the MainPrompt property with the message The expense report has been declined. 9. Drag an InstantMessagingStatementActivity after ifElseActivity4 and change its name from instantMessagingStatementActivity1 to GoodbyeIMMessage. You use GoodbyeIMMessage to play a goodbye message. 10. Update the MainPrompt property with the value Goodbye. The IM dialog branch should now look like the following:
174
Part III
Unified Communications Managed API Workflow
Task 7.4: Add Commands to the Dialog In this task, you enhance the user interface by providing a more natural dialog flow. By performing the following steps, you add commands for help and repeat to the speech dialog and add a command for help to the IM dialog.
Task 7.4.1: Add Commands to the Speech Dialog 1. Right-click the speechDialog activity and then click View Commands to open the Commands view. 2. Drag SpeechHelpCommandActivity onto the Commands view. You use SpeechHelpCommandActivity to provide help to users when they request it. 3. At the end of the ExpectedSpeechInputs property, click the ellipsis (…) button to open the String Collection Editor dialog box and specify the list of text inputs that you want this command to recognize. 4. In the String Collection Editor dialog box, type help. You can type other synonyms on separate lines as well. 5. Click OK. 6. Drag a SpeechRepeatCommand onto the Commands view. You use SpeechRepeatCommand to repeat the question to the user when requested. 7. At the end of the ExpectedSpeechInputs property, click the ellipsis (…) button to open the String Collection Editor dialog box and specify the list of text inputs that you want this command to recognize. 8. In the Array Builder dialog box, type repeat. You can type other synonyms on separate lines as well. 9. Click OK. At this point, the speech dialog has been updated with speech help and speech repeat commands. Follow the next steps to define how you want the workflow to respond when the user triggers any of these commands. The following steps define the application behavior: 10. Right-click the speechDialog activity and click View CommunicationsSequenceActivity to open the Main view of the speechDialog activity. 11. Select askForActionsQuestion activity and, in the Property pane, expand the Prompts property. 12. Update the HelpPrompt property with the message Please say Approve or press 1 to approve the expense report, or say Decline or press 2 to decline the expense report.
Chapter 6
Business Process Communication
175
13. Update the RepeatPrompt property in the askForActionsQuestion_TurnStarting method in the Workflow1.xoml.cs file by adding the following code. this.askForActionsQuestion.Prompts.RepeatPrompt.SetText(string.Format("Report Title Name: {0}, Filed By: {1}, Amount: {2}. Please say approve or decline", ReportTitle, FiledBy, Amount));
Task 7.4.2: Add Commands to the IM Dialog 1. Right-click the imDialog activity and click View Commands to open the Commands view. 2. Drag an InstantMessagingHelpCommand onto the Commands view. You use InstantMessagingHelpCommand to provide help to users when they request it. 3. At the end of the ExpectedInputs property, click the ellipsis (…) button to open the String Collection Editor dialog box and specify the list of text inputs that you want to recognize for this command. 4. In the String Collection Editor dialog box, type help. You can type other synonyms on separate lines as well. 5. Click OK. At this point, you have updated the IM dialog with an IM help command. The following steps define how the workflow should respond if the user triggers any of these commands. The following steps define the application behavior: 6. Right-click the imDialog activity and click View CommunicationsSequenceActivity to open the Main view of the imDialog activity. 7. Select askForActionsIMQuestion and, in the Property pane, expand the Prompts property. 8. Update the HelpPrompt property with the message Please enter Approve to approve the expense report, or enter Decline to decline the expense report.
Task 7.5: Disconnecting the Call After the phone or IM dialog completes, the application must disconnect the call. To do this, drag a DisconnectCall activity after the ifElseActivity1 activity.
Task 7.6: Add Events to the Dialog In this task, you add handlers to the phone and IM dialog in case the user has difficulty responding or the application fails to understand user input. Similar to commands, these handlers improve the user dialog interface by either giving users better options (such as DTMF) or transferring to a live agent. In this example, the dialog event handlers disconnect
176
Part III
Unified Communications Managed API Workflow
the call. Follow these steps to add dialog event handlers to the speech and IM dialog of the application.
Task 7.6.1: Add Events to the Speech Dialog 1. Right-click the speechDialog activity and click View CommunicationsEvents to open the Events view. 2. Drag a ConsecutiveSilencesSpeechEvent activity onto the text Drop A CommunicationsEvent Here. By default, it is named consecutiveSilencesSpeechEventActivity1, and it is executed when the user stays silent in response to a question three times in a row. 3. Drag a Goto activity inside consecutiveSilencesSpeechEventActivity1 and onto the text Drop Activities Here. The default name for this activity is gotoActivity1. 4. In the Property pane, set the TargetActivityName property of gotoActivity1 that you added in step 3 to disconnectCallActivity1. 5. Drag a ConsecutiveNoRecognitionsSpeechEvent activity in the view next to consecutiveSilencesSpeechEventActivity1. By default, it is named consecutiveNoRecognitionsSpeechEventActivity1, and it is executed when the user’s speech or DTMF response is not recognized three times in a row. 6. Drag a Goto activity inside consecutiveNoRecognitionsSpeechEventActivity1 and onto the text Drop Activities Here. 7. In the Property pane, set the TargetActivityName of gotoActivity2 that you added in step 6 to disconnectCallActivity1. 8. Drag a ConsecutiveNoInputsSpeechEvent activity into the view next to consecutiveNoRecognitionsSpeechEventActivity1. By default, it is named consecutiveNoInputsSpeechEventActivity1, and it is executed when the user stays silent or his or her speech or DTMF response is not recognized three times in a row. 9. Drag a Goto activity inside consecutiveNoInputsSpeechEventActivity1 and onto the text Drop Activities Here. 10. In the Property pane, set the TargetActivityName of gotoActivity3 that you added in step 9 to disconnectCallActivity1.
Task 7.6.2: Add Events to the IM Dialog 1. Right-click the imDialog activity and click View CommunicationsEvents to open the Events view. 2. Drag a ConsecutiveSilencesInstantMessagingEvent activity in the view onto the text Drop A CommunicationsEvent Here. By default, it is named consecutiveSilencesInstantMessagingEventActivity1, and it is executed when the user does not respond to a question three times in a row.
Chapter 6
Business Process Communication
177
3. Drag a Goto activity inside consecutiveSilencesInstantMessagingEventActivity1 and onto the text Drop Activities Here. 4. In the Property pane, set the TargetActivityName of gotoActivity4 that you added in step 3 to disconnectCallActivity1. 5. Drag a ConsecutiveNoRecognitionsInstantMessagingEvent activity in the view next to consecutiveSilencesInstantMessagingEventActivity1. By default, it is named consecutiveNoRecognitionsInstantMessagingEventActivity1, and it is executed when the user’s IM response is not recognized three times in a row. 6. Drag a Goto activity inside consecutiveNoRecognitionsInstantMessagingEventActivity1 and onto the text Drop Activities Here. 7. In the Property pane, set the TargetActivityName of gotoActivity5 that you added in step 6 to disconnectCallActivity1. 8. Drag a ConsecutiveNoInputsInstantMessagingEvent activity in the view next to consecutiveNoRecognitionsInstantMessagingEventActivity1. By default, it is named consecutiveNoInputsInstantMessagingEventActivity1, and it is executed when the user does not respond or her or his IM response is not recognized three times in a row. 9. Drag a Goto Activity inside consecutiveNoInputsInstantMessagingEventActivity1 and onto the text Drop Activities Here. 10. In the Property pane, set the TargetActivityName of gotoActivity6 that you added in step 9 to disconnectCallActivity1.
Task 7.7: Add Call Events Now, you need to update the application to support disconnection of a phone call or an IM call. This is necessary to prepare the application to handle a user disconnecting the phone call or IM in the middle of a dialog. Follow these steps to add this support: 1. Right-click the overallContainer activity and click View CommunicationsEvents to open the Events view. 2. Drag a CallDisconnectedEventActivity activity in the view onto the text Drop a CommunicationsEvent Here and then, in the Property pane, change its name from callDisconnectedEventActivity1 to handleCallDisconnect. By doing this, you ensure that the application can handle the situation when the user disconnects the call. If you want the application to take specific action on a disconnected call, you can do this by dragging activities inside the handlerCallDisconnect activity. An example of this type of action is logging the call length.
178
Part III
Unified Communications Managed API Workflow
Task 8: Running the Application To run the application, you need the following: 1. A user account (for example, [email protected]) for the approver logged on to Office Communications Server from Office Communicator. 2. A user account (for example, [email protected]) for the approver’s delegate logged on to Office Communications Server from Office Communicator on a different computer. Follow these steps to run the application: 1. Verify that the presence status of the approver account is set to Available. 2. In Visual Studio, press F5. 3. When the console window opens and the application prompts with “Enter the approver’s SIP URI or Exit to close the application:,” type the SIP URI of the approver. 4. When the application prompts “Enter the Expense report Title:”, type the expense report title. 5. When the application prompts “Enter the Expense report amount:”, type the expense report amount. 6. When the application prompts “Enter the name of the person filing the report:”, type the name of the person filing the report. 7. When the application prompts “Enter the SIP URI of an online delegate:”, type the SIP URI of the online delegate. 8. Click the incoming call notification on the approver machine when the application tries to connect to the approver. Start interacting with the application once the call is established. To test the branch that finds the delegate, perform the following steps: 1. Verify that the approver presence is set to Offline. 2. In Visual Studio, press F5. 3. When the application prompts “Enter the approver’s SIP URI or Exit to close the application”, type the SIP URI of the approver, who is offline. 4. When the application prompts “Enter the expense report title”, type the expense report title. 5. When the application prompts “Enter the expense report amount”, type the expense report amount. 6. When the application prompts “Enter the name of the person filling the report”, type the name of the person filing the report.
Chapter 6
Business Process Communication
179
7. When the application prompts “Enter the SIP URI of an online delegate”, type the SIP URI of the online delegate. 8. The application contacts the delegate account specified in step 7.
Summary This chapter discussed how to implement an application using the UCMA Workflow for business process communications and information access from different modalities, such as phones or IM. By using Visual Studio 2008, you can add communication activities to an application easily by dragging them onto the designer canvas and setting them up to interact with the user over a new interface (for example, phone and IM). The scenario explored in this chapter, an expense report approval process, demonstrates how you can use the UCMA Workflow to enable your applications for Unified Communications quickly.
Additional Resources N
“Unified Communications Managed API 2.0 Workflow SDK Documentation” (http://go.microsoft.com/fwlink/?LinkID=133578)
Part IV
Unified Communications Managed API Part IV covers the Unified Communications Managed API (UCMA), as shown in the following illustration. This API is completely written in managed code using C# and has a small footprint. It provides a powerful API that can easily scale to thousands of connections to Microsoft Office Communications Server. In addition, you will find that it is very versatile. Your Application
Your Application
Your Application
Communicator Automation API Office Communicator 2007 R2 Customizations
UCMA 1.0
UC Workflow API
Unified Communications Managed API 2.0
Office Communications Server 2007 R2
Chapter 7, “Structure of a UCMA Application,” explains the API in detail, and Chapter 8, “Publishing Custom Presence with UCMA,” describes an example of how to extend the Office Communications Server Enhanced Presence.
181
Chapter 7
Structure of a UCMA Application This chapter will help you to: N
Understand the general structure of a Unified Communications Managed API (UCMA) Core application.
N
Understand how to create a UCMA Core application.
N
Understand the structure of the CollaborationPlatform class.
N
Understand how to create and control multimodal calls that include both instant messaging (IM) and audio.
N
Understand how to create, schedule, and participate in multiparty conferences.
N
Understand how to publish and subscribe to presence information.
Creating a UCMA Application As its name indicates, Unified Communications Managed API (UCMA) is a Microsoft .NET Framework–managed API. As such, this API benefits from all of the features that the .NET Framework provides. Because this API is highly scalable, it is ideal for building server applications. It can support thousands of endpoints and concurrent client connections. Applications built using UCMA can be load-balanced for high availability. Many of the services in Microsoft Office Communications Server use the UCMA stack. This chapter explains the anatomy of the UCMA. Creating a UCMA application involves the following programming steps: 1. Instantiate the CollaborationPlatform object that is responsible for managing connections between the local endpoint and the server (or other endpoints), dispatching messages to endpoints, or providing other services. For a server or middle-tier application, the process involves creating an instance of the ServerPlatformSettings class that is initialized with information provided from the provisioning process. For a client application, this process involves creating an instance of the ClientPlatformSettings class to specify the connection transport. 2. Create one or more instances of ApplicationEndpoint or UserEndpoint depending on the application requirements. Typically, you use ApplicationEndpoint for an application that provides services to other clients. This application runs under its own security context and does not require any user credentials. An application that uses UserEndpoint executes in the security context of the corresponding user. If the application is not configured as trusted by Office Communications Server, it requires the user credentials. 183
184
Part IV
Unified Communications Managed API
3. Publish and receive presence information for the application or a user. To publish presence, you need to use the LocalOwnerPresence property of an endpoint instance. To receive presence, you need to use the RemotePresence property of an endpoint instance. An application can receive the presence information on an “ongoing” (subscription) or “on-demand” (query) basis. 4. Create conversations between the local participant and a remote participant, and handle calls between the participants. Every conversation is bound to an established endpoint when the conversation is created. To handle incoming calls, the application must register type-specific call handlers with the local endpoint by calling the RegisterForIncomingCall method on the endpoint instance. 5. Schedule and join a conference involving more than two participants. In a conference, participants converse with each other indirectly through appropriate multipoint control units (MCUs). For a UCMA application, MCUs for instant messaging (IM) and audio/ video (A/V) calls are supported. A two-party conversation is changed into a conference when more participants are invited to join. This process is known as escalating a conversation into a conference. Either for presence or conversations, the operations of the UCMA application consist of asynchronous processing of messages to and from the Office Communications Server or to and from any remote endpoints involved in active sessions of the application. When deployed as server-based applications that support large numbers of connections, the UCMA applications must be trusted by Office Communications Server and the application host computer must be configured to support Mutual Transport Layer Security (MTLS). This process is referred to as application provisioning and must be performed before you can run any trusted UCMA application. For details, see the “Configuring UCMA Core” section in Chapter 9, “Preparing the UC Development Environment.”
CollaborationPlatform The application uses the CollaborationPlatform class to manage the connection between Office Communications Server and the application. A UCMA application can instantiate this class as either a server platform or a client platform, depending on the choice of the input parameter provided to the CollaborationPlatform constructor. For the server platform, the class constructor takes an instance of the ServerPlatformSettings class. For the client platform, the constructor takes an instance of the ClientPlatformSettings class. You use the ClientPlatformSettings class to instantiate a number of endpoints (for example, to emulate a large number of clients to stress-test an application). You use the ServerPlatformSettings class to create server-based applications that provide services to many clients. Query/response Web robots are examples of these types of applications. When an application uses the ServerPlatformSettings class to configure the CollaborationPlatform object, the UCMA library configures and manages a pool of multiple connections to Office Communications Server
Chapter 7
Structure of a UCMA Application
185
that is designed to maximize the flow of data between the application and the Office Communications Server. This provides for large-scale message processing in the application. Every UCMA application must create, configure, and start a CollaborationPlatform instance before it proceeds to calling other UCMA features.
Creating the Collaboration Platform for a Server Application Listing 7-1 shows how to create and configure a CollaborationPlatform class for use by a server application. LISTING 7-1 Creating and Configuring a CollaborationPlatform Class private static void PreparePlatformAndEndpoint() { //Load the local machine's certificate X509Certificate2 cert = GetLocalCertificate(); //create a ServerPlatformSettings instance to //initialize a CollaborationPlatform instance ServerPlatformSettings platformSettings = new ServerPlatformSettings( ConfigurationManager.AppSettings["ocsUserAgentUCMALab1"], Dns.GetHostEntry("localhost").HostName, Int32.Parse(ConfigurationManager.AppSettings["appLocalPort"]), ConfigurationManager.AppSettings["appGruu"], cert); //Collaboration platform initialization _collabPlatform = new CollaborationPlatform(platformSettings); //Now that the CollaborationPlatform is configured, call BeginStartup. _collabPlatform.BeginStartup(EndCollabStartup, _collabPlatform); }
In Listing 7-1, the parameters, which are used as the CollaborationPlatform settings and passed to instantiate the ServerPlatformSettings class, are read from the application configuration file associated with the application by using the ConfigurationManager class defined in the .NET Framework. This file is created as a part of creating the application. By centralizing these settings in the application configuration file, you provide a single source of configuration information for managing them as the application is moved from the development environment to the testing and deployment phases.
Starting the Collaboration Platform Starting the newly created platform is an asynchronous process and involves calling the BeginStartup method on the CollaborationPlatform class to start the process and calling the CollaborationPlatform.EndStartup method when the startup process finishes. The
186
Part IV
Unified Communications Managed API
BeginStartup method takes two input parameters. The first parameter is an instance of the callback method to be invoked when the startup operation completes. The second parameter is the input parameter to the callback method. The instance of the CollaborationPlatform (_collabPlatform) is not ready for use until this startup process finishes successfully. To determine the status of the platform startup, a UCMA application must implement the callback routine to call CollaborationPlatform.EndStartup and to verify the status of the operation. The following code example shows this asynchronous programming pattern. void BeginPlatformStartup() { AsyncCallback callback = new AsyncCallback(EndPlatformStartup); this._collabPlatform.BeginStartup(callback, _collabPlatform); } void EndPlatformStartup(IAsyncResult result) { if (!result.IsCompleted) return; CollaborationPlatform platform = result.AsyncState as CollaborationPlatform; if (platform == null) return; try { platform.EndStartup(result); _platformReady = true; } catch (Exception excep) { //Process any errors here. } // proceed to other tasks ... }
This asynchronous pattern of calling BeginOperation and passing in the EndOperation callback parameter is repeated in almost all operations in the UCMA. It provides the scalability of throughput required by the UCMA server applications.
Note This asynchronous programming pattern must be used when the application is deployed in production. However, this can also make debugging the application during development difficult. One tip to make debugging easier is to turn the asynchronous operations into synchronous operations using the following programming pattern. //Synchronously call the Startup method _collabPlatform.EndStartup(_collabPlatform.BeginStartup(null, null));
Here the callback routine and its input parameters are not used and the two corresponding input parameters of BeginStartup are both set to NULL.
Chapter 7
Structure of a UCMA Application
187
Endpoints Endpoints represent users or applications that engage each other in conversations or conferences, publish their own presence, or receive others’ presence. In UC, endpoints are identified by the Session Initiation Protocol (SIP) Uniform Resource Identifiers (URIs) and other supplemental identification information, such as endpoint ID or application Globally Routable User Agent URI (GRUU). You can think of a SIP URI as an identification of a security principle, whereas endpoint ID or GRUU helps to differentiate different instances of endpoints that are owned by the same security principle. The UCMA defines an abstract class named LocalEndpoint to represent endpoints that are used to communicate with each other and with Office Communications Server. Applications use either ApplicationEndpoint or UserEndpoint, both of which inherit from LocalEndpoint, depending on the scenario and requirements. It is possible, however, for an application to create and use both types of endpoints or to create and use multiple endpoints of the same type.
Using ApplicationEndpoint An application endpoint represents a running instance of a UCMA application that must be trusted by Office Communications Server. It is encapsulated by the ApplicationEndpoint class. This type of application connects to the server using the MTLS protocol. Both the server and the application provide each other with a certificate issued by a mutually trusted certificate authority (CA). Application endpoints are mostly used for server or middle-tier applications providing UC services. An example of this type of application is an IM Web robot that is used to broadcast alerts across a network. A UCMA application that uses ApplicationEndpoint must register the underlying ApplicationEndpoint instance with Office Communications Server if it wants to support presence and UC session services. This also means that the application must be a server application with the CollaborationPlatform instance configured by a ServerPlatformSettings instance. For most UC scenarios, registration with Office Communications Server is required. To enable or disable the registration, the ApplicationEndpoint and ApplicationEndpointSettings classes expose the UseRegistration property. When this property is set to True, the endpoint is registered with the server. If it is set to False, the endpoint is not registered with the server. An application that is based on ApplicationEndpoint is identified by a SIP URI assigned to a Contact object in Active Directory Domain Services. Defining and configuring this Contact object is part of the application provisioning process. The SIP URI of the Contact object is used to register the application with Office Communications Server. The Contact object also defines a display name and a telephone URI that become associated with the application.
188
Part IV
Unified Communications Managed API
Creating an instance of ApplicationEndpoint involves first creating an instance of the ApplicationEndpointSettings class that defines the attributes of the ApplicationEndpoint. These attributes include the following: N
The SIP URI to be used to register with Office Communications Server
N
The fully qualified domain name (FQDN) of the server running Office Communications Server
N
The port number used to connect to Office Communications Server
N
The GRUU that is assigned to the application in the provisioning process
In addition, the UseRegistration property on the ApplicationEndpointSettings instance can be set to True if the application requires that the endpoint must register with Office Communications Server to use the presence and session services. You can use the UseRegistration property on the ApplicationEndpoint instance for this purpose as well. A newly created ApplicationEndpoint instance must be connected to Office Communications Server before it can be functional. To establish this connection, the application must start the process by calling the ApplicationEndpoint.BeginEstablish method and finish the process by calling the ApplicationEndpoint.EndEstablish method after the operation succeeded. Listing 7-2 illustrates the programming pattern to create an ApplicationEndpoint instance and to establish the connection between the endpoint and the underlying server. LISTING 7-2 Programming Pattern for an ApplicationEndpoint Instance //Create the ApplicationEndpointSettings to define the properties of the Endpoint. //These properties are the SIP URI that identifies this endpoint, the FQDN of the //Office Communications Server to connect to, the TCP port to use for the connection, //and the GRUU that uniquely identifies this application to the OCS server. ApplicationEndpointSettings settings = new ApplicationEndpointSettings( ConfigurationManager.AppSettings["appUri"], ConfigurationManager.AppSettings["ocsServerFqdn"], Int32.Parse(ConfigurationManager.AppSettings["ocsServerTlsPort"]), ConfigurationManager.AppSettings["appGruu"], cert); //Enable registration settings.UseRegistration = true; //Create the ApplicationEndpoint //Binding it to the CollaborationPlatform previously created ApplicationEndpoint _appEndpoint = new ApplicationEndpoint(_collabPlatform, settings); //asynchronously call the Establish method _appEndpoint.BeginEstablish(EndEstablishEndpoint, _appEndpoint);
Chapter 7
Structure of a UCMA Application
189
Note that in Listing 7-2, the configuration settings for the endpoint come from the configuration file associated with the application. The call to ApplicationEndpoint.BeginEstablish is required to initialize the endpoint and must complete successfully before the endpoint can be used. The status of the BeginEstablish method is returned in the EndEstablishEndpoint callback.
Using UserEndpoint A user endpoint registers with Office Communications Server using the SIP URI that is assigned to the corresponding Active Directory User object that has been enabled for Office Communications Server. This User object could be a user account defined specifically for this application or associated with a real user. The UserEndpoint class allows UCMA applications to register with Office Communications Server and perform operations on behalf of the user. Creating a UserEndpoint instance involves configuring the settings for UserEndpoint. You use the settings to specify the SIP URI of the user and the FQDN and port number of the underlying server. These settings are encapsulated by the UserEndpointSettings class. The UserEndpoint instance must also be bound to an initialized CollaborationPlatform instance. This binding is specified when UserEndpoint is instantiated. To establish a UserEndpoint instance, you use similar semantics and follow a similar programming pattern as you do to establish an ApplicationEndpoint instance. The main difference is that the UserEndpoint instance uses the SIP URI of an Active Directory User object, whereas an ApplicationEndpoint object uses the SIP URI of an Active Directory Contact object. Listing 7-3 illustrates the programming pattern that establishes a UserEndpoint instance. LISTING 7-3 C# Programming Pattern to Establish a UserEndpoint Instance UserEndpointSettings settings = new UserEndpointSettings("sip:user1@domain", ConfigurationManager.AppSettings["OCSserverFqdn"], ConfigurationManager.AppSettings["applicationServerPort"]); UserEndpoint _userEndpoint = new UserEndpoint(_collabPlatform, settings); _userEndpoint.BeginEstablish(EndpointEstablish, _userEndpoint);
In Listing 7-3, the SIP URI that is used to register the endpoint with Office Communications Server is sip:user1@domain. Note that the sip: prefix is required. This SIP URI must belong to an Active Directory User object that is enabled for UC. In this code example, it is assumed that the UCMA application is trusted by Office Communications Server and Transport Layer Security (TLS) is used as the transport between the application and the server. If the application is not trusted by the server or Transmission Control Protocol (TCP) is used as the transport, you must specify the user credentials on the UserEndpointSettings.Credentials property to establish the endpoint.
190
Part IV
Unified Communications Managed API
Conversation, Call, and Call Flow After you have successfully established a local endpoint, you can use it to create a conversation in which the local participant makes a call to a remote participant. The local endpoint can also join a conversation by accepting an invitation to a call from a remote participant. In UCMA, a conversation encapsulates the participants and the calls between or among the participants. Each call consists of a flow of media. Thus, a call has a specific modality. The supported modalities include IM and A/V. Programmatically, these modality-specific calls are encapsulated by the InstantMessagingCall and AudioVideoCall classes. The corresponding media flows are encapsulated by the InstantMessagingFlow and AudioVideoFlow classes.
Note While the class name in UCMA 2.0 is AudioVideoCall, the only media type supported in this release is audio.
Figure 7-1 illustrates these concepts. UserEndpoint Owner: User A Conversation instance LocalParticipant: User A RemoteParticipant: User B InstantMessagingCall InstantMessagingFlow AudioVideoCall AudioVideoFlow
UserEndpoint Owner: User B Conversation instance
OCS Infrastructure
LocalParticipant: User B RemoteParticipant: User A InstantMessagingCall InstantMessagingFlow AudioVideoCall AudioVideoFlow
FIGURE 7-1 A two-party conversation involving IM and A/V calls.
Chapter 7
Structure of a UCMA Application
191
A conversation involving more than two participants is referred to as a conference. In a twoparty conversation (referred to as a conversation from here on) the participants make calls to each other directly. In a conference, the participants call each other with the help of MCUs that are configured for the supported Office Communications Server deployment. The media stream flows between a local participant’s endpoint and the set of MCUs that are configured to support the conference.
Creating Calls In UCMA, a call corresponds to a modality-specific channel in a communication session. The supported modalities include IM and audio. This means that a UCMA application can make and receive IM and audio calls, provided that an endpoint is established. The type of endpoint can be either an ApplicationEndpoint or UserEndpoint. Calls are managed by sessions. In UCMA, a session is represented by an instance of the Conversation class. Programmatically speaking, a Conversation consists of participants and modality-appropriate calls. The steps to establish calls between two parties are as follows: 1. Create a call. 2. Handle incoming calls. 3. Handle call flows. 4. Handle call state and messages. The relationship between the classes involved in making calls was shown previously in Figure 7-1. Classes are instantiated from the ”outside in“ using the asynchronous call pattern. Each class instance is not ready for operations until its EndOperationCallback method is called and returns a success status. For example, you must create a valid instance of the Conversation class before you can create an instance of the Call class. You need a valid instance of a Call class, such as InstantMessagingCall or AudioVideoCall, to create and use the Flow classes (that is, InstantMessagingFlow or AudioVideoFlow) to exchange data during the call. The Call classes, InstantMessagingCall and AudioVideoCall, represent instances of sessions using the specified media type. The properties of the Call classes define things such as the participants, the state of the call (for example, established or ending) and also the instance of the Flow class that is associated with the call after it is established. The Flow class encapsulates the information related to the actual media (IM text or audio streams) that belong to the call. After a call has been established (that is, the call was offered by the caller and answered by the called party), the application uses the Flow class to send and receive the messages over the call.
192
Part IV
Unified Communications Managed API
Creating a Call To simplify the code, the following example shows the steps to create and use a call using the synchronous design pattern. Note that you should use the asynchronous design pattern for production code. While this sample uses an IM call, the pattern is the same for audio calls. The steps for creating a call are as follows: 1. Use _appEndpoint to create a new instance of the Conversation class named _currentConversation. 2. Use _currentConversation to create a new instance of the InstantMessagingCall class named _currentImCall. 3. Use the BeginEstablish method of _currentImCall to set the parameters of the IM call, such as the target SIP URI. 4. Use the Flow class that is associated with _currentImCall when it is established to send a message saying “Hello World.” 5. Use the BeginTerminate method of _currentImCall to signal that the call is being ended. 6. Use the BeginTerminate method of _currentConversation to delete and clean up the Conversation class. The UCMA code to implement the logic in the previous list is as follows. // Create the conversation Conversation _currentConversation = new Conversation(_appEndpoint); // Create the IM call InstantMessagingCall _currentImCall = new InstantMessagingCall(_currentConversation); // Establish the call synchronously _currentImCall.EndEstablish(_currentImCall.BeginEstablish("SIP:user1@domain", null, // Toast Message null, // Callback routine is not used in the synchronous pattern null)); // Context object // Send the message synchronously _currentImCall.Flow.EndSendMessage( _currentImCall.Flow.BeginSendMessage("Hello World!", null, null)); // Terminate the call synchronously _currentImCall.EndTerminate(_currentImCall.BeginTerminate(null, null)); // Terminate the conversation synchronously _currentConversation.EndTerminate(_currentConversation.BeginTerminate(null, null));
Handling Incoming Calls For an endpoint to accept incoming calls, it must register an event handler for the RegisterForIncomingCall event. This event handler is called whenever there is an incoming call request to this endpoint. For example: _appEndpoint.RegisterForIncomingCall(On_InstantMessagingCall_Received);
Chapter 7
Structure of a UCMA Application
193
This code registers the callback method, On_InstantMessagingCall_Received. This callback method is called when an incoming IM call is received for the endpoint, _appEndpoint. Note that the RegisterForIncomingCall event is defined using a generic type. This allows the application to use the same event pattern for AudioVideoCall as well as for other custom modality types defined by the application. Custom modalities are defined by creating a new call type to pass as the specifier for the generic type. An example of a handler for an incoming AudioVideoCall is as follows. _appendpoint.RegisterForIncomingCall(On_AudioVideoCall_Received);
The handler for this event is called when an incoming AudioVideoCall request is received. A typical handler can examine the details of the session request, such as the SIP URI of the sender, the subject of the call, the priority of the call, or any other call properties that are needed, to make the decision to either accept or reject the request.
Note The other properties of the Call are defined in the UCMA documentation on the Call class. The following is an example of an event handler for an IM call. void On_InstantMessagingCall_Received(object sender, CallReceivedEventArgs e) { _instantMessagingCall = e.Call; /* Register a handler for the Call.StateChanged event to receive the call state transitions. */ _instantMessagingCall.StateChanged += new EventHandler(_instantMessagingCall_StateChanged); // Remote Participant URI represents the caller. // Toast is the message set by the caller as the 'greet' message in the call. Console.WriteLine("Call Received! From: " + e.RemoteParticipant.Uri + " Toast is: " + e.ToastMessage); // Now, accept the call. _instantMessagingCall.BeginAccept(EndAcceptCall, _instantMessagingCall); }
Handling Call Flows After the application accepts the call, the underlying UCMA code builds an instance of the Flow class that is used to handle the media, either IM or audio, that is a part of the call. Because this setup is handled automatically by the UCMA library, the application only needs to register for the event that has the modality of interest. In the following code example, the application registers for the InstantMessagingFlowConfigurationRequested event to track the progress of the creation of the Flow request. This registration can be done by using the StateChanged event handler for the call after the call state, which uses the State property
194
Part IV
Unified Communications Managed API
of the call, is reported to be “Established.” For an AudioVideoCall, the coresponding event is called AudioVideoFlowConfigurationRequested. /* Subscribe for the flow event. When this event is received, the media flow associated with the call is created and can be used to send and receive IM messages. */ _instantMessagingCall.InstantMessagingFlowConfigurationRequested += this.instantMessagingCall_FlowConfigurationRequested;
After the flow is available for the call, the media (that is, IM or audio) can be exchanged during the call. After the InstantMessagingFlowConfigurationRequested handler is called and indicates that the Flow is available, the application can register event handlers for StateChanged and MessageReceived events on the Flow. The StateChanged event signals a change in the Flow state of the call. This state is one of the values defined by the MediaFlowState enumeration (that is, Idle, Active, or Terminated). The MessageReceived event is raised when a message is received from the other participant in the call, as shown in the following code example. /* Flow created indicates that there is a media flow class present that can be used for media operations. */ public void instantMessagingCall_FlowConfigurationRequested(object sender, InstantMessagingFlowConfigurationRequestedEventArgs e) { _instantMessagingFlow = e.Flow; /* Bind to the event handlers to get notification of state changes and messages received. */ /* When the flow becomes active, (as indicated by the state changed event) the call is ready to send IM messages. */ _instantMessagingFlow.StateChanged += this.instantMessagingFlow_StateChanged; /* Message Received is the event used to indicate that a message has been recieved from the remote participant. */ _instantMessagingFlow.MessageReceived += this.instantMessagingFlow_MessageReceived; }
Handling Call State and Incoming Message Events After the InstantMessagingFlow.StateChanged event is signaled and the state of the call is Active, the messages can be sent. If the state is Idle, no action is needed. If the state is Terminated, the application can clean up any application resources associated with the call, if any, and end the call. private void instantMessagingFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e) { // When flow is active, media operations (here, sending an IM) may begin. if (e.State == MediaFlowState.Active) { /* Send the message on the InstantMessagingFlow. _messageToSend is the text of the message, EndSendMessage is the callback routine that is called to report the status of the operation. */ _instantMessagingFlow.BeginSendMessage(_messageToSend, EndSendMessage, _instantMessagingFlow); } }
Chapter 7
Structure of a UCMA Application
195
Conferences Conferences are calls that involve more than two participants. In many cases, applications start with a two-party call and then escalate the call to a conference when one or more participants are added to the two-party call. When the third participant is added, the media for the call is routed through a conferencing server, also referred to as an MCU. This server role is part of the Office Communications Server infrastructure. There are conferencing servers that support the various content types (such as IM, A/V, and Web conferencing media) and replicate the media generated by each participant to all of the participants in the conference. What appears to the participants to be one UC session may be composed of multiple calls, with each call being used to manage and transport one media type. The exact mechanism and behavior used to escalate a two-party session to a conference involving three or more parties is specific to the application.
Scheduling a Conference The UCMA provides classes to schedule conference sessions for participants to connect to the conference. The main class that is used for scheduling is called ConferenceScheduleInformation. This class defines the media types that can be used during the conference, the participants, the roles assigned to participants, and the time and duration of the conference. An example of scheduling a conference is shown in Listing 7-4. LISTING 7-4 Scheduling a Conference // The base conference settings object, used to set the policies for the //conference. ConferenceScheduleInformation _conferenceScheduleInformation = new ConferenceScheduleInformation(); // In an open meeting, any participant can join but authentication is required. //No anonymous users are allowed. Other possible authentication values are: None, //ClosedAuthenticated, and Anonymous. _conferenceScheduleInformation.AdmissionPolicy = ConferenceAdmissionPolicy.OpenAuthenticated; // This flag determines whether the passcode is optional to join the conference. //A value of "true" means that the passcode is optional. _conferenceScheduleInformation.IsPasscodeOptional = true; // The conference passcode. _conferenceScheduleInformation.Passcode = "sample"; // The verbose description of the conference. _ conferenceScheduleInformation.Description = "Example Conference"; // This field indicates the date and time when the conference can be deleted. _conferenceScheduleInformation.ExpiryTime = System.DateTime.Now.AddHours(5);
196
Part IV
Unified Communications Managed API
// Specify the set of modalities (here, only InstantMessage) to use during the //conference. McuType is a UCMA defined enum type. ConferenceMcuInformation _instantMessageMCU = new ConferenceMcuInformation(McuType.InstantMessaging); _conferenceScheduleInformation.Mcus.Add(_instantMessageMCU); // Now that the ConferenceScheduleInformation class is specified, schedule the //conference using the conference services of the Endpoint. The _callerEndpoint //can be either an ApplicationEndpoint or a UserEndpoint. // Note: the conference organizer is considered a leader of the conference //by default. _callerEndpoint.ConferenceServices.BeginScheduleConference (_conferenceScheduleInformation, EndScheduleConference, // Callback method _callerEndpoint.ConferenceServices);
In Listing 7-4, the status of the scheduling operation is returned in the EndScheduleConference callback that is passed to the BeginScheduleConference call. After the EndScheduleConference callback is signaled, the conference is created and can be used by the participants. The conference’s URI property uniquely identifies the conference. Participants use the conference URI to join the conference. The conference URI is available once the conference is scheduled and the value is retrieved by getting the Conference.ConferenceUri property. This URI is available only to the conference organizer and must be communicated to the other participants by using out-of-band methods (for example, e-mail), or an existing Conversation can be escalated to a conference using the Conversation.BeginEscalateToConference method.
Joining a Conference To enable users to join a conference, the application creates a new Conversation class and uses the conference URI, as shown in the following code example. // Now that the conference is scheduled, it's time to join it. As we //already have a reference to the conference object populated from the //EndScheduleConference call, we do not need to get the conference first. //Initalize a conversation off of the endpoint, and join the conference // from the URI provided above. Conversation _callerConversation = new Conversation(_callerEndpoint); ConferenceJoinInformation _confJoinInfo = new ConferenceJoinInformation( new RealTimeAddress(_conference.ConferenceUri)); // Start the process of joining the conference using //the ConferenceSession.BeginJoin call. _callerConversation.ConferenceSession.EndJoin( _callerConversation.ConferenceSession.BeginJoin( _confJoinInfo, null, null));
Chapter 7
Structure of a UCMA Application
197
// Since we are joining using the synchronous pattern, we can now create the calls //for the conference media. Otherwise, the work to create the call would be done //in the ConferenceSession.EndJoin callback handler by using the code below. //Placing the calls on the conference-connected conversation connects to the //respective MCUs. These calls may then be used to communicate with the MCUs. InstantMessagingCall _instantMessagingCall = new InstantMessagingCall(_callerConversation);
If an audio call is included in the conference, the application creates an instance of AudioVideoCall to connect to that media stream.
Publish and Subscribe to Presence Applications written using UCMA 2.0 can publish presence to Office Communications Server, as well as subscribe to presence notifications from the server. Both of these operations require the use of an endpoint that is registered with Office Communications Server. When a user first signs in to Office Communications Server by using Microsoft Office Communicator, the client creates a set of containers for the user in Office Communications Server and publishes one or more instances of presence categories to those containers. Each container created is assigned access control entries (ACEs) to set permission levels. These permission levels define the access level contacts that are allowed. The default set of containers that are created are as follows: N
Blocked
N
Public
N
Company
N
Team
N
Personal
Office Communicator publishes the user’s availability, calendar state, and many other presence categories to these containers. For more information about the containers, access control, and the categories, see the “Office Communicator 2007: Enhanced Presence Model White Paper” at http://go.microsoft.com/fwlink/?linkid=143209.
Note It is possible—in fact, it is common—for a single user to have more than one active endpoint registered with Office Communications Server at the same time. Each of those endpoints publishes one or more instances of the presence categories to one or more containers on behalf of the user. There is a server component on Office Communications Server, named the Aggregation Script, that takes these multiple instances of a given presence category that are published to the aggregation containers (that is, container 2 or 3) and aggregates them into one global value for each category. When user A subscribes to user B’s presence information, the values of the categories returned are these aggregated values. A representation of this aggregation operation is shown in Figure 7-2.
198
Part IV
Unified Communications Managed API System-Level Containers Self Container Default Container
User Replicator
Blocked Container
Active Directory
Public Container Company Container Team Container Personal Container
Aggregation Script
Office Communications Server
Input from Clients FIGURE 7-2 Containers and presence aggregation.
The publication of presence information is always performed in the context of a specific SIP URI and is published to one or more containers. When an application wants to subscribe to presence information, the subscription is always in the context of a specific SIP URI. A user has access to all of the presence categories that he or she published to Office Communications Server. This is referred to as “self presence.” However, when a user subscribes to the presence information of other users, the information returned is limited to the set of presence information published to the container where the subscriber has been granted access. In practice, what this means is that presence subscriptions for the self presence items might return multiple instances for each category that are published to different containers. Presence subscriptions for other users return a single instance of a presence category from a single container.
Publishing Presence When an application uses UCMA 2.0 to publish presence, it first needs to create and initialize an instance of the CollaborationPlatform class and then create either a UserEndpoint
Chapter 7
Structure of a UCMA Application
199
or ApplicationEndpoint for the SIP URI that is used to publish presence information. Because the code for creating an endpoint was covered earlier in the chapter, this section assumes that these steps have been carried out and the resulting endpoint, _userEndpoint, has been created. The steps to publish presence are as follows: 1. Create an instance of the CustomPresenceCategory class, _customCat, to hold the information that is published and supply the category name. This example uses state and the category data as a formatted Extensible Markup Language (XML) string. 2. Create an instance of the List class to hold the category instances to be published. 3. Add any CustomPresenceCategory entries that are to be published to the list. 4. Use the BeginPublishPresence method of the LocalOwnerPresence property of the endpoint to publish the presence value. The following code provides an example of how to publish an instance of the state category. It is an Enhanced Presence category that is defined by Office Communicator. All the Enhanced Presence categories are declared as XML structures, and their formats are specified by the “Unified Communications Enhanced Presence Schemas for Microsoft Office Communications Server 2007” located at http://go.microsoft.com/fwlink/?linkid=143305. The _stateXML variable contains an XML string for the state category describing the availability of a user. Office Communicator uses an integer to indicate the availability. For example, setting 3500 as the availability value indicates that the user state is “Available”; a value of 6500 indicates that the user state is “Busy”; and 15500 indicates that the user state is “Away.” private static String _stateXml = "{0}"; // Create an instance of CustomPresenceCategory to hold the presence data //to publish. In this case, we are publishing an instance of the "state" //category with a value of busyAvailable, which corresponds to the value 6500. //The format of the category is an XML document and the value is of type int. CustomPresenceCategory _customCat = new CustomPresenceCategory("state", String.Format(_stateXml, 6500)); List _catPublish = new List(); _catPublish.Add(_customCat); // The LocalOwnerPresence class on the user endpoint means that we are //publishing presence for the user that owns the endpoint. */ _userEndpoint.LocalOwnerPresence.BeginPublishPresence(_catPublish, EndPublishPresenceCallback, _userEndpoint.LocalOwnerPresence);
200
Part IV
Unified Communications Managed API
Note that BeginPublishPresence takes a collection as an input parameter for the presence categories to be published. This allows this method to publish multiple different presence categories in a single operation. The result of the presence publication operation is returned when the EndPublishPresenceCallback method is called. This callback method is registered during the BeginPublishPresence call. The following is an example of this callback. private void EndPublishPresenceCallback(IAsyncResult result) { /* Verify the result of the publication by calling EndPublishPresence. If there is no exception thrown, then the operation succeeded. */ try { _userEndpoint.LocalOwnerPresence.EndPublishPresence(result); } catch (Exception excpt) { Trace.Writeline(excpt.Message +" in EndPublishPresence"); } }
Because this presence category instance was published using a UserEndpoint, which is bound to a user’s SIP URI, it is published to the containers owned by that user. If the endpoint is an ApplicationEndpoint, the presence information is published to the containers owned by the Contact object that defines the SIP URI. It is possible for the application to update any or all of the presence categories that it has published at any time.
Subscribing to Presence When an application using UCMA subscribes to presence information, it must use an enabled endpoint to create the subscription. The application can subscribe to the signed-in user’s presence information, called self presence, or it can subscribe to contacts’ (that is, other users’) presence information. When subscribing to self presence, the application has full access to the signed-in user’s (that is, endpoint) categories published to the containers owned by the user. However, when subscribing to other users’ presence information, the application has access only to the presence categories visible to the user represented by the signed-in endpoint. Self Presence Applications generally subscribe to self presence to retrieve the user’s information and update his or her presence information. An example of user information is the contact list, which is published as a set of instances of the contactCard category. To subscribe to the self presence information, the application creates a subscription from the LocalOwnerPresence property of the endpoint, as shown in the following code example. Note
Chapter 7
Structure of a UCMA Application
201
that the subscription to LocalOwnerPresence returns all of the presence categories that have been published for the user. // Create a subscription to the "self presence" of the user represented by the endpoint. _userEndpoint.LocalOwnerPresence.BeginSubscribe(SelfPresenceSubscribeCallback, null);
The callback handler, SelfPresenceSubscribeCallback, that is specified in the BeginSubscribe method receives notification of whether the subscription completed successfully. This callback method should then subscribe to the CategoryNotificationReceived event so that the application can be notified when instances of the presence categories are updated in Office Communications Server. This event is signaled the first time a category value is received and any time an updated value is received. The SelfPresenceSubscribeCallback method implementation is shown in the following code example. private void SelfPresenceSubscribeCallback(IAsyncResult result) { // Call EndSubscribe to check the status returned from the BeginSubscribe method. try { _userEndpoint.LocalOwnerPresence.EndSubscribe(result); /* Subscribe to the CategoryNotificationReceived events to be notified when category data is received. */ _userEndpoint.LocalOwnerPresence.CategoryNotificationReceived += new EventHandler(Self_CategoryNotificationReceived); } catch (Exception excpt) { //There was an error in the subscription. Trace.WriteLine(excpt.ToString() + "in EndSubscribe"); } }
To receive notifications of event changes to the user’s categories, the event handler, Self_CategoryNotificationReceived, that is registered for CategoryNotificationReceived events must be implemented. The following code example illustrates this implementation. void Self_CategoryNotificationReceived(object sender, CategoryNotificationEventArgs e) { //e.CategoryList is the list of category instances that were returned from the server foreach (PresenceCategoryWithMetaData cat in e.CategoryList) { // handle the categories of interest in the switch statement switch (cat.Category.CategoryName) //Switch on the name of the category { case "state": //process the user state data. break;
202
Part IV
Unified Communications Managed API case "contactCard": //process a contact card instance. We get one of these per contact in the list. break; default: break; }
} }
Presence from Other Users Subscribing to presence information from other users follows a similar pattern as the self-subscription process. The endpoint registered to the user is used to create the subscription. In this case, use the RemotePresence class to manage the subscription and subscribe to the PresenceNotificationReceived events of that class, as shown in the following code example. These events are used to receive notifications of presence changes from Office Communications Server. The BeginAddTargets method is used to create the subscriptions to one or more users. //Create an instance of the RemotePresence RemotePresence _remotePresence = _userEndpoint.RemotePresence; //Create an event handler for the PresenceNotificationReceived events. _remotePresence.PresenceNotificationReceived += new EventHandler( remotePresence_PresenceNotificationReceived); //Create a list of the remote presentities to subscribe to. RemotePresentitySubscriptionTarget _target1 = new RemotePresentitySubscriptionTarget("sip:user1@domain", String.Empty; RemotePresentitySubscriptionTarget _target2 = new RemotePresentitySubscriptionTarget("sip:user2@domain", String.Empty); RemotePresentitySubscriptionTarget _target3 = new RemotePresentitySubscriptionTarget("sip:user3@domain", String.Empty); // Once the target SIP URIs to subscribe to are defined, add them to a List class. List _targetList = new List(); _targetList.Add(_target1); _targetList.Add(_target2); _targetList.Add(_target3); // First create the string array of category names to query. string [] _cats = {"state", "contactCard"}; //Create the query passing the targets, the category list, the event //handler that will receive the category data and null for the callback //and the status object. _remotePresence.EndPresenceQuery(_remotePresence.BeginPresenceQuery(_targetList, _cats, remotePresence_PresenceNotificationReceived, null, null);
The PresenceNotificationReceived event handler is called whenever presence updates are received from the subscription. Presence information for multiple targets can be delivered in a single event. The data for the targets is delivered in a collection in the Notifications
Chapter 7
Structure of a UCMA Application
203
property of the event arguments. Each entry in the collection applies to one presentity whose SIP URI is indicated by the URI property on the notification. Each notification can contain data for multiple presence categories, as shown in the following code example. void remotePresence_PresenceNotificationReceived(object sender, RemotePresenceNotificationEventArgs e) { foreach (RemotePresentityNotificationData notification in e.Notifications) { string targetUri = notification.Uri; //Presentity URI for this presence data. //Each Notification can contain multiple categories foreach (PresenceCategoryWithMetaData category in notification.Categories) { switch (category.Category.CategoryName) //Switch based on the category name. { case "state": //process state. break; default: break; } } } }
Summary The UCMA 2.0 Software Development Kit (SDK), available at http://go.microsoft.com/fwlink/ ?linkid=143314, contains significant new functionality compared to the 1.0 release. This new functionality provides the application programmer with the ability to do the following: N
Create and control multimodal calls that include both IM and audio.
N
Create, schedule, and participate in multiparty conferences.
N
Publish and subscribe to presence information.
The UCMA SDK is designed to operate using an asynchronous programming model that provides for maximum throughput for applications that need scalability. In addition, the design of the SDK enables you to extend the programming model to add new media types.
204
Part IV
Unified Communications Managed API
Additional Resources N
“Office Communicator 2007: Enhanced Presence Model White Paper” (http://go.microsoft.com/fwlink/?linkid=143209)
N
Microsoft Unified Communications Managed API 2.0 SDK (32 bit) (http://go.microsoft.com/fwlink/?linkid=143314)
N
Microsoft Unified Communications Managed API 2.0 SDK (64 bit) (http://go.microsoft.com/fwlink/?LinkID=139195)
N
Unified Communications Enhanced Presence Schemas for Microsoft Office Communications Server 2007 (http://go.microsoft.com/fwlink/?linkid=143305)
Chapter 8
Publishing Custom Presence with UCMA This chapter will help you to: N
Understand how to define custom presence categories in Microsoft Office Communications Server 2007 R2.
N
Understand how to publish instances of custom presence categories for users using the Unified Communications Managed API (UCMA)
Creating Custom Presence Categories Office Communications Server 2007 R2 supports a flexible presence data model and provides a generic framework for applications to publish, subscribe, and query for presence information for users of the system. The presence information is defined by the Enhanced Presence categories and is published to one or more presence containers on the server. Each container has one or more access control entries (ACEs) that defines the access to the instances of presence categories published to the container. For details about the presence model implemented in Microsoft Office Communicator 2007, see the “Enhanced Presence Model White Paper” at http://go.microsoft.com/fwlink/?linkid=143209. For an application to subscribe to or publish presence information to Office Communications Server, the application must instantiate an endpoint and register that endpoint with Office Communications Server. While any registered endpoint can subscribe to or query for presence information, an endpoint can only publish presence data for the user whose identity is used to register the endpoint with Office Communications Server. In the Unified Communications (UC) platform, applications are responsible for publication, querying, and subscription of presence information. This responsibility includes defining categories as Enhanced Presence data types and defining ACEs on containers to block or permit access to the published presence data. The content of Enhanced Presence data is opaque to the server. An application can define its own presence categories and implement the application-specific semantics for the data in the categories. It can also use the presence categories defined by other applications and follow the rules of publication and subscription defined by other applications.
205
206
Part IV
Unified Communications Managed API
For example, Office Communicator defines a rich set of Enhanced Presence categories, some of which are used to represent the user state. Office Communicator publishes them to indicate whether the user is available, on the phone, away, and so on. Other categories are used to represent the user’s Free/Busy information from the user’s calendar data. Office Communicator reads this information from Microsoft Office Outlook and Microsoft Exchange Server and makes it available to the user’s contacts. Other UC applications can use the presence information defined and published by Office Communicator. They can also define and publish custom presence information. This chapter describes how to publish applicationspecific presence information using custom presence categories.
Common Custom Presence Application Scenario A common custom presence application scenario is publishing presence information for users based on sources of information and applications other than Office Communicator. Before the release of Office Communications Server 2007 R2, there were two main issues with this scenario. The first issue was that to register an endpoint with the server running Office Communications Server for a user, the application required the user’s domain credentials to validate the registration with Office Communications Server. This can be an issue with the security and operation of the application. The second issue was that none of the APIs that supported presence operations (Unified Communications Client API and Communicator Web Access Asynchronous JavaScript and Extensible Markup Language [XML] API) provided the behavior and scale required to support large numbers of simultaneous users. The UCMA API 2.0 provides solutions to both of these issues and makes a custom presence scenario easy to implement.
Choice of Technology UCMA 2.0 provides the ability to create a middle-tier application that registers endpoints and publishes instances of presence categories on behalf of some users. Because an application written with UCMA can be registered with Office Communications Server as a trusted application, the application is not required to supply the user’s domain credentials to register an endpoint for the user. This chapter provides an example of how UCMA can be used to create an application that registers many user endpoints with Office Communications Server and publishes instances of a presence category on their behalf. For this example, we are publishing a custom presence category named GPSLocation, representing the Global Positioning System (GPS) location of the user, but the application can publish instances of any of the system-defined categories that are defined for users as well. However, when publishing the system-defined categories, there can be issues of coexistence with running instances of Office Communicator and multiple simultaneous endpoints for the user, which complicate the scenario. These potential
Chapter 8
Publishing Custom Presence with UCMA
207
issues are not addressed in this chapter; the application is created on the assumption that it is the only endpoint that is publishing GPS location information for users.
Overall Code Structure The sample application is designed to support publication of an XML document containing the GPS coordinates of a user to Office Communications Server. It assumes that the GPS data to be published is generated in some other application or system and supplied to the sample application to be published as presence information for the specified user. This data can be passed into the publishing application, or the application can query the system that supplies the GPS information for the location at some interval. The sample creates and registers endpoints for users of the UserEndpoint type at startup. After the application receives the location information, it uses the registered UserEndpoint instances to publish the new location value in a custom presence category instance. The basic structure and flow of control in the sample is shown in Figure 8-1. Read list of users to support and create UserEndpoints for each user
Create and enable CollaborationPlatform
External System
Receive location data
Publish location data using the UserEndpoint
FIGURE 8-1 Overall structure of the GPS application.
Test Environment To run and test this application, the custom category that is used to store the location information for users must be defined in Office Communications Server. This is accomplished by running a stored procedure on the Microsoft SQL Server database used by Office Communications Server to define the new category. Various tools can be used to access the database, such as the command-line SQLCMD tool, but these details are not covered in this book. After the database is accessed, the stored procedure is invoked with the name of the new category as the input parameter. For example, the commands to the SQLCMD tool are as follows. use rtc exec RtcRegisterCategoryDef N'GPSLocation'
208
Part IV
Unified Communications Managed API
where rtc is the name of the database, RtcRegisterCategoryDef is the name of the stored procedure, and GPSLocation is the name of the new category to be defined. After this category is defined, any application can publish instances of it to Office Communications Server or subscribe to it from Office Communications Server. Note that nothing in the process defines either the syntax or the semantics of the new category because the category is opaque to Office Communications Server. The only requirement that Office Communications Server imposes on instances of the category is that they be written in well-formed XML. It is up to the application that uses the category to define the structure of the instances, to ensure that they are well-formed when published to the server, and to parse them when they are delivered from the server. This is typically achieved by defining the structure of the category data by creating an XML Schema Definition (XSD) file that defines the schema for the custom category. In Listing 8-1, the schema for the GPS location that is published to the custom category is defined. LISTING 8-1 Schema for the GPSLocation Custom Presence Category
The only element that is supplied in the publication is the value, which is a string.
Detailed Code For this sample, we are going to create a console application in C#. The application requires that the UCMA 2.0 Software Development Kit (SDK) is installed, along with any of its prerequisites. 1. Start by running Microsoft Visual Studio 2008 and creating a new Microsoft Windows project for a console application using C#. Name the project PublishPresence. 2. At the top of the Program.cs file, add the following lines to reference the class libraries that the application uses. using using using using using
using Microsoft.Rtc.Signaling; using Microsoft.Rtc.Collaboration; using Microsoft.Rtc.Collaboration.Presence;
3. On the Solution Explorer tab, right-click the References node, and add references to System.Security, System.Configuration, and Microsoft.Rtc.Collaboration, as shown in Figure 8-2.
FIGURE 8-2 Adding assembly references.
4. Inside the Program class, insert the following definitions. private static CollaborationPlatform _collabPlatform; private static Dictionary _userDictionary; private static string OCS_SERVER_FQDN = "contosoocs2.uc.contoso.com"; private static int APPLICATION_PORT = 9000; private static string APPLICATION_GRUU = "sip:contosolabts.uc.contoso. [email protected];gruu;opaque=srvr:contosolabts.9000:NXnkPWAgokGhv62DhnHAIgAA" "; private static string GPSLOCATION_SCHEMA = "{0} "
These lines of code define the following: Q
The CollaborationPlatform for connecting to the server running Office Communications Server
Q
The Dictionary used to store the UserEndpoints for the users the program supports, indexed by the Session Initiation Protocol (SIP) Uniform Resource Identifier (URI)
Q
The fully qualified domain name (FQDN) of the Office Communications Server to which to connect
Q
The Transmission Control Protocol (TCP) port that the application uses
Q
The Globally Routable User Agent URI (GRUU) defined for the application provisioned
Q
The XML syntax to publish the GPS location information
210
Part IV
Unified Communications Managed API
These settings are defined when the application is provisioned. The values for the FQDN of the Office Communications Server, the TCP port, and the GRUU used by the application will need to be modified based on the environment where the application is run. 5. Navigate to the Main method in Program.cs and add the following lines to the body of the procedure. static void Main(string[] args) { string inputLine; char sep = new char(); sep = Convert.ToChar(","); _userDictionary = new Dictionary(); //Prepare the CollaborationPlatform for use. PreparePlatform(); Console.Write("Enter sipuri,Gpslocation to publish user GPS location or exit to quit"); inputLine = Console.ReadLine(); while (!inputLine.ToLowerInvariant().StartsWith("exit")) { if (!string.IsNullOrEmpty(inputLine)) { string[] input = inputLine.Split(sep); //input[0] is the SIP URI for the user and input[1] is the GPS string. PublishUserLocation(input[0], input[1]); inputLine = Console.ReadLine(); } else { Console.WriteLine("Enter sipuri,Gpslocation to publish user GPS location or exit to quit"); inputLine = Console.ReadLine(); } } ShutdownAndCleanup(); }
Here, we are initializing the Dictionary and then calling the PreparePlatform() method to instantiate the CollaborationPlatform. The code then prints a message to the console and waits for user input. The input is either the word exit to exit the program or a SIP URI followed by a comma and the GPS string that defines the user’s location. If the user enters exit, then the ShutdownAndCleanup() method is called to clean up and exit the program. Note that this sample assumes that the data entered for the GPS string is formatted as a valid XML string. Production code should validate the format. 6. Below the Main procedure, create the PreparePlatform method by entering the following. private static void PreparePlatform() { //Get the certificate that is used for making the TLS connection to OCS X509Certificate2 cert = GetLocalCertificate();
Chapter 8
Publishing Custom Presence with UCMA
211
//Create the ServerPlatformSettings to define the connection to the server. ServerPlatformSettings settings = new ServerPlatformSettings( "GPSPublisher", Dns.GetHostEntry("localhost").HostName, APPLICATION_PORT, APPLICATION_GRUU, cert); //Create the platform and call BeginStartup to make it usable. _collabPlatform = new CollaborationPlatform(settings); _collabPlatform.BeginStartup(BeginPlatformStartupCallback, _collabPlatform); }
The CollaborationPlatform will be ready to use after the BeginPlatformStartupCallback method is called. 7. Just below the PreparePlatform method, add the following code to implement the BeginPlatformStartupCallback method. private static void BeginPlatformStartupCallback(IAsyncResult result) { try { //Call EndStartup to finish initializing the platform and then create the //set of UserEndpoints that are registered with Office Communications Server //to publish the user's location. _collabPlatform.EndStartup(result); CreateUserEndpoints(); } catch (ConnectionFailureException connFailEx) { // ConnectionFailureException will be thrown when the platform cannot connect. Trace.WriteLine(connFailEx.Message + " in " + connFailEx.TargetSite); } }
After the call to CollaborationPlatform.EndStartup() is called, the CollaborationPlatform is ready to use. Next, the callback method calls the method, CreateUserEndpoints(), to create the endpoints of users to publish their location. 8. Below the definition of BeginPlatformStartupCallback, insert the following code to implement the CreateUserEndpoints method. private static void CreateUserEndpoints() { List_users = new List(); //Populate the list of users to publish. //In this case we just hardcoded this list for simplicity. _users.Add("sip:[email protected]"); _users.Add("sip:[email protected]"); //For each user, create and establish a UserEndpoint. foreach (string userUri in _users) { UserEndpoint _endPoint; UserEndpointSettings settings =
212
Part IV
Unified Communications Managed API new UserEndpointSettings(userUri, OCS_SERVER_FQDN); _endPoint = new UserEndpoint(_collabPlatform, settings); _endPoint.BeginEstablish(EndPointBeginEstablishCallback, _endPoint); }
In this method, the code creates a UserEndpoint for each user that it is configured to support. Although we use a hard-coded list here, in production code it would have been populated dynamically from a database, Active Directory Domain Services, or another source. The code in the EndPointBeginEstablishCallback stores the prepared endpoints for later use. This is done in the next step.
Note Depending on the usage pattern for the endpoints, it might be a better design to defer creating the endpoints until there is data that needs to be published and to terminate the endpoints after the publication has finished. For example, if the presence data to be published changes infrequently, it might be a better choice to tear down the endpoints after the publication operation. This reduces the memory consumption of the application. If the data to be published changes frequently, then keeping the endpoints active is more efficient than the overhead of creating them again and again at a high rate. However, for simplicity in this sample, we create them once at startup and terminate them only when the application shuts down.
9. Just below the code for CreateUserEndpoints, add the following code to implement the EndPointBeginEstablishCallback method. This method is called for each endpoint that is created by the code in CreateUserEndpoints. private static void EndPointBeginEstablishCallback(IAsyncResult result) { UserEndpoint userEndpoint = result.AsyncState as UserEndpoint; try { userEndpoint.EndEstablish(result); //When the endpoint is ready to use, we will add it to the dictionary //that stores the endpoints for later use in publishing presence. The entries //in the dictionary are indexed by the SIP URI of the user and the value is a //reference to the endpoint itself. SipUriParser parsed = new SipUriParser(userEndpoint.EndpointUri); //Use just the "name@domain" portion of the URI. _userDictionary.Add(parsed.UserAtHost, userEndpoint); } catch (Exception except) { Trace.WriteLine(except.Message + " in " + except.TargetSite); } }
At this point, we have a valid UserEndpoint for each user. We will use this endpoint to publish the location information of that user. The logic to publish the user’s location information is encapsulated in the PublishUserLocation method.
Chapter 8
Publishing Custom Presence with UCMA
213
10. Below the code for EndPointBeginEstablishCallback, add the following code to implement the PublishUserLocation method. public void PublishUserLocation(string userUri, string location) { //Check to make sure that we have been passed a user SIP URI that is in our list. If so, then publish the location for that user. UserEndpoint userEndpoint; if ((!string.IsNullOrEmpty(userUri) && (_userDictionary.TryGetValue(userUri, out userEndpoint)))) { PublishLocation(userEndpoint, location); } else { Trace.WriteLine("Entered URI: " + userUri + " was not found"); Console.WriteLine("Entered URI: " + userUri + " was not found"); } }
This method is called to publish the location information for the specified user, which in this example is called from Main. In practice, it is called whenever the user’s location changes or at regular intervals. It validates the user and calls the PublishLocation method to publish the user’s location. 11. Below the PublishUserLocation method, add the following code to implement the PublishLocation method. private static void PublishLocation(UserEndpoint userEndpoint, string location)
Try { //Insert the location string into the XML blob. string catToPublish = string.Format(GPSLOCATION_SCHEMA, location); //Create an instance of the GPSLocation category and specify that it is //to be published in the 200 container which only makes it available to //contacts in the "Team" level. See the Enhanced Presence Model whitepaper in the //"Additional Resources" section of this chapter for details. PresenceCategoryWithMetaData loc = new PresenceCategoryWithMetaData(1, 200, new CustomPresenceCategory("GPSlocation", catToPublish));
214
Part IV
Unified Communications Managed API loc.ExpiryPolicy = ExpiryPolicy.Persistent;
//Keep this data until overwritten.
//Add it to the list of items to be published. List itemList = new List(); itemList.Add(loc); //Publish the category instance to the user's endpoint. userEndpoint.LocalOwnerPresence.BeginPublishPresence(itemList, PublishPresenceCallback, userEndpoint.LocalOwnerPresence); } catch (Exception excpt) { Trace.WriteLine(excpt.Message + " in " + excpt.TargetSite); } }
The status of the publication is returned in the PublishPresenceCallback method. 12. Just below the PublishLocation code, add the following code to implement the PublishPresenceCallback method. private static void PublishPresenceCallback(IAsyncResult result) { try { //Get the instance of LocalOwnerPresence from the result and end. LocalOwnerPresence userPresence = result.AsyncState as LocalOwnerPresence; userPresence.EndPublishPresence(result); SipUriParser parsed = new SipUriParser(userPresence.SubscriberEndpoint. EndpointUri); Console.WriteLine("Presence published for: " + parsed.UserAtHost);
13. Finally, add the three utilty methods, GetLocalCertificate, ShutdownAndCleanup, and BeginTerminateCallback. GetLocalCertificate is used to get the certificate that the application uses to connect to Office Communications Server using Transport Layer Security (TLS). This certificate must be stored in the local computer’s certificate store and have
Chapter 8
Publishing Custom Presence with UCMA
215
a SubjectName that matches the FQDN of the computer where the application is running. The ShutdownAndCleanup method is called when the application exits. It terminates the cached UserEndpoints that the application created and then shuts down the CollaborationPlatform instance. Just below the code for PublishPresenceCallback, add the following code to implement these three methods. private static X509Certificate2 GetLocalCertificate() { //Get a handle to the local machine's certificate store X509Store store = new X509Store(StoreLocation.LocalMachine); //Open the store store.Open(OpenFlags.ReadOnly); //Get a handle to a collection of the certificates installed on the machine X509Certificate2Collection certificates = store.Certificates; //Loop through the certificates looking for one //where the SubjectName matches the FQDN of the //Local Machine and the private key is available. foreach (X509Certificate2 certificate in certificates) { if (certificate.SubjectName.Name.Contains (Dns.GetHostEntry("localhost").HostName) && certificate.HasPrivateKey) { //Return the certificate that matches return certificate; } } //If not certificates match, return null return null; } internal static void ShutdownAndCleanup() { foreach (UserEndpoint endpoint in _userDictionary.Values) { IAsyncResult result = endpoint.BeginTerminate(BeginTerminateCallback, endpoint); result.AsyncWaitHandle.WaitOne(); } _collabPlatform.BeginShutdown( new AsyncCallback( delegate(IAsyncResult aResult) { _collabPlatform.EndShutdown(aResult); } ), null); }
Summary This sample shows how to use UCMA 2.0 to build an application that publishes custom presence items on behalf of a set of users. Because the Office Communications Server infrastructure is configured to treat the application as a trusted application, the application does not need to supply domain credentials to Office Communications Server for each user when it publishes their presence.
Additional Resources N
Microsoft Unified Communications Managed API 2.0 SDK (32 bit) (http://go.microsoft.com/fwlink/?LinkID=140790)
N
Microsoft Unified Communications Managed API 2.0 SDK (64 bit) (http://go.microsoft.com/fwlink/?LinkID=139195)
N
“Unified Communications Managed API 2.0 Core SDK Documentation” (http://go.microsoft.com/fwlink/?linkid=126312)
N
“Office Communicator 2007: Enhanced Presence Model White Paper” (http://go.microsoft.com/fwlink/?linkid=143209)
Part V
Debugging, Tuning, and Deploying Unified Communications Applications Microsoft Office Communications Server is a complex product, and deploying your Unified Communications (UC) application can be a weighty process that requires proper configurations of the application development components and the underlying infrastructure components. As a developer, you may not be proficient enough with deploying and managing Office Communications Server to know what needs to be done to ensure that your application is properly deployed and successfully executed. Chapter 9, “Preparing the UC Development Environment,” covers the details for properly configuring Office Communications Server and application development components to run your application. In any application development, bugs are inevitable and debugging is necessary. Because UC applications are inherently asynchronous, bugs may seem mysterious and debugging may be frustrating. Bugs, however, are not an option. They are an expected part of any development effort. The key is to release your product with as few bugs as possible, within the time and resource constraints available. Chapter 10, “Debugging a Unified Communications Application,” provides guidance on how to debug your application and troubleshoot the system when problems arise.
217
Chapter 9
Preparing the UC Development Environment This chapter will help you to: N
Understand essential components of a Microsoft Unified Communications (UC) application development environment.
N
Understand the basic requirements of the infrastructure and application development components of a UC application development environment.
N
Prescribe how to configure basic infrastructure components for developing UC applications in a single-domain forest.
N
Prescribe how to configure application development components for developing UC applications by using Microsoft Office Communicator Automation API, Unified Communications Managed API (UCMA) Core, and UCMA Workflow.
UC Application Development Environment Components As an application developer, you can think of the UC environment as consisting of infrastructure components and application development components. The infrastructure components are configured and managed by system administrators, and the application development components can be configured and administered by application developers who may have to obtain appropriate permissions from a system administrator. The infrastructure components include all of the Office Communications Server roles, the dependent Active Directory Domain Services (AD DS), and supporting services such as Domain Name System (DNS), public key infrastructure (PKI), Structured Query Language (SQL), reverse proxy, firewalls, and hardware load balancers for an Enterprise pool. For Office Communications Server Standard Edition, the supported server roles include Front End Server, Web Conferencing Server, Audio/Video (A/V) Conferencing Server, Web Components Server, and Application Sharing Server. The Web Conferencing Server and A/V Conferencing Server roles are not required if the Office Communications Server Standard Edition deployment is intended to support only instant messaging and presence. For more information about server roles in Office Communications Server, see the “Microsoft Office Communications Server 2007 R2” documentation at http://go.microsoft.com/fwlink/ ?LinkID=133608 and the Microsoft Office Communications Server 2007 R2 Resource Kit at http://go.microsoft.com/fwlink/?LinkId=141203.
219
220
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
The server roles in Office Communications Server 2007 R2 must be deployed on computers that are running Windows Server 2003 Service Pack 2 (SP2) or later or Windows Server 2008. You must have appropriate permissions to install, activate, and administer the server components. For example, to install, activate, and administer an infrastructure component, you must be a member of an appropriate Real-Time Communications (RTC) Universal security group that is created and configured by AD DS preparation before Office Communications Server is installed. Most administrative tasks require that you belong to the RTCUniversalServerAdmins group. Some tasks may also require that you have local or domain administrator permissions. For example, to install and activate a server running Office Communications Server 2007 R2 Standard Edition, you must be a domain administrator who belongs to the RTCUniversalServerAdmins security group. To configure a server running Office Communications Server 2007 R2 Standard Edition, you must be a member of the RTCUniversalServerAdmins group. In general, if you are a domain administrator and you belong to the RTCUniversalServerAdmins security group, you can perform all three administrative functions. For more information about the administrative credentials that are required for deploying Office Communications Server, see the “Accounts and Permissions Requirements” topic (http://technet.microsoft.com/en-us/library/dd425321(office.13). aspx) in the “Microsoft Office Communications Server 2007 R2” documentation at http:// go.microsoft.com/fwlink/?LinkID=133608. The application development components can be grouped by the types of UC applications. These application groups include client-side applications that log on to Office Communications Server, middle-tier applications that mediate between the client and Office Communications Server, and server-side applications that extend the functionality of Office Communications Server. Some of these application development components include Office Communicator, Office Communicator Automation application programming interface (API), Unified Communications Client API, Unified Communications Managed API (UCMA) Core, UCMA Workflow, and Office Communications Server API. This book mainly discusses developing applications by using the Office Communicator Automation API, UCMA Core, and UCMA Workflow. You can build UC applications by using one or more application development components. As an application developer, you are responsible for configuring and using the application development components while relying on system administrators in your organization to configure and manage the infrastructure components. For testing purposes, you might want to isolate your development environment from the production deployment of the UC infrastructure. For example, you can do this when you reconfigure infrastructure components to enable custom features or extensions. In these cases, bugs or other unwanted actions can cause UC to operate abnormally in your organization. It will be helpful to create an isolated Office Communications Server environment to use for your application development. This chapter explains how to create an isolated Office Communications Server environment for developing and testing your UC applications in an autonomous manner. Prescriptive
Chapter 9
Preparing the UC Development Environment
221
step-by-step instructions explain how to deploy Office Communications Server Standard Edition for internal users in a single-domain forest topology. This is the most basic environment required to run Office Communications Server. Before explaining how to set up and configure the UC application development environment, this chapter reviews the three central components of the environment: AD DS for managing a network, Office Communications Server roles, and the UC APIs.
AD DS for Managing a Network Office Communications Server uses AD DS to store global settings and the user information that it needs. Global settings include information about the deployment configurations, routing rules, security groups, and specific access permissions for the Office Communications Server infrastructure. User information is used to authenticate the user when an endpoint tries to sign in to Office Communications Server. It is also used to assign user rights to the user’s endpoints. In AD DS, users enabled for UC are represented by Active Directory User objects. Applications or services that are trusted by Office Communications Server are represented by Active Directory Contact objects. Two AD DS server roles support these features: AD DS and Active Directory Certificate Services. When Office Communications Server is deployed, the AD DS schema must be extended. These extensions involve adding new classes and attributes into the AD DS schema and configuring these settings. This process is known as AD DS preparation and must be performed before Office Communications Server can be deployed in an AD DS forest. To start AD DS preparation, you must select an existing AD DS forest or create a new one. This chapter is based on the assumption that you intend to set up a new UC network for development. This means that you must install AD DS on a separate network. The resulting AD DS forest can consist of one or more domains. Make sure that the following requirements are met: N
All domain controllers and global catalog servers must run Windows Server 2003 SP1, Windows Server 2003 R2, or Windows Server 2008 in either the 32-bit or 64-bit edition.
N
All domains must have a domain functional level of Windows Server 2003 or Windows Server 2008. Domain functional levels of Microsoft Windows 2000 Mixed, Windows 2000 Native, or Windows Server 2003 interim domain are not supported.
N
The AD DS forest must have a forest functional level of Windows Server 2003 or Windows Server 2008. Forest levels of Windows 2000 Mixed, Windows 2000 Native, or Windows Server 2003 interim forest are not supported.
222
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
AD DS preparation for Office Communications Server consists of three major tasks: N
Prep Schema
N
Prep Forest
N
Prep Domain
Prep Schema extends the AD DS schema to support new classes and attributes that are specific to Office Communications Server. To review the schema extensions that the Office Communications Server created, see the schema file Schema.ldf., which is located in the installation root directory of the Office Communications Server. To perform Prep Schema, you must be an administrator in the Schema Admins security group, and you must perform this operation on a schema master server. Successful AD DS schema preparation creates AD DS classes and attributes that have names that contain the prefix ms-RTC-SIP-. After Prep Schema completes successfully, you can verify the ms-RTC-SIP prefix by using ADSI Edit, as shown in Figure 9-1. (The instructions to navigate in ADSI Edit are given in the “Verifying Extended AD DS Schemas” section later in this chapter.)
FIGURE 9-1 AD DS schema preparation.
Prep Forest creates global settings that are used by every server running Office Communications Server that is installed in the AD DS forest. To perform this task, you must log on as a member of the Enterprise Admins or Domain Admins group in the AD DS forest root domain. Active Directory Prep Forest does the following: N
Creates universal service and administration groups for Office Communications Server
N
Adds default access control entries (ACEs) to the newly created security groups
Figure 9-2 shows these groups as they appear in Active Directory Users And Computers.
Chapter 9
Preparing the UC Development Environment
223
FIGURE 9-2 Security groups created by AD DS forest preparation.
Prep Domain assigns appropriate permissions to objects and attributes that are enabled for Office Communications Server in each AD DS domain in the chosen forest. To perform this task, you must be logged on as a member of the Enterprise Admins or Domain Admins group for the domain from which you plan to run this task. You must perform Prep Domain for all of the domains in which you want to deploy Office Communications Server and any domains where your Office Communications Server users reside. Preparing an AD DS domain does the following: N
Adds the necessary ACEs to the universal groups that are used to grant permissions to domain controllers and to manage users in the domain
N
Adds ACEs to the domain root and the following built-in containers: Users, Computers, and Domain Controllers
Office Communications Server Roles Office Communications Server supports several server roles and is available in two editions: Standard Edition and Enterprise Edition. Standard Edition is intended for small-scale deployment. You can deploy the Standard Edition server roles on a single host. Enterprise Edition is used for mid- and large-scale deployments that involve multihomed server roles and may require a load balancer. This chapter uses Standard Edition to demonstrate how to set up a UC application development environment in an AD DS forest topology that consists of a single domain. A successful deployment of Office Communications Server 2007 R2 Standard Edition results in the automatic installation of the following server roles, in addition to Microsoft SQL Server 2005 Express Edition SP2 and four applications (Conferencing Attendant, Conferencing Announcement Service, Response Group Service, Outside Voice Control): N
Front End Server
N
Web Conferencing Server
N
Audio/Video (A/V) Conferencing Server
224
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
N
Web Components Server
N
Application Sharing Server
To make sure that the deployment of these server roles is successful, verify that the following minimum operating system and hardware requirements are met: N
Hardware requirements Use only a 64-bit computer that is running a 64-bit edition of Windows Server for all Office Communications Server 2007 R2 Standard Edition server roles. Other technical specifications include the following: Q
CPU Quad-core 2.0 gigahertz (GHz) or greater dual processor or dual-core 2.0 GHz 4-way processor
Q
RAM
Q
Hard drive 2 x 72 GB hard drives of 15 kilobytes (K) or 10K revolutions per minute (RPM), RAID 0 (striped), or equivalent
Q
Network adapter dual port)
8 gigabytes (GB) of memory
2 x 1 gigabit-per-second (Gbps) network adapter (2 refers to
N
Operating system requirements Use only the 64-bit edition of Windows Server 2003 SP2, Windows Server 2003 R2 SP2, or Windows Server 2008.
N
Database requirements Use SQL Server 2005 Express Edition SP2 (32-bit version). This is included with Office Communications Server 2007 R2.
N
Administrative tools requirements Install Office Communications Server Administrative Tools manually, which includes the Office Communications Server Microsoft Management Console (MMC) snap-in, the Active Directory Users And Computers snap-in, the Computer Management console snap-in extension, the Communicator Web Access snap-in, and the Response Group Service snap-in. The administrative tools can be installed independent of the Office Communications Server deployment on a computer that is running the 32-bit or 64-bit edition of Windows Server 2003 SP2, Windows Server 2003 R2 SP2, Windows Server 2008, Windows Vista Business, or Windows Vista Enterprise with SP1.
UC APIs UC APIs are major application development components of a UC application development environment. This chapter discusses the basic requirements for using Office Communicator Automation API, UCMA Core, and UCMA Workflow.
Office Communicator Automation API Office Communicator Automation API is a Component Object Model (COM)–based Automation API that enables an application to manipulate a locally running instance of Office Communicator. It can be used by applications in C/C++, Visual Basic, Visual Basic
Chapter 9
Preparing the UC Development Environment
225
Scripting Edition (VBScript), and other scripting languages, and any .NET-based programming languages, such as C#. For security reasons, some API calls are disabled for scripting languages. To use this API, download the Office Communicator 2007 Software Development Kit (SDK) from MSDN located at http://go.microsoft.com/fwlink/?LinkId=141225. Running an Office Communicator Automation API application requires that Office Communicator be installed on the application’s local computer. To build and run the Win32 C/C++ application by using the Office Communicator Automation API, you must include the COM interface IDs definition file in the application’s project. This file is not included automatically in the Office Communicator 2007 Automation API SDK. However, you can generate it easily from the type library by using the Microsoft Interface Definition Language (MIDL) compiler. To build and run the Microsoft .NET Framework application by using the Office Communicator Automation API through the COM interop service, you must add to your application’s project a reference to the primary interop assembly (PIA) that is appropriate to your application’s target platform. For more information about how to do this, see the “Configuring the Office Communicator Automation API” section later in this chapter.
UCMA Core UCMA Core is a .NET-based API that supports the full suite of UC functionality: instant messaging, telephony, A/V conferencing, and presence. It is optimized for use by middle-tier applications mediating between a UC client and Office Communications Server. The API is supported in the run-time environment of either the latest service pack of Windows Server 2003 R2 (64-bit edition) or the latest service pack of Windows Server 2008. It also requires .NET Framework 3.5 SP1 and Visual C++ 2008 Redistributable Package. For more information about the deployment requirements, see “Unified Communications Managed API 2.0 Core SDK Documentation” at http://go.microsoft.com/fwlink/?LinkID=133571. To use the API, download the Microsoft UCMA 2.0 SDK from the Download Center at http://go.microsoft. com/fwlink/?LinkID=139195. In most application scenarios, a UCMA application must be trusted by Office Communications Server. In these cases, you must have an Active Directory Contact object created and configured for the application. To do this yourself, you can use the ApplicationProvisioner sample application provided with the UCMA Core API SDK. For more information, see the “Configuring UCMA Core” section later in this chapter.
UCMA Workflow The UCMA Workflow extends the Windows Workflow Foundation activities to support instant messaging activities, speech activities, and presence activities that are used in UC. As with the UCMA Core, this workflow API requires you to install .NET Framework 3.5 SP1, which includes Windows Workflow Foundation 3.5. It also requires Microsoft Visual Studio 2008
226
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
and at least one Microsoft Speech Server Language Pack. To use this API, you must install the Microsoft UCMA 2.0 SDK at http://go.microsoft.com/fwlink/?LinkID=139195. In addition, you must install at least one of the Speech Server 2007 Language Packs that are distributed as part of Office Communications Server. For more information, see the “Configuring UCMA Workflow” section later in this chapter.
Deploying Office Communications Server Standard Edition Deploying Office Communications Server Standard Edition on a private network involves the following tasks: 1. Build an AD DS forest. 2. Prepare AD DS for Office Communications Server. 3. Configure DNS for automatic sign-in by UC clients. 4. Set up the Office Communications Server host computer. 5. Install Office Communications Server Standard Edition. 6. Configure UC user accounts. 7. Validate Office Communications Server functionality. 8. Install Office Communicator and other clients to verify that users can log on. The following sections explain how to perform each of these tasks.
Building an AD DS Forest To build a separate AD DS forest on a private network for development purposes, the minimal topology is a single-domain forest topology.
Note Skip this task if you plan to use an existing AD DS forest to set up your development environment.
The AD DS forest fully qualified domain name (FQDN) for the example in this chapter is “contoso.com.” A single computer running Windows Server 2008 hosts all of the network services. This includes the domain controller and DNS server. The FQDN of this computer is “dc.contoso.com.” After the AD DS forest is configured, another computer running Windows Server 2008, set up to host Office Communications Server Standard Edition and one or more application
Chapter 9
Preparing the UC Development Environment
227
hosting computers, is added to the network. For a client application, the operating system on the host computer can be Microsoft Windows XP, Windows Vista, or Windows Server. For a server or middle-tier application, the host computer may have to be a server running Windows Server. In this example, the host computer running Office Communications Server to be added has the FQDN “ocs.contoso.com”. The application computer names follow the naming convention of “appN.contoso.com,” where N=0, 1, 2, and so on. To build an AD DS forest, you must make one computer that is running Windows Server the root domain controller. You must also create and configure the DNS server if you do not intend to use existing domain name services. Finally, you must install an Enterprise certificate authority (CA) that issues certificates to users, computers, and applications within the network. Having a private CA is especially useful for a private network that consists of a set of virtual servers and clients. In such a network, it is recommended that Dynamic Host Configuration Protocol (DHCP) is disabled and that static Internet Protocol (IP) addresses be assigned to each computer manually.
Assigning Static IP Addresses for Domain Controller and Other Computers For the domain controller, you must perform these steps before you run the DCPromo tool to make the server into a domain controller. In this chapter, the IP address of 192.168.100.1 is assigned to the domain controller of the private network.
Note Skip this task if you rely on a DCHP server in your network to assign IP addresses to the computers in your network.
1. On Windows Taskbar, click Start, and then click Control Panel. 2. In Control Panel, double-click Network And Sharing Center. 3. In Network And Sharing Center, under the Tasks pane, click Manage Network Connections. 4. In Network Connection, right-click Local Area Connection, and then click Properties. 5. Select the Internet Protocol version 4 (TCP/IPv4) options, and then click Properties. 6. In the IPv4 Properties window, as shown here, select Use The Following IP Address, assign an IP address as the static IP address for the computer, and type 255.255.255.0 in the Subnet Mask field. Select Use The Following DNS Server Addresses, type the IP address of the domain controller in the Preferred DNS Server field, and then click OK.
228
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
For a private network, the IP address should use the format 192.168.x.y, where x and y are integers between 0 and 255, inclusive. In the Default Gateway field, use the IP address of the gateway, if there is one. Otherwise, leave this field blank. The specification of the preferred DNS server is based on the assumption that your DNS server is hosted on the domain controller as well. For other computers, repeat the previous steps and change the host IP address values so that each computer in the network is identified by a unique IP address. You must do this before the computer joins the domain.
Promoting a Computer Running Windows Server to a Domain Controller To promote a computer running Windows Server to an AD DS domain controller, run DCPromo.exe on the computer as explained in the following steps. In the example in the following procedure, the FQDN of the domain is contoso.com. 1. Move the computer running Windows Server into a workgroup if it is currently joined to an AD DS domain. To do this on a computer running Windows Server 2008, click Start, right-click Computer, and then click Properties. 2. In the System pane, under Computer Name, Domain, and Workgroup Settings, click Change Settings, as shown here.
Chapter 9
Preparing the UC Development Environment
229
3. On the System Properties page, click Change... 4. On the Computer Name/Domain Changes page, select Workgroup, if it is not already selected, and then click OK, as shown here.
5. When you are prompted to restart the computer, click OK. In this example, “dc” is the name of the domain controller that is hosted on a computer running Windows Server 2008. 6. To promote the server to a domain controller, from an elevated command prompt, run DCPromo. This starts the Active Directory Domain Services Installation Wizard. 7. On the Welcome To The Active Directory Domain Services Installation Wizard page, shown here, click Next.
230
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
8. On the Operating System Compatibility page, click Next. 9. On the Choose A Deployment Configuration page, select Create A New Domain In A New Forest, as shown here, and then click Next.
10. On the Name The Forest Root Domain page, in FQDN Of The Forest Root Domain, enter the FQDN of the forest root, as shown here, and then click Next. In this example, the FQDN is contoso.com.
Chapter 9
Preparing the UC Development Environment
11. On the Set Forest Functional Level page, as shown here, from the Forest Functional Level drop-down menu, select Windows Server 2008, and then click Next.
12. On the Additional Domain Controller Options page, select DNS Server (if it is not already selected), as shown in the following screen, and then click Next.
231
232
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
13. If your network uses a DHCP server to assign IP addresses, and you receive a prompt that asks you whether you want to continue without assigning IP addresses, select No, I Will Assign Static IP Addresses To All Physical Network Adapters, as shown here.
You must then figure out which network adapter has a DHCP-assigned IP address. If the IPv6 address is not static, you can either disable IPv6 or assign a static address to it. After this is done, go back to the Additional Domain Controller Options page, shown in step 12, and click Next. 14. On the following page, click Yes to continue without creating a delegation for the new DNS server. 15. On the Location For Database, Log Files And SYSVOL page, shown in the following screen, leave the default values, and then click Next.
Chapter 9
Preparing the UC Development Environment
233
16. On the Directory Services Restore Mode Administrator Password page, enter and confirm the password of the restore mode administrator, and then click Next. 17. On the Summary page, review your selections. If your selections are correct, click Next to finish the installation of AD DS. 18. On the Completing The Active Directory Domain Services Installation Wizard page, click Finish to exit the installation. This step takes awhile to complete. 19. Restart your computer for the settings to take effect.
Verifying that the DNS Server Role Is Running After the domain controller is configured, it is a good practice to verify that the newly installed DNS server role is running. To verify the DNS server role, perform the following steps: 1. Log on to the domain controller as a domain Administrator. 2. Click Start, click Administrative Tools, and then click Server Manager. 3. In Server Manager, expand the Roles node in the tree view on the left pane. 4. Select DNS Server. 5. Verify that the Status value of the DNS Server row in System Services is Running.
234
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
Installing a Domain CA Office Communications Server requires certificates to be issued to servers by a trusted CA. In a private development environment, the most convenient way to issue certificates is to install a private CA in the domain. You can install this CA by adding the Active Directory Certificate Services role to the domain controller. (For more information, see the “Active Directory Certificate Services Step-by-Step Guide” on TechNet at http://technet.microsoft.com/en-us/ library/cc772393.aspx.)
Note If you choose other certificate services such as Certification Authority Web Enrollment or Online Responder, you are prompted to add other supporting roles, such as the Application Server and Web Server (IIS) roles, that have not been enabled. In such cases, make sure that you enable the IIS 6 Management Compatibility service of each Web Server (IIS) role during the installation.
Chapter 9
Preparing the UC Development Environment
235
To install a CA for the domain, perform the following steps: 1. Log on to a computer running Windows Server 2008 that is a domain controller. 2. In Server Manager, right-click Roles, and then click Add Roles. 3. On the Before You Begin page, click Next. 4. On the Select Server Roles page, shown here, select Active Directory Certificate Services, and then click Next.
5. On the Introduction page, click Next. 6. On the Select Role Services page, shown here, select Certification Authority, and, if you want, select Certification Authority Web Enrollment or Online Responder. Then click Next.
236
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
7. On the Specify Setup Type page, select Enterprise, and then click Next. 8. On the Specify CA Type page, select Root CA, and then click Next. 9. On the Set Up Private Key page, select Create A New Private Key, and then click Next. 10. On the Configure Cryptography For CA page, use the default setting, and then click Next. 11. On the Configure CA Name page, use the default setting, and then click Next.
Chapter 9
Preparing the UC Development Environment
237
12. On the Set Validity Period page, use the default setting, and then click Next. 13. On the Configure Certificate Database page, use the default setting, and then click Next. 14. On the Confirm Installation Selections page, confirm the settings that you selected, and then click Install if the settings are correct. 15. On the Installation Results page, verify the installation status, and then click Close.
Preparing AD DS for UC To prepare AD DS for UC, you must perform the following tasks: 1. Extend and verify AD DS schemas for Unified Communications. 2. Configure and verify the Active Directory Forest for Unified Communications. 3. Configure and verify the Active Directory Domain for Unified Communications. The following sections explain the steps to perform each of these tasks.
238
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
Extending AD DS Schemas To extend AD DS schemas, you can use the Microsoft Office Communications Server 2007 R2 Deployment Wizard to complete the following steps: 1. Log on to the domain controller by using a domain account that is a member of the Schema Admins security group on the schema master. 2. Double-click SetupSE.exe to start the Microsoft Office Communications Server 2007 R2 Deployment Wizard. If you are prompted to install the Microsoft Visual C++ 2008 Redistributable package, click Yes. If you are prompted to install .NET Framework 3.5 SP1, click Yes. After the added packages are installed, restart the computer and repeat the procedure from the beginning. 3. On the starting page of the Office Communications Server 2007 R2 Standard Edition Deployment Wizard, click Prepare Active Directory.
4. On the Prepare Active Directory For Office Communications Server page, shown here, under Step 1: Prep Schema, click Run.
Chapter 9
Preparing the UC Development Environment
239
5. On the Welcome To The Schema Preparation Wizard page, click Next. 6. On the Directory Location Of Schema Files page, either use the default option or explicitly specify the path of a directory in which the Office Communications Server extensions of the AD DS schemas are located, and then click Next. The default schema file name is Schema.ldf, which is located in the same folder as SetupSE.exe. 7. On the Ready To Prepare Schema page, click Next to start the schema preparation. 8. On the Schema Preparation Wizard Has Completed Successfully page, click Finish.
Installing Office Communications Server Administrative Tools To perform the tasks prescribed from here on, you need to use the Office Communications Server 2007 R2 Administrative Tools. To install the administrative tools on the AD DS domain controller, perform the following steps: 1. Log on as a member of the DomainAdmins group to the AD DS domain controller. 2. Start the Microsoft Office Communications Server 2007 R2 Deployment Wizard (SetupSE.Exe). 3. On the Microsoft Office Communications Server 2007 R2 Standard Edition introduction page, click Administrative Tools, as shown here.
240
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
4. Follow the steps of the wizard to finish the installation.
Verifying Extended AD DS Schemas After the Prep Schema step completes successfully, verify that the schema extensions are replicated throughout the system. You may have to wait for this to happen, especially with a topology that involves multiple domains. However, with a topology that has a single domain in a single forest, replication is almost instantaneous and verification can start immediately.
Note Performing the procedure described in this section satisfies the requirement set forth by the Step 2: Verify Replication Of Schema Partition In The Prepare Active Directory For Office Communications Server page of the Microsoft Office Communications Server 2007 R2 Deployment Wizard.
To verify that the AD DS schemas are extended properly, perform the following steps: 1. Log on to the domain controller where the Office Communications Server Administrative Tools are installed. 2. On the Windows Tasksbar, click Start, Administrative Tools, and then ADSI Edit. This assumes that you have already installed the Office Communications Server Administrative Tools that are available from the Office Communications Server Installation Wizard.
Chapter 9
Preparing the UC Development Environment
241
3. In ADSI Edit, click Action, and then click Connect To. 4. In the Connection Settings box, shown here, select the Select A Well Known Naming Context option, select Schema on the drop-down menu, and then click OK.
In the ADSI Edit console, expand the Schema node in the left pane, and select CN=Schema. In the right pane, scroll down until you find CN=ms-RTC-SIPSchemaVersion, as shown here.
If the schema preparation is replicated, you see results that are similar to those shown here. If the schema extensions are not shown, wait for the schema changes to replicate in the system, and then refresh the view.
242
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
5. Double-click the ms-RTC-SIP-SchemaVersion attribute to open the Properties dialog box. Scroll down to locate the rangeUpper property value, and verify that it is 1008, as shown here. This value confirms that the schema for Office Communications Server 2007 R2 has been prepared successfully. Once the schemas are extended successfully, click OK, and then close the ADSI Edit console.
Preparing the AD DS Forest After you verify that the schema preparation was successful, follow these steps to perform AD DS forest preparation: 1. In the Microsoft Office Communications Server 2007 R2 Deployment Wizard (SetupSE. exe), on the Prepare Active Directory For Office Communications Server page (shown here), under Step 3: Prep Forest, click Run.
Chapter 9
Preparing the UC Development Environment
243
2. On the Welcome To The Forest Preparation Wizard page, click Next. 3. On the Select Location To Store Global Settings page, shown here, use the default settings, and then click Next. 4. On the Location Of Universal Groups page, select the domain that you want, and then click Next. In this example, there is only one domain from which to choose: the contoso. com domain. 5. On the SIP Domain Used For Default Routing page, select the Session Initiation Protocol (SIP) domain that you want, and then click Next. Again, in this example, there is only one domain from which to choose. 6. On the Ready to Prepare Forest page, review the settings, and then click Next to start the forest preparation. 7. On the Forest Preparation Wizard Has Completed Successfully page, select View The Log When You Click Finish, and then click Finish. 8. Verify that the log was created. The log should look similar to the screenshot shown here. Expand Execute Action, and then confirm that the value next to Forest Settings is Ready. This indicates that the forest preparation process has completed successfully.
244
Part V
Debugging, Tuning, and Deploying Unified Communications Applications
Verifying Prepared Forest Settings If the value next to Forest Settings indicates that the forest is not ready, wait for the system to replicate the changes, and then type the following command at a command prompt to verify the forest settings: LcsCmd /forest /action:CheckForestPrepState /PDCRequired:FALSE The results that are obtained while executing this command are written to a Hypertext Markup Language (HTML) file. By default, the file path is %Userprofile%\AppData\Local\ Temp\2\Forest_CheckForestPrepState[][