Share via


Playing Audio Files in Lync 2010 Client: The Phone Pad (Part 2 of 2)

Summary:   Learn how to use the Microsoft Lync 2010 API to play an audio file in Microsoft Lync 2010. Part 2 discusses the Solution Explorer project and the application controls, and includes a code listing.

Applies to:   Microsoft Lync 2010 API | Microsoft Lync 2010

Published:   December 2011 | Provided by:   John Austin, Microsoft | About the Author

Contents

  • PhonePad Project and Controls

  • PhonePad Code

  • Additional Resources

This is the second in a two-part series of articles about how to play audio files in a Microsoft Lync 2010 API application.

PhonePad Project and Controls

The PhonePad project produces a custom control that you can drop into a Windows Forms application or the Windows Forms Host control of a Microsoft Windows Presentation Foundation (WPF) application. The project references the Microsoft.Lync.Model.dll that is installed at %ProgramFiles%\ Microsoft Lync\SDK\Assemblies\Desktop. Twelve dual-tone multifrequency (DTMF) tone audio files and twelve voice files are included with the sample.

Important

Microsoft .NET Framework 4 must be installed on computers that are used to compile or run this project.

The Solution Explorer view of the project appears in Figure 1. The audio files are included in the project with a Content build action instead of a Resource build action. The Lync 2010 API cannot play an audio resource that is compiled into the library. It must be provided with an audio file from the Windows folder structure.

Figure 1. PhonePad user control application hierarchy in Solution Explorer

Phone pad control. Solution view

Note

For information about how a Microsoft Unified Communications Managed API (UCMA) 3.0 application can process DTMF tones that are sent from a Lync 2010 application, see Creating Automated Attendants in UCMA 3.0 and Lync 2010.

PhonePad User Control

The PhonePad project builds a custom control that you can drop in to a Windows form. A user clicks a button on the telephone pad and the following actions occur:

  1. The value of the text label of the clicked button is concatenated at the end of a string that represents all the clicked buttons. This concatenated string is exposed as the public DialString property.

  2. An audio file associated with the clicked button is played through the system speaker.

  3. A ButtonClicked event is raised to any interested code.

Figure 2. PhonePad UI

Phone pad control. Design time view

The following table lists the public members of the PhonePad control library.

PhonePad Public Members

Member

Description

ButtonClickedEvent Event

Notifies registered listener that a user has clicked a button.

InConversation Property

Read/write property that indicates that a Lync 2010 audio conversation is active.

PlayAudioType Property

Read/write property that indicates that either a DTMF tone or a voice audio file is to be played when a user clicks a button.

DialString Property

Read property. The concatenated dial string keyed by a user.

ClearDialedString Method

Clears the dial string text box at the top of the control.

ClearLastCharacter Method

Clears the last character from the dial string text box.

PhonePad Code

The following sections list the code from the PhonePadControl.cs source file.

Declarations

The following example declares the public button clicked event and several private supporting class fields.

Tip

The local user does not have to be signed in to Lync 2010 in order to use the Lync 2010 API platform to play an audio file.

     /// <summary>
    /// Called when a button in the dial pad dialog is pressed.
    /// </summary>
    public delegate void ButtonClicked(string tone);



    public partial class PhonePadControl : UserControl
    {

...
       /// <summary>
        /// Occurs when a button in the dial pad dialog is pressed.
        /// </summary>
        public event ButtonClicked ButtonClickedEvent;

        #region private Lync API object Model fields

        /// <summary>
        /// The Lync client API platform. 
        /// </summary>
        private LyncClient _LyncClient = LyncClient.GetClient();
        #endregion

        #region private support fields

        /// <summary>
        /// Active conversation flag. If true then do not play DTMF tones.
        /// </summary>
        private Boolean _InConversation = false;

        /// <summary>
        /// Indicates which set of audio files are played when a user clicks a button. 
        /// Choices include DTMF or speech files.
        /// </summary>
        private string _PlayAudioType = "DTMF";

        /// <summary>
        /// The path to the speech audio files.
        /// </summary>
        private string _speechPath = "";

        /// <summary>
        /// The path to the local user's profile folders.
        /// </summary>
        string _userProfilePath = "";

        /// <summary>
        /// The path to the DTMF audio files.
        /// </summary>
        private string _DTMFPath = "";

        #endregion

Public Properties

The following example exposes the public properties that are described in the previous table.

        #region public properties
        /// <summary>
        /// Set this property value to true when PhonePad is opened while an audio conversation is active.
        /// </summary>
        public Boolean InConversation
        {
            set
            {
                _InConversation = value;
            }
            get
            {
                return _InConversation;
            }
        }

        /// <summary>
        /// Set to string values of either "Speech" or "DTMF". The
        /// set value dictates whether DTMF or speech wav files are played.
        /// </summary>
        public string PlayAudioType
        {
            set
            {
              
                _PlayAudioType = value;

                // If invalid value is supplied, set string to DTMF.
                if (_PlayAudioType != "DTMF" && _PlayAudioType != "Speech")
                {
                    _PlayAudioType = "DTMF";
                }
            }
            get
            {
                return _PlayAudioType; 
            }
        }

        /// <summary>
        /// The concatenated string of user button clicks.
        /// </summary>
        public string DialString
        {
            get
            {
                return labelSentDTMFs.Text;
            }
        }
        #endregion

Constructor

The following example constructs the PhonePadControl and initializes the strings that hold the paths to the audio files that are played.

Important

Initialize the DTMF path and speech path strings to the path where the sample and audio files are saved.

        #region constructors
        public PhonePadControl()
        {
            InitializeComponent();
            this.BackColor = SystemColors.Control;
            labelSentDTMFs.Text = string.Empty;

            // Initialize audio file paths to local user desktop folder + sample application path + audio file folders.
            _userProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory).ToString();
            _DTMFPath = _userProfilePath + @"\Lync_SDK_Samples\PhonePad\DTMF_Files\";
            _speechPath = _userProfilePath + @"\Lync_SDK_Samples\PhonePad\Voice_Files\";
        }
        #endregion

Public Methods

The following examples expose public methods that let calling code clear the dial string or the last character of the dial string.

        #region public methods
        /// <summary>
        /// Clears the string of dialed characters.
        /// </summary>
        public void ClearDialedString()
        {
            labelSentDTMFs.Text = string.Empty;
        }

        /// <summary>
        /// Clears the last character from the dialing DTMF character send history label on the top of the phone pad.
        /// </summary>
        public void ClearLastCharacter()
        {
            if (labelSentDTMFs.Text.Length > 0)
            {
                labelSentDTMFs.Text = labelSentDTMFs.Text.Substring(0, labelSentDTMFs.Text.Length - 1);
            }
        }

        #endregion

Form Event Methods

The following examples handle form events that are raised when a user clicks a button on the telephone keypad.

        #region private form event handlers
        /// <summary>
        /// Reads the text of a button and notifies any event listener that user has clicked a phone keypad button.
        /// </summary>
        private void button_Click(object sender, EventArgs e)
        {
            // Reads the text of the button.
            Button button = sender as Button;
            if (button != null)
            {
                string tone = button.Text;

                // Updates the label with the new tone being sent.
                labelSentDTMFs.Text += tone;

                // If the ButtonClicked delegate is registered, invoke registered event callback method to notify 
                // that a phone pad button was clicked.
                if (ButtonClickedEvent != null)
                {
                    ButtonClickedEvent(tone);
                }
            }
        }
        /// <summary>
        /// Handles the Mouse-down event for each phonepad button on the form
        /// </summary>
        /// <param name="sender">object. The Button control that was clicked by the user</param>
        /// <param name="e">MouseEventArgs. The event state</param>
        private void Button_MouseDownEvent(object sender, MouseEventArgs e)
        {

            Button pressedButton = (Button)sender;

            // Playing an audio file using the DeviceManager.BeginPlayAudiofile
            // creates a conflict with the Lync client when a computer has 
            // only 1 playback device. The audio channel in the Lync conversation
            // preempts the playback device and prevents the audio file playback operation
            // from completing. 
            // The issue is avoided by counting audio devices and then playing back 
            // audio files only when there are two or more playback devices configured.
            if (_LyncClient.DeviceManager.AudioDevices.Count > 1 || _InConversation == false)
            {
                if (_PlayAudioType.ToLower() == "speech")
                {
                    // Speak the character pressed by playing a wav file.
                    SaySpeech(pressedButton.Text);
                }
                else
                {
                    // Play a .wav file representing a DTMF tone.
                    SayDTMFTone(pressedButton.Text);
                }
            }
        }
        #endregion

Private Helper Methods

The following examples play recorded human speech or recorded DTMF tones by calling the DeviceManager.BeginPlayAudioFile method. The code in these examples depend on the fact that the sample audio files have been installed locally and the _speechPath and _DTMFPath string variables contain the correct paths to the audio files. The PhonePad constructor initializes these strings. Update the sample code to reflect the location where you saved the audio files.

        #region private helper methods
        /// <summary>
        /// Plays a .wav file corresponding to the character on the button that was clicked.
        /// </summary>
        /// <param name="whatToSay">string. The character displayed on the clicked button</param>
        private void SaySpeech(string whatToSay)
        {
            string audioPath = _speechPath;
            try
            {
                switch (whatToSay)
                {
                    case "1":
                        audioPath += "ONE.WAV";
                        break;
                    case "2":
                        audioPath += "TWO.WAV";
                        break;
                    case "3":
                        audioPath += "THREE.WAV";
                        break;
                    case "4":
                        audioPath += "FOUR.WAV";
                        break;
                    case "5":
                        audioPath += "FIVE.WAV";
                        break;
                    case "6":
                        audioPath += "SIX.WAV";
                        break;
                    case "7":
                        audioPath += "SEVEN.WAV";
                        break;
                    case "8":
                        audioPath += "EIGHT.WAV";
                        break;
                    case "9":
                        audioPath += "NINE.WAV";
                        break;
                    case "0":
                        audioPath += "ZERO.WAV";
                        break;
                    case "#":
                        audioPath += "POUND.WAV";
                        break;
                    case "*":
                        audioPath += "STAR.WAV";
                        break;

                }
                _LyncClient.DeviceManager.EndPlayAudioFile(
                    _LyncClient.DeviceManager.BeginPlayAudioFile(audioPath,
                        AudioPlayBackModes.Communication,
                    false,
                    null,
                    null));

            }
            catch (Microsoft.Lync.Model.LyncClientException )
            {
                _LyncClient.DeviceManager.EndPlayAudioFile(
                    _LyncClient.DeviceManager.BeginPlayAudioFile(_speechPath + "FileNotFound.WAV",
                    AudioPlayBackModes.Alert,
                    false,
                    null,
                    null));
            }
            catch (System.Runtime.InteropServices.COMException )
            {
                _LyncClient.DeviceManager.EndPlayAudioFile(
                    _LyncClient.DeviceManager.BeginPlayAudioFile(_speechPath + "FileNotFound.WAV",
                    AudioPlayBackModes.Alert,
                    false,
                    null,
                    null));
            }

        }

        /// <summary>
        /// Plays a .wav file representing a DTMF tone. 
        /// </summary>
        /// <param name="whatToSay">string. The character displayed on the clicked phone pad button.</param>
        private void SayDTMFTone(string whatToSay)
        {
            string audioPath = _DTMFPath;

            try
            {
                switch (whatToSay)
                {
                    case "1":
                        audioPath += "DTMF_ONE.WAV";
                        break;
                    case "2":
                        audioPath += "DTMF_TWO.WAV";
                        break;
                    case "3":
                        audioPath += "DTMF_THREE.WAV";
                        break;
                    case "4":
                        audioPath += "DTMF_FOUR.WAV";
                        break;
                    case "5":
                        audioPath += "DTMF_FIVE.WAV";
                        break;
                    case "6":
                        audioPath += "DTMF_SIX.WAV";
                        break;
                    case "7":
                        audioPath += "DTMF_SEVEN.WAV";
                        break;
                    case "8":
                        audioPath += "DTMF_EIGHT.WAV";
                        break;
                    case "9":
                        audioPath += "DTMF_NINE.WAV";
                        break;
                    case "0":
                        audioPath += "DTMF_ZERO.WAV";
                        break;
                    case "#":
                        audioPath += "DTMF_POUND.WAV";
                        break;
                    case "*":
                        audioPath += "DTMF_STAR.WAV";
                        break;

                }
                _LyncClient.DeviceManager.EndPlayAudioFile(
                    _LyncClient.DeviceManager.BeginPlayAudioFile(audioPath,
                    AudioPlayBackModes.AlertAndCommunication,
                    false,
                    null,
                    null));
            }
            catch (Microsoft.Lync.Model.LyncClientException lce)
            {
                MessageBox.Show("Exception on playback: " + lce.Message);
            }
            catch (System.Runtime.InteropServices.COMException comExecpt)
            {
                MessageBox.Show("COM Exception on playback: " + comExecpt.Message);
            }
        }


        #endregion

Additional Resources

For more information, see the following resources:

About the Author

John Austin, Microsoft, is a programmer/writer in the Lync client SDK documentation team. He has been writing Microsoft technical documentation for four years. Prior to working for Microsoft, John spent two decades as a software developer.